aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/eina/src/include/eina_benchmark.h
blob: 9e96d64f31bf47be23743096b1d33f006a5afa6b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
/* EINA - EFL data type library
 * Copyright (C) 2008 Cedric Bail
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library;
 * if not, see <http://www.gnu.org/licenses/>.
 */

#ifndef EINA_BENCHMARK_H_
#define EINA_BENCHMARK_H_

#include "eina_array.h"



/**
 * @page tutorial_benchmark_page Benchmark Tutorial
 *
 * The Benchmark module allows you to write easily benchmarks
 * framework in a project for timing critical part and detect slow
 * parts of code. In addition it automatically creates data files of
 * these benchmark, as well as a gnuplot file which can display the
 * comparison curves of the benchmarks.
 *
 * @section tutorial_benchmark_basic_usage Basic Usage
 *
 * To create a basic benchmark, you have to follow these steps:
 *
 * @li Create a new bechmark
 * @li Write the functions that wraps the the functions you want to
 * bechmark.
 * @li Register these wrappers functions.
 * @li Run the benchmark.
 * @li Free the memory.
 *
 * Here is a basic example of bechmark which creates two functions
 * that will be run. These functions just print a message.
 *
 * @code
 * #include <stdlib.h>
 * #include <stdio.h>
 *
 * #include <Eina.h>
 *
 * static
 * void work1(int request)
 * {
 *   printf ("work1 in progress... Request: %d\n", request);
 * }
 *
 * static
 * void work2(int request)
 * {
 *   printf ("work2 in progress... Request: %d\n", request);
 * }
 *
 * int main()
 * {
 *   Eina_Benchmark *test;
 *   Eina_Array     *ea;
 *
 *   if (!eina_init())
 *     return EXIT_FAILURE;
 *
 *   test = eina_benchmark_new("test", "run");
 *   if (!test)
 *     goto shutdown_eina;
 *
 *   eina_benchmark_register(test, "work-1", EINA_BENCHMARK(work1), 200, 300, 10);
 *   eina_benchmark_register(test, "work-2", EINA_BENCHMARK(work2), 100, 150, 5);
 *
 *   ea = eina_benchmark_run(test);
 *
 *   eina_benchmark_free(test);
 *   eina_shutdown();
 *
 *   return EXIT_SUCCESS;
 *
 *  shutdown_eina:
 *   eina_shutdown();
 *
 *   return EXIT_FAILURE;
 * }
 * @endcode
 *
 * As "test", "run" are passed to eina_benchmark_new() and as the tests
 * "work-1" and "work-2" are registered, the data files
 * bench_test_run.work-1.data and bench_test_run.work-2.data will be
 * created after the eina_benchmark_run() call. They contain four
 * columns. The file bench_test_run.work-1.data contains for example:
 *
 * @code
 * # specimen      experiment time starting time   ending time
 * 200     23632   2852446 2876078
 * 210     6924    2883046 2889970
 * 220     6467    2895962 2902429
 * 230     6508    2908271 2914779
 * 240     6278    2920610 2926888
 * 250     6342    2932830 2939172
 * 260     6252    2944954 2951206
 * 270     6463    2956978 2963441
 * 280     6347    2969548 2975895
 * 290     6457    2981702 2988159
 * @endcode
 *
 * The first column (specimen) is the integer passed to the work1()
 * function when the test is run. The second column (experiment time)
 * is the time, in nanosecond, that work1() takes. The third and
 * fourth columnd are self-explicit.
 *
 * You can see that the integer passed work1() starts from 200 and
 * finishes at 290, with a step of 10. These values are computed withe
 * last 3 values passed to eina_benchmark_register(). See the document
 * of that function for the detailed behavior.
 *
 * The gnuplot file will be named bench_test_run.gnuplot. Just run:
 *
 * @code
 * gnuplot bench_test_run.gnuplot
 * @endcode
 *
 * to create the graphic of the comparison curves. The image file is
 * named output_test_run.png.
 *
 * @section tutorial_benchmark_advanced_usage More Advanced Usage
 *
 * In this section, several test will be created and run. The idea is
 * exactly the same than in the previous section, but with some basic
 * automatic way to run all the benchmarks. The following code
 * benchmarks some Eina converts functions, and some Eina containers
 * types:
 *
 * @code
 * #include <stdlib.h>
 * #include <stdio.h>
 * #include <time.h>
 *
 * #include <Eina.h>
 *
 * static void bench_convert(Eina_Benchmark *bench);
 * static void bench_container(Eina_Benchmark *bench);
 *
 * typedef struct _Benchmark_Case Benchmark_Case;
 *
 * struct _Benchmark_Case
 * {
 *    const char *bench_case;
 *    void (*build)(Eina_Benchmark *bench);
 * };
 *
 * static const Benchmark_Case benchmarks[] = {
 *   { "Bench 1", bench_convert },
 *   { "Bench 2", bench_container },
 *   { NULL,      NULL }
 * };
 *
 * static
 * void convert1(int request)
 * {
 *   char tmp[128];
 *   int i;
 *
 *   srand(time(NULL));
 *
 *   for (i = 0; i < request; ++i)
 *     eina_convert_itoa(rand(), tmp);
 * }
 *
 * static
 * void convert2(int request)
 * {
 *   char tmp[128];
 *   int i;
 *
 *   srand(time(NULL));
 *
 *   for (i = 0; i < request; ++i)
 *     eina_convert_xtoa(rand(), tmp);
 * }
 *
 * static void
 * bench_convert(Eina_Benchmark *bench)
 * {
 *   eina_benchmark_register(bench, "convert-1", EINA_BENCHMARK(convert1), 200, 400, 10);
 *   eina_benchmark_register(bench, "convert-2", EINA_BENCHMARK(convert2), 200, 400, 10);
 * }
 *
 * static
 * void array(int request)
 * {
 *   Eina_Array *array;
 *   Eina_Array_Iterator it;
 *   int *data;
 *   int i;
 *
 *   srand(time(NULL));
 *
 *   array = eina_array_new(64);
 *
 *   for (i = 0; i < request; ++i)
 *     {
 *       data = (int *)malloc(sizeof(int));
 *       if (!data) continue;
 *       *data = rand();
 *       eina_array_push(array, data);
 *     }
 *
 *   EINA_ARRAY_ITER_NEXT(array, i, data, it)
 *     free(data);
 *
 *   eina_array_free(array);
 * }
 *
 * static
 * void list(int request)
 * {
 *   Eina_List *l = NULL;
 *   int *data;
 *   int i;
 *
 *   srand(time(NULL));
 *
 *   for (i = 0; i < request; ++i)
 *     {
 *       data = (int *)malloc(sizeof(int));
 *       if (!data) continue;
 *       *data = rand();
 *       l = eina_list_prepend(l, data);
 *     }
 *
 *   while (l)
 *     {
 *       free(eina_list_data_get(l));
 *       l = eina_list_remove_list(l, l);
 *     }
 * }
 *
 * static void
 * bench_container(Eina_Benchmark *bench)
 * {
 *   eina_benchmark_register(bench, "array", EINA_BENCHMARK(array), 200, 300, 10);
 *   eina_benchmark_register(bench, "list", EINA_BENCHMARK(list), 200, 300, 10);
 * }
 *
 * int main()
 * {
 *   Eina_Benchmark *test;
 *   Eina_Array     *ea;
 *   unsigned int    i;
 *
 *   if (!eina_init())
 *     return EXIT_FAILURE;
 *
 *   for (i = 0; benchmarks[i].bench_case != NULL; ++i)
 *     {
 *       test = eina_benchmark_new(benchmarks[i].bench_case, "Benchmark example");
 *       if (!test)
 *         continue;
 *
 *       benchmarks[i].build(test);
 *
 *       ea = eina_benchmark_run(test);
 *
 *       eina_benchmark_free(test);
 *     }
 *
 *   eina_shutdown();
 *
 *   return EXIT_SUCCESS;
 * }
 * @endcode
 *
 * gnuplot can be used to see how are performed the convert functions
 * together, as well as how are performed the containers. So it is now
 * easy to see that the hexadecimal convert function is faster than
 * the decimal one, and that arrays are faster than lists.
 *
 * You can improve all that by executing automatically gnuplot in your
 * program, or integrate the Eina benchmark framework in an autotooled
 * project. See that
 * <a href="http://trac.enlightenment.org/e/wiki/AutotoolsIntegration#Benchmark">page</a>
 * for more informations.
 *
 */


