merge with master
[platform/core/api/face.git] / src / statistics.c
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include <sys/time.h>   // gettimeofday
17
18 #include <stdio.h>
19 #include <malloc.h>
20 #include <string.h>
21 #include <assert.h>
22 #include <time.h>
23
24 #include "statistics.h"
25
26 #ifdef STANDALONE
27 #define EXPORT_API
28 #endif
29
30 #include <sys/time.h>
31 #include <sys/utsname.h>
32 #include <sys/resource.h>
33 #include <unistd.h>
34
35
36 #include <stdarg.h>
37 #include "statistics.h"
38
39 #define MAX_UINT32 (0xFFFFFFFFL)
40 #define MAX_UINT64 (0xFFFFFFFFFFFFFFFFLL)
41
42 // defs.
43 #define MM_TA_MAX_ACCUM                 100
44
45
46 typedef struct _mm_ta_accum_item
47 {
48         unsigned long long elapsed_accum;
49         unsigned long num_calls;
50         unsigned long long elapsed_min;
51         unsigned long long elapsed_max;
52         unsigned long long first_start;
53         unsigned long long last_end;
54
55         char* name;
56
57         unsigned long long timestamp;
58         int on_estimate;
59         int num_unpair;
60 } mm_ta_accum_item;
61
62
63 static void PrintLog(const char *file, int line, const char *msg, ...)
64 {
65         va_list va;
66
67         va_start(va, msg);
68         fprintf(stderr ,"[STAT] %s:%d:",file, line);
69         vfprintf(stderr ,msg, va);
70         fprintf(stderr, "\n");
71         va_end(va);
72 }
73
74 #define MyPrintf(...)  PrintLog(__FILE__, __LINE__, ##__VA_ARGS__ )
75
76
77 // internal func.
78 static void __free_accums(void);
79 static int __get_accum_index(const char* name);
80
81
82 // global var.
83 static mm_ta_accum_item ** g_accums = NULL;
84 static int g_accum_index = 0;
85 static int g_accum_longest_name = 0;
86 static unsigned long long g_accum_first_time = MAX_UINT64;      // jmlee
87
88
89 int PERF_INIT(void)
90 {
91         if (g_accums)
92         {
93                 return 0;
94         }
95
96         g_accums = (mm_ta_accum_item **) calloc (1, MM_TA_MAX_ACCUM * sizeof(mm_ta_accum_item *) );
97         if(!g_accums)
98         {
99                 assert(0);
100                 return -1;
101         }
102
103         g_accum_first_time = MAX_UINT64;
104
105         return 0;
106 }
107
108 int PERF_DEINIT(void)
109 {
110         if ( ! g_accums )
111         {
112                 return 0;
113         }
114
115         __free_accums();
116
117         g_accum_first_time = MAX_UINT64;
118
119         return 0;
120 }
121
122
123 static int __get_accum_index(const char* name)
124 {
125         int i;
126
127         assert(name);
128
129         // find index
130         for ( i = 0; i < g_accum_index; i++ )
131         {
132                 if ( strcmp( name, g_accums[i]->name ) == 0 )
133                         return i;
134         }
135
136         return -1;
137 }
138
139 static void __free_accums(void)
140 {
141         int i = 0;
142
143         if ( ! g_accums )
144                 return;
145
146         for ( i = 0; i < g_accum_index; i++ )
147         {
148                 if ( g_accums[i] )
149                 {
150                         if ( g_accums[i]->name )
151                                 free ( g_accums[i]->name );
152
153                         free ( g_accums[i] );
154
155                         g_accums[i] = NULL;
156                 }
157         }
158
159         g_accum_index = 0;
160         g_accum_longest_name = 0;
161
162         free ( g_accums );
163         g_accums = NULL;
164 }
165
166
167
168 int mm_ta_accum_item_begin(const char* name, bool show, const char* filename, int line)
169 {
170         mm_ta_accum_item * accum = NULL;
171         int index = 0;
172         int name_len = 0;
173         struct timeval t;
174
175         if (!g_accums)
176                 return 0;
177
178         if ( g_accum_index == MM_TA_MAX_ACCUM )
179                 return -1;
180
181         if ( !name )
182                 return -1;
183
184         name_len = strlen(name);
185         if( name_len == 0 )
186                 return -1;
187
188         // if 'name' is new one. create new item.
189         if ( (index = __get_accum_index(name)) == -1 )
190         {
191                 accum = ( mm_ta_accum_item * ) calloc(1, sizeof( mm_ta_accum_item ) );
192                 if ( !accum )
193                 {
194                         assert(0);
195                         return -1;
196                 }
197
198                 // clear first.
199                 memset( accum, 0, sizeof (mm_ta_accum_item) );
200                 accum->elapsed_min = MAX_UINT64;
201
202                 accum->name = strdup(name);
203                 // add it to list.
204                 g_accums[g_accum_index] = accum;
205                 g_accum_index++;
206
207                 if ( g_accum_longest_name < name_len )
208                         g_accum_longest_name = name_len;
209
210         }
211         else
212         {
213                 accum = g_accums[index];
214         }
215
216         // verify pairs of begin, end.
217         if (accum->on_estimate)
218         {
219                 MyPrintf("[%s] is not 'end'ed!\n", accum->name);
220                 accum->num_unpair ++;
221                 return -1;
222         }
223
224         accum->on_estimate = 1;
225
226         // get timestamp
227         gettimeofday( &t, NULL );
228         accum->timestamp = t.tv_sec * 1000000UL + t.tv_usec;
229
230         if ( accum->first_start == 0 )
231         {       // assum that timestamp never could be zero.
232                 accum->first_start = accum->timestamp;
233
234                 if ( g_accum_first_time > accum->first_start )
235                 {
236                         g_accum_first_time = accum->first_start ;
237                 }
238         }
239
240         if ( show )
241                 MyPrintf("[ACCUM BEGIN] %s : %ld ---(%s:%d)\n", name, accum->timestamp, filename, line );
242
243         accum->num_calls++;
244
245         return 0;
246 }
247
248 int mm_ta_accum_item_end(const char* name, bool show, const char* filename, int line)
249 {
250         mm_ta_accum_item * accum = NULL;
251         unsigned long long tval = 0LL;
252         int index = 0;
253         struct timeval  t;
254
255         if (!g_accums)
256                 return 0;
257
258         if ( g_accum_index == MM_TA_MAX_ACCUM )
259                 return -1;
260
261         if ( !name )
262                 return -1;
263
264         if( strlen ( name ) == 0 )
265                 return -1;
266
267         // varify the 'name' is already exist.
268         if ( (index = __get_accum_index(name)) == -1 )
269         {
270                 MyPrintf("[%s] is not added before!\n", name);
271                 return -1;
272         }
273
274         accum = g_accums[index];
275
276         // verify pairs of begin, end.
277         if (!accum->on_estimate)
278         {
279                 MyPrintf("[%s] is not 'begin' yet!\n", accum->name);
280                 accum->num_unpair ++;
281                 return -1;
282         }
283
284         // get time first for more accuracy.
285         gettimeofday( &t, NULL );
286         tval = t.tv_sec*1000000UL + t.tv_usec;
287
288         // update last_end
289         accum->last_end = tval;
290
291 #if 0
292         if ( accum->first_start > accum->last_end )
293         {
294                 MyPrintf("Invalied timestamp:%s. Start:%lu End=%lu\n", accum->name, accum->first_start , accum->last_end);
295         }
296 #endif
297
298         // make get elapsed time.
299         tval = tval - accum->timestamp;
300
301         // update min/max
302         accum->elapsed_max = tval > accum->elapsed_max ? tval : accum->elapsed_max;
303         accum->elapsed_min = tval < accum->elapsed_min ? tval : accum->elapsed_min;
304
305         if ( show )
306                 MyPrintf("[ACCUM END] %s : %llu + %llu ---(%s:%d)\n", name, accum->elapsed_accum, tval, filename, line );
307
308         // add elapsed time
309         accum->elapsed_accum = accum->elapsed_accum + tval;
310         accum->on_estimate = 0;
311
312         return 0;
313 }
314
315 void __print_some_info(FILE* fp)
316 {
317         if (!fp)
318                 return;
319
320         // General infomation
321         {
322                 time_t t_val;
323                 char hostname[256] = {'\0',};
324 #ifdef LINUX
325                 struct utsname uts;
326                 struct rusage r_usage;
327 #endif
328                 fprintf(fp, "\n[[ General info ]]\n");
329
330                 // time and date
331                 time(&t_val);
332                 fprintf(fp, "Date : %s", ctime(&t_val) );
333
334                 // system
335                 if ( gethostname(hostname, 255) == 0 )
336                 {
337                         fprintf(fp, "Hostname : %s\n", hostname);
338                 }
339 #ifdef LINUX
340                 if ( uname(&uts) >= 0 )
341                 {
342                         fprintf(fp, "System : %s\n", uts.sysname);
343                         fprintf(fp, "Machine : %s\n", uts.machine);
344                         fprintf(fp, "Nodename : %s\n", uts.nodename);
345                         fprintf(fp, "Release : %s \n", uts.release);
346                         fprintf(fp, "Version : %s \n", uts.version);
347                 }
348
349                 // process info.
350                 fprintf(fp, "Process priority : %d\n", getpriority(PRIO_PROCESS, getpid()) );
351
352                 getrusage(RUSAGE_SELF, &r_usage);
353                 fprintf(fp, "CPU usage : User = %ld.%06ld, System = %ld.%06ld\n",
354                                 r_usage.ru_utime.tv_sec, r_usage.ru_utime.tv_usec,
355                                 r_usage.ru_stime.tv_sec, r_usage.ru_stime.tv_usec );
356 #endif
357
358         }
359
360         // host environment variables
361         {
362                 extern char** environ;
363                 char** env = environ;
364
365                 fprintf(fp, "\n[[ Host environment variables ]]\n");
366                 while(*env)
367                 {
368                         fprintf(fp, "%s\n", *env);
369                         env++;
370                 }
371         }
372
373         fprintf(fp, "g_accum_first_time = %llu\n", g_accum_first_time);
374
375         fprintf(fp, "\n\n");
376
377 }
378
379
380 void mm_ta_accum_show_result_fp(FILE *fp)
381 {
382         int i = 0;
383         char format[256];
384
385 //      __print_some_info(fp);
386
387
388         fprintf(fp, "============================ BEGIN RESULT ACCUM (usec) ====================\n");
389
390         snprintf(format, (size_t)sizeof(format), "[Idx] %%-%ds %%10s %%6s %%10s %%10s %%10s %%4s \n", g_accum_longest_name);
391
392         fprintf(fp, format, "Name", "avg", "hit", "total", "min", "max", "pair");
393
394         snprintf(format, (size_t)sizeof(format), "[%%3d] %%-%ds %%10llu %%6lu %%10llu %%10llu %%10llu %%4s \n", g_accum_longest_name);
395
396         for ( i = 0; i < g_accum_index; i++ )
397         {
398                 // prevent 'devide by zero' error
399                 if (g_accums[i]->num_calls == 0)
400                         g_accums[i]->num_calls = 1;
401
402                 fprintf(fp,
403                         format,
404                         i,
405                         g_accums[i]->name,
406                         (g_accums[i]->elapsed_accum == 0)?0:(g_accums[i]->elapsed_accum / g_accums[i]->num_calls),  // Fix it! : devide by zero.
407                         g_accums[i]->num_calls,
408                         g_accums[i]->elapsed_accum,
409                         g_accums[i]->elapsed_min,
410                         g_accums[i]->elapsed_max,
411                         g_accums[i]->num_unpair == 1 ? "F" : "T" );
412         }
413
414         fprintf(fp, "============================ END RESULT ACCUM  ============================\n");
415
416         if ( fp != stdout && fp != stderr )
417         {
418                 fclose(fp);
419         }
420 }
421
422
423 #define _CONSTRUCTOR __attribute__ ((constructor))
424 #define _DESTRUCTOR __attribute__ ((destructor))
425
426 static void _CONSTRUCTOR _DLLInit(void)
427 {
428         PERF_INIT();
429 }
430
431 static void _DESTRUCTOR _DLLExit(void)
432 {
433         PERF_DEINIT();
434
435 }
436
437
438 #ifdef STANDALONE
439 int main(int argc, char* argv[])
440 {
441         int a = 0, b = 0;
442
443
444         PERF_CHECK_BEGIN("Test 1");
445
446         for ( a = 0 ; a < 10; a++)
447         {
448                 printf("AAA=%d\n", a);
449                 usleep(1*10E6);
450         }
451
452         PERF_CHECK_END("Test 1");
453
454         printf("Test 111\n");
455         return 0;
456 }
457 #endif
458
459
460