Skip to content

Commit 76ef1a7

Browse files
authored
Merge pull request #5 from layoutBox/improve_reporting
Improve reporting + run all benchmarks
2 parents 335106a + 1c8b3d9 commit 76ef1a7

8 files changed

Lines changed: 99 additions & 36 deletions

File tree

.travis.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
language: objective-c
2-
osx_image: xcode8.3
2+
osx_image: xcode9.2
33

44
before_install:
55
- gem install xcpretty-travis-formatter;
66
- gem install cocoapods --no-document --quiet;
77
- pod install --repo-update;
88

99
script:
10-
- set -o pipefail && xcodebuild -workspace LayoutFrameworkBenchmark.xcworkspace -scheme LayoutFrameworkBenchmark -sdk iphonesimulator10.3 -destination 'platform=iOS Simulator,name=iPhone 6' build | xcpretty -f `xcpretty-travis-formatter`
10+
- set -o pipefail && xcodebuild -workspace LayoutFrameworkBenchmark.xcworkspace -scheme LayoutFrameworkBenchmark -sdk iphonesimulator11.2 -destination 'platform=iOS Simulator,name=iPhone 6' build | xcpretty -f `xcpretty-travis-formatter`

LayoutFrameworkBenchmark.xcodeproj/project.pbxproj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,7 @@
313313
);
314314
runOnlyForDeploymentPostprocessing = 0;
315315
shellPath = /bin/sh;
316-
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
316+
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
317317
showEnvVarsInLog = 0;
318318
};
319319
/* End PBXShellScriptBuildPhase section */
@@ -395,7 +395,7 @@
395395
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
396396
GCC_WARN_UNUSED_FUNCTION = YES;
397397
GCC_WARN_UNUSED_VARIABLE = YES;
398-
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
398+
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
399399
MTL_ENABLE_DEBUG_INFO = YES;
400400
ONLY_ACTIVE_ARCH = YES;
401401
SDKROOT = iphoneos;
@@ -440,7 +440,7 @@
440440
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
441441
GCC_WARN_UNUSED_FUNCTION = YES;
442442
GCC_WARN_UNUSED_VARIABLE = YES;
443-
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
443+
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
444444
MTL_ENABLE_DEBUG_INFO = NO;
445445
SDKROOT = iphoneos;
446446
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";

LayoutFrameworkBenchmark.xcodeproj/xcshareddata/xcschemes/LayoutFrameworkBenchmark.xcscheme

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
buildConfiguration = "Debug"
2727
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
2828
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
29+
language = ""
2930
shouldUseLaunchSchemeArgsEnv = "YES">
3031
<Testables>
3132
</Testables>
@@ -45,6 +46,7 @@
4546
buildConfiguration = "Release"
4647
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
4748
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
49+
language = ""
4850
launchStyle = "0"
4951
useCustomWorkingDirectory = "NO"
5052
ignoresPersistentStateOnLaunch = "NO"

LayoutFrameworkBenchmark/Benchmarks/BenchmarkViewController.swift

Lines changed: 62 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -66,39 +66,92 @@ class BenchmarkViewController: UITableViewController {
6666
}
6767

6868
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
69-
return viewControllers.count
69+
return viewControllers.count + 1
7070
}
7171

7272
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
73-
let cell = tableView.dequeueReusableCell(withIdentifier: reuseIdentifier, for: indexPath)
74-
cell.textLabel?.text = viewControllers[indexPath.row].title
75-
return cell
73+
if indexPath.row == 0 {
74+
let cell = UITableViewCell()
75+
cell.textLabel?.text = "Run all benchmarks"
76+
return cell
77+
} else {
78+
let cell = tableView.dequeueReusableCell(withIdentifier: reuseIdentifier, for: indexPath)
79+
cell.textLabel?.text = viewControllers[indexPath.row - 1].title
80+
return cell
81+
}
7682
}
7783

