1 /* A simple benchmark: how long does it take to use libgccjit to
2    compile and run a simple function?  */
3 #include <stdlib.h>
4 #include <stdio.h>
5 #include <string.h>
6 #include <sys/times.h>
7 
8 #include "libgccjit.h"
9 
10 #define TEST_ESCHEWS_SET_OPTIONS
11 #define TEST_ESCHEWS_TEST_JIT
12 #define TEST_PROVIDES_MAIN
13 #include "harness.h"
14 
15 void
create_code(gcc_jit_context * ctxt,void * user_data)16 create_code (gcc_jit_context *ctxt, void *user_data)
17 {
18   /*
19     Simple sum-of-squares, to test conditionals and looping
20 
21     int loop_test (int n)
22     {
23       int i;
24       int sum = 0;
25       for (i = 0; i < n ; i ++)
26       {
27 	sum += i * i;
28       }
29       return sum;
30    */
31   gcc_jit_type *the_type =
32     gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
33   gcc_jit_type *return_type = the_type;
34 
35   gcc_jit_param *n =
36     gcc_jit_context_new_param (ctxt, NULL, the_type, "n");
37   gcc_jit_param *params[1] = {n};
38   gcc_jit_function *func =
39     gcc_jit_context_new_function (ctxt, NULL,
40 				  GCC_JIT_FUNCTION_EXPORTED,
41 				  return_type,
42 				  "loop_test",
43 				  1, params, 0);
44 
45   /* Build locals:  */
46   gcc_jit_lvalue *i =
47     gcc_jit_function_new_local (func, NULL, the_type, "i");
48   gcc_jit_lvalue *sum =
49     gcc_jit_function_new_local (func, NULL, the_type, "sum");
50 
51   gcc_jit_block *initial =
52     gcc_jit_function_new_block (func, "initial");
53   gcc_jit_block *loop_cond =
54     gcc_jit_function_new_block (func, "loop_cond");
55   gcc_jit_block *loop_body =
56     gcc_jit_function_new_block (func, "loop_body");
57   gcc_jit_block *after_loop =
58     gcc_jit_function_new_block (func, "after_loop");
59 
60   /* sum = 0; */
61   gcc_jit_block_add_assignment (
62     initial, NULL,
63     sum,
64     gcc_jit_context_new_rvalue_from_int (ctxt, the_type, 0));
65 
66   /* i = 0; */
67   gcc_jit_block_add_assignment (
68     initial, NULL,
69     i,
70     gcc_jit_context_new_rvalue_from_int (ctxt, the_type, 0));
71 
72   gcc_jit_block_end_with_jump (initial, NULL, loop_cond);
73 
74   /* if (i >= n) */
75   gcc_jit_block_end_with_conditional (
76     loop_cond, NULL,
77     gcc_jit_context_new_comparison (
78        ctxt, NULL,
79        GCC_JIT_COMPARISON_GE,
80        gcc_jit_lvalue_as_rvalue (i),
81        gcc_jit_param_as_rvalue (n)),
82     after_loop,
83     loop_body);
84 
85   /* sum += i * i */
86   gcc_jit_block_add_assignment (
87     loop_body, NULL,
88     sum,
89     gcc_jit_context_new_binary_op (
90       ctxt, NULL,
91       GCC_JIT_BINARY_OP_PLUS, the_type,
92       gcc_jit_lvalue_as_rvalue (sum),
93       gcc_jit_context_new_binary_op (
94 	 ctxt, NULL,
95 	 GCC_JIT_BINARY_OP_MULT, the_type,
96 	 gcc_jit_lvalue_as_rvalue (i),
97 	 gcc_jit_lvalue_as_rvalue (i))));
98 
99   /* i++ */
100   gcc_jit_block_add_assignment (
101     loop_body, NULL,
102     i,
103     gcc_jit_context_new_binary_op (
104       ctxt, NULL,
105       GCC_JIT_BINARY_OP_PLUS, the_type,
106       gcc_jit_lvalue_as_rvalue (i),
107       gcc_jit_context_new_rvalue_from_int (
108 	ctxt,
109 	the_type,
110 	1)));
111 
112   gcc_jit_block_end_with_jump (loop_body, NULL, loop_cond);
113 
114   /* return sum */
115   gcc_jit_block_end_with_return (
116     after_loop,
117     NULL,
118     gcc_jit_lvalue_as_rvalue (sum));
119 }
120 
121 void
verify_code(gcc_jit_context * ctxt,gcc_jit_result * result)122 verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
123 {
124   typedef int (*loop_test_fn_type) (int);
125   if (!result)
126     {
127       fail ("%s: %s: !result", test, __func__);
128       return;
129     }
130   loop_test_fn_type loop_test =
131     (loop_test_fn_type)gcc_jit_result_get_code (result, "loop_test");
132   if (!loop_test)
133     {
134       fail ("%s: %s: !loop_test", test, __func__);
135       return;
136     }
137   int val = loop_test (100);
138   if (val != 328350)
139     fail ("%s: %s: val != 328350", test, __func__);
140 }
141 
142 /* Run one iteration of the test.  */
143 static void
test_jit(const char * argv0,int opt_level,gcc_jit_timer * timer)144 test_jit (const char *argv0, int opt_level, gcc_jit_timer *timer)
145 {
146   gcc_jit_context *ctxt;
147   gcc_jit_result *result;
148 
149   gcc_jit_timer_push (timer, "test_jit");
150 
151   ctxt = gcc_jit_context_acquire ();
152   if (!ctxt)
153     {
154       fail ("gcc_jit_context_acquire failed");
155       return;
156     }
157 
158   gcc_jit_context_set_timer (ctxt, timer);
159 
160   /* Set up options.  */
161   gcc_jit_context_set_str_option (
162     ctxt,
163     GCC_JIT_STR_OPTION_PROGNAME,
164     argv0);
165 
166   /* Set up options for benchmarking.  */
167   gcc_jit_context_set_int_option (
168     ctxt,
169     GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
170     opt_level);
171   /* Generating debuginfo takes time; turn it off.  */
172   gcc_jit_context_set_bool_option (
173     ctxt,
174     GCC_JIT_BOOL_OPTION_DEBUGINFO,
175     0);
176   /* This option is extremely slow; turn it off.  */
177   gcc_jit_context_set_bool_option (
178     ctxt,
179     GCC_JIT_BOOL_OPTION_SELFCHECK_GC,
180     0);
181 
182   /* Turn this on to get detailed timings.  */
183   if (0)
184     gcc_jit_context_set_bool_option (
185       ctxt,
186       GCC_JIT_BOOL_OPTION_DUMP_SUMMARY,
187       1);
188 
189   gcc_jit_timer_push (timer, "create_code");
190   create_code (ctxt, NULL);
191   gcc_jit_timer_pop (timer, "create_code");
192 
193   gcc_jit_timer_push (timer, "compile");
194   result = gcc_jit_context_compile (ctxt);
195   gcc_jit_timer_pop (timer, "compile");
196 
197   gcc_jit_timer_push (timer, "verify_code");
198   verify_code (ctxt, result);
199   gcc_jit_timer_pop (timer, "verify_code");
200 
201   gcc_jit_context_release (ctxt);
202   gcc_jit_result_release (result);
203 
204   gcc_jit_timer_pop (timer, "test_jit");
205 }
206 
207 /* Taken from timevar.c.  */
208 static double ticks_to_msec;
209 #define TICKS_PER_SECOND sysconf (_SC_CLK_TCK) /* POSIX 1003.1-1996 */
210 #define TICKS_TO_MSEC (1 / (double)TICKS_PER_SECOND)
get_wallclock_time(void)211 static double get_wallclock_time (void)
212 {
213   struct tms tms;
214   return times (&tms) * ticks_to_msec;
215 }
216 
217 /* Time 100 iterations, at each optimization level
218    (for 400 iterations in all).  */
219 
220 int
main(int argc,char ** argv)221 main (int argc, char **argv)
222 {
223   int opt_level;
224   int num_iterations = 100;
225   double elapsed_time[4];
226 
227   ticks_to_msec = TICKS_TO_MSEC;
228 
229   for (opt_level = 0; opt_level < 4; opt_level++)
230     {
231       int i;
232       double start_time, end_time;
233       start_time = get_wallclock_time ();
234       gcc_jit_timer *timer = gcc_jit_timer_new ();
235       for (i = 1; i <= num_iterations; i++)
236 	{
237 	  snprintf (test, sizeof (test),
238 		    "%s iteration %d of %d",
239 		    extract_progname (argv[0]),
240 		    i, num_iterations);
241 	  test_jit (argv[0], opt_level, timer);
242 	}
243       end_time = get_wallclock_time ();
244       elapsed_time[opt_level] = end_time - start_time;
245       gcc_jit_timer_print (timer, stderr);
246       gcc_jit_timer_release (timer);
247       pass ("%s: survived %i iterations at optlevel %i",
248 	    argv[0], num_iterations, opt_level);
249       note (("%s: %i iterations at optlevel %i"
250 	     " took a total of %.3fs (%.3fs per iteration)"),
251 	    argv[0], num_iterations, opt_level,
252 	    elapsed_time[opt_level],
253 	    elapsed_time[opt_level] / num_iterations);
254     }
255 
256   totals ();
257 
258   /* Print a summary.  */
259   printf ("%s: %i iterations: time taken (lower is better)\n",
260 	  argv[0], num_iterations);
261   for (opt_level = 0; opt_level < 4; opt_level++)
262     printf ("optlevel %i: %.3fs (%.3fs per iteration)\n",
263 	    opt_level,
264 	    elapsed_time[opt_level],
265 	    elapsed_time[opt_level] / num_iterations);
266 
267   return 0;
268 }
269