Author: dcreager
Date: Tue Jul 12 20:21:04 2011
New Revision: 1145750
URL: http://svn.apache.org/viewvc?rev=1145750&view=rev
Log:
AVO-746. C: Atomic reference counts
This patch updates all of the reference counts in various Avro objects
to be updated atomically. This takes care of some race conditions when
Avro instances are passed between threads. The atomic increment and
decrement operations are slower than the previous non-atomic operations,
but according to some basic performance tests, reference counting isn't
the dominating factor in the running time.
Added:
avro/trunk/lang/c/examples/.gitignore
avro/trunk/lang/c/jansson/test/.gitignore
avro/trunk/lang/c/jansson/test/testprogs/.gitignore
avro/trunk/lang/c/src/.gitignore
avro/trunk/lang/c/src/avro/refcount.h
avro/trunk/lang/c/tests/.gitignore
avro/trunk/lang/c/tests/performance.c
Modified:
avro/trunk/lang/c/.gitignore
avro/trunk/lang/c/src/CMakeLists.txt
avro/trunk/lang/c/src/Makefile.am
avro/trunk/lang/c/src/avro.h
avro/trunk/lang/c/src/datum.c
avro/trunk/lang/c/src/io.c
avro/trunk/lang/c/src/schema.c
avro/trunk/lang/c/tests/CMakeLists.txt
avro/trunk/lang/c/tests/Makefile.am
Modified: avro/trunk/lang/c/.gitignore
URL:
http://svn.apache.org/viewvc/avro/trunk/lang/c/.gitignore?rev=1145750&r1=1145749&r2=1145750&view=diff
==============================================================================
--- avro/trunk/lang/c/.gitignore (original)
+++ avro/trunk/lang/c/.gitignore Tue Jul 12 20:21:04 2011
@@ -1,10 +1,19 @@
+.deps
+.libs
+Makefile
Makefile.in
aclocal.m4
autom4te.cache
+build
config
+config.h
config.h.in
+config.log
+config.status
configure
-*.lo
+libtool
+stamp-h1
+*.l[ao]
*.o
INSTALL
cscope.*
Added: avro/trunk/lang/c/examples/.gitignore
URL:
http://svn.apache.org/viewvc/avro/trunk/lang/c/examples/.gitignore?rev=1145750&view=auto
==============================================================================
--- avro/trunk/lang/c/examples/.gitignore (added)
+++ avro/trunk/lang/c/examples/.gitignore Tue Jul 12 20:21:04 2011
@@ -0,0 +1,2 @@
+quickstop
+quickstop.db
Added: avro/trunk/lang/c/jansson/test/.gitignore
URL:
http://svn.apache.org/viewvc/avro/trunk/lang/c/jansson/test/.gitignore?rev=1145750&view=auto
==============================================================================
--- avro/trunk/lang/c/jansson/test/.gitignore (added)
+++ avro/trunk/lang/c/jansson/test/.gitignore Tue Jul 12 20:21:04 2011
@@ -0,0 +1,9 @@
+bin/json_process
+suites/api/test_array
+suites/api/test_copy
+suites/api/test_dump
+suites/api/test_equal
+suites/api/test_load
+suites/api/test_number
+suites/api/test_object
+suites/api/test_simple
Added: avro/trunk/lang/c/jansson/test/testprogs/.gitignore
URL:
http://svn.apache.org/viewvc/avro/trunk/lang/c/jansson/test/testprogs/.gitignore?rev=1145750&view=auto
==============================================================================
--- avro/trunk/lang/c/jansson/test/testprogs/.gitignore (added)
+++ avro/trunk/lang/c/jansson/test/testprogs/.gitignore Tue Jul 12 20:21:04 2011
@@ -0,0 +1,5 @@
+test_array
+test_load
+test_number
+test_object
+test_simple
Added: avro/trunk/lang/c/src/.gitignore
URL:
http://svn.apache.org/viewvc/avro/trunk/lang/c/src/.gitignore?rev=1145750&view=auto
==============================================================================
--- avro/trunk/lang/c/src/.gitignore (added)
+++ avro/trunk/lang/c/src/.gitignore Tue Jul 12 20:21:04 2011
@@ -0,0 +1 @@
+avro-c.pc
Modified: avro/trunk/lang/c/src/CMakeLists.txt
URL:
http://svn.apache.org/viewvc/avro/trunk/lang/c/src/CMakeLists.txt?rev=1145750&r1=1145749&r2=1145750&view=diff
==============================================================================
--- avro/trunk/lang/c/src/CMakeLists.txt (original)
+++ avro/trunk/lang/c/src/CMakeLists.txt Tue Jul 12 20:21:04 2011
@@ -22,6 +22,7 @@ set(AVRO_SRC
allocation.c
avro.h
avro/consumer.h
+ avro/refcount.h
avro_errors.h
avro_private.h
consumer.c
@@ -82,9 +83,10 @@ set_target_properties(avro-shared PROPER
install(FILES
${CMAKE_CURRENT_SOURCE_DIR}/avro.h
DESTINATION include)
-install(FILES
- ${CMAKE_CURRENT_SOURCE_DIR}/avro/consumer.h
- DESTINATION include/avro)
+install(DIRECTORY
+ ${CMAKE_CURRENT_SOURCE_DIR}/avro
+ DESTINATION include
+ FILES_MATCHING PATTERN "*.h")
install(TARGETS avro-static avro-shared
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
Modified: avro/trunk/lang/c/src/Makefile.am
URL:
http://svn.apache.org/viewvc/avro/trunk/lang/c/src/Makefile.am?rev=1145750&r1=1145749&r2=1145750&view=diff
==============================================================================
--- avro/trunk/lang/c/src/Makefile.am (original)
+++ avro/trunk/lang/c/src/Makefile.am Tue Jul 12 20:21:04 2011
@@ -6,7 +6,9 @@ ACLOCAL_AMFLAGS=-I m4
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = avro-c.pc
-nobase_include_HEADERS = avro.h avro/consumer.h
+nobase_include_HEADERS = avro.h \
+avro/consumer.h \
+avro/refcount.h
lib_LTLIBRARIES = libavro.la
libavro_la_SOURCES = st.c st.h schema.c schema.h schema_equal.c \
Modified: avro/trunk/lang/c/src/avro.h
URL:
http://svn.apache.org/viewvc/avro/trunk/lang/c/src/avro.h?rev=1145750&r1=1145749&r2=1145750&view=diff
==============================================================================
--- avro/trunk/lang/c/src/avro.h (original)
+++ avro/trunk/lang/c/src/avro.h Tue Jul 12 20:21:04 2011
@@ -84,7 +84,7 @@ typedef enum avro_class_t avro_class_t;
struct avro_obj_t {
avro_type_t type;
avro_class_t class_type;
- unsigned long refcount;
+ volatile int refcount;
};
#define avro_classof(obj) ((obj)->class_type)
Added: avro/trunk/lang/c/src/avro/refcount.h
URL:
http://svn.apache.org/viewvc/avro/trunk/lang/c/src/avro/refcount.h?rev=1145750&view=auto
==============================================================================
--- avro/trunk/lang/c/src/avro/refcount.h (added)
+++ avro/trunk/lang/c/src/avro/refcount.h Tue Jul 12 20:21:04 2011
@@ -0,0 +1,270 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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.
+ */
+
+#ifndef AVRO_REFCOUNT_H
+#define AVRO_REFCOUNT_H
+#ifdef __cplusplus
+extern "C" {
+#define CLOSE_EXTERN }
+#else
+#define CLOSE_EXTERN
+#endif
+
+/**
+ * Atomically sets the value of a reference count.
+ */
+
+static inline void
+avro_refcount_set(volatile int *refcount, int value);
+
+/**
+ * Increments a reference count, ensuring that its value doesn't
+ * overflow.
+ */
+
+static inline void
+avro_refcount_inc(volatile int *refcount);
+
+/**
+ * Decrements a reference count, and returns whether the resulting
+ * (decremented) value is 0.
+ */
+
+static inline int
+avro_refcount_dec(volatile int *refcount);
+
+
+/*-----------------------------------------------------------------------
+ * Mac OS X
+ */
+
+#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1050
+
+#include <libkern/OSAtomic.h>
+
+static inline void
+avro_refcount_set(volatile int *refcount, int value)
+{
+ *refcount = value;
+}
+
+static inline void
+avro_refcount_inc(volatile int *refcount)
+{
+ if (*refcount != (int) -1) {
+ OSAtomicIncrement32(refcount);
+ }
+}
+
+static inline int
+avro_refcount_dec(volatile int *refcount)
+{
+ if (*refcount != (int) -1) {
+ return (OSAtomicDecrement32(refcount) == 0);
+ }
+ return 0;
+}
+
+
+/*-----------------------------------------------------------------------
+ * GCC intrinsics
+ */
+
+#elif (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) > 40100
+
+static inline void
+avro_refcount_set(volatile int *refcount, int value)
+{
+ *refcount = value;
+}
+
+static inline void
+avro_refcount_inc(volatile int *refcount)
+{
+ if (*refcount != (int) -1) {
+ __sync_add_and_fetch(refcount, 1);
+ }
+}
+
+static inline int
+avro_refcount_dec(volatile int *refcount)
+{
+ if (*refcount != (int) -1) {
+ return (__sync_sub_and_fetch(refcount, 1) == 0);
+ }
+ return 0;
+}
+
+
+/*-----------------------------------------------------------------------
+ * Raw x86 assembly
+ */
+
+#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+
+/* determine the size of int */
+
+#include <limits.h>
+#include <stdint.h>
+#if INT_MAX == INT32_MAX
+#define REFCOUNT_SS "l"
+#elif INT_MAX == INT64_MAX
+#define REFCOUNT_SS "q"
+#else
+#error "Unknown int size"
+#endif
+
+static inline void
+avro_refcount_set(volatile int *refcount, int value)
+{
+ *refcount = value;
+}
+
+static inline void
+avro_refcount_inc(volatile int *refcount)
+{
+ if (*refcount != (int) -1) {
+ __asm__ __volatile__ ("lock ; inc"REFCOUNT_SS" %0"
+ :"=m" (refcount)
+ :"m" (refcount));
+ }
+}
+
+static inline int
+avro_refcount_dec(volatile int *refcount)
+{
+ if (*refcount != (int) -1) {
+ char result;
+ __asm__ __volatile__ ("lock ; dec"REFCOUNT_SS" %0; setz %1"
+ :"=m" (refcount), "=q" (result)
+ :"m" (refcount));
+ return result;
+ }
+ return 0;
+}
+
+#undef REFCOUNT_SS
+
+
+/*-----------------------------------------------------------------------
+ * Raw PPC assembly
+ */
+
+#elif defined(__GNUC__) && defined(__ppc__)
+
+static inline int
+avro_refcount_LL_int(volatile int *ptr)
+{
+ int val;
+ __asm__ __volatile__ ("lwarx %[val],0,%[ptr]"
+ : [val] "=r" (val)
+ : [ptr] "r" (&ptr)
+ : "cc");
+
+ return val;
+}
+
+/* Returns non-zero if the store was successful, zero otherwise. */
+static inline int
+avro_refcount_SC_int(volatile int *ptr, int val)
+{
+ int ret = 1; /* init to non-zero, will be reset to 0 if SC was
successful */
+ __asm__ __volatile__ ("stwcx. %[val],0,%[ptr];\n"
+ "beq 1f;\n"
+ "li %[ret], 0;\n"
+ "1: ;\n"
+ : [ret] "=r" (ret)
+ : [ptr] "r" (&ptr), [val] "r" (val), "0" (ret)
+ : "cc", "memory");
+ return ret;
+}
+
+static inline void
+avro_refcount_set(volatile int *refcount, int value)
+{
+ *refcount = value;
+}
+
+static inline void
+avro_refcount_inc(volatile int *refcount)
+{
+ int prev;
+ do {
+ prev = avro_refcount_LL_int(refcount);
+ if (prev == (int) -1) {
+ return;
+ }
+ } while (!avro_refcount_SC_int(refcount, prev + 1));
+}
+
+static inline int
+avro_refcount_dec(volatile int *refcount)
+{
+ int prev;
+ do {
+ prev = avro_refcount_LL_int(refcount);
+ if (prev == (int) -1) {
+ return 0;
+ }
+ } while (!avro_refcount_SC_int(refcount, prev - 1));
+ return prev == 1;
+}
+
+
+/*-----------------------------------------------------------------------
+ * Windows intrinsics
+ */
+
+#elif defined(__WIN32__)
+
+#include <windows.h>
+#include <intrin.h>
+
+static inline void
+avro_refcount_set(volatile int *refcount, int value)
+{
+ *refcount = value;
+}
+
+static inline void
+avro_refcount_inc(volatile int *refcount)
+{
+ if (*refcount != (int) -1) {
+ _InterlockedIncrement(refcount);
+ }
+}
+
+static inline int
+avro_refcount_dec(volatile int *refcount)
+{
+ if (*refcount != (int) -1) {
+ return (_InterlockedDecrement(refcount) == 0);
+ }
+ return 0;
+}
+
+
+/*-----------------------------------------------------------------------
+ * Fallback
+ */
+
+#else
+#error "No atomic implementation!"
+#endif
+
+CLOSE_EXTERN
+#endif
Modified: avro/trunk/lang/c/src/datum.c
URL:
http://svn.apache.org/viewvc/avro/trunk/lang/c/src/datum.c?rev=1145750&r1=1145749&r2=1145750&view=diff
==============================================================================
--- avro/trunk/lang/c/src/datum.c (original)
+++ avro/trunk/lang/c/src/datum.c Tue Jul 12 20:21:04 2011
@@ -15,6 +15,7 @@
* permissions and limitations under the License.
*/
+#include "avro/refcount.h"
#include "avro_errors.h"
#include "avro_private.h"
#include "allocation.h"
@@ -31,7 +32,7 @@ static void avro_datum_init(avro_datum_t
{
datum->type = type;
datum->class_type = AVRO_DATUM;
- datum->refcount = 1;
+ avro_refcount_set(&datum->refcount, 1);
}
static void
@@ -385,9 +386,9 @@ int avro_boolean_get(avro_datum_t datum,
avro_datum_t avro_null(void)
{
static struct avro_obj_t obj = {
- .type = AVRO_NULL,
- .class_type = AVRO_DATUM,
- .refcount = 1
+ AVRO_NULL,
+ AVRO_DATUM,
+ 1
};
return avro_datum_incref(&obj);
}
@@ -1097,16 +1098,15 @@ static void avro_datum_free(avro_datum_t
avro_datum_t avro_datum_incref(avro_datum_t datum)
{
- if (datum && datum->refcount != (unsigned int)-1) {
- ++datum->refcount;
+ if (datum) {
+ avro_refcount_inc(&datum->refcount);
}
return datum;
}
void avro_datum_decref(avro_datum_t datum)
{
- if (datum && datum->refcount != (unsigned int)-1
- && --datum->refcount == 0) {
+ if (datum && avro_refcount_dec(&datum->refcount)) {
avro_datum_free(datum);
}
}
Modified: avro/trunk/lang/c/src/io.c
URL:
http://svn.apache.org/viewvc/avro/trunk/lang/c/src/io.c?rev=1145750&r1=1145749&r2=1145750&view=diff
==============================================================================
--- avro/trunk/lang/c/src/io.c (original)
+++ avro/trunk/lang/c/src/io.c Tue Jul 12 20:21:04 2011
@@ -15,6 +15,7 @@
* permissions and limitations under the License.
*/
+#include "avro/refcount.h"
#include "avro_errors.h"
#include "avro_private.h"
#include "allocation.h"
@@ -32,12 +33,12 @@ typedef enum avro_io_type_t avro_io_type
struct avro_reader_t_ {
avro_io_type_t type;
- unsigned long refcount;
+ volatile int refcount;
};
struct avro_writer_t_ {
avro_io_type_t type;
- unsigned long refcount;
+ volatile int refcount;
};
struct _avro_reader_file_t {
@@ -79,13 +80,13 @@ struct _avro_writer_memory_t {
static void reader_init(avro_reader_t reader, avro_io_type_t type)
{
reader->type = type;
- reader->refcount = 1;
+ avro_refcount_set(&reader->refcount, 1);
}
static void writer_init(avro_writer_t writer, avro_io_type_t type)
{
writer->type = type;
- writer->refcount = 1;
+ avro_refcount_set(&writer->refcount, 1);
}
avro_reader_t avro_reader_file(FILE * fp)
Modified: avro/trunk/lang/c/src/schema.c
URL:
http://svn.apache.org/viewvc/avro/trunk/lang/c/src/schema.c?rev=1145750&r1=1145749&r2=1145750&view=diff
==============================================================================
--- avro/trunk/lang/c/src/schema.c (original)
+++ avro/trunk/lang/c/src/schema.c Tue Jul 12 20:21:04 2011
@@ -15,6 +15,7 @@
* permissions and limitations under the License.
*/
+#include "avro/refcount.h"
#include "avro_errors.h"
#include "avro_private.h"
#include "allocation.h"
@@ -39,7 +40,7 @@ static void avro_schema_init(avro_schema
{
schema->type = type;
schema->class_type = AVRO_SCHEMA;
- schema->refcount = 1;
+ avro_refcount_set(&schema->refcount, 1);
}
static int is_avro_id(const char *name)
@@ -183,16 +184,15 @@ static void avro_schema_free(avro_schema
avro_schema_t avro_schema_incref(avro_schema_t schema)
{
- if (schema && schema->refcount != (unsigned int)-1) {
- ++schema->refcount;
+ if (schema) {
+ avro_refcount_inc(&schema->refcount);
}
return schema;
}
void avro_schema_decref(avro_schema_t schema)
{
- if (schema && schema->refcount != (unsigned int)-1
- && --schema->refcount == 0) {
+ if (schema && avro_refcount_dec(&schema->refcount)) {
avro_schema_free(schema);
}
}
@@ -200,9 +200,9 @@ void avro_schema_decref(avro_schema_t sc
avro_schema_t avro_schema_string(void)
{
static struct avro_obj_t obj = {
- .type = AVRO_STRING,
- .class_type = AVRO_SCHEMA,
- .refcount = 1
+ AVRO_STRING,
+ AVRO_SCHEMA,
+ 1
};
return avro_schema_incref(&obj);
}
@@ -210,9 +210,9 @@ avro_schema_t avro_schema_string(void)
avro_schema_t avro_schema_bytes(void)
{
static struct avro_obj_t obj = {
- .type = AVRO_BYTES,
- .class_type = AVRO_SCHEMA,
- .refcount = 1
+ AVRO_BYTES,
+ AVRO_SCHEMA,
+ 1
};
return avro_schema_incref(&obj);
}
@@ -220,9 +220,9 @@ avro_schema_t avro_schema_bytes(void)
avro_schema_t avro_schema_int(void)
{
static struct avro_obj_t obj = {
- .type = AVRO_INT32,
- .class_type = AVRO_SCHEMA,
- .refcount = 1
+ AVRO_INT32,
+ AVRO_SCHEMA,
+ 1
};
return avro_schema_incref(&obj);
}
@@ -230,9 +230,9 @@ avro_schema_t avro_schema_int(void)
avro_schema_t avro_schema_long(void)
{
static struct avro_obj_t obj = {
- .type = AVRO_INT64,
- .class_type = AVRO_SCHEMA,
- .refcount = 1
+ AVRO_INT64,
+ AVRO_SCHEMA,
+ 1
};
return avro_schema_incref(&obj);
}
@@ -240,9 +240,9 @@ avro_schema_t avro_schema_long(void)
avro_schema_t avro_schema_float(void)
{
static struct avro_obj_t obj = {
- .type = AVRO_FLOAT,
- .class_type = AVRO_SCHEMA,
- .refcount = 1
+ AVRO_FLOAT,
+ AVRO_SCHEMA,
+ 1
};
return avro_schema_incref(&obj);
}
@@ -250,9 +250,9 @@ avro_schema_t avro_schema_float(void)
avro_schema_t avro_schema_double(void)
{
static struct avro_obj_t obj = {
- .type = AVRO_DOUBLE,
- .class_type = AVRO_SCHEMA,
- .refcount = 1
+ AVRO_DOUBLE,
+ AVRO_SCHEMA,
+ 1
};
return avro_schema_incref(&obj);
}
@@ -260,9 +260,9 @@ avro_schema_t avro_schema_double(void)
avro_schema_t avro_schema_boolean(void)
{
static struct avro_obj_t obj = {
- .type = AVRO_BOOLEAN,
- .class_type = AVRO_SCHEMA,
- .refcount = 1
+ AVRO_BOOLEAN,
+ AVRO_SCHEMA,
+ 1
};
return avro_schema_incref(&obj);
}
@@ -270,9 +270,9 @@ avro_schema_t avro_schema_boolean(void)
avro_schema_t avro_schema_null(void)
{
static struct avro_obj_t obj = {
- .type = AVRO_NULL,
- .class_type = AVRO_SCHEMA,
- .refcount = 1
+ AVRO_NULL,
+ AVRO_SCHEMA,
+ 1
};
return avro_schema_incref(&obj);
}
Added: avro/trunk/lang/c/tests/.gitignore
URL:
http://svn.apache.org/viewvc/avro/trunk/lang/c/tests/.gitignore?rev=1145750&view=auto
==============================================================================
--- avro/trunk/lang/c/tests/.gitignore (added)
+++ avro/trunk/lang/c/tests/.gitignore Tue Jul 12 20:21:04 2011
@@ -0,0 +1,7 @@
+generate_interop_data
+performance
+test_avro_data
+test_avro_schema
+test_avro_schema_names
+test_cpp
+test_interop_data
Modified: avro/trunk/lang/c/tests/CMakeLists.txt
URL:
http://svn.apache.org/viewvc/avro/trunk/lang/c/tests/CMakeLists.txt?rev=1145750&r1=1145749&r2=1145750&view=diff
==============================================================================
--- avro/trunk/lang/c/tests/CMakeLists.txt (original)
+++ avro/trunk/lang/c/tests/CMakeLists.txt Tue Jul 12 20:21:04 2011
@@ -19,6 +19,10 @@
add_executable(generate_interop_data generate_interop_data.c)
target_link_libraries(generate_interop_data avro-static)
+
+add_executable(performance performance.c)
+target_link_libraries(performance avro-static)
+
add_executable(test_interop_data test_interop_data.c)
target_link_libraries(test_interop_data avro-static)
Modified: avro/trunk/lang/c/tests/Makefile.am
URL:
http://svn.apache.org/viewvc/avro/trunk/lang/c/tests/Makefile.am?rev=1145750&r1=1145749&r2=1145750&view=diff
==============================================================================
--- avro/trunk/lang/c/tests/Makefile.am (original)
+++ avro/trunk/lang/c/tests/Makefile.am Tue Jul 12 20:21:04 2011
@@ -7,7 +7,7 @@ EXTRA_DIST=schema_tests test_valgrind
check_PROGRAMS=test_avro_schema test_avro_schema_names test_avro_data test_cpp
-noinst_PROGRAMS=generate_interop_data test_interop_data
+noinst_PROGRAMS=generate_interop_data test_interop_data performance
test_LDADD=$(top_builddir)/src/libavro.la
@@ -26,6 +26,9 @@ test_cpp_LDADD=$(test_LDADD)
generate_interop_data_SOURCES=generate_interop_data.c
generate_interop_data_LDADD=$(test_LDADD)
+performance_SOURCES=performance.c
+performance_LDADD=$(test_LDADD)
+
test_interop_data_SOURCES=test_interop_data.c
test_interop_data_LDADD=$(test_LDADD)
Added: avro/trunk/lang/c/tests/performance.c
URL:
http://svn.apache.org/viewvc/avro/trunk/lang/c/tests/performance.c?rev=1145750&view=auto
==============================================================================
--- avro/trunk/lang/c/tests/performance.c (added)
+++ avro/trunk/lang/c/tests/performance.c Tue Jul 12 20:21:04 2011
@@ -0,0 +1,203 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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.
+ */
+
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "avro.h"
+#include "avro_private.h"
+
+/*
+ * A series of performance tests.
+ */
+
+typedef void
+(*test_func_t)(void);
+
+
+void init_rand(void)
+{
+ srand(time(NULL));
+}
+
+double rand_number(double from, double to)
+{
+ double range = to - from;
+ return from + ((double)rand() / (RAND_MAX + 1.0)) * range;
+}
+
+int64_t rand_int64(void)
+{
+ return (int64_t) rand_number(LONG_MIN, LONG_MAX);
+}
+
+int32_t rand_int32(void)
+{
+ return (int32_t) rand_number(INT_MIN, INT_MAX);
+}
+
+
+/**
+ * Tests the single-threaded performance of our reference counting
+ * mechanism. We create a single datum, and then reference and
+ * deference it many many times.
+ */
+
+static void
+test_refcount(void)
+{
+ const unsigned long NUM_TESTS = 100000000;
+ unsigned long i;
+
+ avro_datum_t datum = avro_int32(42);
+ for (i = 0; i < NUM_TESTS; i++) {
+ avro_datum_incref(datum);
+ avro_datum_decref(datum);
+ }
+ avro_datum_decref(datum);
+}
+
+
+/**
+ * Tests the performance of serializing and deserializing a somewhat
+ * complex record type.
+ */
+
+static void
+test_nested_record(void)
+{
+ static const char *schema_json =
+ "{"
+ " \"type\": \"record\","
+ " \"name\": \"test\","
+ " \"fields\": ["
+ " { \"name\": \"i\", \"type\": \"int\" },"
+ " { \"name\": \"l\", \"type\": \"long\" },"
+ " { \"name\": \"s\", \"type\": \"string\" },"
+ " {"
+ " \"name\": \"subrec\","
+ " \"type\": {"
+ " \"type\": \"record\","
+ " \"name\": \"sub\","
+ " \"fields\": ["
+ " { \"name\": \"f\", \"type\": \"float\" },"
+ " { \"name\": \"d\", \"type\": \"double\" }"
+ " ]"
+ " }"
+ " }"
+ " ]"
+ "}";
+
+ static const char *strings[] = {
+ "Four score and seven years ago",
+ "our father brought forth on this continent",
+ "a new nation", "conceived in Liberty",
+ "and dedicated to the proposition that all men are created
equal."
+ };
+ static const unsigned int NUM_STRINGS =
+ sizeof(strings) / sizeof(strings[0]);
+
+ int rc;
+ static char buf[4096];
+ avro_reader_t reader;
+ avro_writer_t writer;
+
+ avro_schema_t schema = NULL;
+ avro_schema_error_t error = NULL;
+ avro_schema_from_json(schema_json, strlen(schema_json),
+ &schema, &error);
+
+ const unsigned long NUM_TESTS = 100000;
+ unsigned long i;
+
+ avro_datum_t in = avro_datum_from_schema(schema);
+
+ for (i = 0; i < NUM_TESTS; i++) {
+ avro_record_set_field_value(rc, in, int32, "i", rand_int32());
+ avro_record_set_field_value(rc, in, int64, "l", rand_int64());
+ avro_record_set_field_value(rc, in, givestring, "s",
+ strings[i % NUM_STRINGS], NULL);
+
+ avro_datum_t subrec = NULL;
+ avro_record_get(in, "subrec", &subrec);
+ avro_record_set_field_value(rc, in, float, "f",
rand_number(-1e10, 1e10));
+ avro_record_set_field_value(rc, in, double, "d",
rand_number(-1e10, 1e10));
+
+ writer = avro_writer_memory(buf, sizeof(buf));
+ avro_write_data(writer, schema, in);
+ avro_writer_free(writer);
+
+ avro_datum_t out = NULL;
+
+ reader = avro_reader_memory(buf, sizeof(buf));
+ avro_read_data(reader, schema, schema, &out);
+ avro_reader_free(reader);
+
+ avro_datum_equal(in, out);
+ avro_datum_decref(out);
+ }
+
+ avro_datum_decref(in);
+}
+
+
+/**
+ * Test harness
+ */
+
+#define NUM_RUNS 3
+
+int
+main(int argc, char **argv)
+{
+ AVRO_UNUSED(argc);
+ AVRO_UNUSED(argv);
+
+ init_rand();
+
+ unsigned int i;
+ struct avro_tests {
+ const char *name;
+ test_func_t func;
+ } tests[] = {
+ { "refcount", test_refcount },
+ { "nested record", test_nested_record }
+ };
+
+ for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
+ fprintf(stderr, "**** Running %s ****\n", tests[i].name);
+ unsigned int run;
+
+ double sum = 0.0;
+
+ for (run = 1; run <= NUM_RUNS; run++) {
+ fprintf(stderr, " Run %u\n", run);
+
+ clock_t before = clock();
+ tests[i].func();
+ clock_t after = clock();
+ double secs = ((double) after-before) / CLOCKS_PER_SEC;
+ sum += secs;
+ }
+
+ fprintf(stderr, " Average time: %.03lf seconds\n", sum /
NUM_RUNS);
+ }
+
+ return EXIT_SUCCESS;
+}