/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import com.google.protobuf.ByteString; import com.google.protobuf.Descriptors.Descriptor; import com.google.protobuf.Descriptors.FieldDescriptor; import com.google.protobuf.ExtensionRegistry; import protos.Typical; import protos.TypicalData; import protos.TypicalDataMessage; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; /** * Tests the performance of protocol buffers. * * @author Keith Stanger */ class PerformanceBenchmarks { public static void main(String[] args) throws Exception { System.out.println("Running performance tests..."); Method[] methods = PerformanceBenchmarks.class.getDeclaredMethods(); for (Method method : methods) { if (method.getName().startsWith("test")) { long startTime = System.currentTimeMillis(); method.invoke(null); long endTime = System.currentTimeMillis(); System.out.println(method.getName() + ": " + (endTime - startTime)); } } } private static void testSetPrimitiveFields() { for (int i = 0; i < 100000; i++) { setAllPrimitiveFields(TypicalData.newBuilder()); } } private static void testGetPrimitiveFields() { TypicalData.Builder builder = TypicalData.newBuilder(); setAllPrimitiveFields(builder); TypicalData data = builder.build(); for (int i = 0; i < 100000; i++) { data.getMyInt(); data.getMyBool(); data.getMyFloat(); data.getMyDouble(); data.getMyUint(); data.getMyLong(); data.getMyUlong(); } } private static void testGetPrimitiveFieldsWithDescriptors() { TypicalData.Builder builder = TypicalData.newBuilder(); setAllPrimitiveFields(builder); TypicalData data = builder.build(); List<FieldDescriptor> fields = getPrimitiveFieldDescriptors(); for (int i = 0; i < 10000; i++) { for (FieldDescriptor field : fields) { data.getField(field); } } } private static void testSetPrimitiveFieldsWithDescriptors() { List<FieldDescriptor> fields = getPrimitiveFieldDescriptors(); List<Object> values = new ArrayList<Object>(); values.add(Integer.valueOf(1)); values.add(Boolean.TRUE); values.add(Float.valueOf(2.3f)); values.add(Double.valueOf(4.5)); values.add(Integer.valueOf(6)); values.add(Long.valueOf(7)); values.add(Long.valueOf(8)); for (int i = 0; i < 5000; i++) { TypicalData.Builder builder = TypicalData.newBuilder(); for (int j = 0; j < 7; j++) { builder.setField(fields.get(j), values.get(j)); } } } private static void testSetRepeatedFields() { for (int i = 0; i < 1000; i++) { setAllRepeatedFields(TypicalData.newBuilder(), 25); } } private static void testGetRepeatedFields() { TypicalData.Builder builder = TypicalData.newBuilder(); setAllRepeatedFields(builder, 25); TypicalData data = builder.build(); for (int i = 0; i < 3000; i++) { for (int j = 0; j < 25; j++) { data.getRepeatedInt32(j); data.getRepeatedInt64(j); data.getRepeatedUint32(j); data.getRepeatedUint64(j); data.getRepeatedBool(j); data.getRepeatedFloat(j); data.getRepeatedDouble(j); data.getRepeatedString(j); data.getRepeatedBytes(j); data.getRepeatedEnum(j); } } } private static void testGetRepeatedFieldList() { TypicalData.Builder builder = TypicalData.newBuilder(); setAllRepeatedFields(builder, 25); TypicalData data = builder.build(); for (int i = 0; i < 2000; i++) { data.getRepeatedInt32List(); data.getRepeatedInt64List(); data.getRepeatedUint32List(); data.getRepeatedUint64List(); data.getRepeatedBoolList(); data.getRepeatedFloatList(); data.getRepeatedDoubleList(); data.getRepeatedStringList(); data.getRepeatedBytesList(); data.getRepeatedEnumList(); } } private static void testClearRepeatedFields() { TypicalData.Builder builder = TypicalData.newBuilder(); for (int i = 0; i < 1000; i++) { setAllRepeatedFields(builder, 25); builder.clearRepeatedInt32(); builder.clearRepeatedInt64(); builder.clearRepeatedUint32(); builder.clearRepeatedUint64(); builder.clearRepeatedBool(); builder.clearRepeatedFloat(); builder.clearRepeatedDouble(); builder.clearRepeatedString(); builder.clearRepeatedBytes(); builder.clearRepeatedEnum(); } } private static void testGetRepeatedFieldsWithDescriptors() { TypicalData.Builder builder = TypicalData.newBuilder(); setAllRepeatedFields(builder, 25); TypicalData data = builder.build(); List<FieldDescriptor> fields = getRepeatedFieldDescriptors(); for (int i = 0; i < 50; i++) { for (int j = 0; j < 25; j++) { for (FieldDescriptor field : fields) { data.getRepeatedField(field, j); } } } } private static void testAddRepeatedFieldsWithDescriptors() { List<FieldDescriptor> fields = getRepeatedFieldDescriptors(); List<Object> values = new ArrayList<Object>(); values.add(Integer.valueOf(1)); values.add(Long.valueOf(2)); values.add(Integer.valueOf(3)); values.add(Long.valueOf(4)); values.add(Boolean.TRUE); values.add(Float.valueOf(5.6f)); values.add(Double.valueOf(7.8)); values.add("foo"); values.add(ByteString.copyFrom("bar".getBytes())); values.add(TypicalData.EnumType.VALUE1.getValueDescriptor()); for (int i = 0; i < 150; i++) { TypicalData.Builder builder = TypicalData.newBuilder(); for (int j = 0; j < 25; j++) { for (int k = 0; k < 10; k++) { builder.addRepeatedField(fields.get(k), values.get(k)); } } } } private static void testSetPrimitiveExtension() { for (int i = 0; i < 3000; i++) { TypicalData.Builder builder = TypicalData.newBuilder(); for (int j = 0; j < 25; j++) { builder.setExtension(Typical.myPrimitiveExtension, j); } } } private static void testGetPrimitiveExtension() { TypicalData data = TypicalData.newBuilder() .setExtension(Typical.myPrimitiveExtension, 3).build(); for (int i = 0; i < 100000; i++) { data.getExtension(Typical.myPrimitiveExtension); } } private static void testWriteTo() throws Exception { TypicalData.Builder builder = TypicalData.newBuilder(); setAllPrimitiveFields(builder); setAllRepeatedFields(builder, 5); setMessageField(builder); TypicalData data = builder.build(); for (int i = 0; i < 10000; i++) { ByteArrayOutputStream out = new ByteArrayOutputStream(); data.writeTo(out); } } private static void testMergeFrom() throws Exception { ByteArrayInputStream in = new ByteArrayInputStream(PROTO_DATA); ExtensionRegistry registry = ExtensionRegistry.getEmptyRegistry(); for (int i = 0; i < 30000; i++) { TypicalData.newBuilder().mergeFrom(in, registry); } } private static void setAllPrimitiveFields(TypicalData.Builder builder) { builder.setMyInt(1); builder.setMyBool(true); builder.setMyFloat(2.3f); builder.setMyDouble(4.5); builder.setMyUint(6); builder.setMyLong(7); builder.setMyUlong(8); } private static void setAllRepeatedFields(TypicalData.Builder builder, int times) { TypicalData.EnumType[] enumValues = TypicalData.EnumType.values(); int numValues = enumValues.length; for (int i = 0; i < times; i++) { builder.addRepeatedInt32(i); builder.addRepeatedInt64(i); builder.addRepeatedUint32(i); builder.addRepeatedUint64(i); builder.addRepeatedBool(i % 2 == 1); builder.addRepeatedFloat(i); builder.addRepeatedDouble(i); builder.addRepeatedString("test" + i); builder.addRepeatedBytes(ByteString.copyFrom(("abc" + i).getBytes())); builder.addRepeatedEnum(enumValues[i % numValues]); } } private static void setMessageField(TypicalData.Builder builder) { builder.setMyMessage(TypicalDataMessage.newBuilder().setMyMessageInt(42).build()); } private static List<FieldDescriptor> getPrimitiveFieldDescriptors() { Descriptor descriptor = TypicalData.Builder.getDescriptor(); List<FieldDescriptor> fields = new ArrayList<FieldDescriptor>(); fields.add(descriptor.findFieldByNumber(1)); fields.add(descriptor.findFieldByNumber(12)); fields.add(descriptor.findFieldByNumber(13)); fields.add(descriptor.findFieldByNumber(14)); fields.add(descriptor.findFieldByNumber(16)); fields.add(descriptor.findFieldByNumber(17)); fields.add(descriptor.findFieldByNumber(18)); return fields; } private static List<FieldDescriptor> getRepeatedFieldDescriptors() { Descriptor descriptor = TypicalData.Builder.getDescriptor(); List<FieldDescriptor> fields = new ArrayList<FieldDescriptor>(); fields.add(descriptor.findFieldByNumber(4)); fields.add(descriptor.findFieldByNumber(19)); fields.add(descriptor.findFieldByNumber(20)); fields.add(descriptor.findFieldByNumber(21)); fields.add(descriptor.findFieldByNumber(5)); fields.add(descriptor.findFieldByNumber(6)); fields.add(descriptor.findFieldByNumber(7)); fields.add(descriptor.findFieldByNumber(8)); fields.add(descriptor.findFieldByNumber(9)); fields.add(descriptor.findFieldByNumber(10)); return fields; } // So we don't have to add byte casts within hard-coded arrays. private static byte[] asBytes(int[] ints) { byte[] bytes = new byte[ints.length]; for (int i = 0; i < ints.length; i++) { bytes[i] = (byte) ints[i]; } return bytes; } private static final byte[] PROTO_DATA = asBytes(new int[] { 0x08, 0x01, 0x20, 0x00, 0x20, 0x01, 0x20, 0x02, 0x20, 0x03, 0x20, 0x04, 0x28, 0x00, 0x28, 0x01, 0x28, 0x00, 0x28, 0x01, 0x28, 0x00, 0x35, 0x00, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x80, 0x3F, 0x35, 0x00, 0x00, 0x00, 0x40, 0x35, 0x00, 0x00, 0x40, 0x40, 0x35, 0x00, 0x00, 0x80, 0x40, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x3F, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x40, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, 0x42, 0x05, 0x74, 0x65, 0x73, 0x74, 0x30, 0x42, 0x05, 0x74, 0x65, 0x73, 0x74, 0x31, 0x42, 0x05, 0x74, 0x65, 0x73, 0x74, 0x32, 0x42, 0x05, 0x74, 0x65, 0x73, 0x74, 0x33, 0x42, 0x05, 0x74, 0x65, 0x73, 0x74, 0x34, 0x4A, 0x04, 0x61, 0x62, 0x63, 0x30, 0x4A, 0x04, 0x61, 0x62, 0x63, 0x31, 0x4A, 0x04, 0x61, 0x62, 0x63, 0x32, 0x4A, 0x04, 0x61, 0x62, 0x63, 0x33, 0x4A, 0x04, 0x61, 0x62, 0x63, 0x34, 0x50, 0x01, 0x50, 0x02, 0x50, 0x03, 0x50, 0x04, 0x50, 0x09, 0x5A, 0x02, 0x08, 0x2A, 0x60, 0x01, 0x6D, 0x33, 0x33, 0x13, 0x40, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x40, 0x80, 0x01, 0x06, 0x88, 0x01, 0x07, 0x90, 0x01, 0x08, 0x98, 0x01, 0x00, 0x98, 0x01, 0x01, 0x98, 0x01, 0x02, 0x98, 0x01, 0x03, 0x98, 0x01, 0x04, 0xA0, 0x01, 0x00, 0xA0, 0x01, 0x01, 0xA0, 0x01, 0x02, 0xA0, 0x01, 0x03, 0xA0, 0x01, 0x04, 0xA8, 0x01, 0x00, 0xA8, 0x01, 0x01, 0xA8, 0x01, 0x02, 0xA8, 0x01, 0x03, 0xA8, 0x01, 0x04 }); }