This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH, committed] jit: add test-benchmark.c
- 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: Wed, 6 May 2015 16:29:15 -0400
- Subject: [PATCH, committed] jit: add test-benchmark.c
- Authentication-results: sourceware.org; auth=none
Add a simple benchmark to the jit testsuite: measuring the wallclock
time of:
* building a simple function (sum of squares from 0..n-1)
* compiling it in-memory
* running it (with n=100)
doing this combined test 100 times, at each optimization level.
On this machine I get this output:
PASSED: ./test-benchmark.c.exe: survived 100 iterations at optlevel 0
NOTE: ./test-benchmark.c.exe: 100 iterations at optlevel 0 took a total of 5.140s (0.051s per iteration)
PASSED: ./test-benchmark.c.exe: survived 100 iterations at optlevel 1
NOTE: ./test-benchmark.c.exe: 100 iterations at optlevel 1 took a total of 5.260s (0.053s per iteration)
PASSED: ./test-benchmark.c.exe: survived 100 iterations at optlevel 2
NOTE: ./test-benchmark.c.exe: 100 iterations at optlevel 2 took a total of 5.450s (0.054s per iteration)
PASSED: ./test-benchmark.c.exe: survived 100 iterations at optlevel 3
NOTE: ./test-benchmark.c.exe: 100 iterations at optlevel 3 took a total of 6.050s (0.061s per iteration)
Takes jit.sum to 7609 passes
Committed to trunk as r222863.
gcc/testsuite/ChangeLog:
* jit.dg/harness.h (set_options): Wrap with
#ifndef TEST_ESCHEWS_SET_OPTIONS.
* jit.dg/jit.exp (is_testcase_meant_to_generate_a_reproducer):
Special-case test-benchmark.c as a negative.
* jit.dg/test-benchmark.c: New file.
---
gcc/testsuite/jit.dg/harness.h | 2 +
gcc/testsuite/jit.dg/jit.exp | 6 +-
gcc/testsuite/jit.dg/test-benchmark.c | 240 ++++++++++++++++++++++++++++++++++
3 files changed, 247 insertions(+), 1 deletion(-)
create mode 100644 gcc/testsuite/jit.dg/test-benchmark.c
diff --git a/gcc/testsuite/jit.dg/harness.h b/gcc/testsuite/jit.dg/harness.h
index 907da56..6b59fb5 100644
--- a/gcc/testsuite/jit.dg/harness.h
+++ b/gcc/testsuite/jit.dg/harness.h
@@ -230,6 +230,7 @@ check_string_contains (const char *funcname,
test, funcname, name, expected_substring);
}
+#ifndef TEST_ESCHEWS_SET_OPTIONS
static void set_options (gcc_jit_context *ctxt, const char *argv0)
{
/* Set up options. */
@@ -262,6 +263,7 @@ static void set_options (gcc_jit_context *ctxt, const char *argv0)
GCC_JIT_BOOL_OPTION_DUMP_SUMMARY,
0);
}
+#endif /* #ifndef TEST_ESCHEWS_SET_OPTIONS */
/* Concatenate two strings. The result must be released using "free". */
diff --git a/gcc/testsuite/jit.dg/jit.exp b/gcc/testsuite/jit.dg/jit.exp
index d13f6b5..39e37c2 100644
--- a/gcc/testsuite/jit.dg/jit.exp
+++ b/gcc/testsuite/jit.dg/jit.exp
@@ -308,12 +308,16 @@ verbose "tests: $tests"
proc is_testcase_meant_to_generate_a_reproducer {name} {
# We expect most testcases to generate a reproducer.
# The exceptions are the tutorials (which don't have a "test-"
- # prefix), and test-threads.c (which is unique).
+ # prefix), and test-threads.c and test-benchmark.c (which are each
+ # unique).
verbose "is_testcase_meant_to_generate_a_reproducer: $name"
if { [string match "*test-*" $name] } {
if { [string match "*test-threads.c" $name] } {
return 0
}
+ if { [string match "*test-benchmark.c" $name] } {
+ return 0
+ }
return 1
}
return 0
diff --git a/gcc/testsuite/jit.dg/test-benchmark.c b/gcc/testsuite/jit.dg/test-benchmark.c
new file mode 100644
index 0000000..324ba93
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-benchmark.c
@@ -0,0 +1,240 @@
+/* A simple benchmark: how long does it take to use libgccjit to
+ compile and run a simple function? */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/times.h>
+
+#include "libgccjit.h"
+
+#define TEST_ESCHEWS_SET_OPTIONS
+#define TEST_ESCHEWS_TEST_JIT
+#define TEST_PROVIDES_MAIN
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /*
+ Simple sum-of-squares, to test conditionals and looping
+
+ int loop_test (int n)
+ {
+ int i;
+ int sum = 0;
+ for (i = 0; i < n ; i ++)
+ {
+ sum += i * i;
+ }
+ return sum;
+ */
+ gcc_jit_type *the_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+ gcc_jit_type *return_type = the_type;
+
+ gcc_jit_param *n =
+ gcc_jit_context_new_param (ctxt, NULL, the_type, "n");
+ gcc_jit_param *params[1] = {n};
+ gcc_jit_function *func =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ return_type,
+ "loop_test",
+ 1, params, 0);
+
+ /* Build locals: */
+ gcc_jit_lvalue *i =
+ gcc_jit_function_new_local (func, NULL, the_type, "i");
+ gcc_jit_lvalue *sum =
+ gcc_jit_function_new_local (func, NULL, the_type, "sum");
+
+ gcc_jit_block *initial =
+ gcc_jit_function_new_block (func, "initial");
+ gcc_jit_block *loop_cond =
+ gcc_jit_function_new_block (func, "loop_cond");
+ gcc_jit_block *loop_body =
+ gcc_jit_function_new_block (func, "loop_body");
+ gcc_jit_block *after_loop =
+ gcc_jit_function_new_block (func, "after_loop");
+
+ /* sum = 0; */
+ gcc_jit_block_add_assignment (
+ initial, NULL,
+ sum,
+ gcc_jit_context_new_rvalue_from_int (ctxt, the_type, 0));
+
+ /* i = 0; */
+ gcc_jit_block_add_assignment (
+ initial, NULL,
+ i,
+ gcc_jit_context_new_rvalue_from_int (ctxt, the_type, 0));
+
+ gcc_jit_block_end_with_jump (initial, NULL, loop_cond);
+
+ /* if (i >= n) */
+ gcc_jit_block_end_with_conditional (
+ loop_cond, NULL,
+ gcc_jit_context_new_comparison (
+ ctxt, NULL,
+ GCC_JIT_COMPARISON_GE,
+ gcc_jit_lvalue_as_rvalue (i),
+ gcc_jit_param_as_rvalue (n)),
+ after_loop,
+ loop_body);
+
+ /* sum += i * i */
+ gcc_jit_block_add_assignment (
+ loop_body, NULL,
+ sum,
+ gcc_jit_context_new_binary_op (
+ ctxt, NULL,
+ GCC_JIT_BINARY_OP_PLUS, the_type,
+ gcc_jit_lvalue_as_rvalue (sum),
+ gcc_jit_context_new_binary_op (
+ ctxt, NULL,
+ GCC_JIT_BINARY_OP_MULT, the_type,
+ gcc_jit_lvalue_as_rvalue (i),
+ gcc_jit_lvalue_as_rvalue (i))));
+
+ /* i++ */
+ gcc_jit_block_add_assignment (
+ loop_body, NULL,
+ i,
+ gcc_jit_context_new_binary_op (
+ ctxt, NULL,
+ GCC_JIT_BINARY_OP_PLUS, the_type,
+ gcc_jit_lvalue_as_rvalue (i),
+ gcc_jit_context_new_rvalue_from_int (
+ ctxt,
+ the_type,
+ 1)));
+
+ gcc_jit_block_end_with_jump (loop_body, NULL, loop_cond);
+
+ /* return sum */
+ gcc_jit_block_end_with_return (
+ after_loop,
+ NULL,
+ gcc_jit_lvalue_as_rvalue (sum));
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ typedef int (*loop_test_fn_type) (int);
+ if (!result)
+ {
+ fail ("%s: %s: !result", test, __func__);
+ return;
+ }
+ loop_test_fn_type loop_test =
+ (loop_test_fn_type)gcc_jit_result_get_code (result, "loop_test");
+ if (!loop_test)
+ {
+ fail ("%s: %s: !loop_test", test, __func__);
+ return;
+ }
+ int val = loop_test (100);
+ if (val != 328350)
+ fail ("%s: %s: val != 328350", test, __func__);
+}
+
+/* Run one iteration of the test. */
+static void
+test_jit (const char *argv0, int opt_level)
+{
+ gcc_jit_context *ctxt;
+ gcc_jit_result *result;
+
+ ctxt = gcc_jit_context_acquire ();
+ if (!ctxt)
+ {
+ fail ("gcc_jit_context_acquire failed");
+ return;
+ }
+
+ /* Set up options. */
+ gcc_jit_context_set_str_option (
+ ctxt,
+ GCC_JIT_STR_OPTION_PROGNAME,
+ argv0);
+
+ /* Set up options for benchmarking. */
+ gcc_jit_context_set_int_option (
+ ctxt,
+ GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
+ opt_level);
+ /* Generating debuginfo takes time; turn it off. */
+ gcc_jit_context_set_bool_option (
+ ctxt,
+ GCC_JIT_BOOL_OPTION_DEBUGINFO,
+ 0);
+ /* This option is extremely slow; turn it off. */
+ gcc_jit_context_set_bool_option (
+ ctxt,
+ GCC_JIT_BOOL_OPTION_SELFCHECK_GC,
+ 0);
+
+ /* Turn this on to get detailed timings. */
+ if (0)
+ gcc_jit_context_set_bool_option (
+ ctxt,
+ GCC_JIT_BOOL_OPTION_DUMP_SUMMARY,
+ 1);
+
+ create_code (ctxt, NULL);
+
+ result = gcc_jit_context_compile (ctxt);
+ verify_code (ctxt, result);
+
+ gcc_jit_context_release (ctxt);
+ gcc_jit_result_release (result);
+}
+
+/* Taken from timevar.c. */
+static double ticks_to_msec;
+#define TICKS_PER_SECOND sysconf (_SC_CLK_TCK) /* POSIX 1003.1-1996 */
+#define TICKS_TO_MSEC (1 / (double)TICKS_PER_SECOND)
+static double get_wallclock_time (void)
+{
+ struct tms tms;
+ return times (&tms) * ticks_to_msec;
+}
+
+/* Time 100 iterations, at each optimization level
+ (for 400 iterations in all). */
+
+int
+main (int argc, char **argv)
+{
+ int opt_level;
+ int num_iterations = 100;
+
+ ticks_to_msec = TICKS_TO_MSEC;
+
+ for (opt_level = 0; opt_level < 4; opt_level++)
+ {
+ int i;
+ double start_time, end_time, elapsed_time;
+ start_time = get_wallclock_time ();
+ for (i = 1; i <= num_iterations; i++)
+ {
+ snprintf (test, sizeof (test),
+ "%s iteration %d of %d",
+ extract_progname (argv[0]),
+ i, num_iterations);
+ test_jit (argv[0], opt_level);
+ }
+ end_time = get_wallclock_time ();
+ elapsed_time = end_time - start_time;
+ pass ("%s: survived %i iterations at optlevel %i",
+ argv[0], num_iterations, opt_level);
+ note (("%s: %i iterations at optlevel %i"
+ " took a total of %.3fs (%.3fs per iteration)"),
+ argv[0], num_iterations, opt_level,
+ elapsed_time, elapsed_time / num_iterations);
+ }
+ totals ();
+
+ return 0;
+}
--
1.8.5.3