From be3cc0b9ada039aee21eec4041432aee8d12cf29 Mon Sep 17 00:00:00 2001 From: "pc (st21405)" Date: Thu, 30 May 2019 18:22:36 +0900 Subject: [PATCH 1/6] swift 5 comformance --- BuildTimeAnalyzer/ProjectSelection.swift | 0 BuildTimeAnalyzer/RawMeasure.swift | 4 +++- BuildTimeAnalyzer/ViewController.swift | 0 3 files changed, 3 insertions(+), 1 deletion(-) mode change 100644 => 100755 BuildTimeAnalyzer/ProjectSelection.swift mode change 100644 => 100755 BuildTimeAnalyzer/RawMeasure.swift mode change 100644 => 100755 BuildTimeAnalyzer/ViewController.swift diff --git a/BuildTimeAnalyzer/ProjectSelection.swift b/BuildTimeAnalyzer/ProjectSelection.swift old mode 100644 new mode 100755 diff --git a/BuildTimeAnalyzer/RawMeasure.swift b/BuildTimeAnalyzer/RawMeasure.swift old mode 100644 new mode 100755 index ef8fe35..241db29 --- a/BuildTimeAnalyzer/RawMeasure.swift +++ b/BuildTimeAnalyzer/RawMeasure.swift @@ -28,7 +28,9 @@ func ==(lhs: RawMeasure, rhs: RawMeasure) -> Bool { // MARK: Hashable extension RawMeasure: Hashable { + func hash(into hasher: inout Hasher) { - hasher.combine(time.hashValue ^ text.hashValue) + hasher.combine(time) + hasher.combine(text) } } diff --git a/BuildTimeAnalyzer/ViewController.swift b/BuildTimeAnalyzer/ViewController.swift old mode 100644 new mode 100755 From 1ef55aef5dab00c23cb093bcded1b0eb307577fe Mon Sep 17 00:00:00 2001 From: "pc (st21405)" Date: Thu, 30 May 2019 19:14:50 +0900 Subject: [PATCH 2/6] reduce string processing overhead --- BuildTimeAnalyzer/CompileMeasure.swift | 20 +++++++++++--------- BuildTimeAnalyzer/LogProcessor.swift | 25 ++++++++++++++++--------- 2 files changed, 27 insertions(+), 18 deletions(-) mode change 100644 => 100755 BuildTimeAnalyzer/LogProcessor.swift diff --git a/BuildTimeAnalyzer/CompileMeasure.swift b/BuildTimeAnalyzer/CompileMeasure.swift index 1dd0579..6c7ceb1 100755 --- a/BuildTimeAnalyzer/CompileMeasure.swift +++ b/BuildTimeAnalyzer/CompileMeasure.swift @@ -37,19 +37,21 @@ import Foundation } init?(time: Double, rawPath: String, code: String, references: Int) { - let untrimmedFilename = rawPath.split(separator: "/").map(String.init).last - - guard let filepath = rawPath.split(separator: ":").map(String.init).first, - let filename = untrimmedFilename?.split(separator: ":").map(String.init).first else { return nil } - - let locationString = String(rawPath[filepath.endIndex...].dropFirst()) - let locations = locationString.split(separator: ":").compactMap{ Int(String.init($0)) } + let untrimmedFilename: Substring + if let lastIdx = rawPath.lastIndex(of: "/") { + untrimmedFilename = rawPath.suffix(from: rawPath.index(after: lastIdx)) + } else { + untrimmedFilename = rawPath[...] + } + let filepath = rawPath.prefix(while: {$0 != ":"}) + let filename = untrimmedFilename.prefix(while: {$0 != ":"}) + let locations = untrimmedFilename.split(separator: ":").dropFirst().compactMap({Int(String($0))}) guard locations.count == 2 else { return nil } self.time = time self.code = code - self.path = filepath - self.filename = filename + self.path = String(filepath) + self.filename = String(filename) self.locationArray = locations self.references = references } diff --git a/BuildTimeAnalyzer/LogProcessor.swift b/BuildTimeAnalyzer/LogProcessor.swift old mode 100644 new mode 100755 index 4b98e19..3868913 --- a/BuildTimeAnalyzer/LogProcessor.swift +++ b/BuildTimeAnalyzer/LogProcessor.swift @@ -7,6 +7,8 @@ import Foundation typealias CMUpdateClosure = (_ result: [CompileMeasure], _ didComplete: Bool, _ didCancel: Bool) -> () +fileprivate let regex = try! NSRegularExpression(pattern: "^\\d*\\.?\\d*ms\\t/", options: []) + protocol LogProcessorProtocol: class { var rawMeasures: [String: RawMeasure] { get set } var updateHandler: CMUpdateClosure? { get set } @@ -32,25 +34,30 @@ extension LogProcessorProtocol { // MARK: Private methods private func process(text: String) { + let text = text as NSString let characterSet = CharacterSet(charactersIn:"\r\"") - var remainingRange = text.startIndex.. Date: Thu, 30 May 2019 20:06:16 +0900 Subject: [PATCH 3/6] improve performance --- .../xcschemes/BuildTimeAnalyzer.xcscheme | 3 +- BuildTimeAnalyzer/LogProcessor.swift | 42 ++++++++++--------- BuildTimeAnalyzer/RawMeasure.swift | 2 +- 3 files changed, 26 insertions(+), 21 deletions(-) diff --git a/BuildTimeAnalyzer.xcodeproj/xcshareddata/xcschemes/BuildTimeAnalyzer.xcscheme b/BuildTimeAnalyzer.xcodeproj/xcshareddata/xcschemes/BuildTimeAnalyzer.xcscheme index f8d451d..7a47967 100644 --- a/BuildTimeAnalyzer.xcodeproj/xcshareddata/xcschemes/BuildTimeAnalyzer.xcscheme +++ b/BuildTimeAnalyzer.xcodeproj/xcshareddata/xcschemes/BuildTimeAnalyzer.xcscheme @@ -1,6 +1,6 @@ 10 } - if filteredResults.count < 20 { - filteredResults = rawMeasures.values.filter{ $0.time > 0.1 } - } - - let sortedResults = filteredResults.sorted(by: { $0.time > $1.time }) - updateHandler?(processResult(sortedResults), completed, didCancel) - - if completed { - rawMeasures.removeAll() + DispatchQueue.global(qos: .userInteractive).async { + let measures = self.rawMeasures.values + var filteredResults = measures.filter{ $0.time > 10 } + if filteredResults.count < 20 { + filteredResults = measures.filter{ $0.time > 0.1 } + } + + let sortedResults = filteredResults.sorted(by: { $0.time > $1.time }) + let result = self.processResult(sortedResults) + + if completed { + self.rawMeasures.removeAll() + } + + DispatchQueue.main.async { + self.updateHandler?(result, completed, didCancel) + } } } diff --git a/BuildTimeAnalyzer/RawMeasure.swift b/BuildTimeAnalyzer/RawMeasure.swift index 241db29..c0aead0 100755 --- a/BuildTimeAnalyzer/RawMeasure.swift +++ b/BuildTimeAnalyzer/RawMeasure.swift @@ -5,7 +5,7 @@ import Foundation -struct RawMeasure { +class RawMeasure { var time: Double var text: String var references: Int From e07ab48683de4448a5fe8b0493aad9d567bb3345 Mon Sep 17 00:00:00 2001 From: "pc (st21405)" Date: Fri, 31 May 2019 14:20:23 +0900 Subject: [PATCH 4/6] update project setttins --- BuildTimeAnalyzer.xcodeproj/project.pbxproj | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/BuildTimeAnalyzer.xcodeproj/project.pbxproj b/BuildTimeAnalyzer.xcodeproj/project.pbxproj index 21c8586..87d8af8 100644 --- a/BuildTimeAnalyzer.xcodeproj/project.pbxproj +++ b/BuildTimeAnalyzer.xcodeproj/project.pbxproj @@ -252,7 +252,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0730; - LastUpgradeCheck = 0930; + LastUpgradeCheck = 1020; ORGANIZATIONNAME = "Cane Media Ltd"; TargetAttributes = { 2AF8213F1D21D6B900D65186 = { @@ -353,6 +353,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -408,6 +409,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; From cf8173542bd01c4d99d98525684ffecf4a2c6baa Mon Sep 17 00:00:00 2001 From: "pc (st21405)" Date: Wed, 5 Jun 2019 14:10:33 +0900 Subject: [PATCH 5/6] move the extension method into class so we can debug on variables. --- BuildTimeAnalyzer/LogProcessor.swift | 82 ++++++++++++++-------------- 1 file changed, 40 insertions(+), 42 deletions(-) diff --git a/BuildTimeAnalyzer/LogProcessor.swift b/BuildTimeAnalyzer/LogProcessor.swift index 980d374..4ab8e7c 100755 --- a/BuildTimeAnalyzer/LogProcessor.swift +++ b/BuildTimeAnalyzer/LogProcessor.swift @@ -18,30 +18,56 @@ protocol LogProcessorProtocol: class { func processingDidFinish() } -extension LogProcessorProtocol { +class LogProcessor: NSObject, LogProcessorProtocol { + + var rawMeasures: [String: RawMeasure] = [:] + var updateHandler: CMUpdateClosure? + var shouldCancel = false + var timer: Timer? + + func processingDidStart() { + DispatchQueue.main.async { + self.timer = Timer.scheduledTimer(timeInterval: 1.5, target: self, selector: #selector(self.timerCallback(_:)), userInfo: nil, repeats: true) + } + } + + func processingDidFinish() { + DispatchQueue.main.async { + self.timer?.invalidate() + self.timer = nil + let didCancel = self.shouldCancel + self.shouldCancel = false + self.updateResults(didComplete: true, didCancel: didCancel) + } + } + + @objc func timerCallback(_ timer: Timer) { + updateResults(didComplete: false, didCancel: false) + } + func processDatabase(database: XcodeDatabase, updateHandler: CMUpdateClosure?) { guard let text = database.processLog() else { updateHandler?([], true, false) return } - + self.updateHandler = updateHandler - DispatchQueue.global().async { + DispatchQueue.global(qos: .background).async { self.process(text: text) } } - + // MARK: Private methods - + private func process(text: String) { - let text = text as NSString + let text: NSString = text as NSString let characterSet = CharacterSet(charactersIn:"\r\"") var remainingRange = NSMakeRange(0, text.length) rawMeasures.removeAll() - + processingDidStart() - + while true { let nextRange = text.rangeOfCharacter(from: characterSet, options: .literal, range: remainingRange) guard nextRange.location != NSNotFound else { break } @@ -53,7 +79,7 @@ extension LogProcessorProtocol { defer { remainingRange = NSMakeRange(endIdx, remainingRange.upperBound - endIdx) } - + let range = NSMakeRange(beginIdx, textCount) guard let match = regex.firstMatch(in: text as String, options: [], range: range) else { continue } let timeString = text.substring(with: NSMakeRange(beginIdx, match.range.length - 4)) @@ -70,7 +96,7 @@ extension LogProcessorProtocol { } processingDidFinish() } - + fileprivate func updateResults(didComplete completed: Bool, didCancel: Bool) { DispatchQueue.global(qos: .userInteractive).async { let measures = self.rawMeasures.values @@ -91,22 +117,22 @@ extension LogProcessorProtocol { } } } - + private func processResult(_ unprocessedResult: [RawMeasure]) -> [CompileMeasure] { let characterSet = CharacterSet(charactersIn:"\r\"") - + var result: [CompileMeasure] = [] for entry in unprocessedResult { let code = entry.text.split(separator: "\t").map(String.init) let method = code.count >= 2 ? trimPrefixes(code[1]) : "-" - + if let path = code.first?.trimmingCharacters(in: characterSet), let measure = CompileMeasure(time: entry.time, rawPath: path, code: method, references: entry.references) { result.append(measure) } } return result } - + private func trimPrefixes(_ code: String) -> String { var code = code ["@objc ", "final ", "@IBAction "].forEach { (prefix) in @@ -117,31 +143,3 @@ extension LogProcessorProtocol { return code } } - -class LogProcessor: NSObject, LogProcessorProtocol { - - var rawMeasures: [String: RawMeasure] = [:] - var updateHandler: CMUpdateClosure? - var shouldCancel = false - var timer: Timer? - - func processingDidStart() { - DispatchQueue.main.async { - self.timer = Timer.scheduledTimer(timeInterval: 1.5, target: self, selector: #selector(self.timerCallback(_:)), userInfo: nil, repeats: true) - } - } - - func processingDidFinish() { - DispatchQueue.main.async { - self.timer?.invalidate() - self.timer = nil - let didCancel = self.shouldCancel - self.shouldCancel = false - self.updateResults(didComplete: true, didCancel: didCancel) - } - } - - @objc func timerCallback(_ timer: Timer) { - updateResults(didComplete: false, didCancel: false) - } -} From 016fd176a79fdc34c2d8b0c040f5c35de80f27b5 Mon Sep 17 00:00:00 2001 From: "pc (st21405)" Date: Thu, 6 Jun 2019 11:22:41 +0900 Subject: [PATCH 6/6] code refine --- BuildTimeAnalyzer/LogProcessor.swift | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/BuildTimeAnalyzer/LogProcessor.swift b/BuildTimeAnalyzer/LogProcessor.swift index 4ab8e7c..4efbc5d 100755 --- a/BuildTimeAnalyzer/LogProcessor.swift +++ b/BuildTimeAnalyzer/LogProcessor.swift @@ -60,31 +60,28 @@ class LogProcessor: NSObject, LogProcessorProtocol { // MARK: Private methods private func process(text: String) { - let text: NSString = text as NSString - let characterSet = CharacterSet(charactersIn:"\r\"") - var remainingRange = NSMakeRange(0, text.length) + let characterSet = CharacterSet(charactersIn:"\r") + var remainingRange = text.startIndex...init(match.range, in: text)! + let timeString = text[remainingRange.lowerBound..