86a5571c778ac628c642c9e52997d206d47c4d56
[platform/core/multimedia/libmm-ta.git] / src / mm_ta.c
1 /*
2  * libmm-ta
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Jonghyuk Choi <jhchoi.choi@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21
22 #ifndef _MM_TA_C_
23 #define _MM_TA_C_
24
25 #include <stdio.h>
26 #include <malloc.h>
27 #include <string.h>
28 #include <assert.h>
29 #include <sys/time.h>
30 #include <sys/utsname.h>
31 #include <sys/resource.h>
32 #include <unistd.h>
33 #include <stdarg.h>
34 #include <stdlib.h>
35 #include <time.h>
36
37 #include "mm_ta.h"
38
39 /* internal func. */
40 static void __free_cps(void);
41 static int __get_cp_index(char* name);
42
43 static void __free_accums(void);
44 static int __get_accum_index(char* name);
45
46 /* global var. */
47 gst_ta_checkpoint ** g_cps = NULL;
48 static int g_cp_index = 0;
49
50 gst_ta_accum_item ** g_accums = NULL;
51 static int g_accum_index = 0;
52 static int g_accum_longest_name = 0;
53 static unsigned long g_accum_first_time = 0xFFFFFFFF;
54 static int g_enable = 0;
55
56 #define MMTA_ENV_NAME   "MMTA_ENABLE"
57
58 void __set_enable_by_env ()
59 {
60         char* env = getenv (MMTA_ENV_NAME);
61         if (env != NULL && strcmp (env,"1") == 0)
62                 gst_ta_set_enable(1);
63 }
64
65 int gst_ta_init(void)
66 {
67         __set_enable_by_env();
68
69         if (g_enable == 0)
70                 return 0;
71
72         if (g_accums)
73                 return 0;
74         
75         g_cps = (gst_ta_checkpoint **) malloc ( GST_TA_MAX_CHECKPOINT * sizeof(gst_ta_checkpoint *) );
76         if(!g_cps)
77                 return -1;
78         
79         g_accums = (gst_ta_accum_item **) malloc ( GST_TA_MAX_CHECKPOINT * sizeof(gst_ta_accum_item *) );
80         if(!g_accums)
81                 return -1;
82
83         g_accum_first_time = 0xFFFFFFFF;
84         
85         return 0;
86 }
87
88 int gst_ta_release(void)
89 {
90         if ( ! g_accums )
91                 return 0;
92         
93         __free_cps();
94         __free_accums();
95
96         g_accum_first_time = 0xFFFFFFFF;
97
98         return 0;
99 }
100
101 void gst_ta_set_enable(int enable)
102 {
103         printf("MMTA : setting enable to %d\n", enable);
104         g_enable = enable;      
105 }
106
107 int gst_ta_get_numof_checkpoints()
108 {
109         return g_cp_index;
110 }
111
112 char* gst_ta_fmt(const char* fmt, ...)
113 {
114         static char ta_buf[512];
115         va_list args;
116         
117         memset(ta_buf, '\0', 512);
118
119         va_start(args, fmt);
120         vsnprintf(ta_buf, 512, fmt, args);
121         va_end(args);
122         
123         return ta_buf;
124 }
125
126
127 int gst_ta_add_checkpoint(char* name, int show, char* filename, int line)
128 {
129         gst_ta_checkpoint * cp = NULL;
130         struct timeval  t;
131         
132         if (!g_enable)
133                 return -1;
134
135         if (!g_accums)
136                 return 0;
137
138         if ( g_cp_index == GST_TA_MAX_CHECKPOINT )
139                 return -1;
140
141         if ( !name )
142                 return -1;
143
144         if( strlen ( name ) == 0 )
145                 return -1;
146
147         cp = ( gst_ta_checkpoint * ) malloc( sizeof( gst_ta_checkpoint ) );
148         if ( !cp )
149                 return -1;
150
151         cp->name = strdup (name);
152         if ( !cp->name )
153         {
154                 free(cp);
155                 return -1;
156         }
157
158         if ( show )
159                 printf("[CHECK-POINT] %s...(%s:%d)\n", name, filename, line );
160
161         gettimeofday( &t, NULL );
162         cp->timestamp = t.tv_sec*1000000L + t.tv_usec;
163 #ifdef GST_EXT_TA_UNIT_MSEC     
164         cp->timestamp = (cp->timestamp >= 1000)?cp->timestamp/1000:0;
165 #endif
166
167         g_cps[g_cp_index] = cp;
168
169         g_cp_index++;
170
171         return 0;
172 }
173
174 void gst_ta_show_checkpoints(void)
175 {
176         int i = 0;
177
178         if (!g_accums)
179                 return;
180
181         printf("BEGIN RESULT ============================\n");
182         for ( i = 0; i < g_cp_index; i++ )
183         {
184                 printf("[%d] %s : %ld us.\n", i, g_cps[i]->name, g_cps[i]->timestamp);
185         }
186         printf("END RESULT   ============================\n");
187 }
188
189 void gst_ta_show_diff(char* name1, char* name2)
190 {
191         if (!g_accums)
192                 return ;
193
194
195         printf("Time takes from [%s] to [%s] : %ld us.\n", name1, name2, gst_ta_get_diff(name1, name2));
196 }
197
198 unsigned long gst_ta_get_diff(char* name1, char* name2)
199 {
200         int cp1, cp2;
201
202         if (!g_accums)
203                 return 0;
204
205
206         /* fail if bad param. */
207         if ( !name1 || !name2 )
208                 return -1;
209
210         /* fail if same. */
211         if ( strcmp( name1, name2 ) == 0 )
212                 return -1;
213
214         /* get index */
215         if ( ( cp1 = __get_cp_index(name1) ) == -1 )
216                 return -1;
217
218         if ( ( cp2 = __get_cp_index(name2) ) == -1 )
219                 return -1;
220
221         /* NOTE :
222          * return value must be positive value.
223          * bcz the value of higher index of g_cps always higher than lower one. */
224         return g_cps[cp2]->timestamp - g_cps[cp1]->timestamp;
225         
226 }
227
228 static int __get_cp_index(char* name)
229 {
230         int i;
231
232         assert(name);
233         
234         /* find index */
235         for ( i = 0; i < g_cp_index; i++ )
236         {
237                 if ( strcmp( name, g_cps[i]->name ) == 0 )
238                         return i;
239         }
240
241         return -1;
242 }
243
244 static int __get_accum_index(char* name)
245 {
246         int i;
247
248         assert(name);
249         
250         /* find index */
251         for ( i = 0; i < g_accum_index; i++ )
252         {
253                 if ( strcmp( name, g_accums[i]->name ) == 0 )
254                         return i;
255         }
256
257         return -1;
258 }
259
260 static void __free_cps(void)
261 {
262         int i = 0;
263
264         if ( ! g_cps )
265                 return;
266
267         for ( i = 0; i < g_cp_index; i++ )
268         {
269                 if ( g_cps[i] )
270                 {
271                         if ( g_cps[i]->name )
272                                 free ( g_cps[i]->name );
273
274                         free ( g_cps[i] );
275
276                         g_cps[i] = NULL;
277                 }
278         }
279
280         free ( g_cps );
281         g_cps = NULL;
282
283         g_cp_index = 0;
284 }
285
286 static void __free_accums(void)
287 {
288         int i = 0;
289
290         if ( ! g_accums )
291                 return;
292
293         for ( i = 0; i < g_accum_index; i++ )
294         {
295                 if ( g_accums[i] )
296                 {
297                         if ( g_accums[i]->name )
298                                 free ( g_accums[i]->name );
299
300                         free ( g_accums[i] );
301
302                         g_accums[i] = NULL;
303                 }
304         }
305
306         g_accum_index = 0;
307         g_accum_longest_name = 0;
308
309         free ( g_accums );
310         g_accums = NULL;
311 }
312
313
314 int gst_ta_accum_item_begin(char* name, int show, char* filename, int line)
315 {
316         gst_ta_accum_item * accum = NULL;
317         int index = 0;
318         int name_len = 0;
319         struct timeval t;
320
321         if (!g_enable)
322                 return -1;
323
324         if (!g_accums)
325                 return 0;
326
327
328
329         if ( g_accum_index == GST_TA_MAX_ACCUM )
330                 return -1;
331
332         if ( !name )
333                 return -1;
334
335         name_len = strlen(name);
336         if( name_len == 0 )
337                 return -1;
338
339         /* if 'name' is new one. create new item. */
340         if ( (index = __get_accum_index(name)) == -1 )
341         {
342                 accum = ( gst_ta_accum_item * ) malloc( sizeof( gst_ta_accum_item ) );
343                 if ( !accum )
344                         return -1;
345
346                 /* clear first. */
347                 memset( accum, 0, sizeof (gst_ta_accum_item) );
348                 accum->elapsed_min = 0xFFFFFFFF;
349
350                 accum->name = strdup (name);
351                 if ( !accum->name )
352                 {
353                         free(accum);
354                         return -1;
355                 }
356
357                 /* add it to list. */
358                 g_accums[g_accum_index] = accum;
359                 g_accum_index++;
360
361                 if ( g_accum_longest_name < name_len )
362                         g_accum_longest_name = name_len;
363                 
364         }
365         else
366         {
367                 accum = g_accums[index];
368         }
369
370         /* verify pairs of begin, end. */
371         if (accum->on_estimate)
372         {
373                 printf("[%s] is not 'end'ed!\n", accum->name);
374                 accum->num_unpair ++;
375                 return -1;
376         }
377
378         /* get timestamp */
379         gettimeofday( &t, NULL );
380         accum->timestamp = t.tv_sec*1000000L + t.tv_usec;
381 #ifdef GST_EXT_TA_UNIT_MSEC     
382         accum->timestamp = ( accum->timestamp >= 1000) ? accum->timestamp/1000 : 0;
383 #endif  
384         accum->on_estimate = 1;
385
386         if ( accum->first_start == 0 )  {       /* assum that timestamp never could be zero.*/
387                 accum->first_start = accum->timestamp;
388
389                 if ( g_accum_first_time > accum->first_start )
390                         g_accum_first_time = accum->first_start ;
391         }
392                 
393         if ( show )
394                 printf("[ACCUM BEGIN] %s : %ld ---(%s:%d)\n", name, accum->timestamp, filename, line );
395
396         accum->num_calls++;
397
398         return 0;
399 }
400
401 int gst_ta_accum_item_end(char* name, int show, char* filename, int line)
402 {
403         gst_ta_accum_item * accum = NULL;
404         unsigned int tval = 0;
405         int index = 0;
406         struct timeval  t;
407
408         if (!g_enable)
409                 return -1;
410
411         if (!g_accums)
412                 return 0;
413
414
415         /* get time first for more accuracy. */
416         gettimeofday( &t, NULL );
417
418         if ( g_accum_index == GST_TA_MAX_ACCUM )
419                 return -1;
420
421         if ( !name )
422                 return -1;
423
424         if( strlen ( name ) == 0 )
425                 return -1;
426
427         /* varify the 'name' is already exist. */
428         if ( (index = __get_accum_index(name)) == -1 )
429         {
430                 printf("[%s] is not added before!\n", name);
431                 return -1;
432         }
433
434         accum = g_accums[index];
435
436         /* verify pairs of begin, end. */
437         if (!accum->on_estimate)
438         {
439                 printf("[%s] is not 'begin' yet!\n", accum->name);
440                 accum->num_unpair ++;
441                 return -1;
442         }
443         
444         /* get current timestamp. */
445         tval = t.tv_sec*1000000L + t.tv_usec;
446 #ifdef GST_EXT_TA_UNIT_MSEC     
447         tval = (tval>=1000) ? tval/1000 : 0;
448 #endif
449
450         /* update last_end */
451         accum->last_end = tval;
452
453         /* make get elapsed time. */
454         tval = tval - accum->timestamp;
455
456         /* update min/max */
457         accum->elapsed_max = tval > accum->elapsed_max ? tval : accum->elapsed_max;
458         accum->elapsed_min = tval < accum->elapsed_min ? tval : accum->elapsed_min;
459
460         if ( show )
461                 printf("[ACCUM END] %s : %ld + %d ---(%s:%d)\n", name, accum->elapsed_accum, tval, filename, line );
462
463         /* add elapsed time */
464         accum->elapsed_accum += tval;
465         accum->on_estimate = 0;
466
467         return 0;
468 }
469
470 void __print_some_info(FILE* fp)
471 {
472         if (!fp)
473                 return;
474
475         /* comment */
476         {
477                 fprintf(fp,     
478 "\nThe following content is automatically generated by gstreamer\n \
479 with GST_EXT_TIME_ANALYSIS feature. This feature can affects\n \
480 performance of multimedia functionality. so if you want to\n \
481 disable it. just comment the feature in /limo-middleware/\n \
482 multimedia-framework/media-service/msl_feature_config.py\n" );
483         }
484
485         /* General infomation */
486         {
487                 time_t t_val;
488                 char hostname[256] = {'\0',};           
489                 char ctime_str[256] = {'\0',};
490                 struct utsname uts;
491                 struct rusage r_usage;
492
493                 fprintf(fp, "\n[[ General info ]]\n");
494                 
495                 /* time and date */
496                 time(&t_val);
497                 fprintf(fp, "Date : %s", ctime_r(&t_val, ctime_str) );
498
499                 /* system */
500                 if ( gethostname(hostname, 255) == 0 && uname(&uts) >= 0 )
501                 {
502                         fprintf(fp, "Hostname : %s\n", hostname);
503                         fprintf(fp, "System : %s\n", uts.sysname);
504                         fprintf(fp, "Machine : %s\n", uts.machine);
505                         fprintf(fp, "Nodename : %s\n", uts.nodename);
506                         fprintf(fp, "Release : %s \n", uts.release);
507                         fprintf(fp, "Version : %s \n", uts.version);
508                 }
509
510                 /* process info. */
511                 fprintf(fp, "Process priority : %d\n", getpriority(PRIO_PROCESS, getpid()) );
512                 getrusage(RUSAGE_SELF, &r_usage);
513                 fprintf(fp, "CPU usage : User = %ld.%06ld, System = %ld.%06ld\n", 
514                                 r_usage.ru_utime.tv_sec, r_usage.ru_utime.tv_usec,
515                                 r_usage.ru_stime.tv_sec, r_usage.ru_stime.tv_usec );
516
517
518         }
519
520         /* host environment variables */
521         {
522                 extern char** environ;
523                 char** env = environ;
524
525                 fprintf(fp, "\n[[ Host environment variables ]]\n");
526                 while(*env)
527                 {
528                         fprintf(fp, "%s\n", *env);
529                         env++;
530                 }
531         }
532         
533         /* applied target feature */
534         {
535                 fprintf(fp, "\n[[ Applied target feature ]]\n");
536                 #ifdef GST_EXT_TIME_ANALYSIS
537                 fprintf(fp, "GST_EXT_TIME_ANALYSIS\n");
538                 #endif
539                 #ifdef GST_EXT_SKIP_RESCAN_REGISTRY
540                 fprintf(fp, "GST_EXT_SKIP_RESCAN_REGISTRY\n");
541                 #endif
542                 #ifdef GST_EXT_USE_TINY_REGISTRY                
543
544                 fprintf(fp, "GST_EXT_USE_TINY_REGISTRY\n");
545                 #endif
546                 #ifdef GST_EXT_PAD_LINK_UNCHECKED
547                 fprintf(fp, "GST_EXT_PAD_LINK_UNCHECKED\n");
548                 #endif
549                 #ifdef GST_EXT_DFBVIDEOSINK_IPP
550                 fprintf(fp, "GST_EXT_DFBVIDEOSINK_IPP\n");
551                 #endif
552                 #ifdef GST_EXT_REDUCE_PLUGIN_NUM
553                 fprintf(fp, "GST_EXT_REDUCE_PLUGIN_NUM\n");
554                 #endif
555                 #ifdef GST_EXT_USE_PDP_NETWORK
556                 fprintf(fp, "GST_EXT_USE_PDP_NETWORK\n");
557                 #endif
558                 #ifdef GST_EXT_VOLUME_WITHOUT_LIBOIL
559                 fprintf(fp, "GST_EXT_VOLUME_WITHOUT_LIBOIL\n");
560                 #endif
561                 #ifdef GST_EXT_DECODEBIN_QUEUE_ENLARGE
562                 fprintf(fp, "GST_EXT_DECODEBIN_QUEUE_ENLARGE\n");
563                 #endif
564                 
565                 /* Camcorder releated feature */
566
567                 #ifdef GST_EXT_NONBLOCKDQUE
568                 fprintf(fp, "GST_EXT_NONBLOCKDQUE\n");
569                 #endif
570                 #ifdef GST_EXT_RENEGOTIATION
571                 fprintf(fp, "GST_EXT_RENEGOTIATION\n");
572                 #endif
573                 #ifdef GST_EXT_MOBILECAMERA
574                 fprintf(fp, "GST_EXT_MOBILECAMERA\n");
575                 #endif
576                 #ifdef GST_EXT_VIDEOSCALE_IPP
577                 fprintf(fp, "GST_EXT_VIDEOSCALE_IPP\n");
578                 #endif
579                 #ifdef GST_EXT_ASYNC_DEV
580                 fprintf(fp, "GST_EXT_ASYNC_DEV\n");
581                 #endif
582                 #ifdef GST_EXT_AV_RECORDING
583                 fprintf(fp, "GST_EXT_AV_RECORDING\n");
584                 #endif
585                 #ifdef GST_EXT_SWITCH_CAMERA
586                 fprintf(fp, "GST_EXT_SWITCH_CAMERA\n");
587                 #endif
588
589                 fprintf(fp, "\n\n");
590         }
591
592         
593 }
594
595 void gst_ta_accum_show_result(int direction)
596 {
597         int i = 0;
598         char format[256];
599         FILE* fp = stderr;
600
601         if (!g_accums)
602                 return;
603
604
605         switch (direction)
606         {
607                 case    MMTA_SHOW_STDOUT: fp = stdout;  break;
608                 case    MMTA_SHOW_STDERR: fp = stderr;  break;
609                 case    MMTA_SHOW_FILE:
610                 {
611                         fp = fopen("/tmp/gst-ta.log", "wt");
612                         if (!fp)
613                                 return;
614                 }
615                 break;
616         }
617
618         __print_some_info(fp);
619
620
621 #ifdef GST_EXT_TA_UNIT_MSEC
622         sprintf(format, "[%%3d] %%-%ds | \ttotal : %%4ld\tcalls : %%3ld\tavg : %%4ld\tmin : %%4ld\tmax : %%4ld\tstart : %%4lu\tend : %%4lu\tunpair : %%3ld\n", g_accum_longest_name);
623         fprintf(fp, "BEGIN RESULT ACCUM============================ : NumOfItems : %d, unit(msec)\n", g_accum_index);
624 #else
625         snprintf(format, sizeof(format)-1, "[%%3d] %%-%ds | \ttotal : %%ld\tcalls : %%ld\tavg : %%ld\tmin : %%ld\tmax : %%ld\tstart : %%lu\tend : %%lu\tunpair : %%ld\n", g_accum_longest_name);
626         fprintf(fp, "BEGIN RESULT ACCUM============================ : NumOfItems : %d, unit(usec)\n", g_accum_index);
627 #endif
628
629         for ( i = 0; i < g_accum_index; i++ )
630         {       
631                 /* prevent 'devide by zero' error */
632                 if (g_accums[i]->num_calls == 0)
633                         g_accums[i]->num_calls = 1;
634                         
635                 fprintf(fp, 
636                         format,         
637                         i, 
638                         g_accums[i]->name, 
639                         g_accums[i]->elapsed_accum,
640                         g_accums[i]->num_calls,
641                         (g_accums[i]->elapsed_accum == 0)?0:(int)(g_accums[i]->elapsed_accum / g_accums[i]->num_calls),
642                         g_accums[i]->elapsed_min,
643                         g_accums[i]->elapsed_max,
644                         g_accums[i]->first_start - g_accum_first_time,
645                         g_accums[i]->last_end - g_accum_first_time,
646                         g_accums[i]->num_unpair );
647         }
648         fprintf(fp, "END RESULT ACCUM  ============================\n");
649
650         if ( direction == MMTA_SHOW_FILE )
651                 fclose(fp);
652 }
653
654 #endif  /*_MM_TA_C_*/