1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to you under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  * https://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
14  * implied.  See the License for the specific language governing
15  * permissions and limitations under the License.
16  */
17 
18 #include <limits.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <time.h>
22 
23 #include "avro.h"
24 #include "avro_private.h"
25 
26 
27 /* The following definitions can be used as bitflags. They can also be
28  * passed in as the resolution_mode flags to the helper functions.
29  */
30 #define USE_MATCHED_SCHEMAS (0x00)
31 #define USE_RESOLVED_READER (0x01)
32 #define USE_RESOLVED_WRITER (0x02)
33 #define USE_BOTH_RESOLVED   (0x03)
34 
35 
36 /*
37  * A series of performance tests.
38  */
39 
40 typedef void
41 (*test_func_t)(unsigned long);
42 
43 
init_rand(void)44 void init_rand(void)
45 {
46 	srand(time(NULL));
47 }
48 
rand_number(double from,double to)49 double rand_number(double from, double to)
50 {
51 	double range = to - from;
52 	return from + ((double)rand() / (RAND_MAX + 1.0)) * range;
53 }
54 
rand_int64(void)55 int64_t rand_int64(void)
56 {
57 	return (int64_t) rand_number(LONG_MIN, LONG_MAX);
58 }
59 
rand_int32(void)60 int32_t rand_int32(void)
61 {
62 	return (int32_t) rand_number(INT_MIN, INT_MAX);
63 }
64 
65 
66 /**
67  * Tests the single-threaded performance of our reference counting
68  * mechanism.  We create a single datum, and then reference and
69  * deference it many many times.
70  */
71 
72 static void
test_refcount(unsigned long num_tests)73 test_refcount(unsigned long num_tests)
74 {
75 	unsigned long  i;
76 
77 	avro_datum_t  datum = avro_int32(42);
78 	for (i = 0; i < num_tests; i++) {
79 		avro_datum_incref(datum);
80 		avro_datum_decref(datum);
81 	}
82 	avro_datum_decref(datum);
83 }
84 
85 
86 /**
87  * Tests the performance of serializing and deserializing a somewhat
88  * complex record type using the legacy datum API.
89  */
90 
91 static void
test_nested_record_datum(unsigned long num_tests)92 test_nested_record_datum(unsigned long num_tests)
93 {
94 	static const char  *schema_json =
95 		"{"
96 		"  \"type\": \"record\","
97 		"  \"name\": \"test\","
98 		"  \"fields\": ["
99 		"    { \"name\": \"i\", \"type\": \"int\" },"
100 		"    { \"name\": \"l\", \"type\": \"long\" },"
101 		"    { \"name\": \"s\", \"type\": \"string\" },"
102 		"    {"
103 		"      \"name\": \"subrec\","
104 		"      \"type\": {"
105 		"        \"type\": \"record\","
106 		"        \"name\": \"sub\","
107 		"        \"fields\": ["
108 		"          { \"name\": \"f\", \"type\": \"float\" },"
109 		"          { \"name\": \"d\", \"type\": \"double\" }"
110 		"        ]"
111 		"      }"
112 		"    }"
113 		"  ]"
114 		"}";
115 
116 	static const char *strings[] = {
117 		"Four score and seven years ago",
118 		"our father brought forth on this continent",
119 		"a new nation", "conceived in Liberty",
120 		"and dedicated to the proposition that all men are created equal."
121 	};
122 	static const unsigned int  NUM_STRINGS =
123 	  sizeof(strings) / sizeof(strings[0]);
124 
125 	int  rc;
126 	static char  buf[4096];
127 	avro_reader_t  reader = avro_reader_memory(buf, sizeof(buf));
128 	avro_writer_t  writer = avro_writer_memory(buf, sizeof(buf));
129 
130 	avro_schema_t  schema = NULL;
131 	avro_schema_error_t  error = NULL;
132 	avro_schema_from_json(schema_json, strlen(schema_json),
133 						  &schema, &error);
134 
135 	unsigned long  i;
136 
137 	avro_datum_t  in = avro_datum_from_schema(schema);
138 
139 	for (i = 0; i < num_tests; i++) {
140 		avro_record_set_field_value(rc, in, int32, "i", rand_int32());
141 		avro_record_set_field_value(rc, in, int64, "l", rand_int64());
142 		avro_record_set_field_value(rc, in, givestring, "s",
143 									strings[i % NUM_STRINGS], NULL);
144 
145 		avro_datum_t  subrec = NULL;
146 		avro_record_get(in, "subrec", &subrec);
147 		avro_record_set_field_value(rc, in, float, "f", rand_number(-1e10, 1e10));
148 		avro_record_set_field_value(rc, in, double, "d", rand_number(-1e10, 1e10));
149 
150 		avro_writer_reset(writer);
151 		avro_write_data(writer, schema, in);
152 
153 		avro_datum_t  out = NULL;
154 
155 		avro_reader_reset(reader);
156 		avro_read_data(reader, schema, schema, &out);
157 
158 		avro_datum_equal(in, out);
159 		avro_datum_decref(out);
160 	}
161 
162 	avro_datum_decref(in);
163 	avro_schema_decref(schema);
164 	avro_writer_free(writer);
165 	avro_reader_free(reader);
166 }
167 
168 
169 /**
170  * Tests the performance of serializing and deserializing a somewhat
171  * complex record type using the new value API, retrieving record fields
172  * by index.
173  */
174 
175 static void
test_nested_record_value_by_index(unsigned long num_tests)176 test_nested_record_value_by_index(unsigned long num_tests)
177 {
178 	static const char  *schema_json =
179 		"{"
180 		"  \"type\": \"record\","
181 		"  \"name\": \"test\","
182 		"  \"fields\": ["
183 		"    { \"name\": \"i\", \"type\": \"int\" },"
184 		"    { \"name\": \"l\", \"type\": \"long\" },"
185 		"    { \"name\": \"s\", \"type\": \"string\" },"
186 		"    {"
187 		"      \"name\": \"subrec\","
188 		"      \"type\": {"
189 		"        \"type\": \"record\","
190 		"        \"name\": \"sub\","
191 		"        \"fields\": ["
192 		"          { \"name\": \"f\", \"type\": \"float\" },"
193 		"          { \"name\": \"d\", \"type\": \"double\" }"
194 		"        ]"
195 		"      }"
196 		"    }"
197 		"  ]"
198 		"}";
199 
200 	static char *strings[] = {
201 		"Four score and seven years ago",
202 		"our father brought forth on this continent",
203 		"a new nation", "conceived in Liberty",
204 		"and dedicated to the proposition that all men are created equal."
205 	};
206 	static const unsigned int  NUM_STRINGS =
207 	  sizeof(strings) / sizeof(strings[0]);
208 
209 	static char  buf[4096];
210 	avro_reader_t  reader = avro_reader_memory(buf, sizeof(buf));
211 	avro_writer_t  writer = avro_writer_memory(buf, sizeof(buf));
212 
213 	avro_schema_t  schema = NULL;
214 	avro_schema_error_t  error = NULL;
215 	avro_schema_from_json(schema_json, strlen(schema_json),
216 						  &schema, &error);
217 
218 	unsigned long  i;
219 
220 	avro_value_iface_t  *iface = avro_generic_class_from_schema(schema);
221 
222 	avro_value_t  val;
223 	avro_generic_value_new(iface, &val);
224 
225 	avro_value_t  out;
226 	avro_generic_value_new(iface, &out);
227 
228 	for (i = 0; i < num_tests; i++) {
229 		avro_value_t  field;
230 
231 		avro_value_get_by_index(&val, 0, &field, NULL);
232 		avro_value_set_int(&field, rand_int32());
233 
234 		avro_value_get_by_index(&val, 1, &field, NULL);
235 		avro_value_set_long(&field, rand_int64());
236 
237 		avro_wrapped_buffer_t  wbuf;
238 		avro_wrapped_buffer_new_string(&wbuf, strings[i % NUM_STRINGS]);
239 		avro_value_get_by_index(&val, 2, &field, NULL);
240 		avro_value_give_string_len(&field, &wbuf);
241 
242 		avro_value_t  subrec;
243 		avro_value_get_by_index(&val, 3, &subrec, NULL);
244 
245 		avro_value_get_by_index(&subrec, 0, &field, NULL);
246 		avro_value_set_float(&field, rand_number(-1e10, 1e10));
247 
248 		avro_value_get_by_index(&subrec, 1, &field, NULL);
249 		avro_value_set_double(&field, rand_number(-1e10, 1e10));
250 
251 		avro_writer_reset(writer);
252 		avro_value_write(writer, &val);
253 
254 		avro_reader_reset(reader);
255 		avro_value_read(reader, &out);
256 
257 		if (! avro_value_equal_fast(&val, &out) ) {
258 			printf("Broken\n");
259 			exit (1);
260 		}
261 	}
262 
263 	avro_value_decref(&val);
264 	avro_value_decref(&out);
265 	avro_value_iface_decref(iface);
266 	avro_schema_decref(schema);
267 	avro_writer_free(writer);
268 	avro_reader_free(reader);
269 }
270 
271 
272 
273 /**
274  * Tests the performance of serializing and deserializing a somewhat
275  * complex record type using the new value API, retrieving record fields
276  * by name.
277  */
278 
279 static void
test_nested_record_value_by_name(unsigned long num_tests)280 test_nested_record_value_by_name(unsigned long num_tests)
281 {
282 	static const char  *schema_json =
283 		"{"
284 		"  \"type\": \"record\","
285 		"  \"name\": \"test\","
286 		"  \"fields\": ["
287 		"    { \"name\": \"i\", \"type\": \"int\" },"
288 		"    { \"name\": \"l\", \"type\": \"long\" },"
289 		"    { \"name\": \"s\", \"type\": \"string\" },"
290 		"    {"
291 		"      \"name\": \"subrec\","
292 		"      \"type\": {"
293 		"        \"type\": \"record\","
294 		"        \"name\": \"sub\","
295 		"        \"fields\": ["
296 		"          { \"name\": \"f\", \"type\": \"float\" },"
297 		"          { \"name\": \"d\", \"type\": \"double\" }"
298 		"        ]"
299 		"      }"
300 		"    }"
301 		"  ]"
302 		"}";
303 
304 	static char *strings[] = {
305 		"Four score and seven years ago",
306 		"our father brought forth on this continent",
307 		"a new nation", "conceived in Liberty",
308 		"and dedicated to the proposition that all men are created equal."
309 	};
310 	static const unsigned int  NUM_STRINGS =
311 	  sizeof(strings) / sizeof(strings[0]);
312 
313 	static char  buf[4096];
314 	avro_reader_t  reader = avro_reader_memory(buf, sizeof(buf));
315 	avro_writer_t  writer = avro_writer_memory(buf, sizeof(buf));
316 
317 	avro_schema_t  schema = NULL;
318 	avro_schema_error_t  error = NULL;
319 	avro_schema_from_json(schema_json, strlen(schema_json),
320 						  &schema, &error);
321 
322 	unsigned long  i;
323 
324 	avro_value_iface_t  *iface = avro_generic_class_from_schema(schema);
325 
326 	avro_value_t  val;
327 	avro_generic_value_new(iface, &val);
328 
329 	avro_value_t  out;
330 	avro_generic_value_new(iface, &out);
331 
332 	for (i = 0; i < num_tests; i++) {
333 		avro_value_t  field;
334 
335 		avro_value_get_by_name(&val, "i", &field, NULL);
336 		avro_value_set_int(&field, rand_int32());
337 
338 		avro_value_get_by_name(&val, "l", &field, NULL);
339 		avro_value_set_long(&field, rand_int64());
340 
341 		avro_wrapped_buffer_t  wbuf;
342 		avro_wrapped_buffer_new_string(&wbuf, strings[i % NUM_STRINGS]);
343 		avro_value_get_by_name(&val, "s", &field, NULL);
344 		avro_value_give_string_len(&field, &wbuf);
345 
346 		avro_value_t  subrec;
347 		avro_value_get_by_name(&val, "subrec", &subrec, NULL);
348 
349 		avro_value_get_by_name(&subrec, "f", &field, NULL);
350 		avro_value_set_float(&field, rand_number(-1e10, 1e10));
351 
352 		avro_value_get_by_name(&subrec, "d", &field, NULL);
353 		avro_value_set_double(&field, rand_number(-1e10, 1e10));
354 
355 		avro_writer_reset(writer);
356 		avro_value_write(writer, &val);
357 
358 		avro_reader_reset(reader);
359 		avro_value_read(reader, &out);
360 
361 		if (! avro_value_equal_fast(&val, &out) ) {
362 			printf("Broken\n");
363 			exit (1);
364 		}
365 	}
366 
367 	avro_value_decref(&val);
368 	avro_value_decref(&out);
369 	avro_value_iface_decref(iface);
370 	avro_schema_decref(schema);
371 	avro_writer_free(writer);
372 	avro_reader_free(reader);
373 }
374 
375 
376 
377 /**
378  * Helper function to test the performance of serializing and
379  * deserializing a given avro value using the provided function to
380  * populate avro value using the new value API. Allows testing using
381  * matching schemas or using schema resolution.
382  */
383 
384 static void
test_generic_helper(unsigned long num_tests,int resolution_type,const char * schema_json,void (* populate_value_func)(avro_value_t *,unsigned long))385 test_generic_helper( unsigned long num_tests,
386 					 int resolution_type,
387 					 const char *schema_json,
388 					 void (*populate_value_func)(avro_value_t *,
389 												 unsigned long)
390 					 )
391 {
392 	static char  buf[4096];
393 
394 	avro_reader_t  reader = avro_reader_memory(buf, sizeof(buf));
395 	avro_writer_t  writer = avro_writer_memory(buf, sizeof(buf));
396 
397 	avro_schema_t  schema = NULL;
398 	avro_schema_error_t  error = NULL;
399 	avro_schema_from_json(schema_json, strlen(schema_json),
400 						  &schema, &error);
401 
402 	unsigned long  i;
403 
404 	avro_value_iface_t  *writer_iface = avro_generic_class_from_schema(schema);
405 	avro_value_iface_t  *reader_iface = avro_generic_class_from_schema(schema);
406 
407 	avro_value_t  val;
408 	avro_generic_value_new(writer_iface, &val);
409 
410 	avro_value_t  out;
411 	avro_generic_value_new(reader_iface, &out);
412 
413 	/* Use resolved reader to resolve schemas while writing data to memory */
414 	avro_value_iface_t *resolved_reader_iface = NULL;
415 	avro_value_t resolved_reader_value;
416 	if ( resolution_type & USE_RESOLVED_READER ) {
417 		resolved_reader_iface = avro_resolved_reader_new( schema, schema );
418 		avro_resolved_reader_new_value( resolved_reader_iface,
419 										&resolved_reader_value );
420 	  avro_resolved_reader_set_source( &resolved_reader_value, &val );
421 	}
422 
423 	/* Use resolved writer to resolve schemas while reading data from memory */
424 	avro_value_iface_t *resolved_writer_iface = NULL;
425 	avro_value_t resolved_writer_value;
426 	if ( resolution_type & USE_RESOLVED_WRITER ) {
427 		resolved_writer_iface = avro_resolved_writer_new( schema, schema );
428 		avro_resolved_writer_new_value( resolved_writer_iface,
429 										&resolved_writer_value );
430 	  avro_resolved_writer_set_dest( &resolved_writer_value, &out );
431 	}
432 
433 	/* Set up pointers */
434 	avro_value_t *p_value_to_write_to_memory = NULL;
435 	avro_value_t *p_value_to_read_from_memory = NULL;
436 
437 	if ( resolution_type == USE_MATCHED_SCHEMAS ) {
438 		p_value_to_write_to_memory = &val;
439 		p_value_to_read_from_memory = &out;
440 	}
441 	else if ( resolution_type == USE_RESOLVED_READER ) {
442 		p_value_to_write_to_memory = &resolved_reader_value;
443 		p_value_to_read_from_memory = &out;
444 	}
445 	else if ( resolution_type == USE_RESOLVED_WRITER ) {
446 		p_value_to_write_to_memory = &val;
447 		p_value_to_read_from_memory = &resolved_writer_value;
448 	}
449 	else if ( resolution_type == USE_BOTH_RESOLVED ) {
450 		p_value_to_write_to_memory = &resolved_reader_value;
451 		p_value_to_read_from_memory = &resolved_writer_value;
452 	}
453 
454 	/* Perform the tests */
455 	for (i = 0; i < num_tests; i++) {
456 
457 		avro_value_reset(&val);
458 
459 		/* Execute the function to populate the Avro Value */
460 		(*populate_value_func)(&val, i);
461 
462 		avro_writer_reset(writer);
463 		avro_value_write(writer, p_value_to_write_to_memory);
464 
465 		avro_reader_reset(reader);
466 		avro_value_read(reader, p_value_to_read_from_memory);
467 
468 		if (! avro_value_equal_fast(&val, &out) ) {
469 			printf("Broken\n");
470 			exit (1);
471 		}
472 	}
473 
474 	avro_value_decref(&val);
475 	avro_value_decref(&out);
476 	if ( resolution_type & USE_RESOLVED_READER ) {
477 		avro_value_decref(&resolved_reader_value);
478 		avro_value_iface_decref(resolved_reader_iface);
479 	}
480 	if ( resolution_type & USE_RESOLVED_WRITER ) {
481 		avro_value_decref(&resolved_writer_value);
482 		avro_value_iface_decref(resolved_writer_iface);
483 	}
484 	avro_value_iface_decref(writer_iface);
485 	avro_value_iface_decref(reader_iface);
486 	avro_schema_decref(schema);
487 	avro_writer_free(writer);
488 	avro_reader_free(reader);
489 }
490 
491 
492 
493 
494 /**
495  * Helper function to populate a somewhat complex record type using
496  * the new value API, retrieving record fields by index.
497  */
498 
499 static const char  *complex_record_schema_json =
500 		"{"
501 		"  \"type\": \"record\","
502 		"  \"name\": \"test\","
503 		"  \"fields\": ["
504 		"    { \"name\": \"i\", \"type\": \"int\" },"
505 		"    { \"name\": \"l\", \"type\": \"long\" },"
506 		"    { \"name\": \"s\", \"type\": \"string\" },"
507 		"    {"
508 		"      \"name\": \"subrec\","
509 		"      \"type\": {"
510 		"        \"type\": \"record\","
511 		"        \"name\": \"sub\","
512 		"        \"fields\": ["
513 		"          { \"name\": \"f\", \"type\": \"float\" },"
514 		"          { \"name\": \"d\", \"type\": \"double\" }"
515 		"        ]"
516 		"      }"
517 		"    }"
518 		"  ]"
519 		"}";
520 
521 
522 
523 static void
populate_complex_record(avro_value_t * p_val,unsigned long i)524 populate_complex_record(avro_value_t *p_val, unsigned long i)
525 {
526 	static char *strings[] = {
527 		"Four score and seven years ago",
528 		"our father brought forth on this continent",
529 		"a new nation", "conceived in Liberty",
530 		"and dedicated to the proposition that all men are created equal."
531 	};
532 	static const unsigned int  NUM_STRINGS =
533 	  sizeof(strings) / sizeof(strings[0]);
534 
535 	avro_value_t  field;
536 
537 	avro_value_get_by_index(p_val, 0, &field, NULL);
538 	avro_value_set_int(&field, rand_int32());
539 
540 	avro_value_get_by_index(p_val, 1, &field, NULL);
541 	avro_value_set_long(&field, rand_int64());
542 
543 	avro_wrapped_buffer_t  wbuf;
544 	avro_wrapped_buffer_new_string(&wbuf, strings[i % NUM_STRINGS]);
545 	avro_value_get_by_index(p_val, 2, &field, NULL);
546 	avro_value_give_string_len(&field, &wbuf);
547 
548 	avro_value_t  subrec;
549 	avro_value_get_by_index(p_val, 3, &subrec, NULL);
550 
551 	avro_value_get_by_index(&subrec, 0, &field, NULL);
552 	avro_value_set_float(&field, rand_number(-1e10, 1e10));
553 
554 	avro_value_get_by_index(&subrec, 1, &field, NULL);
555 	avro_value_set_double(&field, rand_number(-1e10, 1e10));
556 
557 }
558 
559 
560 
561 /**
562  * Tests the performance of serializing and deserializing a somewhat
563  * complex record type using the new value API, retrieving record
564  * fields by index. The functionality is almost identical to
565  * test_nested_record_value_by_index(), however, there may be some
566  * overhead of using function calls instead of inline code, and
567  * running some additional "if" statements..
568  */
569 
570 static void
test_nested_record_value_by_index_matched_schemas(unsigned long num_tests)571 test_nested_record_value_by_index_matched_schemas(unsigned long num_tests)
572 {
573 	test_generic_helper(num_tests,
574 						USE_MATCHED_SCHEMAS,
575 						complex_record_schema_json,
576 						populate_complex_record);
577 }
578 
579 
580 /**
581  * Tests the performance of serializing and deserializing a somewhat
582  * complex record type using the new value API, retrieving record
583  * fields by index. Uses a resolved_writer to resolve between two
584  * (identical) schemas when reading the array.
585  */
586 
587 static void
test_nested_record_value_by_index_resolved_writer(unsigned long num_tests)588 test_nested_record_value_by_index_resolved_writer(unsigned long num_tests)
589 {
590 	test_generic_helper(num_tests,
591 						USE_RESOLVED_WRITER,
592 						complex_record_schema_json,
593 						populate_complex_record);
594 }
595 
596 
597 
598 /**
599  * Tests the performance of serializing and deserializing a somewhat
600  * complex record type using the new value API, retrieving record
601  * fields by index. Uses a resolved_reader to resolve between two
602  * (identical) schemas when writing the array.
603  */
604 
605 static void
test_nested_record_value_by_index_resolved_reader(unsigned long num_tests)606 test_nested_record_value_by_index_resolved_reader(unsigned long num_tests)
607 {
608 	test_generic_helper(num_tests,
609 						USE_RESOLVED_READER,
610 						complex_record_schema_json,
611 						populate_complex_record);
612 }
613 
614 
615 
616 /**
617  * Helper function to test the performance of serializing and
618  * deserializing a simple array using the new value API. Allows
619  * testing using matching schemas or using schema resolution.
620  */
621 
622 static const char  *simple_array_schema_json =
623   "{\"name\": \"a\", \"type\": \"array\", \"items\":\"long\"}";
624 
625 static void
populate_simple_array(avro_value_t * p_val,unsigned long i)626 populate_simple_array(avro_value_t *p_val, unsigned long i)
627 {
628 	const size_t array_length = 21;
629 	avro_value_t  field;
630 	size_t idx;
631 	size_t dummy_index;
632 	(void) i;
633 
634 	for ( idx = 0; idx < array_length; idx++ ) {
635 		avro_value_append(p_val, &field, &dummy_index);
636 		avro_value_set_long(&field, rand_int64());
637 	}
638 }
639 
640 
641 
642 /**
643  * Tests the performance of serializing and deserializing a simple
644  * array using the new value API.
645  */
646 
647 static void
test_simple_array(unsigned long num_tests)648 test_simple_array(unsigned long num_tests)
649 {
650 	test_generic_helper(num_tests,
651 						USE_MATCHED_SCHEMAS,
652 						simple_array_schema_json,
653 						populate_simple_array);
654 }
655 
656 
657 
658 /**
659  * Tests the performance of serializing and deserializing a simple
660  * array using the new value API, using a resolved writer to resolve
661  * between (identical) reader and writer schemas, when reading the
662  * array.
663  */
664 static void
test_simple_array_resolved_writer(unsigned long num_tests)665 test_simple_array_resolved_writer(unsigned long num_tests)
666 {
667 	test_generic_helper(num_tests,
668 						USE_RESOLVED_WRITER,
669 						simple_array_schema_json,
670 						populate_simple_array);
671 }
672 
673 
674 
675 /**
676  * Tests the performance of serializing and deserializing a simple
677  * array using the new value API, using a resolved reader to resolve
678  * between (identical) reader and writer schemas, when writing the
679  * array.
680  */
681 
682 static void
test_simple_array_resolved_reader(unsigned long num_tests)683 test_simple_array_resolved_reader(unsigned long num_tests)
684 {
685 	test_generic_helper(num_tests,
686 						USE_RESOLVED_READER,
687 						simple_array_schema_json,
688 						populate_simple_array);
689 }
690 
691 
692 
693 
694 /**
695  * Helper function to test the performance of serializing and
696  * deserializing a nested array using the new value API. Allows
697  * testing using matching schemas or using schema resolution.
698  */
699 
700 static const char  *nested_array_schema_json =
701   "{\"type\":\"array\", \"items\": {\"type\": \"array\", \"items\": \"long\"}}";
702 
703 
704 static void
populate_nested_array(avro_value_t * p_val,unsigned long i)705 populate_nested_array(avro_value_t *p_val, unsigned long i)
706 {
707 
708 	const size_t array_length = 7;
709 	const size_t subarray_length = 3;
710 	avro_value_t  subarray;
711 	avro_value_t  field;
712 	size_t idx;
713 	size_t jdx;
714 	size_t dummy_index;
715 	(void) i;
716 
717 	for ( idx = 0; idx < array_length; idx++ ) {
718 		avro_value_append(p_val, &subarray, &dummy_index);
719 		for ( jdx = 0; jdx < subarray_length; jdx ++ ) {
720 		  avro_value_append(&subarray, &field, &dummy_index);
721 		  avro_value_set_long(&field, rand_int64());
722 		}
723 	}
724 }
725 
726 
727 /**
728  * Tests the performance of serializing and deserializing a nested
729  * array using the new value API.
730  */
731 
732 static void
test_nested_array(unsigned long num_tests)733 test_nested_array(unsigned long num_tests)
734 {
735 	test_generic_helper(num_tests,
736 						USE_MATCHED_SCHEMAS,
737 						nested_array_schema_json,
738 						populate_nested_array);
739 }
740 
741 
742 /**
743  * Tests the performance of serializing and deserializing a nested
744  * array using the new value API, using a resolved writer to resolve
745  * between (identical) reader and writer schemas, when reading the
746  * array.
747  */
748 
749 static void
test_nested_array_resolved_writer(unsigned long num_tests)750 test_nested_array_resolved_writer(unsigned long num_tests)
751 {
752 	test_generic_helper(num_tests,
753 						USE_RESOLVED_WRITER,
754 						nested_array_schema_json,
755 						populate_nested_array);
756 }
757 
758 
759 /**
760  * Tests the performance of serializing and deserializing a nested
761  * array using the new value API, using a resolved reader to resolve
762  * between (identical) reader and writer schemas, when writing the
763  * array.
764  */
765 
766 static void
test_nested_array_resolved_reader(unsigned long num_tests)767 test_nested_array_resolved_reader(unsigned long num_tests)
768 {
769 	test_generic_helper(num_tests,
770 						USE_RESOLVED_READER,
771 						nested_array_schema_json,
772 						populate_nested_array);
773 }
774 
775 
776 
777 /**
778  * Test harness
779  */
780 
781 #define NUM_RUNS  3
782 
783 int
main(int argc,char ** argv)784 main(int argc, char **argv)
785 {
786 	AVRO_UNUSED(argc);
787 	AVRO_UNUSED(argv);
788 
789 	init_rand();
790 
791 	unsigned int  i;
792 	struct avro_tests {
793 		const char  *name;
794 		unsigned long  num_tests;
795 		test_func_t  func;
796 	} tests[] = {
797 		{ "refcount", 100000000,
798 		  test_refcount },
799 		{ "nested record (legacy)", 100000,
800 		  test_nested_record_datum },
801 		{ "nested record (value by index)", 1000000,
802 		  test_nested_record_value_by_index },
803 		{ "nested record (value by name)", 1000000,
804 		  test_nested_record_value_by_name },
805 		{ "nested record (value by index) matched schemas", 1000000,
806 		  test_nested_record_value_by_index_matched_schemas },
807 		{ "nested record (value by index) resolved writer", 1000000,
808 		  test_nested_record_value_by_index_resolved_writer },
809 		{ "nested record (value by index) resolved reader", 1000000,
810 		  test_nested_record_value_by_index_resolved_reader },
811 		{ "simple array matched schemas", 250000,
812 		  test_simple_array },
813 		{ "simple array resolved writer", 250000,
814 		  test_simple_array_resolved_writer },
815 		{ "simple array resolved reader", 250000,
816 		  test_simple_array_resolved_reader },
817 		{ "nested array matched schemas", 250000,
818 		  test_nested_array },
819 		{ "nested array resolved writer", 250000,
820 		  test_nested_array_resolved_writer },
821 		{ "nested array resolved reader", 250000,
822 		  test_nested_array_resolved_reader },
823 	};
824 
825 	for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
826 		fprintf(stderr, "**** Running %s ****\n  %lu tests per run\n",
827 			tests[i].name, tests[i].num_tests);
828 		unsigned int  run;
829 
830 		double  sum = 0.0;
831 
832 		for (run = 1; run <= NUM_RUNS; run++) {
833 			fprintf(stderr, "  Run %u\n", run);
834 
835 			clock_t  before = clock();
836 			tests[i].func(tests[i].num_tests);
837 			clock_t  after = clock();
838 			double  secs = ((double) after-before) / CLOCKS_PER_SEC;
839 			sum += secs;
840 		}
841 
842 		fprintf(stderr, "  Average time: %.03lfs\n", sum / NUM_RUNS);
843 		fprintf(stderr, "  Tests/sec:    %.0lf\n",
844 			tests[i].num_tests / (sum / NUM_RUNS));
845 	}
846 
847 	return EXIT_SUCCESS;
848 }
849