├── PerformanceTest iOS ├── Info.plist └── main.m ├── PerformanceTest.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcuserdata │ └── mikeash.xcuserdatad │ └── xcschemes │ ├── PerformanceTest iOS.xcscheme │ ├── PerformanceTest.xcscheme │ └── xcschememanagement.plist ├── PerformanceTest └── main.m ├── perf.h └── perf.mm /PerformanceTest iOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /PerformanceTest iOS/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // PerformanceTest iOS 4 | // 5 | // Created by Mike Ash on 4/10/16. 6 | // Copyright © 2016 mikeash. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "perf.h" 12 | 13 | int main(int argc, char * argv[]) { 14 | @autoreleasepool { 15 | Test(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /PerformanceTest.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | C25FC3E51CBAE4A800894F64 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = C25FC3E41CBAE4A800894F64 /* main.m */; }; 11 | C25FC3F31CBAE4C700894F64 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = C25FC3F21CBAE4C700894F64 /* main.m */; }; 12 | C2E5584B1CBC6E1300F6943C /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C2E5584A1CBC6E1300F6943C /* Cocoa.framework */; }; 13 | C2F597731CBAE5760051D0F0 /* perf.mm in Sources */ = {isa = PBXBuildFile; fileRef = C2F597721CBAE5760051D0F0 /* perf.mm */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 14 | C2F597741CBAE5760051D0F0 /* perf.mm in Sources */ = {isa = PBXBuildFile; fileRef = C2F597721CBAE5760051D0F0 /* perf.mm */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 15 | /* End PBXBuildFile section */ 16 | 17 | /* Begin PBXCopyFilesBuildPhase section */ 18 | C25FC3DF1CBAE4A700894F64 /* CopyFiles */ = { 19 | isa = PBXCopyFilesBuildPhase; 20 | buildActionMask = 2147483647; 21 | dstPath = /usr/share/man/man1/; 22 | dstSubfolderSpec = 0; 23 | files = ( 24 | ); 25 | runOnlyForDeploymentPostprocessing = 1; 26 | }; 27 | /* End PBXCopyFilesBuildPhase section */ 28 | 29 | /* Begin PBXFileReference section */ 30 | C25FC3E11CBAE4A800894F64 /* PerformanceTest Mac */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "PerformanceTest Mac"; sourceTree = BUILT_PRODUCTS_DIR; }; 31 | C25FC3E41CBAE4A800894F64 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 32 | C25FC3EF1CBAE4C700894F64 /* PerformanceTest iOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "PerformanceTest iOS.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 33 | C25FC3F21CBAE4C700894F64 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 34 | C25FC4021CBAE4C700894F64 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 35 | C2E5584A1CBC6E1300F6943C /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; 36 | C2F597721CBAE5760051D0F0 /* perf.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = perf.mm; sourceTree = ""; }; 37 | C2F597751CBAE57D0051D0F0 /* perf.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = perf.h; sourceTree = ""; }; 38 | /* End PBXFileReference section */ 39 | 40 | /* Begin PBXFrameworksBuildPhase section */ 41 | C25FC3DE1CBAE4A700894F64 /* Frameworks */ = { 42 | isa = PBXFrameworksBuildPhase; 43 | buildActionMask = 2147483647; 44 | files = ( 45 | C2E5584B1CBC6E1300F6943C /* Cocoa.framework in Frameworks */, 46 | ); 47 | runOnlyForDeploymentPostprocessing = 0; 48 | }; 49 | C25FC3EC1CBAE4C700894F64 /* Frameworks */ = { 50 | isa = PBXFrameworksBuildPhase; 51 | buildActionMask = 2147483647; 52 | files = ( 53 | ); 54 | runOnlyForDeploymentPostprocessing = 0; 55 | }; 56 | /* End PBXFrameworksBuildPhase section */ 57 | 58 | /* Begin PBXGroup section */ 59 | C25FC3D81CBAE4A700894F64 = { 60 | isa = PBXGroup; 61 | children = ( 62 | C2E5584A1CBC6E1300F6943C /* Cocoa.framework */, 63 | C2F597711CBAE56A0051D0F0 /* Shared */, 64 | C25FC3E31CBAE4A800894F64 /* PerformanceTest */, 65 | C25FC3F01CBAE4C700894F64 /* PerformanceTest iOS */, 66 | C25FC3E21CBAE4A800894F64 /* Products */, 67 | ); 68 | sourceTree = ""; 69 | }; 70 | C25FC3E21CBAE4A800894F64 /* Products */ = { 71 | isa = PBXGroup; 72 | children = ( 73 | C25FC3E11CBAE4A800894F64 /* PerformanceTest Mac */, 74 | C25FC3EF1CBAE4C700894F64 /* PerformanceTest iOS.app */, 75 | ); 76 | name = Products; 77 | sourceTree = ""; 78 | }; 79 | C25FC3E31CBAE4A800894F64 /* PerformanceTest */ = { 80 | isa = PBXGroup; 81 | children = ( 82 | C25FC3E41CBAE4A800894F64 /* main.m */, 83 | ); 84 | path = PerformanceTest; 85 | sourceTree = ""; 86 | }; 87 | C25FC3F01CBAE4C700894F64 /* PerformanceTest iOS */ = { 88 | isa = PBXGroup; 89 | children = ( 90 | C25FC3F21CBAE4C700894F64 /* main.m */, 91 | C25FC4021CBAE4C700894F64 /* Info.plist */, 92 | ); 93 | path = "PerformanceTest iOS"; 94 | sourceTree = ""; 95 | }; 96 | C2F597711CBAE56A0051D0F0 /* Shared */ = { 97 | isa = PBXGroup; 98 | children = ( 99 | C2F597751CBAE57D0051D0F0 /* perf.h */, 100 | C2F597721CBAE5760051D0F0 /* perf.mm */, 101 | ); 102 | name = Shared; 103 | sourceTree = ""; 104 | }; 105 | /* End PBXGroup section */ 106 | 107 | /* Begin PBXNativeTarget section */ 108 | C25FC3E01CBAE4A700894F64 /* PerformanceTest Mac */ = { 109 | isa = PBXNativeTarget; 110 | buildConfigurationList = C25FC3E81CBAE4A800894F64 /* Build configuration list for PBXNativeTarget "PerformanceTest Mac" */; 111 | buildPhases = ( 112 | C25FC3DD1CBAE4A700894F64 /* Sources */, 113 | C25FC3DE1CBAE4A700894F64 /* Frameworks */, 114 | C25FC3DF1CBAE4A700894F64 /* CopyFiles */, 115 | ); 116 | buildRules = ( 117 | ); 118 | dependencies = ( 119 | ); 120 | name = "PerformanceTest Mac"; 121 | productName = PerformanceTest; 122 | productReference = C25FC3E11CBAE4A800894F64 /* PerformanceTest Mac */; 123 | productType = "com.apple.product-type.tool"; 124 | }; 125 | C25FC3EE1CBAE4C700894F64 /* PerformanceTest iOS */ = { 126 | isa = PBXNativeTarget; 127 | buildConfigurationList = C25FC4031CBAE4C700894F64 /* Build configuration list for PBXNativeTarget "PerformanceTest iOS" */; 128 | buildPhases = ( 129 | C25FC3EB1CBAE4C700894F64 /* Sources */, 130 | C25FC3EC1CBAE4C700894F64 /* Frameworks */, 131 | C25FC3ED1CBAE4C700894F64 /* Resources */, 132 | ); 133 | buildRules = ( 134 | ); 135 | dependencies = ( 136 | ); 137 | name = "PerformanceTest iOS"; 138 | productName = "PerformanceTest iOS"; 139 | productReference = C25FC3EF1CBAE4C700894F64 /* PerformanceTest iOS.app */; 140 | productType = "com.apple.product-type.application"; 141 | }; 142 | /* End PBXNativeTarget section */ 143 | 144 | /* Begin PBXProject section */ 145 | C25FC3D91CBAE4A700894F64 /* Project object */ = { 146 | isa = PBXProject; 147 | attributes = { 148 | LastUpgradeCheck = 0730; 149 | ORGANIZATIONNAME = mikeash; 150 | TargetAttributes = { 151 | C25FC3E01CBAE4A700894F64 = { 152 | CreatedOnToolsVersion = 7.3; 153 | }; 154 | C25FC3EE1CBAE4C700894F64 = { 155 | CreatedOnToolsVersion = 7.3; 156 | }; 157 | }; 158 | }; 159 | buildConfigurationList = C25FC3DC1CBAE4A700894F64 /* Build configuration list for PBXProject "PerformanceTest" */; 160 | compatibilityVersion = "Xcode 3.2"; 161 | developmentRegion = English; 162 | hasScannedForEncodings = 0; 163 | knownRegions = ( 164 | en, 165 | Base, 166 | ); 167 | mainGroup = C25FC3D81CBAE4A700894F64; 168 | productRefGroup = C25FC3E21CBAE4A800894F64 /* Products */; 169 | projectDirPath = ""; 170 | projectRoot = ""; 171 | targets = ( 172 | C25FC3E01CBAE4A700894F64 /* PerformanceTest Mac */, 173 | C25FC3EE1CBAE4C700894F64 /* PerformanceTest iOS */, 174 | ); 175 | }; 176 | /* End PBXProject section */ 177 | 178 | /* Begin PBXResourcesBuildPhase section */ 179 | C25FC3ED1CBAE4C700894F64 /* Resources */ = { 180 | isa = PBXResourcesBuildPhase; 181 | buildActionMask = 2147483647; 182 | files = ( 183 | ); 184 | runOnlyForDeploymentPostprocessing = 0; 185 | }; 186 | /* End PBXResourcesBuildPhase section */ 187 | 188 | /* Begin PBXSourcesBuildPhase section */ 189 | C25FC3DD1CBAE4A700894F64 /* Sources */ = { 190 | isa = PBXSourcesBuildPhase; 191 | buildActionMask = 2147483647; 192 | files = ( 193 | C25FC3E51CBAE4A800894F64 /* main.m in Sources */, 194 | C2F597731CBAE5760051D0F0 /* perf.mm in Sources */, 195 | ); 196 | runOnlyForDeploymentPostprocessing = 0; 197 | }; 198 | C25FC3EB1CBAE4C700894F64 /* Sources */ = { 199 | isa = PBXSourcesBuildPhase; 200 | buildActionMask = 2147483647; 201 | files = ( 202 | C25FC3F31CBAE4C700894F64 /* main.m in Sources */, 203 | C2F597741CBAE5760051D0F0 /* perf.mm in Sources */, 204 | ); 205 | runOnlyForDeploymentPostprocessing = 0; 206 | }; 207 | /* End PBXSourcesBuildPhase section */ 208 | 209 | /* Begin XCBuildConfiguration section */ 210 | C25FC3E61CBAE4A800894F64 /* Debug */ = { 211 | isa = XCBuildConfiguration; 212 | buildSettings = { 213 | ALWAYS_SEARCH_USER_PATHS = NO; 214 | CLANG_ANALYZER_NONNULL = YES; 215 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 216 | CLANG_CXX_LIBRARY = "libc++"; 217 | CLANG_ENABLE_MODULES = YES; 218 | CLANG_ENABLE_OBJC_ARC = YES; 219 | CLANG_WARN_BOOL_CONVERSION = YES; 220 | CLANG_WARN_CONSTANT_CONVERSION = YES; 221 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 222 | CLANG_WARN_EMPTY_BODY = YES; 223 | CLANG_WARN_ENUM_CONVERSION = YES; 224 | CLANG_WARN_INT_CONVERSION = YES; 225 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 226 | CLANG_WARN_UNREACHABLE_CODE = YES; 227 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 228 | CODE_SIGN_IDENTITY = "-"; 229 | COPY_PHASE_STRIP = NO; 230 | DEBUG_INFORMATION_FORMAT = dwarf; 231 | ENABLE_STRICT_OBJC_MSGSEND = YES; 232 | ENABLE_TESTABILITY = YES; 233 | GCC_C_LANGUAGE_STANDARD = gnu99; 234 | GCC_DYNAMIC_NO_PIC = NO; 235 | GCC_NO_COMMON_BLOCKS = YES; 236 | GCC_OPTIMIZATION_LEVEL = 0; 237 | GCC_PREPROCESSOR_DEFINITIONS = ( 238 | "DEBUG=1", 239 | "$(inherited)", 240 | ); 241 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 242 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 243 | GCC_WARN_UNDECLARED_SELECTOR = YES; 244 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 245 | GCC_WARN_UNUSED_FUNCTION = YES; 246 | GCC_WARN_UNUSED_VARIABLE = YES; 247 | MACOSX_DEPLOYMENT_TARGET = 10.11; 248 | MTL_ENABLE_DEBUG_INFO = YES; 249 | ONLY_ACTIVE_ARCH = YES; 250 | SDKROOT = macosx; 251 | }; 252 | name = Debug; 253 | }; 254 | C25FC3E71CBAE4A800894F64 /* Release */ = { 255 | isa = XCBuildConfiguration; 256 | buildSettings = { 257 | ALWAYS_SEARCH_USER_PATHS = NO; 258 | CLANG_ANALYZER_NONNULL = YES; 259 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 260 | CLANG_CXX_LIBRARY = "libc++"; 261 | CLANG_ENABLE_MODULES = YES; 262 | CLANG_ENABLE_OBJC_ARC = YES; 263 | CLANG_WARN_BOOL_CONVERSION = YES; 264 | CLANG_WARN_CONSTANT_CONVERSION = YES; 265 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 266 | CLANG_WARN_EMPTY_BODY = YES; 267 | CLANG_WARN_ENUM_CONVERSION = YES; 268 | CLANG_WARN_INT_CONVERSION = YES; 269 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 270 | CLANG_WARN_UNREACHABLE_CODE = YES; 271 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 272 | CODE_SIGN_IDENTITY = "-"; 273 | COPY_PHASE_STRIP = NO; 274 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 275 | ENABLE_NS_ASSERTIONS = NO; 276 | ENABLE_STRICT_OBJC_MSGSEND = YES; 277 | GCC_C_LANGUAGE_STANDARD = gnu99; 278 | GCC_NO_COMMON_BLOCKS = YES; 279 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 280 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 281 | GCC_WARN_UNDECLARED_SELECTOR = YES; 282 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 283 | GCC_WARN_UNUSED_FUNCTION = YES; 284 | GCC_WARN_UNUSED_VARIABLE = YES; 285 | MACOSX_DEPLOYMENT_TARGET = 10.11; 286 | MTL_ENABLE_DEBUG_INFO = NO; 287 | SDKROOT = macosx; 288 | }; 289 | name = Release; 290 | }; 291 | C25FC3E91CBAE4A800894F64 /* Debug */ = { 292 | isa = XCBuildConfiguration; 293 | buildSettings = { 294 | PRODUCT_NAME = "$(TARGET_NAME)"; 295 | }; 296 | name = Debug; 297 | }; 298 | C25FC3EA1CBAE4A800894F64 /* Release */ = { 299 | isa = XCBuildConfiguration; 300 | buildSettings = { 301 | PRODUCT_NAME = "$(TARGET_NAME)"; 302 | }; 303 | name = Release; 304 | }; 305 | C25FC4041CBAE4C700894F64 /* Debug */ = { 306 | isa = XCBuildConfiguration; 307 | buildSettings = { 308 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 309 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 310 | INFOPLIST_FILE = "PerformanceTest iOS/Info.plist"; 311 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 312 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 313 | PRODUCT_BUNDLE_IDENTIFIER = "com.mikeash.PerformanceTest-iOS"; 314 | PRODUCT_NAME = "$(TARGET_NAME)"; 315 | SDKROOT = iphoneos; 316 | TARGETED_DEVICE_FAMILY = "1,2"; 317 | }; 318 | name = Debug; 319 | }; 320 | C25FC4051CBAE4C700894F64 /* Release */ = { 321 | isa = XCBuildConfiguration; 322 | buildSettings = { 323 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 324 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 325 | INFOPLIST_FILE = "PerformanceTest iOS/Info.plist"; 326 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 327 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 328 | PRODUCT_BUNDLE_IDENTIFIER = "com.mikeash.PerformanceTest-iOS"; 329 | PRODUCT_NAME = "$(TARGET_NAME)"; 330 | SDKROOT = iphoneos; 331 | TARGETED_DEVICE_FAMILY = "1,2"; 332 | VALIDATE_PRODUCT = YES; 333 | }; 334 | name = Release; 335 | }; 336 | /* End XCBuildConfiguration section */ 337 | 338 | /* Begin XCConfigurationList section */ 339 | C25FC3DC1CBAE4A700894F64 /* Build configuration list for PBXProject "PerformanceTest" */ = { 340 | isa = XCConfigurationList; 341 | buildConfigurations = ( 342 | C25FC3E61CBAE4A800894F64 /* Debug */, 343 | C25FC3E71CBAE4A800894F64 /* Release */, 344 | ); 345 | defaultConfigurationIsVisible = 0; 346 | defaultConfigurationName = Release; 347 | }; 348 | C25FC3E81CBAE4A800894F64 /* Build configuration list for PBXNativeTarget "PerformanceTest Mac" */ = { 349 | isa = XCConfigurationList; 350 | buildConfigurations = ( 351 | C25FC3E91CBAE4A800894F64 /* Debug */, 352 | C25FC3EA1CBAE4A800894F64 /* Release */, 353 | ); 354 | defaultConfigurationIsVisible = 0; 355 | defaultConfigurationName = Release; 356 | }; 357 | C25FC4031CBAE4C700894F64 /* Build configuration list for PBXNativeTarget "PerformanceTest iOS" */ = { 358 | isa = XCConfigurationList; 359 | buildConfigurations = ( 360 | C25FC4041CBAE4C700894F64 /* Debug */, 361 | C25FC4051CBAE4C700894F64 /* Release */, 362 | ); 363 | defaultConfigurationIsVisible = 0; 364 | defaultConfigurationName = Release; 365 | }; 366 | /* End XCConfigurationList section */ 367 | }; 368 | rootObject = C25FC3D91CBAE4A700894F64 /* Project object */; 369 | } 370 | -------------------------------------------------------------------------------- /PerformanceTest.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /PerformanceTest.xcodeproj/xcuserdata/mikeash.xcuserdatad/xcschemes/PerformanceTest iOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /PerformanceTest.xcodeproj/xcuserdata/mikeash.xcuserdatad/xcschemes/PerformanceTest.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /PerformanceTest.xcodeproj/xcuserdata/mikeash.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | PerformanceTest iOS.xcscheme 8 | 9 | orderHint 10 | 1 11 | 12 | PerformanceTest.xcscheme 13 | 14 | orderHint 15 | 0 16 | 17 | 18 | SuppressBuildableAutocreation 19 | 20 | C25FC3E01CBAE4A700894F64 21 | 22 | primary 23 | 24 | 25 | C25FC3EE1CBAE4C700894F64 26 | 27 | primary 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /PerformanceTest/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // PerformanceTest 4 | // 5 | // Created by Mike Ash on 4/10/16. 6 | // Copyright © 2016 mikeash. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "perf.h" 12 | 13 | 14 | int main(int argc, const char * argv[]) { 15 | @autoreleasepool { 16 | Test(); 17 | } 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /perf.h: -------------------------------------------------------------------------------- 1 | // 2 | // perf_iphone.h 3 | // PerformanceTest 4 | // 5 | // Created by Michael Ash on 4/5/16. 6 | // Copyright © 2016 mikeash. All rights reserved. 7 | // 8 | 9 | #ifdef __cplusplus 10 | extern "C" 11 | #endif 12 | void Test(void); 13 | -------------------------------------------------------------------------------- /perf.mm: -------------------------------------------------------------------------------- 1 | #import 2 | #if TARGET_OS_IOS 3 | #import 4 | #else 5 | #import 6 | #endif 7 | 8 | #import 9 | #import 10 | #import "perf.h" 11 | 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | 18 | 19 | struct RawTestResult { 20 | uint64_t iterations; 21 | uint64_t testsPerIteration; 22 | uint64_t startTime; 23 | uint64_t endTime; 24 | }; 25 | 26 | struct TestResult { 27 | const char *name; 28 | uint64_t iterations; 29 | NSTimeInterval total; 30 | NSTimeInterval each; 31 | }; 32 | 33 | struct TestInfo { 34 | const char *name; 35 | RawTestResult (*fptr)(void); 36 | }; 37 | 38 | static std::vector AllTests; 39 | TestInfo EmptyLoopTest; 40 | TestInfo *RunOnlyTest; 41 | 42 | void Test(void) { 43 | struct mach_timebase_info tbinfo; 44 | mach_timebase_info( &tbinfo ); 45 | auto absToNanos = [&](uint64_t abs) { return abs * tbinfo.numer / tbinfo.denom; }; 46 | 47 | auto overheadResult = EmptyLoopTest.fptr(); 48 | NSTimeInterval totalOverhead = absToNanos(overheadResult.endTime - overheadResult.startTime); 49 | NSTimeInterval overheadPerIteration = totalOverhead / overheadResult.iterations; 50 | 51 | if(RunOnlyTest != NULL) { 52 | AllTests.clear(); 53 | AllTests.push_back(*RunOnlyTest); 54 | } 55 | 56 | std::vector results; 57 | 58 | // size_t i = AllTests.size(); 59 | // while(i --> 0) { 60 | // auto info = AllTests[i]; 61 | for(auto info : AllTests) { 62 | @autoreleasepool { 63 | NSLog(@"Beginning test %s", info.name); 64 | auto rawResult = info.fptr(); 65 | NSTimeInterval totalTime = absToNanos(rawResult.endTime - rawResult.startTime); 66 | NSTimeInterval totalMinusOverhead = totalTime - rawResult.iterations * overheadPerIteration; 67 | NSTimeInterval timePerIteration = totalMinusOverhead / (rawResult.iterations * rawResult.testsPerIteration); 68 | NSLog(@"Completed test %s in %f seconds total, %fns each", info.name, totalMinusOverhead / NSEC_PER_SEC, timePerIteration); 69 | 70 | TestResult result; 71 | result.name = info.name; 72 | result.iterations = rawResult.iterations * rawResult.testsPerIteration; 73 | result.total = totalMinusOverhead / NSEC_PER_SEC; 74 | result.each = timePerIteration; 75 | results.push_back(result); 76 | } 77 | } 78 | 79 | printf("\n"); 80 | 81 | std::sort(results.begin(), results.end(), [](TestResult &a, TestResult &b) { return a.each < b.each; }); 82 | for(auto result : results) { 83 | printf("\n", result.name, result.iterations, result.total, result.each); 84 | } 85 | 86 | printf("
NameIterationsTotal time (sec)Time per (ns)
%s%" PRIu64 "%.1f%.1f
\n"); 87 | } 88 | 89 | struct RegisterTest { 90 | TestInfo info; 91 | 92 | RegisterTest(const char *name, RawTestResult (*fptr)(void)) { 93 | info.name = name; 94 | info.fptr = fptr; 95 | 96 | if(strcmp(name, "Empty loop") == 0) { 97 | EmptyLoopTest = info; 98 | } else { 99 | AllTests.push_back(info); 100 | } 101 | } 102 | 103 | /// Add a call to this after DECLARE_TEST to make this the only performance test that runs, 104 | /// so you don't have to wait through the whole test cycle to check one while working on it. 105 | RegisterTest runOnlyThis() { 106 | RunOnlyTest = new TestInfo; 107 | *RunOnlyTest = info; 108 | return *this; 109 | } 110 | }; 111 | 112 | #define CONCAT2(x, y) x ## y 113 | #define CONCAT(x, y) CONCAT2(x, y) 114 | 115 | #define DECLARE_TEST(_name, _iterations, _testsPerIteration, _setupCode, _testCode, _cleanupCode) \ 116 | static RegisterTest CONCAT(test, __COUNTER__) = RegisterTest(_name, []() -> RawTestResult { \ 117 | RawTestResult info; \ 118 | info.iterations = _iterations; \ 119 | info.testsPerIteration = _testsPerIteration; \ 120 | _setupCode; \ 121 | info.startTime = mach_absolute_time(); \ 122 | for(uint64_t i = 1; i <= _iterations; i++) { \ 123 | /* NOTE: i starts from 1 so it can be used as a divisor for integer division testing, silly I know. */ \ 124 | _testCode; \ 125 | } \ 126 | info.endTime = mach_absolute_time(); \ 127 | _cleanupCode; \ 128 | return info; \ 129 | }) 130 | 131 | DECLARE_TEST("Empty loop", 1000000000, 1, {}, {}, {}); 132 | 133 | 134 | class StubClass 135 | { 136 | public: 137 | virtual void stub() { } 138 | }; 139 | 140 | DECLARE_TEST("C++ virtual method call", 100000000, 10, 141 | class StubClass *obj = new StubClass, 142 | obj->stub(); 143 | obj->stub(); 144 | obj->stub(); 145 | obj->stub(); 146 | obj->stub(); 147 | obj->stub(); 148 | obj->stub(); 149 | obj->stub(); 150 | obj->stub(); 151 | obj->stub();, 152 | delete obj); 153 | 154 | @interface DummyClass: NSObject 155 | - (void)dummyMethod; 156 | @end 157 | @implementation DummyClass 158 | - (void)dummyMethod {} 159 | @end 160 | 161 | DECLARE_TEST("Objective-C message send", 100000000, 10, 162 | DummyClass *dummy = [[DummyClass alloc] init], 163 | [dummy dummyMethod]; 164 | [dummy dummyMethod]; 165 | [dummy dummyMethod]; 166 | [dummy dummyMethod]; 167 | [dummy dummyMethod]; 168 | [dummy dummyMethod]; 169 | [dummy dummyMethod]; 170 | [dummy dummyMethod]; 171 | [dummy dummyMethod]; 172 | [dummy dummyMethod];, 173 | [dummy release]); 174 | 175 | DECLARE_TEST("IMP-cached message send", 100000000, 10, 176 | DummyClass *dummy = [[DummyClass alloc] init]; 177 | SEL sel = @selector(dummyMethod); 178 | void (*imp)(id, SEL) = (void (*)(id, SEL))[dummy methodForSelector: sel], 179 | imp(dummy, sel); 180 | imp(dummy, sel); 181 | imp(dummy, sel); 182 | imp(dummy, sel); 183 | imp(dummy, sel); 184 | imp(dummy, sel); 185 | imp(dummy, sel); 186 | imp(dummy, sel); 187 | imp(dummy, sel); 188 | imp(dummy, sel);, 189 | [dummy release]); 190 | 191 | DECLARE_TEST("NSInvocation message send", 1000000, 10, 192 | DummyClass *dummy = [[DummyClass alloc] init]; 193 | SEL sel = @selector(dummyMethod); 194 | NSInvocation *invocation = [NSInvocation invocationWithMethodSignature: [dummy methodSignatureForSelector: sel]]; 195 | [invocation setSelector: sel]; 196 | [invocation setTarget: dummy];, 197 | [invocation invoke]; 198 | [invocation invoke]; 199 | [invocation invoke]; 200 | [invocation invoke]; 201 | [invocation invoke]; 202 | [invocation invoke]; 203 | [invocation invoke]; 204 | [invocation invoke]; 205 | [invocation invoke]; 206 | [invocation invoke];, 207 | [dummy release]); 208 | 209 | DECLARE_TEST("Integer division", 100000000, 10, 210 | int x, 211 | x = 1000000000 / i; 212 | x = 1000000000 / i; 213 | x = 1000000000 / i; 214 | x = 1000000000 / i; 215 | x = 1000000000 / i; 216 | x = 1000000000 / i; 217 | x = 1000000000 / i; 218 | x = 1000000000 / i; 219 | x = 1000000000 / i; 220 | x = 1000000000 / i;, 221 | ); 222 | 223 | DECLARE_TEST("Floating-point division", 100000000, 10, 224 | double x; 225 | double y = 42.3;, 226 | x = 100000000.0 / y; 227 | x = 100000000.0 / y; 228 | x = 100000000.0 / y; 229 | x = 100000000.0 / y; 230 | x = 100000000.0 / y; 231 | x = 100000000.0 / y; 232 | x = 100000000.0 / y; 233 | x = 100000000.0 / y; 234 | x = 100000000.0 / y; 235 | x = 100000000.0 / y;, 236 | ); 237 | 238 | DECLARE_TEST("Floating-point division with integer conversion", 100000000, 10, 239 | double x, 240 | x = 100000000.0 / i; 241 | x = 100000000.0 / i; 242 | x = 100000000.0 / i; 243 | x = 100000000.0 / i; 244 | x = 100000000.0 / i; 245 | x = 100000000.0 / i; 246 | x = 100000000.0 / i; 247 | x = 100000000.0 / i; 248 | x = 100000000.0 / i; 249 | x = 100000000.0 / i;, 250 | ); 251 | 252 | extern "C" void objc_release(id); 253 | extern "C" void objc_retain(id); 254 | 255 | DECLARE_TEST("ObjC retain and release", 10000000, 10, 256 | id obj = [[NSObject alloc] init], 257 | objc_retain(obj); objc_release(obj); 258 | objc_retain(obj); objc_release(obj); 259 | objc_retain(obj); objc_release(obj); 260 | objc_retain(obj); objc_release(obj); 261 | objc_retain(obj); objc_release(obj); 262 | objc_retain(obj); objc_release(obj); 263 | objc_retain(obj); objc_release(obj); 264 | objc_retain(obj); objc_release(obj); 265 | objc_retain(obj); objc_release(obj); 266 | objc_retain(obj); objc_release(obj);, 267 | objc_release(obj)); 268 | 269 | DECLARE_TEST("Object creation", 1000000, 10, {}, 270 | objc_release([[NSObject alloc] init]); 271 | objc_release([[NSObject alloc] init]); 272 | objc_release([[NSObject alloc] init]); 273 | objc_release([[NSObject alloc] init]); 274 | objc_release([[NSObject alloc] init]); 275 | objc_release([[NSObject alloc] init]); 276 | objc_release([[NSObject alloc] init]); 277 | objc_release([[NSObject alloc] init]); 278 | objc_release([[NSObject alloc] init]); 279 | objc_release([[NSObject alloc] init]);, 280 | ); 281 | 282 | DECLARE_TEST("Autorelease pool push/pop", 10000000, 10, {}, 283 | @autoreleasepool {} 284 | @autoreleasepool {} 285 | @autoreleasepool {} 286 | @autoreleasepool {} 287 | @autoreleasepool {} 288 | @autoreleasepool {} 289 | @autoreleasepool {} 290 | @autoreleasepool {} 291 | @autoreleasepool {} 292 | @autoreleasepool {}, 293 | ); 294 | 295 | DECLARE_TEST("16-byte malloc/free", 10000000, 10, {}, 296 | free(malloc(16)); 297 | free(malloc(16)); 298 | free(malloc(16)); 299 | free(malloc(16)); 300 | free(malloc(16)); 301 | free(malloc(16)); 302 | free(malloc(16)); 303 | free(malloc(16)); 304 | free(malloc(16)); 305 | free(malloc(16));, 306 | ); 307 | 308 | DECLARE_TEST("16MB malloc/free", 1000000, 10, {}, 309 | free(malloc(1 << 24)); 310 | free(malloc(1 << 24)); 311 | free(malloc(1 << 24)); 312 | free(malloc(1 << 24)); 313 | free(malloc(1 << 24)); 314 | free(malloc(1 << 24)); 315 | free(malloc(1 << 24)); 316 | free(malloc(1 << 24)); 317 | free(malloc(1 << 24)); 318 | free(malloc(1 << 24));, 319 | ); 320 | 321 | #define DECLARE_MEMCPY_TEST(humanSize, machineSize, count) \ 322 | DECLARE_TEST(humanSize " memcpy", count, 10, \ 323 | char *src = (char *)calloc((machineSize) + 16, 1); \ 324 | char *dst = (char *)malloc((machineSize) + 16); \ 325 | char *offsetSrc = src + 16; \ 326 | char *offsetDst = dst + 16;, \ 327 | memcpy(offsetDst, offsetSrc, machineSize); \ 328 | memcpy(offsetDst, offsetSrc, machineSize); \ 329 | memcpy(offsetDst, offsetSrc, machineSize); \ 330 | memcpy(offsetDst, offsetSrc, machineSize); \ 331 | memcpy(offsetDst, offsetSrc, machineSize); \ 332 | memcpy(offsetDst, offsetSrc, machineSize); \ 333 | memcpy(offsetDst, offsetSrc, machineSize); \ 334 | memcpy(offsetDst, offsetSrc, machineSize); \ 335 | memcpy(offsetDst, offsetSrc, machineSize); \ 336 | memcpy(offsetDst, offsetSrc, machineSize);, \ 337 | free(src); \ 338 | free(dst)) 339 | 340 | DECLARE_MEMCPY_TEST("16 byte", 16, 100000000); 341 | DECLARE_MEMCPY_TEST("1MB", 1 << 20, 10000); 342 | 343 | static NSString *tmpFilePath = [NSTemporaryDirectory() stringByAppendingPathComponent: @"testrand"]; 344 | 345 | #define DECLARE_WRITE_FILE_TEST(humanSize, machineSize, count, atomic) \ 346 | DECLARE_TEST(atomic ? "Write " humanSize " file (atomic)" : "Write " humanSize " file", count, 1, \ 347 | NSData *data = [[NSFileHandle fileHandleForReadingAtPath: @"/dev/random"] readDataOfLength: machineSize], \ 348 | [data writeToFile: tmpFilePath atomically: atomic], \ 349 | [[NSFileManager defaultManager] removeItemAtPath: tmpFilePath error: NULL]) 350 | 351 | DECLARE_WRITE_FILE_TEST("16 byte", 16, 10000, NO); 352 | DECLARE_WRITE_FILE_TEST("16 byte", 16, 10000, YES); 353 | DECLARE_WRITE_FILE_TEST("16MB", 1 << 24, 30, NO); 354 | DECLARE_WRITE_FILE_TEST("16MB", 1 << 24, 30, YES); 355 | 356 | #define DECLARE_READ_FILE_TEST(humanSize, machineSize, count) \ 357 | DECLARE_TEST("Read " humanSize " file", count, 1, \ 358 | NSData *data = [[NSFileHandle fileHandleForReadingAtPath: @"/dev/random"] readDataOfLength: machineSize]; \ 359 | [data writeToFile: tmpFilePath atomically: NO];, \ 360 | [[[NSData alloc] initWithContentsOfFile: tmpFilePath] release], \ 361 | [[NSFileManager defaultManager] removeItemAtPath: tmpFilePath error: NULL]) 362 | 363 | DECLARE_READ_FILE_TEST("16 byte", 16, 1000000); 364 | DECLARE_READ_FILE_TEST("16MB", 1 << 24, 1000); 365 | 366 | static void *stub_pthread( void * ) 367 | { 368 | return NULL; 369 | } 370 | 371 | DECLARE_TEST("pthread create/join", 100000, 1, {}, 372 | pthread_t pt; 373 | pthread_create(&pt, NULL, stub_pthread, NULL); 374 | pthread_join(pt, NULL);, 375 | {}); 376 | 377 | DECLARE_TEST("Dispatch queue create/destroy", 1000000, 10, {}, 378 | dispatch_release(dispatch_queue_create("dummy testing queue", NULL)); 379 | dispatch_release(dispatch_queue_create("dummy testing queue", NULL)); 380 | dispatch_release(dispatch_queue_create("dummy testing queue", NULL)); 381 | dispatch_release(dispatch_queue_create("dummy testing queue", NULL)); 382 | dispatch_release(dispatch_queue_create("dummy testing queue", NULL)); 383 | dispatch_release(dispatch_queue_create("dummy testing queue", NULL)); 384 | dispatch_release(dispatch_queue_create("dummy testing queue", NULL)); 385 | dispatch_release(dispatch_queue_create("dummy testing queue", NULL)); 386 | dispatch_release(dispatch_queue_create("dummy testing queue", NULL)); 387 | dispatch_release(dispatch_queue_create("dummy testing queue", NULL));, 388 | {}); 389 | 390 | DECLARE_TEST("Dispatch_sync", 10000000, 10, 391 | dispatch_queue_t queue = dispatch_queue_create("dummy testing queue", NULL), 392 | dispatch_sync(queue, ^{}); 393 | dispatch_sync(queue, ^{}); 394 | dispatch_sync(queue, ^{}); 395 | dispatch_sync(queue, ^{}); 396 | dispatch_sync(queue, ^{}); 397 | dispatch_sync(queue, ^{}); 398 | dispatch_sync(queue, ^{}); 399 | dispatch_sync(queue, ^{}); 400 | dispatch_sync(queue, ^{}); 401 | dispatch_sync(queue, ^{});, 402 | dispatch_release(queue)); 403 | 404 | DECLARE_TEST("Dispatch_async and wait", 100000, 10, 405 | dispatch_queue_t queue = dispatch_queue_create("dummy testing queue", NULL); 406 | __block volatile int done, 407 | done = 0; dispatch_async(queue, ^{ done = 1; }); while(!done); 408 | done = 0; dispatch_async(queue, ^{ done = 1; }); while(!done); 409 | done = 0; dispatch_async(queue, ^{ done = 1; }); while(!done); 410 | done = 0; dispatch_async(queue, ^{ done = 1; }); while(!done); 411 | done = 0; dispatch_async(queue, ^{ done = 1; }); while(!done); 412 | done = 0; dispatch_async(queue, ^{ done = 1; }); while(!done); 413 | done = 0; dispatch_async(queue, ^{ done = 1; }); while(!done); 414 | done = 0; dispatch_async(queue, ^{ done = 1; }); while(!done); 415 | done = 0; dispatch_async(queue, ^{ done = 1; }); while(!done); 416 | done = 0; dispatch_async(queue, ^{ done = 1; }); while(!done);, 417 | dispatch_release(queue)); 418 | 419 | @interface DelayedPerformClass: NSObject @end 420 | @implementation DelayedPerformClass { 421 | uint64_t _currentIteration; 422 | @public 423 | uint64_t _iterationLimit; 424 | } 425 | 426 | - (void)delayedPerform { 427 | if(_currentIteration++ < _iterationLimit) { 428 | [self performSelector: @selector(delayedPerform) withObject: nil afterDelay: 0]; 429 | } else { 430 | CFRunLoopStop(CFRunLoopGetCurrent()); 431 | } 432 | } 433 | 434 | @end 435 | 436 | DECLARE_TEST("Zero-zecond delayed perform", 100000, 1, 437 | DelayedPerformClass *obj = [[DelayedPerformClass alloc] init]; 438 | obj->_iterationLimit = 100000;, 439 | [obj performSelector: @selector(delayedPerform) withObject: nil afterDelay: 0]; 440 | CFRunLoopRun(); 441 | break;, /* We do our own loop, so break out of the testing loop. Uuuugly. */ 442 | [obj release]); 443 | 444 | DECLARE_TEST("Simple JSON encode", 1000000, 1, 445 | NSDictionary *dict = (@{@"one": @"won", @"two": @2, @"three": @"free"}), 446 | @autoreleasepool { 447 | [NSJSONSerialization dataWithJSONObject: dict options: 0 error: NULL]; 448 | }, 449 | {}); 450 | 451 | DECLARE_TEST("Simple JSON decode", 1000000, 1, 452 | NSDictionary *dict = (@{@"one": @"won", @"two": @2, @"three": @"free"}); 453 | NSData *json = [NSJSONSerialization dataWithJSONObject: dict options: 0 error: NULL], 454 | @autoreleasepool { 455 | [NSJSONSerialization JSONObjectWithData: json options: 0 error: NULL]; 456 | }, 457 | {}); 458 | 459 | DECLARE_TEST("Simple XML plist encode", 1000000, 1, 460 | NSDictionary *dict = (@{@"one": @"won", @"two": @2, @"three": @"free"}), 461 | @autoreleasepool { 462 | [NSPropertyListSerialization dataWithPropertyList:dict format: NSPropertyListXMLFormat_v1_0 options: 0 error: NULL]; 463 | }, 464 | {}); 465 | 466 | DECLARE_TEST("Simple binary plist encode", 1000000, 1, 467 | NSDictionary *dict = (@{@"one": @"won", @"two": @2, @"three": @"free"}), 468 | @autoreleasepool { 469 | [NSPropertyListSerialization dataWithPropertyList:dict format: NSPropertyListBinaryFormat_v1_0 options: 0 error: NULL]; 470 | }, 471 | {}); 472 | 473 | DECLARE_TEST("Simple XML plist decode", 1000000, 1, 474 | NSDictionary *dict = (@{@"one": @"won", @"two": @2, @"three": @"free"}); 475 | NSData *plist = [NSPropertyListSerialization dataWithPropertyList:dict format: NSPropertyListXMLFormat_v1_0 options: 0 error: NULL], 476 | @autoreleasepool { 477 | [NSPropertyListSerialization propertyListWithData: plist options: 0 format: NULL error: NULL]; 478 | }, 479 | {}); 480 | 481 | DECLARE_TEST("Simple binary plist decode", 1000000, 1, 482 | NSDictionary *dict = (@{@"one": @"won", @"two": @2, @"three": @"free"}); 483 | NSData *plist = [NSPropertyListSerialization dataWithPropertyList:dict format: NSPropertyListBinaryFormat_v1_0 options: 0 error: NULL], 484 | @autoreleasepool { 485 | [NSPropertyListSerialization propertyListWithData: plist options: 0 format: NULL error: NULL]; 486 | }, 487 | {}); 488 | 489 | #pragma mark Mac-specific tests 490 | 491 | #if !TARGET_OS_IOS 492 | DECLARE_TEST("NSTask process spawn", 100, 1, {}, 493 | NSTask *task = [[NSTask alloc] init]; 494 | [task setLaunchPath: @"/usr/bin/false"]; 495 | [task launch]; 496 | [task waitUntilExit]; 497 | [task release];, 498 | ); 499 | 500 | DECLARE_TEST("NSWindow create/destroy", 1000, 1, {}, 501 | objc_release([[NSWindow alloc] init]), 502 | {}); 503 | 504 | DECLARE_TEST("NSView create/destroy", 1000000, 1, {}, 505 | objc_release([[NSView alloc] init]), 506 | {}); 507 | #endif 508 | 509 | 510 | #pragma mark iOS-specific tests 511 | 512 | #if TARGET_OS_IOS 513 | DECLARE_TEST("UIView create/destroy", 1000000, 1, {}, 514 | objc_release([[UIView alloc] init]), 515 | {}); 516 | #endif 517 | 518 | --------------------------------------------------------------------------------