1// Protocol Buffers - Google's data interchange format 2// Copyright 2013 Google Inc. All rights reserved. 3// https://developers.google.com/protocol-buffers/ 4// 5// Redistribution and use in source and binary forms, with or without 6// modification, are permitted provided that the following conditions are 7// met: 8// 9// * Redistributions of source code must retain the above copyright 10// notice, this list of conditions and the following disclaimer. 11// * Redistributions in binary form must reproduce the above 12// copyright notice, this list of conditions and the following disclaimer 13// in the documentation and/or other materials provided with the 14// distribution. 15// * Neither the name of Google Inc. nor the names of its 16// contributors may be used to endorse or promote products derived from 17// this software without specific prior written permission. 18// 19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31#import "GPBTestUtilities.h" 32#import "google/protobuf/Unittest.pbobjc.h" 33#import "google/protobuf/UnittestImport.pbobjc.h" 34#import "google/protobuf/UnittestObjc.pbobjc.h" 35 36// 37// This file really just uses the unittests framework as a testbed to 38// run some simple performance tests. The data can then be used to help 39// evaluate changes to the runtime. 40// 41 42static const uint32_t kRepeatedCount = 100; 43 44@interface PerfTests : GPBTestCase 45@end 46 47@implementation PerfTests 48 49- (void)setUp { 50 // A convenient place to put a break point if you want to connect instruments. 51 [super setUp]; 52} 53 54- (void)testMessagePerformance { 55 [self measureBlock:^{ 56 for (int i = 0; i < 200; ++i) { 57 TestAllTypes* message = [[TestAllTypes alloc] init]; 58 [self setAllFields:message repeatedCount:kRepeatedCount]; 59 NSData* rawBytes = [message data]; 60 [message release]; 61 message = [[TestAllTypes alloc] initWithData:rawBytes error:NULL]; 62 [message release]; 63 } 64 }]; 65} 66 67- (void)testMessageSerialParsingPerformance { 68 // This and the next test are meant to monitor that the parsing functionality of protos does not 69 // lock across threads when parsing different instances. The Serial version of the test should run 70 // around ~2 times slower than the Parallel version since it's parsing the protos in the same 71 // thread. 72 TestAllTypes *allTypesMessage = [TestAllTypes message]; 73 [self setAllFields:allTypesMessage repeatedCount:2]; 74 NSData *allTypesData = allTypesMessage.data; 75 76 [self measureBlock:^{ 77 for (int i = 0; i < 500; ++i) { 78 [TestAllTypes parseFromData:allTypesData error:NULL]; 79 [TestAllTypes parseFromData:allTypesData error:NULL]; 80 } 81 }]; 82} 83 84- (void)testMessageParallelParsingPerformance { 85 // This and the previous test are meant to monitor that the parsing functionality of protos does 86 // not lock across threads when parsing different instances. The Serial version of the test should 87 // run around ~2 times slower than the Parallel version since it's parsing the protos in the same 88 // thread. 89 TestAllTypes *allTypesMessage = [TestAllTypes message]; 90 [self setAllFields:allTypesMessage repeatedCount:2]; 91 NSData *allTypesData = allTypesMessage.data; 92 93 dispatch_queue_t concurrentQueue = dispatch_queue_create("perfQueue", DISPATCH_QUEUE_CONCURRENT); 94 95 [self measureBlock:^{ 96 for (int i = 0; i < 500; ++i) { 97 dispatch_group_t group = dispatch_group_create(); 98 99 dispatch_group_async(group, concurrentQueue, ^{ 100 [TestAllTypes parseFromData:allTypesData error:NULL]; 101 }); 102 103 dispatch_group_async(group, concurrentQueue, ^{ 104 [TestAllTypes parseFromData:allTypesData error:NULL]; 105 }); 106 107 dispatch_group_notify(group, concurrentQueue, ^{}); 108 109 dispatch_release(group); 110 } 111 }]; 112 113 dispatch_release(concurrentQueue); 114} 115 116- (void)testMessageSerialExtensionsParsingPerformance { 117 // This and the next test are meant to monitor that the parsing functionality of protos does not 118 // lock across threads when parsing different instances when using extensions. The Serial version 119 // of the test should run around ~2 times slower than the Parallel version since it's parsing the 120 // protos in the same thread. 121 TestAllExtensions *allExtensionsMessage = [TestAllExtensions message]; 122 [self setAllExtensions:allExtensionsMessage repeatedCount:2]; 123 NSData *allExtensionsData = allExtensionsMessage.data; 124 125 [self measureBlock:^{ 126 for (int i = 0; i < 500; ++i) { 127 [TestAllExtensions parseFromData:allExtensionsData 128 extensionRegistry:[self extensionRegistry] 129 error:NULL]; 130 [TestAllExtensions parseFromData:allExtensionsData 131 extensionRegistry:[self extensionRegistry] 132 error:NULL]; 133 } 134 }]; 135} 136 137- (void)testMessageParallelExtensionsParsingPerformance { 138 // This and the previous test are meant to monitor that the parsing functionality of protos does 139 // not lock across threads when parsing different instances when using extensions. The Serial 140 // version of the test should run around ~2 times slower than the Parallel version since it's 141 // parsing the protos in the same thread. 142 TestAllExtensions *allExtensionsMessage = [TestAllExtensions message]; 143 [self setAllExtensions:allExtensionsMessage repeatedCount:2]; 144 NSData *allExtensionsData = allExtensionsMessage.data; 145 146 dispatch_queue_t concurrentQueue = dispatch_queue_create("perfQueue", DISPATCH_QUEUE_CONCURRENT); 147 148 [self measureBlock:^{ 149 for (int i = 0; i < 500; ++i) { 150 dispatch_group_t group = dispatch_group_create(); 151 152 dispatch_group_async(group, concurrentQueue, ^{ 153 [TestAllExtensions parseFromData:allExtensionsData 154 extensionRegistry:[UnittestRoot extensionRegistry] 155 error:NULL]; 156 }); 157 158 dispatch_group_async(group, concurrentQueue, ^{ 159 [TestAllExtensions parseFromData:allExtensionsData 160 extensionRegistry:[UnittestRoot extensionRegistry] 161 error:NULL]; 162 }); 163 164 dispatch_group_notify(group, concurrentQueue, ^{}); 165 166 dispatch_release(group); 167 } 168 }]; 169 170 dispatch_release(concurrentQueue); 171} 172 173- (void)testExtensionsPerformance { 174 [self measureBlock:^{ 175 for (int i = 0; i < 200; ++i) { 176 TestAllExtensions* message = [[TestAllExtensions alloc] init]; 177 [self setAllExtensions:message repeatedCount:kRepeatedCount]; 178 NSData* rawBytes = [message data]; 179 [message release]; 180 TestAllExtensions* message2 = 181 [[TestAllExtensions alloc] initWithData:rawBytes error:NULL]; 182 [message2 release]; 183 } 184 }]; 185} 186 187- (void)testPackedTypesPerformance { 188 [self measureBlock:^{ 189 for (int i = 0; i < 1000; ++i) { 190 TestPackedTypes* message = [[TestPackedTypes alloc] init]; 191 [self setPackedFields:message repeatedCount:kRepeatedCount]; 192 NSData* rawBytes = [message data]; 193 [message release]; 194 message = [[TestPackedTypes alloc] initWithData:rawBytes error:NULL]; 195 [message release]; 196 } 197 }]; 198} 199 200- (void)testPackedExtensionsPerformance { 201 [self measureBlock:^{ 202 for (int i = 0; i < 1000; ++i) { 203 TestPackedExtensions* message = [[TestPackedExtensions alloc] init]; 204 [self setPackedExtensions:message repeatedCount:kRepeatedCount]; 205 NSData* rawBytes = [message data]; 206 [message release]; 207 TestPackedExtensions* message2 = 208 [[TestPackedExtensions alloc] initWithData:rawBytes error:NULL]; 209 [message2 release]; 210 } 211 }]; 212} 213 214- (void)testHas { 215 TestAllTypes* message = [self allSetRepeatedCount:1]; 216 [self measureBlock:^{ 217 for (int i = 0; i < 10000; ++i) { 218 [message hasOptionalInt32]; 219 message.hasOptionalInt32 = NO; 220 [message hasOptionalInt32]; 221 222 [message hasOptionalInt64]; 223 message.hasOptionalInt64 = NO; 224 [message hasOptionalInt64]; 225 226 [message hasOptionalUint32]; 227 message.hasOptionalUint32 = NO; 228 [message hasOptionalUint32]; 229 230 [message hasOptionalUint64]; 231 message.hasOptionalUint64 = NO; 232 [message hasOptionalUint64]; 233 234 [message hasOptionalSint32]; 235 message.hasOptionalSint32 = NO; 236 [message hasOptionalSint32]; 237 238 [message hasOptionalSint64]; 239 message.hasOptionalSint64 = NO; 240 [message hasOptionalSint64]; 241 242 [message hasOptionalFixed32]; 243 message.hasOptionalFixed32 = NO; 244 [message hasOptionalFixed32]; 245 246 [message hasOptionalFixed64]; 247 message.hasOptionalFixed64 = NO; 248 [message hasOptionalFixed64]; 249 250 [message hasOptionalSfixed32]; 251 message.hasOptionalSfixed32 = NO; 252 [message hasOptionalSfixed32]; 253 254 [message hasOptionalSfixed64]; 255 message.hasOptionalSfixed64 = NO; 256 [message hasOptionalSfixed64]; 257 258 [message hasOptionalFloat]; 259 message.hasOptionalFloat = NO; 260 [message hasOptionalFloat]; 261 262 [message hasOptionalDouble]; 263 message.hasOptionalDouble = NO; 264 [message hasOptionalDouble]; 265 266 [message hasOptionalBool]; 267 message.hasOptionalBool = NO; 268 [message hasOptionalBool]; 269 270 [message hasOptionalString]; 271 message.hasOptionalString = NO; 272 [message hasOptionalString]; 273 274 [message hasOptionalBytes]; 275 message.hasOptionalBytes = NO; 276 [message hasOptionalBytes]; 277 278 [message hasOptionalGroup]; 279 message.hasOptionalGroup = NO; 280 [message hasOptionalGroup]; 281 282 [message hasOptionalNestedMessage]; 283 message.hasOptionalNestedMessage = NO; 284 [message hasOptionalNestedMessage]; 285 286 [message hasOptionalForeignMessage]; 287 message.hasOptionalForeignMessage = NO; 288 [message hasOptionalForeignMessage]; 289 290 [message hasOptionalImportMessage]; 291 message.hasOptionalImportMessage = NO; 292 [message hasOptionalImportMessage]; 293 294 [message.optionalGroup hasA]; 295 message.optionalGroup.hasA = NO; 296 [message.optionalGroup hasA]; 297 298 [message.optionalNestedMessage hasBb]; 299 message.optionalNestedMessage.hasBb = NO; 300 [message.optionalNestedMessage hasBb]; 301 302 [message.optionalForeignMessage hasC]; 303 message.optionalForeignMessage.hasC = NO; 304 [message.optionalForeignMessage hasC]; 305 306 [message.optionalImportMessage hasD]; 307 message.optionalImportMessage.hasD = NO; 308 [message.optionalImportMessage hasD]; 309 310 [message hasOptionalNestedEnum]; 311 message.hasOptionalNestedEnum = NO; 312 [message hasOptionalNestedEnum]; 313 314 [message hasOptionalForeignEnum]; 315 message.hasOptionalForeignEnum = NO; 316 [message hasOptionalForeignEnum]; 317 318 [message hasOptionalImportEnum]; 319 message.hasOptionalImportEnum = NO; 320 [message hasOptionalImportEnum]; 321 322 [message hasOptionalStringPiece]; 323 message.hasOptionalStringPiece = NO; 324 [message hasOptionalStringPiece]; 325 326 [message hasOptionalCord]; 327 message.hasOptionalCord = NO; 328 [message hasOptionalCord]; 329 330 [message hasDefaultInt32]; 331 message.hasDefaultInt32 = NO; 332 [message hasDefaultInt32]; 333 334 [message hasDefaultInt64]; 335 message.hasDefaultInt64 = NO; 336 [message hasDefaultInt64]; 337 338 [message hasDefaultUint32]; 339 message.hasDefaultUint32 = NO; 340 [message hasDefaultUint32]; 341 342 [message hasDefaultUint64]; 343 message.hasDefaultUint64 = NO; 344 [message hasDefaultUint64]; 345 346 [message hasDefaultSint32]; 347 message.hasDefaultSint32 = NO; 348 [message hasDefaultSint32]; 349 350 [message hasDefaultSint64]; 351 message.hasDefaultSint64 = NO; 352 [message hasDefaultSint64]; 353 354 [message hasDefaultFixed32]; 355 message.hasDefaultFixed32 = NO; 356 [message hasDefaultFixed32]; 357 358 [message hasDefaultFixed64]; 359 message.hasDefaultFixed64 = NO; 360 [message hasDefaultFixed64]; 361 362 [message hasDefaultSfixed32]; 363 message.hasDefaultSfixed32 = NO; 364 [message hasDefaultSfixed32]; 365 366 [message hasDefaultSfixed64]; 367 message.hasDefaultSfixed64 = NO; 368 [message hasDefaultSfixed64]; 369 370 [message hasDefaultFloat]; 371 message.hasDefaultFloat = NO; 372 [message hasDefaultFloat]; 373 374 [message hasDefaultDouble]; 375 message.hasDefaultDouble = NO; 376 [message hasDefaultDouble]; 377 378 [message hasDefaultBool]; 379 message.hasDefaultBool = NO; 380 [message hasDefaultBool]; 381 382 [message hasDefaultString]; 383 message.hasDefaultString = NO; 384 [message hasDefaultString]; 385 386 [message hasDefaultBytes]; 387 message.hasDefaultBytes = NO; 388 [message hasDefaultBytes]; 389 390 [message hasDefaultNestedEnum]; 391 message.hasDefaultNestedEnum = NO; 392 [message hasDefaultNestedEnum]; 393 394 [message hasDefaultForeignEnum]; 395 message.hasDefaultForeignEnum = NO; 396 [message hasDefaultForeignEnum]; 397 398 [message hasDefaultImportEnum]; 399 message.hasDefaultImportEnum = NO; 400 [message hasDefaultImportEnum]; 401 402 [message hasDefaultStringPiece]; 403 message.hasDefaultStringPiece = NO; 404 [message hasDefaultStringPiece]; 405 406 [message hasDefaultCord]; 407 message.hasDefaultCord = NO; 408 [message hasDefaultCord]; 409 } 410 }]; 411} 412 413@end 414