diff options
Diffstat (limited to '')
-rw-r--r-- | libraries/eina/src/include/eina_benchmark.h | 453 |
1 files changed, 453 insertions, 0 deletions
diff --git a/libraries/eina/src/include/eina_benchmark.h b/libraries/eina/src/include/eina_benchmark.h new file mode 100644 index 0000000..721e1c0 --- /dev/null +++ b/libraries/eina/src/include/eina_benchmark.h | |||
@@ -0,0 +1,453 @@ | |||
1 | /* EINA - EFL data type library | ||
2 | * Copyright (C) 2008 Cedric Bail | ||
3 | * | ||
4 | * This library is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU Lesser General Public | ||
6 | * License as published by the Free Software Foundation; either | ||
7 | * version 2.1 of the License, or (at your option) any later version. | ||
8 | * | ||
9 | * This library is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | * Lesser General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU Lesser General Public | ||
15 | * License along with this library; | ||
16 | * if not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | #ifndef EINA_BENCHMARK_H_ | ||
20 | #define EINA_BENCHMARK_H_ | ||
21 | |||
22 | #include "eina_array.h" | ||
23 | |||
24 | |||
25 | |||
26 | /** | ||
27 | * @page tutorial_benchmark_page Benchmark Tutorial | ||
28 | * | ||
29 | * The Benchmark module allows you to write easily benchmarks | ||
30 | * framework in a project for timing critical part and detect slow | ||
31 | * parts of code. In addition it automatically creates data files of | ||
32 | * these benchmark, as well as a gnuplot file which can display the | ||
33 | * comparison curves of the benchmarks. | ||
34 | * | ||
35 | * @section tutorial_benchmark_basic_usage Basic Usage | ||
36 | * | ||
37 | * To create a basic benchmark, you have to follow these steps: | ||
38 | * | ||
39 | * @li Create a new bechmark | ||
40 | * @li Write the functions that wraps the the functions you want to | ||
41 | * bechmark. | ||
42 | * @li Register these wrappers functions. | ||
43 | * @li Run the benchmark. | ||
44 | * @li Free the memory. | ||
45 | * | ||
46 | * Here is a basic example of bechmark which creates two functions | ||
47 | * that will be run. These functions just print a message. | ||
48 | * | ||
49 | * @code | ||
50 | * #include <stdlib.h> | ||
51 | * #include <stdio.h> | ||
52 | * | ||
53 | * #include <Eina.h> | ||
54 | * | ||
55 | * static | ||
56 | * void work1(int request) | ||
57 | * { | ||
58 | * printf ("work1 in progress... Request: %d\n", request); | ||
59 | * } | ||
60 | * | ||
61 | * static | ||
62 | * void work2(int request) | ||
63 | * { | ||
64 | * printf ("work2 in progress... Request: %d\n", request); | ||
65 | * } | ||
66 | * | ||
67 | * int main() | ||
68 | * { | ||
69 | * Eina_Benchmark *test; | ||
70 | * Eina_Array *ea; | ||
71 | * | ||
72 | * if (!eina_init()) | ||
73 | * return EXIT_FAILURE; | ||
74 | * | ||
75 | * test = eina_benchmark_new("test", "run"); | ||
76 | * if (!test) | ||
77 | * goto shutdown_eina; | ||
78 | * | ||
79 | * eina_benchmark_register(test, "work-1", EINA_BENCHMARK(work1), 200, 300, 10); | ||
80 | * eina_benchmark_register(test, "work-2", EINA_BENCHMARK(work2), 100, 150, 5); | ||
81 | * | ||
82 | * ea = eina_benchmark_run(test); | ||
83 | * | ||
84 | * eina_benchmark_free(test); | ||
85 | * eina_shutdown(); | ||
86 | * | ||
87 | * return EXIT_SUCCESS; | ||
88 | * | ||
89 | * shutdown_eina: | ||
90 | * eina_shutdown(); | ||
91 | * | ||
92 | * return EXIT_FAILURE; | ||
93 | * } | ||
94 | * @endcode | ||
95 | * | ||
96 | * As "test", "run" are passed to eina_benchmark_new() and as the tests | ||
97 | * "work-1" and "work-2" are registered, the data files | ||
98 | * bench_test_run.work-1.data and bench_test_run.work-2.data will be | ||
99 | * created after the eina_benchmark_run() call. They contain four | ||
100 | * columns. The file bench_test_run.work-1.data contains for example: | ||
101 | * | ||
102 | * @code | ||
103 | * # specimen experiment time starting time ending time | ||
104 | * 200 23632 2852446 2876078 | ||
105 | * 210 6924 2883046 2889970 | ||
106 | * 220 6467 2895962 2902429 | ||
107 | * 230 6508 2908271 2914779 | ||
108 | * 240 6278 2920610 2926888 | ||
109 | * 250 6342 2932830 2939172 | ||
110 | * 260 6252 2944954 2951206 | ||
111 | * 270 6463 2956978 2963441 | ||
112 | * 280 6347 2969548 2975895 | ||
113 | * 290 6457 2981702 2988159 | ||
114 | * @endcode | ||
115 | * | ||
116 | * The first column (specimen) is the integer passed to the work1() | ||
117 | * function when the test is run. The second column (experiment time) | ||
118 | * is the time, in nanosecond, that work1() takes. The third and | ||
119 | * fourth columnd are self-explicit. | ||
120 | * | ||
121 | * You can see that the integer passed work1() starts from 200 and | ||
122 | * finishes at 290, with a step of 10. These values are computed withe | ||
123 | * last 3 values passed to eina_benchmark_register(). See the document | ||
124 | * of that function for the detailed behavior. | ||
125 | * | ||
126 | * The gnuplot file will be named bench_test_run.gnuplot. Just run: | ||
127 | * | ||
128 | * @code | ||
129 | * gnuplot bench_test_run.gnuplot | ||
130 | * @endcode | ||
131 | * | ||
132 | * to create the graphic of the comparison curves. The image file is | ||
133 | * named output_test_run.png. | ||
134 | * | ||
135 | * @section tutorial_benchmark_advanced_usage More Advanced Usage | ||
136 | * | ||
137 | * In this section, several test will be created and run. The idea is | ||
138 | * exactly the same than in the previous section, but with some basic | ||
139 | * automatic way to run all the benchmarks. The following code | ||
140 | * benchmarks some Eina converts functions, and some Eina containers | ||
141 | * types: | ||
142 | * | ||
143 | * @code | ||
144 | * #include <stdlib.h> | ||
145 | * #include <stdio.h> | ||
146 | * #include <time.h> | ||
147 | * | ||
148 | * #include <Eina.h> | ||
149 | * | ||
150 | * static void bench_convert(Eina_Benchmark *bench); | ||
151 | * static void bench_container(Eina_Benchmark *bench); | ||
152 | * | ||
153 | * typedef struct _Benchmark_Case Benchmark_Case; | ||
154 | * | ||
155 | * struct _Benchmark_Case | ||
156 | * { | ||
157 | * const char *bench_case; | ||
158 | * void (*build)(Eina_Benchmark *bench); | ||
159 | * }; | ||
160 | * | ||
161 | * static const Benchmark_Case benchmarks[] = { | ||
162 | * { "Bench 1", bench_convert }, | ||
163 | * { "Bench 2", bench_container }, | ||
164 | * { NULL, NULL } | ||
165 | * }; | ||
166 | * | ||
167 | * static | ||
168 | * void convert1(int request) | ||
169 | * { | ||
170 | * char tmp[128]; | ||
171 | * int i; | ||
172 | * | ||
173 | * srand(time(NULL)); | ||
174 | * | ||
175 | * for (i = 0; i < request; ++i) | ||
176 | * eina_convert_itoa(rand(), tmp); | ||
177 | * } | ||
178 | * | ||
179 | * static | ||
180 | * void convert2(int request) | ||
181 | * { | ||
182 | * char tmp[128]; | ||
183 | * int i; | ||
184 | * | ||
185 | * srand(time(NULL)); | ||
186 | * | ||
187 | * for (i = 0; i < request; ++i) | ||
188 | * eina_convert_xtoa(rand(), tmp); | ||
189 | * } | ||
190 | * | ||
191 | * static void | ||
192 | * bench_convert(Eina_Benchmark *bench) | ||
193 | * { | ||
194 | * eina_benchmark_register(bench, "convert-1", EINA_BENCHMARK(convert1), 200, 400, 10); | ||
195 | * eina_benchmark_register(bench, "convert-2", EINA_BENCHMARK(convert2), 200, 400, 10); | ||
196 | * } | ||
197 | * | ||
198 | * static | ||
199 | * void array(int request) | ||
200 | * { | ||
201 | * Eina_Array *array; | ||
202 | * Eina_Array_Iterator it; | ||
203 | * int *data; | ||
204 | * int i; | ||
205 | * | ||
206 | * srand(time(NULL)); | ||
207 | * | ||
208 | * array = eina_array_new(64); | ||
209 | * | ||
210 | * for (i = 0; i < request; ++i) | ||
211 | * { | ||
212 | * data = (int *)malloc(sizeof(int)); | ||
213 | * if (!data) continue; | ||
214 | * *data = rand(); | ||
215 | * eina_array_push(array, data); | ||
216 | * } | ||
217 | * | ||
218 | * EINA_ARRAY_ITER_NEXT(array, i, data, it) | ||
219 | * free(data); | ||
220 | * | ||
221 | * eina_array_free(array); | ||
222 | * } | ||
223 | * | ||
224 | * static | ||
225 | * void list(int request) | ||
226 | * { | ||
227 | * Eina_List *l = NULL; | ||
228 | * int *data; | ||
229 | * int i; | ||
230 | * | ||
231 | * srand(time(NULL)); | ||
232 | * | ||
233 | * for (i = 0; i < request; ++i) | ||
234 | * { | ||
235 | * data = (int *)malloc(sizeof(int)); | ||
236 | * if (!data) continue; | ||
237 | * *data = rand(); | ||
238 | * l = eina_list_prepend(l, data); | ||
239 | * } | ||
240 | * | ||
241 | * while (l) | ||
242 | * { | ||
243 | * free(eina_list_data_get(l)); | ||
244 | * l = eina_list_remove_list(l, l); | ||
245 | * } | ||
246 | * } | ||
247 | * | ||
248 | * static void | ||
249 | * bench_container(Eina_Benchmark *bench) | ||
250 | * { | ||
251 | * eina_benchmark_register(bench, "array", EINA_BENCHMARK(array), 200, 300, 10); | ||
252 | * eina_benchmark_register(bench, "list", EINA_BENCHMARK(list), 200, 300, 10); | ||
253 | * } | ||
254 | * | ||
255 | * int main() | ||
256 | * { | ||
257 | * Eina_Benchmark *test; | ||
258 | * Eina_Array *ea; | ||
259 | * unsigned int i; | ||
260 | * | ||
261 | * if (!eina_init()) | ||
262 | * return EXIT_FAILURE; | ||
263 | * | ||
264 | * for (i = 0; benchmarks[i].bench_case != NULL; ++i) | ||
265 | * { | ||
266 | * test = eina_benchmark_new(benchmarks[i].bench_case, "Benchmark example"); | ||
267 | * if (!test) | ||
268 | * continue; | ||
269 | * | ||
270 | * benchmarks[i].build(test); | ||
271 | * | ||
272 | * ea = eina_benchmark_run(test); | ||
273 | * | ||
274 | * eina_benchmark_free(test); | ||
275 | * } | ||
276 | * | ||
277 | * eina_shutdown(); | ||
278 | * | ||
279 | * return EXIT_SUCCESS; | ||
280 | * } | ||
281 | * @endcode | ||
282 | * | ||
283 | * gnuplot can be used to see how are performed the convert functions | ||
284 | * together, as well as how are performed the containers. So it is now | ||
285 | * easy to see that the hexadecimal convert function is faster than | ||
286 | * the decimal one, and that arrays are faster than lists. | ||
287 | * | ||
288 | * You can improve all that by executing automatically gnuplot in your | ||
289 | * program, or integrate the Eina benchmark framework in an autotooled | ||
290 | * project. See that | ||
291 | * <a href="http://trac.enlightenment.org/e/wiki/AutotoolsIntegration#Benchmark">page</a> | ||
292 | * for more informations. | ||
293 | * | ||
294 | */ | ||
295 | |||
296 | |||
297 | /** | ||
298 | * @addtogroup Eina_Benchmark_Group Benchmark | ||
299 | * | ||
300 | * These functions allow you to add benchmark framework in a project | ||
301 | * for timing critical part and detect slow parts of code. It is used | ||
302 | * in Eina to compare the time used by eina, glib, evas and ecore data | ||
303 | * types. | ||
304 | * | ||
305 | * To use the benchmark module, Eina must be initialized with | ||
306 | * eina_init() and later shut down with eina_shutdown(). A benchmark | ||
307 | * is created with eina_benchmark_new() and freed with | ||
308 | * eina_benchmark_free(). | ||
309 | * | ||
310 | * eina_benchmark_register() adds a test to a benchmark. That test can | ||
311 | * be run a certain amount of times. Adding more than one test to be | ||
312 | * executed allows the comparison between several parts of a program, | ||
313 | * or different implementations. | ||
314 | * | ||
315 | * eina_benchmark_run() runs all the tests registered with | ||
316 | * eina_benchmark_register(). The amount of time of each test is | ||
317 | * written in a gnuplot file. | ||
318 | * | ||
319 | * For more information, you can look at the @ref tutorial_benchmark_page. | ||
320 | */ | ||
321 | |||
322 | /** | ||
323 | * @addtogroup Eina_Tools_Group Tools | ||
324 | * | ||
325 | * @{ | ||
326 | */ | ||
327 | |||
328 | /** | ||
329 | * @defgroup Eina_Benchmark_Group Benchmark | ||
330 | * | ||
331 | * @{ | ||
332 | */ | ||
333 | |||
334 | /** | ||
335 | * @typedef Eina_Benchmark | ||
336 | * Type for a benchmark. | ||
337 | */ | ||
338 | typedef struct _Eina_Benchmark Eina_Benchmark; | ||
339 | |||
340 | /** | ||
341 | * @typedef Eina_Benchmark_Specimens | ||
342 | * Type for a test function to be called when running a benchmark. | ||
343 | */ | ||
344 | typedef void (*Eina_Benchmark_Specimens)(int request); | ||
345 | |||
346 | /** | ||
347 | * @def EINA_BENCHMARK | ||
348 | * @brief cast to an #Eina_Benchmark_Specimens. | ||
349 | * | ||
350 | * @param function The function to cast. | ||
351 | * | ||
352 | * This macro casts @p function to Eina_Benchmark_Specimens. | ||
353 | */ | ||
354 | #define EINA_BENCHMARK(function) ((Eina_Benchmark_Specimens)function) | ||
355 | |||
356 | |||
357 | /** | ||
358 | * @brief Create a new array. | ||
359 | * | ||
360 | * @param name The name of the benchmark. | ||
361 | * @param run The name of the run. | ||
362 | * @return @c NULL on failure, non @c NULL otherwise. | ||
363 | * | ||
364 | * This function creates a new benchmark. @p name and @p run are used | ||
365 | * to name the gnuplot file that eina_benchmark_run() will create. | ||
366 | * | ||
367 | * This function return a valid benchmark on success, or @c NULL if | ||
368 | * memory allocation fails. In that case, the error is set to | ||
369 | * #EINA_ERROR_OUT_OF_MEMORY. | ||
370 | * | ||
371 | * When the new module is not needed anymore, use | ||
372 | * eina_benchmark_free() to free the allocated memory. | ||
373 | */ | ||
374 | EAPI Eina_Benchmark *eina_benchmark_new(const char *name, | ||
375 | const char *run); | ||
376 | |||
377 | /** | ||
378 | * @brief Free a benchmark object. | ||
379 | * | ||
380 | * @param bench The benchmark to free. | ||
381 | * | ||
382 | * This function removes all the benchmark tests that have been | ||
383 | * registered and frees @p bench. If @p bench is @c NULL, this | ||
384 | * function returns immediately. | ||
385 | */ | ||
386 | EAPI void eina_benchmark_free(Eina_Benchmark *bench); | ||
387 | |||
388 | /** | ||
389 | * @brief Add a test to a benchmark. | ||
390 | * | ||
391 | * @param bench The benchmark. | ||
392 | * @param name The name of the test. | ||
393 | * @param bench_cb The test function to be called. | ||
394 | * @param count_start The start data to be passed to @p bench_cb. | ||
395 | * @param count_end The end data to be passed to @p bench_cb. | ||
396 | * @param count_step The step data to be passed to @p bench_cb. | ||
397 | * @return #EINA_FALSE on failure, #EINA_TRUE otherwise. | ||
398 | * | ||
399 | * This function adds the test named @p name to @p benchmark. @p | ||
400 | * bench_cb is the function called when the test is executed. That | ||
401 | * test can be executed a certain amount of time. @p start, @p end and | ||
402 | * @p step define a loop with a step increment. The integer that is | ||
403 | * increasing by @p step from @p start to @p end is passed to @p | ||
404 | * bench_cb when eina_benchmark_run() is called. | ||
405 | * | ||
406 | * If @p bench is @c NULL, this function returns imediatly. If the | ||
407 | * allocation of the memory of the test to add fails, the error is set | ||
408 | * to #EINA_ERROR_OUT_OF_MEMORY. This function returns #EINA_FALSE | ||
409 | * on failure, #EINA_TRUE otherwise. | ||
410 | */ | ||
411 | EAPI Eina_Bool eina_benchmark_register(Eina_Benchmark *bench, | ||
412 | const char *name, | ||
413 | Eina_Benchmark_Specimens bench_cb, | ||
414 | int count_start, | ||
415 | int count_end, | ||
416 | int count_set); | ||
417 | |||
418 | /** | ||
419 | * @brief Run the benchmark tests that have been registered. | ||
420 | * | ||
421 | * @param bench The benchmark. | ||
422 | * @return The list of names of the test files. | ||
423 | * | ||
424 | * This function runs all the tests that as been registered with | ||
425 | * eina_benchmark_register() and save the result in a gnuplot | ||
426 | * file. The name of the file has the following format: | ||
427 | * | ||
428 | * @code | ||
429 | * bench_[name]_[run]%s.gnuplot | ||
430 | * @endcode | ||
431 | * | ||
432 | * where [name] and [run] are the values passed to | ||
433 | * eina_benchmark_new(). | ||
434 | * | ||
435 | * Each registered test is executed and timed. The time is written to | ||
436 | * the gnuplot file. The number of times each test is executed is | ||
437 | * controlled by the parameters passed to eina_benchmark_register(). | ||
438 | * | ||
439 | * If @p bench is @c NULL, this functions returns @c NULL | ||
440 | * immediately. Otherwise, it returns the list of the names of each | ||
441 | * test. | ||
442 | */ | ||
443 | EAPI Eina_Array *eina_benchmark_run(Eina_Benchmark *bench); | ||
444 | |||
445 | /** | ||
446 | * @} | ||
447 | */ | ||
448 | |||
449 | /** | ||
450 | * @} | ||
451 | */ | ||
452 | |||
453 | #endif /* EINA_BENCHMARK_H_ */ | ||