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