This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[jit] Add a multithreaded test case.
- From: David Malcolm <dmalcolm at redhat dot com>
- To: jit at gcc dot gnu dot org, gcc-patches at gcc dot gnu dot org
- Cc: David Malcolm <dmalcolm at redhat dot com>
- Date: Mon, 11 Aug 2014 14:04:49 -0400
- Subject: [jit] Add a multithreaded test case.
- Authentication-results: sourceware.org; auth=none
Committed and pushed to branch dmalcolm/jit:
gcc/testsuite/
* jit.dg/test-threads.c: New test case, running all of the
individual test cases in separate threads.
* jit.dg/test-combination.c: Move inclusion of the various
individual testcases into...
* jit.dg/all-non-failing-tests.h: ...this new file, and rename
TEST_COMBINATION to COMBINED_TEST.
* jit.dg/harness.h: Respond to new macro MAKE_DEJAGNU_H_THREADSAFE
by hacking up <dejagnu.h> to be threadsafe. Rename
TEST_COMBINATION to COMBINED_TEST.
* jit.dg/jit.exp (proc jit-dg-test): Add "-lpthread" when building
test-threads.exe.
---
gcc/testsuite/ChangeLog.jit | 14 ++
gcc/testsuite/jit.dg/all-non-failing-tests.h | 152 ++++++++++++++++++
gcc/testsuite/jit.dg/harness.h | 25 ++-
gcc/testsuite/jit.dg/jit.exp | 5 +
gcc/testsuite/jit.dg/test-combination.c | 152 +-----------------
gcc/testsuite/jit.dg/test-threads.c | 230 +++++++++++++++++++++++++++
6 files changed, 423 insertions(+), 155 deletions(-)
create mode 100644 gcc/testsuite/jit.dg/all-non-failing-tests.h
create mode 100644 gcc/testsuite/jit.dg/test-threads.c
diff --git a/gcc/testsuite/ChangeLog.jit b/gcc/testsuite/ChangeLog.jit
index cdde662..846540f 100644
--- a/gcc/testsuite/ChangeLog.jit
+++ b/gcc/testsuite/ChangeLog.jit
@@ -1,3 +1,17 @@
+2014-08-11 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/test-threads.c: New test case, running all of the
+ individual test cases in separate threads.
+ * jit.dg/test-combination.c: Move inclusion of the various
+ individual testcases into...
+ * jit.dg/all-non-failing-tests.h: ...this new file, and rename
+ TEST_COMBINATION to COMBINED_TEST.
+ * jit.dg/harness.h: Respond to new macro MAKE_DEJAGNU_H_THREADSAFE
+ by hacking up <dejagnu.h> to be threadsafe. Rename
+ TEST_COMBINATION to COMBINED_TEST.
+ * jit.dg/jit.exp (proc jit-dg-test): Add "-lpthread" when building
+ test-threads.exe.
+
2014-08-08 David Malcolm <dmalcolm@redhat.com>
* jit.dg/test-accessing-union.c: New test case.
diff --git a/gcc/testsuite/jit.dg/all-non-failing-tests.h b/gcc/testsuite/jit.dg/all-non-failing-tests.h
new file mode 100644
index 0000000..54dacb7
--- /dev/null
+++ b/gcc/testsuite/jit.dg/all-non-failing-tests.h
@@ -0,0 +1,152 @@
+/* This file is used by test-combination.c and test-threads.c to
+ bring all of the non-failing test cases into one source file,
+ renaming each "create_code" and "verify_code" hook so that they
+ each have unique name. */
+
+/* Include various other test cases, defining COMBINED_TEST so that
+ harness.h doesn't duplicate copes of e.g. main, and renaming the
+ hooks provided by each test case. */
+#define COMBINED_TEST
+
+/* test-accessing-struct.c */
+#define create_code create_code_accessing_struct
+#define verify_code verify_code_accessing_struct
+#include "test-accessing-struct.c"
+#undef create_code
+#undef verify_code
+
+/* test-accessing-union.c */
+#define create_code create_code_accessing_union
+#define verify_code verify_code_accessing_union
+#include "test-accessing-union.c"
+#undef create_code
+#undef verify_code
+
+/* test-array-as-pointer.c */
+#define create_code create_code_array_as_pointer
+#define verify_code verify_code_array_as_pointer
+#include "test-array-as-pointer.c"
+#undef create_code
+#undef verify_code
+
+/* test-arrays.c */
+#define create_code create_code_arrays
+#define verify_code verify_code_arrays
+#include "test-arrays.c"
+#undef create_code
+#undef verify_code
+
+/* test-calling-external-function.c */
+#define create_code create_code_calling_external_function
+#define verify_code verify_code_calling_external_function
+#include "test-calling-external-function.c"
+#undef create_code
+#undef verify_code
+
+/* test-calling-function-ptr.c */
+#define create_code create_code_calling_function_ptr
+#define verify_code verify_code_calling_function_ptr
+#include "test-calling-function-ptr.c"
+#undef create_code
+#undef verify_code
+
+/* test-dot-product.c */
+#define create_code create_code_dot_product
+#define verify_code verify_code_dot_product
+#include "test-dot-product.c"
+#undef create_code
+#undef verify_code
+
+/* test-error-*.c: We don't use these test cases, since they deliberately
+ introduce errors, which we don't want here. */
+
+/* test-expressions.c */
+#define create_code create_code_expressions
+#define verify_code verify_code_expressions
+#include "test-expressions.c"
+#undef create_code
+#undef verify_code
+
+/* test-factorial.c */
+#define create_code create_code_factorial
+#define verify_code verify_code_factorial
+#include "test-factorial.c"
+#undef create_code
+#undef verify_code
+
+/* test-fibonacci.c */
+#define create_code create_code_fibonacci
+#define verify_code verify_code_fibonacci
+#include "test-fibonacci.c"
+#undef create_code
+#undef verify_code
+
+/* test-functions.c */
+#define create_code create_code_functions
+#define verify_code verify_code_functions
+#include "test-functions.c"
+#undef create_code
+#undef verify_code
+
+/* test-hello-world.c */
+#define create_code create_code_hello_world
+#define verify_code verify_code_hello_world
+#include "test-hello-world.c"
+#undef create_code
+#undef verify_code
+
+/* test-linked-list.c */
+#define create_code create_code_linked_list
+#define verify_code verify_code_linked_list
+#include "test-linked-list.c"
+#undef create_code
+#undef verify_code
+
+/* test-quadratic.c */
+#define create_code create_code_quadratic
+#define verify_code verify_code_quadratic
+#include "test-quadratic.c"
+#undef create_code
+#undef verify_code
+
+/* test-reading-struct.c */
+#define create_code create_code_reading_struct
+#define verify_code verify_code_reading_struct
+#include "test-reading-struct.c"
+#undef create_code
+#undef verify_code
+
+/* test-string-literal.c */
+#define create_code create_code_string_literal
+#define verify_code verify_code_string_literal
+#include "test-string-literal.c"
+#undef create_code
+#undef verify_code
+
+/* test-sum-of-squares.c */
+#define create_code create_code_sum_of_squares
+#define verify_code verify_code_sum_of_squares
+#include "test-sum-of-squares.c"
+#undef create_code
+#undef verify_code
+
+/* test-types.c */
+#define create_code create_code_types
+#define verify_code verify_code_types
+#include "test-types.c"
+#undef create_code
+#undef verify_code
+
+/* test-using-global.c */
+#define create_code create_code_using_global
+#define verify_code verify_code_using_global
+#include "test-using-global.c"
+#undef create_code
+#undef verify_code
+
+/* test-volatile.c */
+#define create_code create_code_volatile
+#define verify_code verify_code_volatile
+#include "test-volatile.c"
+#undef create_code
+#undef verify_code
diff --git a/gcc/testsuite/jit.dg/harness.h b/gcc/testsuite/jit.dg/harness.h
index e67ac36..cee42f3 100644
--- a/gcc/testsuite/jit.dg/harness.h
+++ b/gcc/testsuite/jit.dg/harness.h
@@ -14,9 +14,22 @@
#include <stdlib.h>
#include <stdio.h>
+/* test-threads.c use threads, but dejagnu.h isn't thread-safe; there's a
+ shared "buffer", and the counts of passed/failed etc are globals.
+
+ The solution is to use macros to rename "pass" and "fail", replacing them
+ with mutex-guarded alternatives. */
+#ifdef MAKE_DEJAGNU_H_THREADSAFE
+#define pass dejagnu_pass
+#define fail dejagnu_fail
+#endif
+
#include <dejagnu.h>
-#include "libgccjit.h"
+#ifdef MAKE_DEJAGNU_H_THREADSAFE
+#undef pass
+#undef fail
+#endif
static char test[1024];
@@ -89,10 +102,10 @@ verify_code (gcc_jit_context *ctxt, gcc_jit_result *result);
extern void check_string_value (const char *actual, const char *expected);
/* Implement framework needed for turning the testcase hooks into an
- executable. test-combination.c combines multiple testcases into one
- testcase, so we have TEST_COMBINATION as a way of temporarily turning
- off this part of harness.h. */
-#ifndef TEST_COMBINATION
+ executable. test-combination.c and test-threads.c each combine multiple
+ testcases into larger testcases, so we have COMBINED_TEST as a way of
+ temporarily turning off this part of harness.h. */
+#ifndef COMBINED_TEST
void check_string_value (const char *actual, const char *expected)
{
@@ -224,4 +237,4 @@ main (int argc, char **argv)
}
#endif /* #ifndef TEST_PROVIDES_MAIN */
-#endif /* #ifndef TEST_COMBINATION */
+#endif /* #ifndef COMBINED_TEST */
diff --git a/gcc/testsuite/jit.dg/jit.exp b/gcc/testsuite/jit.dg/jit.exp
index e998d69..b157955 100644
--- a/gcc/testsuite/jit.dg/jit.exp
+++ b/gcc/testsuite/jit.dg/jit.exp
@@ -41,6 +41,11 @@ proc jit-dg-test { prog do_what extra_tool_flags } {
verbose " do_what: $do_what"
verbose " extra_tool_flags: $extra_tool_flags"
+ # test-threads.c needs to be linked against pthreads
+ if {[string match "*test-threads.c" $prog]} {
+ append extra_tool_flags " -lpthread"
+ }
+
# Determine what to name the built executable.
set output_file "[file rootname [file tail $prog]].exe"
verbose "output_file: $output_file"
diff --git a/gcc/testsuite/jit.dg/test-combination.c b/gcc/testsuite/jit.dg/test-combination.c
index a3e3102..1b9432b 100644
--- a/gcc/testsuite/jit.dg/test-combination.c
+++ b/gcc/testsuite/jit.dg/test-combination.c
@@ -2,159 +2,13 @@
out state issues: all of the test cases are run in one process, inside
one gcc_jit_context (per iteration). */
-/* Include various other test cases, defining TEST_COMBINATION so that
- harness.h doesn't duplicate copes of e.g. main, and renaming the
- hooks provided by each test case. */
-#define TEST_COMBINATION
-
-/* test-accessing-struct.c */
-#define create_code create_code_accessing_struct
-#define verify_code verify_code_accessing_struct
-#include "test-accessing-struct.c"
-#undef create_code
-#undef verify_code
-
-/* test-accessing-union.c */
-#define create_code create_code_accessing_union
-#define verify_code verify_code_accessing_union
-#include "test-accessing-union.c"
-#undef create_code
-#undef verify_code
-
-/* test-array-as-pointer.c */
-#define create_code create_code_array_as_pointer
-#define verify_code verify_code_array_as_pointer
-#include "test-array-as-pointer.c"
-#undef create_code
-#undef verify_code
-
-/* test-arrays.c */
-#define create_code create_code_arrays
-#define verify_code verify_code_arrays
-#include "test-arrays.c"
-#undef create_code
-#undef verify_code
-
-/* test-calling-external-function.c */
-#define create_code create_code_calling_external_function
-#define verify_code verify_code_calling_external_function
-#include "test-calling-external-function.c"
-#undef create_code
-#undef verify_code
-
-/* test-calling-function-ptr.c */
-#define create_code create_code_calling_function_ptr
-#define verify_code verify_code_calling_function_ptr
-#include "test-calling-function-ptr.c"
-#undef create_code
-#undef verify_code
-
-/* test-dot-product.c */
-#define create_code create_code_dot_product
-#define verify_code verify_code_dot_product
-#include "test-dot-product.c"
-#undef create_code
-#undef verify_code
-
-/* test-error-*.c: We don't use these test cases, since they deliberately
- introduce errors, which we don't want here. */
-
-/* test-expressions.c */
-#define create_code create_code_expressions
-#define verify_code verify_code_expressions
-#include "test-expressions.c"
-#undef create_code
-#undef verify_code
-
-/* test-factorial.c */
-#define create_code create_code_factorial
-#define verify_code verify_code_factorial
-#include "test-factorial.c"
-#undef create_code
-#undef verify_code
-
-/* test-fibonacci.c */
-#define create_code create_code_fibonacci
-#define verify_code verify_code_fibonacci
-#include "test-fibonacci.c"
-#undef create_code
-#undef verify_code
-
-/* test-functions.c */
-#define create_code create_code_functions
-#define verify_code verify_code_functions
-#include "test-functions.c"
-#undef create_code
-#undef verify_code
-
-/* test-hello-world.c */
-#define create_code create_code_hello_world
-#define verify_code verify_code_hello_world
-#include "test-hello-world.c"
-#undef create_code
-#undef verify_code
-
-/* test-linked-list.c */
-#define create_code create_code_linked_list
-#define verify_code verify_code_linked_list
-#include "test-linked-list.c"
-#undef create_code
-#undef verify_code
-
-/* test-quadratic.c */
-#define create_code create_code_quadratic
-#define verify_code verify_code_quadratic
-#include "test-quadratic.c"
-#undef create_code
-#undef verify_code
-
-/* test-reading-struct.c */
-#define create_code create_code_reading_struct
-#define verify_code verify_code_reading_struct
-#include "test-reading-struct.c"
-#undef create_code
-#undef verify_code
-
-/* test-string-literal.c */
-#define create_code create_code_string_literal
-#define verify_code verify_code_string_literal
-#include "test-string-literal.c"
-#undef create_code
-#undef verify_code
-
-/* test-sum-of-squares.c */
-#define create_code create_code_sum_of_squares
-#define verify_code verify_code_sum_of_squares
-#include "test-sum-of-squares.c"
-#undef create_code
-#undef verify_code
-
-/* test-types.c */
-#define create_code create_code_types
-#define verify_code verify_code_types
-#include "test-types.c"
-#undef create_code
-#undef verify_code
-
-/* test-using-global.c */
-#define create_code create_code_using_global
-#define verify_code verify_code_using_global
-#include "test-using-global.c"
-#undef create_code
-#undef verify_code
-
-/* test-volatile.c */
-#define create_code create_code_volatile
-#define verify_code verify_code_volatile
-#include "test-volatile.c"
-#undef create_code
-#undef verify_code
+#include "all-non-failing-tests.h"
/* Now construct a test case from all the other test cases.
- We undefine TEST_COMBINATION so that we can now include harness.h
+ We undefine COMBINED_TEST so that we can now include harness.h
"for real". */
-#undef TEST_COMBINATION
+#undef COMBINED_TEST
#include "harness.h"
/* Our testing hooks are the combination of the other test cases. */
diff --git a/gcc/testsuite/jit.dg/test-threads.c b/gcc/testsuite/jit.dg/test-threads.c
new file mode 100644
index 0000000..f31d094
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-threads.c
@@ -0,0 +1,230 @@
+/* test-threads.c
+
+ As per test-combination.c, construct a test case by combining other test
+ cases, to try to shake out state issues. However each test runs in a
+ separate thread. */
+
+#include <pthread.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+/* dejagnu.h isn't thread-safe; there's a shared "buffer", and the counts
+ of "passed"/"failed" etc are globals.
+
+ We get around this by putting a mutex around pass/fail calls.
+ */
+
+static pthread_mutex_t dg_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* By defining MAKE_DEJAGNU_H_THREADSAFE before we include harness.h,
+ harness.h injects macros before including <dejagnu.h> so that the
+ pass/fail functions become "dejagnu_pass"/"dejagnu_fail". */
+
+void dejagnu_pass (const char* fmt, ...);
+void dejagnu_fail (const char* fmt, ...);
+
+/* We now provide our own implementations of "pass"/"fail", which call
+ the underlying dejagnu implementations, but with a mutex. */
+
+inline void
+pass (const char* fmt, ...)
+{
+ va_list ap;
+ char buffer[512];
+
+ va_start (ap, fmt);
+ vsnprintf (buffer, sizeof (buffer), fmt, ap);
+ va_end (ap);
+
+ pthread_mutex_lock (&dg_mutex);
+ dejagnu_pass (buffer);
+ pthread_mutex_unlock (&dg_mutex);
+}
+
+inline void
+fail (const char* fmt, ...)
+{
+ va_list ap;
+ char buffer[512];
+
+ va_start (ap, fmt);
+ vsnprintf (buffer, sizeof (buffer), fmt, ap);
+ va_end (ap);
+
+ pthread_mutex_lock (&dg_mutex);
+ dejagnu_fail (buffer);
+ pthread_mutex_unlock (&dg_mutex);
+}
+
+#define MAKE_DEJAGNU_H_THREADSAFE
+
+/* We also need to provide our own version of TEST_NAME. */
+#define TEST_NAME
+
+/* We can now include all of the relevant selftests. */
+
+#include "all-non-failing-tests.h"
+
+#define TEST_PROVIDES_MAIN
+#define TEST_ESCHEWS_TEST_JIT
+
+/* Now construct a test case from all the other test cases.
+
+ We undefine COMBINED_TEST so that we can now include harness.h
+ "for real". */
+#undef COMBINED_TEST
+#include "harness.h"
+
+struct testcase
+{
+ const char *m_name;
+ void (*m_hook_to_create_code) (gcc_jit_context *ctxt,
+ void * user_data);
+ void (*m_hook_to_verify_code) (gcc_jit_context *ctxt,
+ gcc_jit_result *result);
+};
+
+const struct testcase testcases[] = {
+ {"accessing_struct",
+ create_code_accessing_struct,
+ verify_code_accessing_struct},
+ {"accessing_union",
+ create_code_accessing_union,
+ verify_code_accessing_union},
+ {"array_as_pointer",
+ create_code_array_as_pointer,
+ verify_code_array_as_pointer},
+ {"arrays",
+ create_code_arrays,
+ verify_code_arrays},
+ {"calling_external_function",
+ create_code_calling_external_function,
+ verify_code_calling_external_function},
+ {"calling_function_ptr",
+ create_code_calling_function_ptr,
+ verify_code_calling_function_ptr},
+ {"dot_product",
+ create_code_dot_product,
+ verify_code_dot_product},
+ {"expressions",
+ create_code_expressions,
+ verify_code_expressions},
+ {"factorial",
+ create_code_factorial,
+ verify_code_factorial},
+ {"fibonacci",
+ create_code_fibonacci,
+ verify_code_fibonacci},
+ {"functions",
+ create_code_functions,
+ verify_code_functions},
+ {"hello_world",
+ create_code_hello_world,
+ verify_code_hello_world},
+ {"linked_list",
+ create_code_linked_list,
+ verify_code_linked_list},
+ {"quadratic",
+ create_code_quadratic,
+ verify_code_quadratic},
+ {"reading_struct ",
+ create_code_reading_struct ,
+ verify_code_reading_struct },
+ {"string_literal",
+ create_code_string_literal,
+ verify_code_string_literal},
+ {"sum_of_squares",
+ create_code_sum_of_squares,
+ verify_code_sum_of_squares},
+ {"types",
+ create_code_types,
+ verify_code_types},
+ {"using_global",
+ create_code_using_global,
+ verify_code_using_global},
+ {"volatile",
+ create_code_volatile,
+ verify_code_volatile}
+};
+
+const int num_testcases = (sizeof (testcases) / sizeof (testcases[0]));
+
+struct thread_data
+{
+ pthread_t m_tid;
+ const struct testcase *m_testcase;
+};
+
+static const char *argv0;
+
+void *
+run_threaded_test (void *data)
+{
+ struct thread_data *thread = (struct thread_data *)data;
+ int i;
+
+ for (i = 0; i < 5; i++)
+ {
+ gcc_jit_context *ctxt;
+ gcc_jit_result *result;
+
+ printf ("run_threaded_test: %s iteration: %d\n",
+ thread->m_testcase->m_name, i);
+
+ ctxt = gcc_jit_context_acquire ();
+
+ set_options (ctxt, argv0);
+
+ thread->m_testcase->m_hook_to_create_code (ctxt, NULL);
+
+ result = gcc_jit_context_compile (ctxt);
+
+ thread->m_testcase->m_hook_to_verify_code (ctxt, result);
+
+ gcc_jit_context_release (ctxt);
+
+ /* Once we're done with the code, this unloads the built .so file: */
+ gcc_jit_result_release (result);
+ }
+
+ return NULL;
+}
+
+int
+main (int argc, char **argv)
+{
+ int i;
+
+ snprintf (test, sizeof (test),
+ "%s",
+ extract_progname (argv[0]));
+
+ argv0 = argv[0];
+
+ /* The individual testcases are not thread-safe (some have their own
+ global variables), so we have one thread per test-case. */
+ struct thread_data *threads =
+ calloc (num_testcases, sizeof (struct thread_data));
+
+ /* Start a thread per test-case. */
+ for (i = 0; i < num_testcases; i++)
+ {
+ struct thread_data *thread = &threads[i];
+ thread->m_testcase = &testcases[i];
+ pthread_create (&thread->m_tid,
+ NULL,
+ run_threaded_test,
+ thread);
+ }
+
+ /* Wait for all the threads to be done. */
+ for (i = 0; i < num_testcases; i++)
+ {
+ struct thread_data *thread = &threads[i];
+ (void)pthread_join (thread->m_tid, NULL);
+ }
+
+ totals ();
+
+ return 0;
+}
--
1.8.5.3