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 <dmalc...@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 <dmalc...@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