1 /* 2 * Copyright (C) 2008 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.gson.metrics; 18 19 import static org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertTrue; 21 22 import com.google.gson.Gson; 23 import com.google.gson.JsonParseException; 24 import com.google.gson.annotations.Expose; 25 import com.google.gson.reflect.TypeToken; 26 import java.io.StringWriter; 27 import java.lang.reflect.Type; 28 import java.util.ArrayList; 29 import java.util.HashMap; 30 import java.util.List; 31 import java.util.Map; 32 import org.junit.Before; 33 import org.junit.Ignore; 34 import org.junit.Test; 35 36 /** 37 * Tests to measure performance for Gson. All tests in this file will be disabled in code. To run 38 * them remove disabled_ prefix from the tests and run them. 39 * 40 * @author Inderjeet Singh 41 * @author Joel Leitch 42 */ 43 public class PerformanceTest { 44 private static final int COLLECTION_SIZE = 5000; 45 46 private static final int NUM_ITERATIONS = 100; 47 48 private Gson gson; 49 50 @Before setUp()51 public void setUp() throws Exception { 52 gson = new Gson(); 53 } 54 55 @Test testDummy()56 public void testDummy() { 57 // This is here to prevent Junit for complaining when we disable all tests. 58 } 59 60 @Test 61 @Ignore disabled_testStringDeserialization()62 public void disabled_testStringDeserialization() { 63 StringBuilder sb = new StringBuilder(8096); 64 sb.append("Error Yippie"); 65 66 while (true) { 67 try { 68 String stackTrace = sb.toString(); 69 sb.append(stackTrace); 70 String json = "{\"message\":\"Error message.\"," + "\"stackTrace\":\"" + stackTrace + "\"}"; 71 parseLongJson(json); 72 System.out.println("Gson could handle a string of size: " + stackTrace.length()); 73 } catch (JsonParseException expected) { 74 break; 75 } 76 } 77 } 78 parseLongJson(String json)79 private void parseLongJson(String json) throws JsonParseException { 80 ExceptionHolder target = gson.fromJson(json, ExceptionHolder.class); 81 assertTrue(target.message.contains("Error")); 82 assertTrue(target.stackTrace.contains("Yippie")); 83 } 84 85 private static class ExceptionHolder { 86 public final String message; 87 public final String stackTrace; 88 89 // For use by Gson 90 @SuppressWarnings("unused") ExceptionHolder()91 private ExceptionHolder() { 92 this("", ""); 93 } ExceptionHolder(String message, String stackTrace)94 public ExceptionHolder(String message, String stackTrace) { 95 this.message = message; 96 this.stackTrace = stackTrace; 97 } 98 } 99 100 @SuppressWarnings("unused") 101 private static class CollectionEntry { 102 final String name; 103 final String value; 104 105 // For use by Gson CollectionEntry()106 private CollectionEntry() { 107 this(null, null); 108 } 109 CollectionEntry(String name, String value)110 CollectionEntry(String name, String value) { 111 this.name = name; 112 this.value = value; 113 } 114 } 115 116 /** 117 * Created in response to http://code.google.com/p/google-gson/issues/detail?id=96 118 */ 119 @Test 120 @Ignore disabled_testLargeCollectionSerialization()121 public void disabled_testLargeCollectionSerialization() { 122 int count = 1400000; 123 List<CollectionEntry> list = new ArrayList<>(count); 124 for (int i = 0; i < count; ++i) { 125 list.add(new CollectionEntry("name"+i,"value"+i)); 126 } 127 gson.toJson(list); 128 } 129 130 /** 131 * Created in response to http://code.google.com/p/google-gson/issues/detail?id=96 132 */ 133 @Test 134 @Ignore disabled_testLargeCollectionDeserialization()135 public void disabled_testLargeCollectionDeserialization() { 136 StringBuilder sb = new StringBuilder(); 137 int count = 87000; 138 boolean first = true; 139 sb.append('['); 140 for (int i = 0; i < count; ++i) { 141 if (first) { 142 first = false; 143 } else { 144 sb.append(','); 145 } 146 sb.append("{name:'name").append(i).append("',value:'value").append(i).append("'}"); 147 } 148 sb.append(']'); 149 String json = sb.toString(); 150 Type collectionType = new TypeToken<ArrayList<CollectionEntry>>(){}.getType(); 151 List<CollectionEntry> list = gson.fromJson(json, collectionType); 152 assertEquals(count, list.size()); 153 } 154 155 /** 156 * Created in response to http://code.google.com/p/google-gson/issues/detail?id=96 157 */ 158 // Last I tested, Gson was able to serialize upto 14MB byte array 159 @Test 160 @Ignore disabled_testByteArraySerialization()161 public void disabled_testByteArraySerialization() { 162 for (int size = 4145152; true; size += 1036288) { 163 byte[] ba = new byte[size]; 164 for (int i = 0; i < size; ++i) { 165 ba[i] = 0x05; 166 } 167 gson.toJson(ba); 168 System.out.printf("Gson could serialize a byte array of size: %d\n", size); 169 } 170 } 171 172 /** 173 * Created in response to http://code.google.com/p/google-gson/issues/detail?id=96 174 */ 175 // Last I tested, Gson was able to deserialize a byte array of 11MB 176 @Test 177 @Ignore disabled_testByteArrayDeserialization()178 public void disabled_testByteArrayDeserialization() { 179 for (int numElements = 10639296; true; numElements += 16384) { 180 StringBuilder sb = new StringBuilder(numElements*2); 181 sb.append("["); 182 boolean first = true; 183 for (int i = 0; i < numElements; ++i) { 184 if (first) { 185 first = false; 186 } else { 187 sb.append(","); 188 } 189 sb.append("5"); 190 } 191 sb.append("]"); 192 String json = sb.toString(); 193 byte[] ba = gson.fromJson(json, byte[].class); 194 System.out.printf("Gson could deserialize a byte array of size: %d\n", ba.length); 195 } 196 } 197 198 // The tests to measure serialization and deserialization performance of Gson 199 // Based on the discussion at 200 // http://groups.google.com/group/google-gson/browse_thread/thread/7a50b17a390dfaeb 201 // Test results: 10/19/2009 202 // Serialize classes avg time: 60 ms 203 // Deserialized classes avg time: 70 ms 204 // Serialize exposed classes avg time: 159 ms 205 // Deserialized exposed classes avg time: 173 ms 206 207 @Test 208 @Ignore disabled_testSerializeClasses()209 public void disabled_testSerializeClasses() { 210 ClassWithList c = new ClassWithList("str"); 211 for (int i = 0; i < COLLECTION_SIZE; ++i) { 212 c.list.add(new ClassWithField("element-" + i)); 213 } 214 StringWriter w = new StringWriter(); 215 long t1 = System.currentTimeMillis(); 216 for (int i = 0; i < NUM_ITERATIONS; ++i) { 217 gson.toJson(c, w); 218 } 219 long t2 = System.currentTimeMillis(); 220 long avg = (t2 - t1) / NUM_ITERATIONS; 221 System.out.printf("Serialize classes avg time: %d ms\n", avg); 222 } 223 224 @Test 225 @Ignore disabled_testDeserializeClasses()226 public void disabled_testDeserializeClasses() { 227 String json = buildJsonForClassWithList(); 228 ClassWithList[] target = new ClassWithList[NUM_ITERATIONS]; 229 long t1 = System.currentTimeMillis(); 230 for (int i = 0; i < NUM_ITERATIONS; ++i) { 231 target[i] = gson.fromJson(json, ClassWithList.class); 232 } 233 long t2 = System.currentTimeMillis(); 234 long avg = (t2 - t1) / NUM_ITERATIONS; 235 System.out.printf("Deserialize classes avg time: %d ms\n", avg); 236 } 237 238 @Test 239 @Ignore disabled_testLargeObjectSerializationAndDeserialization()240 public void disabled_testLargeObjectSerializationAndDeserialization() { 241 Map<String, Long> largeObject = new HashMap<>(); 242 for (long l = 0; l < 100000; l++) { 243 largeObject.put("field" + l, l); 244 } 245 246 long t1 = System.currentTimeMillis(); 247 String json = gson.toJson(largeObject); 248 long t2 = System.currentTimeMillis(); 249 System.out.printf("Large object serialized in: %d ms\n", (t2 - t1)); 250 251 t1 = System.currentTimeMillis(); 252 gson.fromJson(json, new TypeToken<Map<String, Long>>() {}.getType()); 253 t2 = System.currentTimeMillis(); 254 System.out.printf("Large object deserialized in: %d ms\n", (t2 - t1)); 255 256 } 257 258 @Test 259 @Ignore disabled_testSerializeExposedClasses()260 public void disabled_testSerializeExposedClasses() { 261 ClassWithListOfObjects c1 = new ClassWithListOfObjects("str"); 262 for (int i1 = 0; i1 < COLLECTION_SIZE; ++i1) { 263 c1.list.add(new ClassWithExposedField("element-" + i1)); 264 } 265 ClassWithListOfObjects c = c1; 266 StringWriter w = new StringWriter(); 267 long t1 = System.currentTimeMillis(); 268 for (int i = 0; i < NUM_ITERATIONS; ++i) { 269 gson.toJson(c, w); 270 } 271 long t2 = System.currentTimeMillis(); 272 long avg = (t2 - t1) / NUM_ITERATIONS; 273 System.out.printf("Serialize exposed classes avg time: %d ms\n", avg); 274 } 275 276 @Test 277 @Ignore disabled_testDeserializeExposedClasses()278 public void disabled_testDeserializeExposedClasses() { 279 String json = buildJsonForClassWithList(); 280 ClassWithListOfObjects[] target = new ClassWithListOfObjects[NUM_ITERATIONS]; 281 long t1 = System.currentTimeMillis(); 282 for (int i = 0; i < NUM_ITERATIONS; ++i) { 283 target[i] = gson.fromJson(json, ClassWithListOfObjects.class); 284 } 285 long t2 = System.currentTimeMillis(); 286 long avg = (t2 - t1) / NUM_ITERATIONS; 287 System.out.printf("Deserialize exposed classes avg time: %d ms\n", avg); 288 } 289 290 @Test 291 @Ignore disabled_testLargeGsonMapRoundTrip()292 public void disabled_testLargeGsonMapRoundTrip() throws Exception { 293 Map<Long, Long> original = new HashMap<>(); 294 for (long i = 0; i < 1000000; i++) { 295 original.put(i, i + 1); 296 } 297 298 Gson gson = new Gson(); 299 String json = gson.toJson(original); 300 Type longToLong = new TypeToken<Map<Long, Long>>(){}.getType(); 301 gson.fromJson(json, longToLong); 302 } 303 buildJsonForClassWithList()304 private String buildJsonForClassWithList() { 305 StringBuilder sb = new StringBuilder("{"); 306 sb.append("field:").append("'str',"); 307 sb.append("list:["); 308 boolean first = true; 309 for (int i = 0; i < COLLECTION_SIZE; ++i) { 310 if (first) { 311 first = false; 312 } else { 313 sb.append(","); 314 } 315 sb.append("{field:'element-" + i + "'}"); 316 } 317 sb.append("]"); 318 sb.append("}"); 319 String json = sb.toString(); 320 return json; 321 } 322 323 @SuppressWarnings("unused") 324 private static final class ClassWithList { 325 final String field; 326 final List<ClassWithField> list = new ArrayList<>(COLLECTION_SIZE); ClassWithList()327 ClassWithList() { 328 this(null); 329 } ClassWithList(String field)330 ClassWithList(String field) { 331 this.field = field; 332 } 333 } 334 335 @SuppressWarnings("unused") 336 private static final class ClassWithField { 337 final String field; ClassWithField()338 ClassWithField() { 339 this(""); 340 } ClassWithField(String field)341 public ClassWithField(String field) { 342 this.field = field; 343 } 344 } 345 346 @SuppressWarnings("unused") 347 private static final class ClassWithListOfObjects { 348 @Expose 349 final String field; 350 @Expose 351 final List<ClassWithExposedField> list = new ArrayList<>(COLLECTION_SIZE); ClassWithListOfObjects()352 ClassWithListOfObjects() { 353 this(null); 354 } ClassWithListOfObjects(String field)355 ClassWithListOfObjects(String field) { 356 this.field = field; 357 } 358 } 359 360 @SuppressWarnings("unused") 361 private static final class ClassWithExposedField { 362 @Expose 363 final String field; ClassWithExposedField()364 ClassWithExposedField() { 365 this(""); 366 } ClassWithExposedField(String field)367 ClassWithExposedField(String field) { 368 this.field = field; 369 } 370 } 371 } 372