EFL 1.7 svn doobies
[profile/ivi/eina.git] / src / include / eina_benchmark.h
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 benchmark
40  * @li Write the functions that wraps the functions you want to
41  * benchmark.
42  * @li Register these wrappers functions.
43  * @li Run the benchmark.
44  * @li Free the memory.
45  *
46  * Here is a basic example of benchmark 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
369  * to #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 count_start, @p count_end and
402  * @p count_step define a loop with a step increment. The integer that is
403  * increasing by @p count_step from @p count_start to @p count_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 immediately. 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_step);
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_ */