/* * 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.j2objc.annotations.AutoreleasePool; import com.google.protobuf.AbstractMessage; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import protos.MessageWithExtensions; import protos.NoFields; import protos.SingleInt; import protos.SingleLong; import protos.SingleMessage; import protos.SingleRepeatedInt; import protos.SingleRepeatedLong; import protos.SingleRepeatedMessage; import protos.SizeTest; import protos.TypicalData; /*-[ #include "my_malloc.h" ]-*/ /** * Tests the memory usage of protocol buffers. * * @author Keith Stanger */ class MemoryBenchmarks { // Used to maintain a strong reference to a protocol buffer and avoid // deallocation by the autorelease pool on "testMemUsageInner". private static Object protoReference; public static void main(String[] args) { System.out.println("Running memory usage tests..."); memUsageEmptyProto(NoFields.class); memUsageEmptyProto(MessageWithExtensions.class); memUsageEmptyProto(SingleInt.class); memUsageEmptyProto(SingleLong.class); memUsageEmptyProto(SingleRepeatedInt.class); memUsageEmptyProto(SingleRepeatedLong.class); memUsageEmptyProto(SingleMessage.class); memUsageEmptyProto(SingleRepeatedMessage.class); memUsageEmptyProto(TypicalData.class); memUsageRepeatedInts(1); memUsageRepeatedInts(2); memUsageRepeatedInts(10); memUsageRepeatedInts(50); memUsageSingleInnerMessage(); memUsageRepeatedMessages(1); memUsageRepeatedMessages(2); memUsageRepeatedMessages(10); memUsageIntExtension(); memUsageRepeatedIntExtension(1); memUsageRepeatedIntExtension(2); memUsageRepeatedIntExtension(10); } private static void memUsageEmptyProto(final Class<? extends AbstractMessage> protoClass) { System.out.println("*** memUsageEmptyProto - " + protoClass.getName() + " ***"); testMemUsage(new Runnable() { public void run() { try { protoReference = newBuilder(protoClass); } catch (Exception e) { throw new RuntimeException(e); } } public native Object newBuilder(Class<? extends AbstractMessage> protoClass) /*-[ return [protoClass.objcClass newBuilder]; ]-*/; }); } private static void memUsageRepeatedInts(final int numInts) { System.out.println("*** memUsageRepeatedInts - " + numInts + " ***"); testMemUsage(new Runnable() { public void run() { SingleRepeatedInt.Builder builder = SingleRepeatedInt.newBuilder(); for (int i = 0; i < numInts; i++) { builder.addInt(123); } protoReference = builder.build(); } }); } private static void memUsageSingleInnerMessage() { System.out.println("*** memUsageSingleInnerMessage ***"); testMemUsage(new Runnable() { public void run() { protoReference = SingleMessage.newBuilder().setMsg(NoFields.newBuilder().build()).build(); } }); } private static void memUsageRepeatedMessages(final int numMessages) { System.out.println("*** memUsageRepeatedMessages - " + numMessages + " ***"); testMemUsage(new Runnable() { public void run() { SingleRepeatedMessage.Builder builder = SingleRepeatedMessage.newBuilder(); for (int i = 0; i < numMessages; i++) { builder.addMsg(NoFields.newBuilder().build()); } protoReference = builder.build(); } }); } private static void memUsageIntExtension() { System.out.println("*** memUsageIntExtension ***"); testMemUsage(new Runnable() { public void run() { protoReference = MessageWithExtensions.newBuilder() .setExtension(SizeTest.intExt, 321) .build(); } }); } private static void memUsageRepeatedIntExtension(final int numInts) { System.out.println("*** memUsageRepeatedIntExtension - " + numInts + " ***"); testMemUsage(new Runnable() { public void run() { List<Integer> ints = new ArrayList<Integer>(numInts); for (int i = 0; i < numInts; i++) { ints.add(i); } protoReference = MessageWithExtensions.newBuilder() .setExtension(SizeTest.repeatedIntExt, ints) .build(); } }); } /** * Tests the size of a protocol buffer by enabling the malloc hook, then * calling the provided runnable within an autorelease pool so that all * temporary objects are cleaned up before memory usage is reported. The * runnable parameter must create a protocol buffer and assign it to * "protoReference". */ private static void testMemUsage(Runnable runnable) { // Do a couple pre-runs to avoid capturing allocations that come from class // initialization and other runtime magic. testMemUsageInner(runnable); testMemUsageInner(runnable); protoReference = null; startTrackingMemory(); testMemUsageInner(runnable); stopTrackingMemoryAndReport(); System.out.println(); } @AutoreleasePool private static void testMemUsageInner(Runnable runnable) { runnable.run(); } private static native void startTrackingMemory() /*-[ my_malloc_install(); my_malloc_clear(); ]-*/; private static native void stopTrackingMemoryAndReport() /*-[ my_malloc_reset_and_report(); ]-*/; }