/**
 * @addtogroup Eina_Benchmark_Group Benchmark
 *
 * These functions allow you to add benchmark framework in a project
 * for timing critical part and detect slow parts of code. It is used
 * in Eina to compare the time used by eina, glib, evas and ecore data
 * types.
 *
 * To use the benchmark module, Eina must be initialized with
 * eina_init() and later shut down with eina_shutdown(). A benchmark
 * is created with eina_benchmark_new() and freed with
 * eina_benchmark_free().
 *
 * eina_benchmark_register() adds a test to a benchmark. That test can
 * be run a certain amount of times. Adding more than one test to be
 * executed allows the comparison between several parts of a program,
 * or different implementations.
 *
 * eina_benchmark_run() runs all the tests registered with
 * eina_benchmark_register(). The amount of time of each test is
 * written in a gnuplot file.
 *
 * For more information, you can look at the @ref tutorial_benchmark_page.
 */

/**
 * @addtogroup Eina_Tools_Group Tools
 *
 * @{
 */

/**
 * @defgroup Eina_Benchmark_Group Benchmark
 *
 * @{
 */

/**
 * @typedef Eina_Benchmark
 * Type for a benchmark.
 */
typedef struct _Eina_Benchmark Eina_Benchmark;

/**
 * @typedef Eina_Benchmark_Specimens
 * Type for a test function to be called when running a benchmark.
 */
