// Protocol Buffers - Google's data interchange format // Copyright 2013 Google Inc. All rights reserved. // https://developers.google.com/protocol-buffers/ // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #import "GPBTestUtilities.h" #import "google/protobuf/Unittest.pbobjc.h" #import "google/protobuf/UnittestImport.pbobjc.h" #import "google/protobuf/UnittestObjc.pbobjc.h" // // This file really just uses the unittests framework as a testbed to // run some simple performance tests. The data can then be used to help // evaluate changes to the runtime. // static const uint32_t kRepeatedCount = 100; @interface PerfTests : GPBTestCase @end @implementation PerfTests - (void)setUp { // A convenient place to put a break point if you want to connect instruments. [super setUp]; } - (void)testMessagePerformance { [self measureBlock:^{ for (int i = 0; i < 200; ++i) { TestAllTypes* message = [[TestAllTypes alloc] init]; [self setAllFields:message repeatedCount:kRepeatedCount]; NSData* rawBytes = [message data]; [message release]; message = [[TestAllTypes alloc] initWithData:rawBytes error:NULL]; [message release]; } }]; } - (void)testMessageSerialParsingPerformance { // This and the next test are meant to monitor that the parsing functionality of protos does not // lock across threads when parsing different instances. The Serial version of the test should run // around ~2 times slower than the Parallel version since it's parsing the protos in the same // thread. TestAllTypes *allTypesMessage = [TestAllTypes message]; [self setAllFields:allTypesMessage repeatedCount:2]; NSData *allTypesData = allTypesMessage.data; [self measureBlock:^{ for (int i = 0; i < 500; ++i) { [TestAllTypes parseFromData:allTypesData error:NULL]; [TestAllTypes parseFromData:allTypesData error:NULL]; } }]; } - (void)testMessageParallelParsingPerformance { // This and the previous test are meant to monitor that the parsing functionality of protos does // not lock across threads when parsing different instances. The Serial version of the test should // run around ~2 times slower than the Parallel version since it's parsing the protos in the same // thread. TestAllTypes *allTypesMessage = [TestAllTypes message]; [self setAllFields:allTypesMessage repeatedCount:2]; NSData *allTypesData = allTypesMessage.data; dispatch_queue_t concurrentQueue = dispatch_queue_create("perfQueue", DISPATCH_QUEUE_CONCURRENT); [self measureBlock:^{ for (int i = 0; i < 500; ++i) { dispatch_group_t group = dispatch_group_create(); dispatch_group_async(group, concurrentQueue, ^{ [TestAllTypes parseFromData:allTypesData error:NULL]; }); dispatch_group_async(group, concurrentQueue, ^{ [TestAllTypes parseFromData:allTypesData error:NULL]; }); dispatch_group_notify(group, concurrentQueue, ^{}); dispatch_release(group); } }]; dispatch_release(concurrentQueue); } - (void)testMessageSerialExtensionsParsingPerformance { // This and the next test are meant to monitor that the parsing functionality of protos does not // lock across threads when parsing different instances when using extensions. The Serial version // of the test should run around ~2 times slower than the Parallel version since it's parsing the // protos in the same thread. TestAllExtensions *allExtensionsMessage = [TestAllExtensions message]; [self setAllExtensions:allExtensionsMessage repeatedCount:2]; NSData *allExtensionsData = allExtensionsMessage.data; [self measureBlock:^{ for (int i = 0; i < 500; ++i) { [TestAllExtensions parseFromData:allExtensionsData extensionRegistry:[self extensionRegistry] error:NULL]; [TestAllExtensions parseFromData:allExtensionsData extensionRegistry:[self extensionRegistry] error:NULL]; } }]; } - (void)testMessageParallelExtensionsParsingPerformance { // This and the previous test are meant to monitor that the parsing functionality of protos does // not lock across threads when parsing different instances when using extensions. The Serial // version of the test should run around ~2 times slower than the Parallel version since it's // parsing the protos in the same thread. TestAllExtensions *allExtensionsMessage = [TestAllExtensions message]; [self setAllExtensions:allExtensionsMessage repeatedCount:2]; NSData *allExtensionsData = allExtensionsMessage.data; dispatch_queue_t concurrentQueue = dispatch_queue_create("perfQueue", DISPATCH_QUEUE_CONCURRENT); [self measureBlock:^{ for (int i = 0; i < 500; ++i) { dispatch_group_t group = dispatch_group_create(); dispatch_group_async(group, concurrentQueue, ^{ [TestAllExtensions parseFromData:allExtensionsData extensionRegistry:[UnittestRoot extensionRegistry] error:NULL]; }); dispatch_group_async(group, concurrentQueue, ^{ [TestAllExtensions parseFromData:allExtensionsData extensionRegistry:[UnittestRoot extensionRegistry] error:NULL]; }); dispatch_group_notify(group, concurrentQueue, ^{}); dispatch_release(group); } }]; dispatch_release(concurrentQueue); } - (void)testExtensionsPerformance { [self measureBlock:^{ for (int i = 0; i < 200; ++i) { TestAllExtensions* message = [[TestAllExtensions alloc] init]; [self setAllExtensions:message repeatedCount:kRepeatedCount]; NSData* rawBytes = [message data]; [message release]; TestAllExtensions* message2 = [[TestAllExtensions alloc] initWithData:rawBytes error:NULL]; [message2 release]; } }]; } - (void)testPackedTypesPerformance { [self measureBlock:^{ for (int i = 0; i < 1000; ++i) { TestPackedTypes* message = [[TestPackedTypes alloc] init]; [self setPackedFields:message repeatedCount:kRepeatedCount]; NSData* rawBytes = [message data]; [message release]; message = [[TestPackedTypes alloc] initWithData:rawBytes error:NULL]; [message release]; } }]; } - (void)testPackedExtensionsPerformance { [self measureBlock:^{ for (int i = 0; i < 1000; ++i) { TestPackedExtensions* message = [[TestPackedExtensions alloc] init]; [self setPackedExtensions:message repeatedCount:kRepeatedCount]; NSData* rawBytes = [message data]; [message release]; TestPackedExtensions* message2 = [[TestPackedExtensions alloc] initWithData:rawBytes error:NULL]; [message2 release]; } }]; } - (void)testHas { TestAllTypes* message = [self allSetRepeatedCount:1]; [self measureBlock:^{ for (int i = 0; i < 10000; ++i) { [message hasOptionalInt32]; message.hasOptionalInt32 = NO; [message hasOptionalInt32]; [message hasOptionalInt64]; message.hasOptionalInt64 = NO; [message hasOptionalInt64]; [message hasOptionalUint32]; message.hasOptionalUint32 = NO; [message hasOptionalUint32]; [message hasOptionalUint64]; message.hasOptionalUint64 = NO; [message hasOptionalUint64]; [message hasOptionalSint32]; message.hasOptionalSint32 = NO; [message hasOptionalSint32]; [message hasOptionalSint64]; message.hasOptionalSint64 = NO; [message hasOptionalSint64]; [message hasOptionalFixed32]; message.hasOptionalFixed32 = NO; [message hasOptionalFixed32]; [message hasOptionalFixed64]; message.hasOptionalFixed64 = NO; [message hasOptionalFixed64]; [message hasOptionalSfixed32]; message.hasOptionalSfixed32 = NO; [message hasOptionalSfixed32]; [message hasOptionalSfixed64]; message.hasOptionalSfixed64 = NO; [message hasOptionalSfixed64]; [message hasOptionalFloat]; message.hasOptionalFloat = NO; [message hasOptionalFloat]; [message hasOptionalDouble]; message.hasOptionalDouble = NO; [message hasOptionalDouble]; [message hasOptionalBool]; message.hasOptionalBool = NO; [message hasOptionalBool]; [message hasOptionalString]; message.hasOptionalString = NO; [message hasOptionalString]; [message hasOptionalBytes]; message.hasOptionalBytes = NO; [message hasOptionalBytes]; [message hasOptionalGroup]; message.hasOptionalGroup = NO; [message hasOptionalGroup]; [message hasOptionalNestedMessage]; message.hasOptionalNestedMessage = NO; [message hasOptionalNestedMessage]; [message hasOptionalForeignMessage]; message.hasOptionalForeignMessage = NO; [message hasOptionalForeignMessage]; [message hasOptionalImportMessage]; message.hasOptionalImportMessage = NO; [message hasOptionalImportMessage]; [message.optionalGroup hasA]; message.optionalGroup.hasA = NO; [message.optionalGroup hasA]; [message.optionalNestedMessage hasBb]; message.optionalNestedMessage.hasBb = NO; [message.optionalNestedMessage hasBb]; [message.optionalForeignMessage hasC]; message.optionalForeignMessage.hasC = NO; [message.optionalForeignMessage hasC]; [message.optionalImportMessage hasD]; message.optionalImportMessage.hasD = NO; [message.optionalImportMessage hasD]; [message hasOptionalNestedEnum]; message.hasOptionalNestedEnum = NO; [message hasOptionalNestedEnum]; [message hasOptionalForeignEnum]; message.hasOptionalForeignEnum = NO; [message hasOptionalForeignEnum]; [message hasOptionalImportEnum]; message.hasOptionalImportEnum = NO; [message hasOptionalImportEnum]; [message hasOptionalStringPiece]; message.hasOptionalStringPiece = NO; [message hasOptionalStringPiece]; [message hasOptionalCord]; message.hasOptionalCord = NO; [message hasOptionalCord]; [message hasDefaultInt32]; message.hasDefaultInt32 = NO; [message hasDefaultInt32]; [message hasDefaultInt64]; message.hasDefaultInt64 = NO; [message hasDefaultInt64]; [message hasDefaultUint32]; message.hasDefaultUint32 = NO; [message hasDefaultUint32]; [message hasDefaultUint64]; message.hasDefaultUint64 = NO; [message hasDefaultUint64]; [message hasDefaultSint32]; message.hasDefaultSint32 = NO; [message hasDefaultSint32]; [message hasDefaultSint64]; message.hasDefaultSint64 = NO; [message hasDefaultSint64]; [message hasDefaultFixed32]; message.hasDefaultFixed32 = NO; [message hasDefaultFixed32]; [message hasDefaultFixed64]; message.hasDefaultFixed64 = NO; [message hasDefaultFixed64]; [message hasDefaultSfixed32]; message.hasDefaultSfixed32 = NO; [message hasDefaultSfixed32]; [message hasDefaultSfixed64]; message.hasDefaultSfixed64 = NO; [message hasDefaultSfixed64]; [message hasDefaultFloat]; message.hasDefaultFloat = NO; [message hasDefaultFloat]; [message hasDefaultDouble]; message.hasDefaultDouble = NO; [message hasDefaultDouble]; [message hasDefaultBool]; message.hasDefaultBool = NO; [message hasDefaultBool]; [message hasDefaultString]; message.hasDefaultString = NO; [message hasDefaultString]; [message hasDefaultBytes]; message.hasDefaultBytes = NO; [message hasDefaultBytes]; [message hasDefaultNestedEnum]; message.hasDefaultNestedEnum = NO; [message hasDefaultNestedEnum]; [message hasDefaultForeignEnum]; message.hasDefaultForeignEnum = NO; [message hasDefaultForeignEnum]; [message hasDefaultImportEnum]; message.hasDefaultImportEnum = NO; [message hasDefaultImportEnum]; [message hasDefaultStringPiece]; message.hasDefaultStringPiece = NO; [message hasDefaultStringPiece]; [message hasDefaultCord]; message.hasDefaultCord = NO; [message hasDefaultCord]; } }]; } @end