7884
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
79-
let viewControllerData = viewControllers[indexPath.row]
85+
print("\nseconds/ops for each iterations (10, 20, ..., 100)")
86+
print("-------------------------------------")
87+
88+
if indexPath.row == 0 {
89+
runAllBenchmarks()
90+
} else {
91+
let viewControllerData = viewControllers[indexPath.row - 1]
92+
runBenchmark(viewControllerData: viewControllerData, logResults: true, completed: { (results) in
93+
self.printResults(name: viewControllerData.title, results: results)
94+
})
95+
}
96+
}
97+
98+
private func runAllBenchmarks() {
99+
var benchmarkIndex = 0
100+
101+
func benchmarkCompleted(_ results: [Result]) {
102+
printResults(name: viewControllers[benchmarkIndex].title, results: results)
103+
104+
Timer.scheduledTimer(withTimeInterval: 0, repeats: false, block: { (_) in
105+
self.navigationController?.popViewController(animated: false)
106+
107+
benchmarkIndex += 1
108+
if benchmarkIndex < self.viewControllers.count {
109+
self.runBenchmark(viewControllerData: self.viewControllers[benchmarkIndex], logResults: false, completed: benchmarkCompleted)
110+
} else {
111+
print("Completed!")
112+
}
113+
})
114+
}
115+
116+
runBenchmark(viewControllerData: viewControllers[benchmarkIndex], logResults: false, completed: benchmarkCompleted)
117+
}
118+
119+
private func printResults(name: String, results: [Result]) {
120+
var resultsString = "\(name)\t"
121+
results.forEach { (result) in
122+
resultsString += "\(result.secondsPerOperation)\t"
123+
}
124+
print(resultsString)
125+
}
126+
127+
private func runBenchmark(viewControllerData: ViewControllerData, logResults: Bool, completed: ((_ results: [Result]) -> Void)?) {
80128
guard let viewController = viewControllerData.factoryBlock(20) else {
81129
return
82130
}
83131

84-
benchmark(viewControllerData)
132+
benchmark(viewControllerData, logResults: logResults, completed: completed)
85133

86134
viewController.title = viewControllerData.title
87-
navigationController?.pushViewController(viewController, animated: true)
135+
navigationController?.pushViewController(viewController, animated: logResults)
88136
}
89137