typedef void (*Eina_Benchmark_Specimens)(int request);

/**
 * @def EINA_BENCHMARK
 * @brief cast to an #Eina_Benchmark_Specimens.
 *
 * @param function The function to cast.
 *
 * This macro casts @p function to Eina_Benchmark_Specimens.
 */
#define EINA_BENCHMARK(function) ((Eina_Benchmark_Specimens)function)


/**
 * @brief Create a new array.
 *
 * @param name The name of the benchmark.
 * @param run The name of the run.
 * @return @c NULL on failure, non @c NULL otherwise.
 *
 * This function creates a new benchmark. @p name and @p run are used
 * to name the gnuplot file that eina_benchmark_run() will create.
 *
 * This function return a valid benchmark on success, or @c NULL if
 * memory allocation fails. In that case, the error is set to
 * #EINA_ERROR_OUT_OF_MEMORY.
 *
 * When the new module is not needed anymore, use
 * eina_benchmark_free() to free the allocated memory.
 */
EAPI Eina_Benchmark *eina_benchmark_new(const char *name,
                                        const char *run);

/**
 * @brief Free a benchmark object.
 *
 * @param bench The benchmark to free.
 *
 * This function removes all the benchmark tests that have been
 * registered and frees @p bench. If @p bench is @c NULL, this
 * function returns immediately.
 */
EAPI void            eina_benchmark_free(Eina_Benchmark *bench);

/**
 * @brief Add a test to a benchmark.
 *
 * @param bench The benchmark.
 * @param name The name of the test.
 * @param bench_cb The test function to be called.
 * @param count_start The start data to be passed to @p bench_cb.
 * @param count_end The end data to be passed to @p bench_cb.
 * @param count_step The step data to be passed to @p bench_cb.
 * @return #EINA_FALSE on failure, #EINA_TRUE otherwise.
 *
 * This function adds the test named @p name to @p benchmark. @p
 * bench_cb is the function called when the test is executed. That
 * test can be executed a certain amount of time. @p count_start, @p count_end and
 * @p count_step define a loop with a step increment. The integer that is
 * increasing by @p count_step from @p count_start to @p count_end is passed to @p
 * bench_cb when eina_benchmark_run() is called.
 *
 * If @p bench is @c NULL, this function returns imediatly. If the
 * allocation of the memory of the test to add fails, the error is set
 * to #EINA_ERROR_OUT_OF_MEMORY. This function returns #EINA_FALSE
 * on failure, #EINA_TRUE otherwise.
 */
EAPI Eina_Bool       eina_benchmark_register(Eina_Benchmark          *bench,
                                             const char              *name,
                                             Eina_Benchmark_Specimens bench_cb,
                                             int                      count_start,
                                             int                      count_end,
                                             int                      count_step);

/**
 * @brief Run the benchmark tests that have been registered.
 *
 * @param bench The benchmark.
 * @return The list of names of the test files.
 *
 * This function runs all the tests that as been registered with
 * eina_benchmark_register() and save the result in a gnuplot
 * file. The name of the file has the following format:
 *
 * @code
 * bench_[name]_[run]%s.gnuplot
 * @endcode
 *
 * where [name] and [run] are the values passed to
 * eina_benchmark_new().
 *
 * Each registered test is executed and timed. The time is written to
 * the gnuplot file. The number of times each test is executed is
 * controlled by the parameters passed to eina_benchmark_register().
 *
 * If @p bench is @c NULL, this functions returns @c NULL
 * immediately. Otherwise, it returns the list of the names of each
 * test.
 */
EAPI Eina_Array *eina_benchmark_run(Eina_Benchmark *bench);

/**
 * @}
 */

/**
 * @}
 */

#endif /* EINA_BENCHMARK_H_ */