This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH, committed] jit: add test-benchmark.c


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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]