90-
private func benchmark(_ viewControllerData: ViewControllerData) {
138+
private func benchmark(_ viewControllerData: ViewControllerData, logResults: Bool, completed: ((_ results: [Result]) -> Void)?) {
91139
let iterations = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
140+
var results: [Result] = []
92141

93142
for i in iterations {
94143
let description = "\(i)\tsubviews\t\(viewControllerData.title)"
95-
Stopwatch.benchmark(description, block: { (stopwatch: Stopwatch) -> Void in
144+
let result = Stopwatch.benchmark(description, logResults: logResults, block: { (stopwatch: Stopwatch) -> Void in
96145
let vc = viewControllerData.factoryBlock(i)
97146
stopwatch.resume()
98147
vc?.view.layoutIfNeeded()
99148
stopwatch.pause()
100149
})
150+
151+
results.append(result)
101152
}
153+
154+
completed?(results)
102155
}
103156
}
104157

LayoutFrameworkBenchmark/Benchmarks/PinLayout/FeedItemPinLayoutView.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -152,15 +152,15 @@ class FeedItemPinLayoutView: UIView, DataBinder {
152152

153153
posterImageView.pin.below(of: actionLabel, aligned: .left).marginTop(10)
154154

155-
posterNameLabel.pin.right(of: posterImageView, aligned: .top).margin(-6, 6).right(hMargin).sizeToFit()
156-
posterHeadlineLabel.pin.below(of: posterNameLabel, aligned: .left).right(hMargin).marginTop(1).sizeToFit()
157-
posterTimeLabel.pin.below(of: posterHeadlineLabel, aligned: .left).right(hMargin).marginTop(1).sizeToFit()
155+
posterNameLabel.pin.right(of: posterImageView, aligned: .top).margin(-6, 6).right(hMargin).sizeToFit(.width)
156+
posterHeadlineLabel.pin.below(of: posterNameLabel, aligned: .left).right(hMargin).marginTop(1).sizeToFit(.width)
157+
posterTimeLabel.pin.below(of: posterHeadlineLabel, aligned: .left).right(hMargin).marginTop(1).sizeToFit(.width)
158158

159-
posterCommentLabel.pin.below(of: posterTimeLabel).left(hMargin).right().right(hMargin).marginTop(vMargin).sizeToFit()
159+
posterCommentLabel.pin.below(of: posterTimeLabel).left(hMargin).right(hMargin).marginTop(vMargin).sizeToFit(.width)
160160

161161
contentImageView.pin.below(of: posterCommentLabel, aligned: .left).right().marginRight(hMargin)
162-
contentTitleLabel.pin.below(of: contentImageView).left().right().marginHorizontal(hMargin).sizeToFit()
163-
contentDomainLabel.pin.below(of: contentTitleLabel, aligned: .left).right().marginRight(hMargin).sizeToFit()
162+
contentTitleLabel.pin.below(of: contentImageView).left().right().marginHorizontal(hMargin).sizeToFit(.width)
163+
contentDomainLabel.pin.below(of: contentTitleLabel, aligned: .left).right().marginRight(hMargin).sizeToFit(.width)
164164

165165
likeLabel.pin.below(of: contentDomainLabel, aligned: .left).marginTop(vMargin)
166166
commentLabel.pin.top(to: likeLabel.edge.top).hCenter(50%)

LayoutFrameworkBenchmark/Benchmarks/Stopwatch.swift

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@
88

99
import Foundation
1010

11+
struct Result {
12+
var iterationCount: Int
13+
var opsPerSecond: Double
14+
var secondsPerOperation: Double
15+
}
16+
1117
/// A stopwatch that can record elapsed time and benchmark closures.
1218
class Stopwatch {
1319

@@ -41,8 +47,8 @@ class Stopwatch {
4147
Benchmarks the block and logs the result.
4248
The block is responsible for calling `resume()` and `pause()` on the stopwatch.
4349
*/
44-
static func benchmark(_ name: String, block: @escaping (_ stopwatch: Stopwatch) -> Void) {
45-
autoreleasepool {
50+
static func benchmark(_ name: String, logResults: Bool, block: @escaping (_ stopwatch: Stopwatch) -> Void) -> Result {
51+
return autoreleasepool { () -> Result in
4652
let stopwatch = Stopwatch(name: name)
4753

4854
// Make sure we collect enough samples.
@@ -61,11 +67,16 @@ class Stopwatch {
6167
}
6268
stopwatch.pause()
6369

64-
let iterations = NSString(format: "%6d", iterationCount)
65-
let opsPerSecond = NSString(format: "%8.2f", Double(iterationCount)/stopwatch.elapsedTime)
66-
let secondsPerOperation = NSString(format: "%8.3f", stopwatch.elapsedTime / Double(iterationCount))
67-
68-
print("\(opsPerSecond)\tops/s\t\(secondsPerOperation)\tseconds/ops\t\(iterations)\titerations\t\(name)")
70+
if logResults {
71+
let iterations = NSString(format: "%6d", iterationCount)
72+
let opsPerSecond = NSString(format: "%8.2f", Double(iterationCount)/stopwatch.elapsedTime)
73+
let secondsPerOperation = NSString(format: "%8.3f", stopwatch.elapsedTime / Double(iterationCount))
74+
print("\(opsPerSecond)\tops/s\t\(secondsPerOperation)\tseconds/ops\t\(iterations)\titerations\t\(name)")
75+
}
76+
77+
return Result(iterationCount: iterationCount,
78+
opsPerSecond: Double(iterationCount) / stopwatch.elapsedTime,
79+
secondsPerOperation: stopwatch.elapsedTime / Double(iterationCount))
6980
}
7081
}
7182
}

Podfile.lock

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
PODS:
2-
- FlexLayout (1.1.1):
3-
- YogaKit (~> 1.6)
2+
- FlexLayout (1.2.2):
3+
- Yoga
44
- LayoutKit (5.0.0)
5-
- PinLayout (1.2.1)
5+
- PinLayout (1.5.4)
66
- Reveal-SDK (10)
77
- Yoga (1.6.0)
8-
- YogaKit (1.6.0):
9-
- Yoga (~> 1.6)
108

119
DEPENDENCIES:
1210
- FlexLayout
@@ -15,13 +13,12 @@ DEPENDENCIES:
1513
- Reveal-SDK
1614

1715
SPEC CHECKSUMS:
18-
FlexLayout: 93a7fd31d83e1dc888164f7de89fba685a4e982a
16+
FlexLayout: 96fb7794cf3d427112cd7f110e958bfe7f02b3af
1917
LayoutKit: 09e015b77fe5cd58696c427d496704b9226876cf
20-
PinLayout: a0e88fc0a5888400144fe336d2300c4012e5f8cc
18+
PinLayout: c5049f38476c193a4fe39920e4878823dfac59fa
2119
Reveal-SDK: 7869ddf1f902cabbb07a1f0dd06bd25861a126f7
2220
Yoga: 81670877477311136b1b3f69a6307ce62e1c89cf
23-
YogaKit: 8fe0ddd21673226c0b6077fc3ad5c8fa6cda722e
2421

2522
PODFILE CHECKSUM: ae655f930c514ff23a524af2662b04f9eb65b4a4
2623

27-
COCOAPODS: 1.3.1
24+
COCOAPODS: 1.2.1

docs_markdown/benchmark.xlsx

636 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)