EFL 1.7 svn doobies
[profile/ivi/eina.git] / src / lib / eina_counter.c
1 /* EINA - EFL data type library
2  * Copyright (C) 2008 Cedric Bail, Vincent Torri
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 #ifdef HAVE_CONFIG_H
20 # include "config.h"
21 #endif
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdarg.h>
27 #ifndef _WIN32
28 # include <time.h>
29 # include <sys/time.h>
30 #else
31 # define WIN32_LEAN_AND_MEAN
32 # include <windows.h>
33 # undef WIN32_LEAN_AND_MEAN
34 #endif /* _WIN2 */
35
36 #include "eina_config.h"
37 #include "eina_private.h"
38 #include "eina_inlist.h"
39 #include "eina_error.h"
40
41 /* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
42 #include "eina_safety_checks.h"
43 #include "eina_counter.h"
44
45 #ifdef HAVE_ESCAPE
46 # include <Escape.h>
47 #endif
48
49 /*============================================================================*
50  *                                  Local                                     *
51  *============================================================================*/
52
53 /**
54  * @cond LOCAL
55  */
56
57 #ifndef _WIN32
58 typedef struct timespec Eina_Nano_Time;
59 #else
60 typedef LARGE_INTEGER Eina_Nano_Time;
61 #endif
62
63 typedef struct _Eina_Clock Eina_Clock;
64
65 struct _Eina_Counter
66 {
67    EINA_INLIST;
68
69    Eina_Inlist *clocks;
70    const char *name;
71 };
72
73 struct _Eina_Clock
74 {
75    EINA_INLIST;
76
77    Eina_Nano_Time start;
78    Eina_Nano_Time end;
79    int specimen;
80
81    Eina_Bool valid;
82 };
83
84 #ifndef _WIN32
85 static inline int
86 _eina_counter_time_get(Eina_Nano_Time *tp)
87 {
88 # if defined(CLOCK_PROCESS_CPUTIME_ID)
89    return clock_gettime(CLOCK_PROCESS_CPUTIME_ID, tp);
90 # elif defined(CLOCK_PROF)
91    return clock_gettime(CLOCK_PROF, tp);
92 # elif defined(CLOCK_REALTIME)
93    return clock_gettime(CLOCK_REALTIME, tp);
94 # else
95    struct timeval tv;
96
97    if (gettimeofday(&tv, NULL))
98      return -1;
99
100    tp->tv_sec = tv.tv_sec;
101    tp->tv_nsec = tv.tv_usec * 1000L;
102
103    return 0;
104 # endif
105 }
106 #else
107 static const char EINA_ERROR_COUNTER_WINDOWS_STR[] =
108    "Change your OS, you moron !";
109 static int EINA_ERROR_COUNTER_WINDOWS = 0;
110 static LARGE_INTEGER _eina_counter_frequency;
111
112 static inline int
113 _eina_counter_time_get(Eina_Nano_Time *tp)
114 {
115    return QueryPerformanceCounter(tp);
116 }
117 #endif /* _WIN2 */
118
119 static char *
120 _eina_counter_asiprintf(char *base, int *position, const char *format, ...)
121 {
122    char *tmp, *result;
123    int size = 32;
124    int n;
125    va_list ap;
126
127    tmp = realloc(base, sizeof (char) * (*position + size));
128    if (!tmp)
129       return base;
130
131    result = tmp;
132
133    while (1)
134      {
135         va_start(ap, format);
136         n = vsnprintf(result + *position, size, format, ap);
137         va_end(ap);
138
139         if (n > -1 && n < size)
140           {
141              /* If we always have glibc > 2.2, we could just return *position += n. */
142              *position += strlen(result + *position);
143              return result;
144           }
145
146         if (n > -1)
147            size = n + 1;
148         else
149            size <<= 1;
150
151         tmp = realloc(result, sizeof (char) * (*position + size));
152         if (!tmp)
153            return result;
154
155         result = tmp;
156      }
157 }
158
159 /**
160  * @endcond
161  */
162
163 /*============================================================================*
164  *                                 Global                                     *
165  *============================================================================*/
166
167 /**
168  * @internal
169  * @brief Initialize the eina counter internal structure.
170  *
171  * @return #EINA_TRUE on success, #EINA_FALSE on failure.
172  *
173  * This function shuts down the counter module set up by
174  * eina_counter_init(). It is called by eina_init().
175  *
176  * This function sets up the error module of Eina and only on Windows,
177  * it initializes the high precision timer. It also registers, only on
178  * Windows, the error #EINA_ERROR_COUNTER_WINDOWS. It is also called
179  * by eina_init(). It returns 0 on failure, otherwise it returns the
180  * number of times it has already been called.
181  *
182  * @see eina_init()
183  */
184 Eina_Bool
185 eina_counter_init(void)
186 {
187 #ifdef _WIN32
188    EINA_ERROR_COUNTER_WINDOWS = eina_error_msg_static_register(
189          EINA_ERROR_COUNTER_WINDOWS_STR);
190    if (!QueryPerformanceFrequency(&_eina_counter_frequency))
191      {
192         eina_error_set(EINA_ERROR_COUNTER_WINDOWS);
193         return EINA_FALSE;
194      }
195
196 #endif /* _WIN2 */
197    return EINA_TRUE;
198 }
199
200 /**
201  * @internal
202  * @brief Shut down the counter module.
203  *
204  * @return #EINA_TRUE on success, #EINA_FALSE on failure.
205  *
206  * This function shuts down the counter module set up by
207  * eina_counter_init(). It is called by eina_shutdown().
208  *
209  * @see eina_shutdown()
210  */
211 Eina_Bool
212 eina_counter_shutdown(void)
213 {
214    return EINA_TRUE;
215 }
216
217 /*============================================================================*
218  *                                   API                                      *
219  *============================================================================*/
220
221 EAPI Eina_Counter *
222 eina_counter_new(const char *name)
223 {
224    Eina_Counter *counter;
225    size_t length;
226
227    EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL);
228
229    length = strlen(name) + 1;
230
231         eina_error_set(0);
232    counter = calloc(1, sizeof (Eina_Counter) + length);
233    if (!counter)
234      {
235         eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
236         return NULL;
237      }
238
239    counter->name = (char *)(counter + 1);
240    memcpy((char *)counter->name, name, length);
241
242    return counter;
243 }
244
245 EAPI void
246 eina_counter_free(Eina_Counter *counter)
247 {
248    EINA_SAFETY_ON_NULL_RETURN(counter);
249
250    while (counter->clocks)
251      {
252         Eina_Clock *clk = (Eina_Clock *)counter->clocks;
253
254         counter->clocks = eina_inlist_remove(counter->clocks, counter->clocks);
255         free(clk);
256      }
257
258         free(counter);
259 }
260
261 EAPI void
262 eina_counter_start(Eina_Counter *counter)
263 {
264    Eina_Clock *clk;
265    Eina_Nano_Time tp;
266
267    EINA_SAFETY_ON_NULL_RETURN(counter);
268    if (_eina_counter_time_get(&tp) != 0)
269       return;
270
271         eina_error_set(0);
272    clk = calloc(1, sizeof (Eina_Clock));
273    if (!clk)
274      {
275         eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
276         return;
277      }
278
279    counter->clocks = eina_inlist_prepend(counter->clocks, EINA_INLIST_GET(clk));
280
281    clk->valid = EINA_FALSE;
282    clk->start = tp;
283 }
284
285 EAPI void
286 eina_counter_stop(Eina_Counter *counter, int specimen)
287 {
288    Eina_Clock *clk;
289    Eina_Nano_Time tp;
290
291    EINA_SAFETY_ON_NULL_RETURN(counter);
292    if (_eina_counter_time_get(&tp) != 0)
293       return;
294
295    clk = (Eina_Clock *)counter->clocks;
296
297    if (!clk || clk->valid == EINA_TRUE)
298       return;
299
300    clk->end = tp;
301    clk->specimen = specimen;
302    clk->valid = EINA_TRUE;
303 }
304
305 EAPI char *
306 eina_counter_dump(Eina_Counter *counter)
307 {
308    Eina_Clock *clk;
309    char *result = NULL;
310    int position = 0;
311
312    EINA_SAFETY_ON_NULL_RETURN_VAL(counter, NULL);
313
314    result = _eina_counter_asiprintf(
315          result,
316          &position,
317          "# specimen\texperiment time\tstarting time\tending time\n");
318    if (!result)
319       return NULL;
320
321    EINA_INLIST_REVERSE_FOREACH(counter->clocks, clk)
322    {
323       long int start;
324       long int end;
325       long int diff;
326
327       if (clk->valid == EINA_FALSE)
328          continue;
329
330 #ifndef _WIN32
331       start = clk->start.tv_sec * 1000000000 + clk->start.tv_nsec;
332       end = clk->end.tv_sec * 1000000000 + clk->end.tv_nsec;
333       diff =
334          (clk->end.tv_sec -
335           clk->start.tv_sec) * 1000000000 + clk->end.tv_nsec -
336          clk->start.tv_nsec;
337 #else
338       start =
339          (long int)(((long long int)clk->start.QuadPart *
340                      1000000000ll) /
341                     (long long int)_eina_counter_frequency.QuadPart);
342       end =
343          (long int)(((long long int)clk->end.QuadPart *
344                      1000000000LL) /
345                     (long long int)_eina_counter_frequency.QuadPart);
346       diff =
347          (long int)(((long long int)(clk->end.QuadPart -
348                                      clk->start.QuadPart) *
349                      1000000000LL) /
350                     (long long int)_eina_counter_frequency.QuadPart);
351 #endif /* _WIN2 */
352
353       result = _eina_counter_asiprintf(result, &position,
354                                        "%i\t%li\t%li\t%li\n",
355                                        clk->specimen,
356                                        diff,
357                                        start,
358                                        end);
359    }
360
361    return result;
362 }