set unix line endings instead of windows ones
[platform/core/system/swap-probe.git] / custom_chart / da_chart.c
1 /*
2  *  DA probe
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: 
7  *
8  * Jaewon Lim <jaewon81.lim@samsung.com>
9  * Woojin Jung <woojin2.jung@samsung.com>
10  * Juyoung Kim <j0.kim@samsung.com>
11  * 
12  * This library is free software; you can redistribute it and/or modify it under
13  * the terms of the GNU Lesser General Public License as published by the
14  * Free Software Foundation; either version 2.1 of the License, or (at your option)
15  * any later version.
16  * 
17  * This library is distributed in the hope that it will be useful, but WITHOUT ANY
18  * WARRANTY; without even the implied warranty of MERCHANTABILITY or
19  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
20  * License for more details.
21  *
22  * You should have received a copy of the GNU Lesser General Public License
23  * along with this library; if not, write to the Free Software Foundation, Inc., 51
24  * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25  *
26  * Contributors:
27  * - S-Core Co., Ltd
28  * 
29  */
30
31 #include <pthread.h>
32 #include <signal.h>                     // for signal
33 #include <unistd.h>                     // for ualarm, sleep
34 #include <sys/timerfd.h>        // for timerfd
35 #include <stdio.h>
36 #include <errno.h>                      // for errno
37 #include <string.h>                     // for memset
38 #include <stdint.h>                     // for uint64_t
39
40 #include "daprobe.h"
41 #include "dahelper.h"
42 #include "probeinfo.h"
43 #define _USE_DA_
44 #include "da_chart.h"
45
46 #include "binproto.h"
47
48 #define ERR_THREAD_CREATE_FAIL  -2001   // thread creation fail
49
50 #define MAX_TITLE_LENGTH                16
51 #define MAX_CHART_HANDLE                10              // cannot be exceeded 10
52 #define MAX_SERIES_PER_CHART    4               // cannot be exceeded 10
53 // chart handle is  from 1 to 9
54 // series handle is from 11 to 99
55 // series handle 32 means that the series is 2nd series in 3rd chart.
56 // zero value handle means error
57
58 // =====================================================================
59 // global variable
60 // =====================================================================
61
62 typedef struct _chart_interval_callback
63 {
64         da_handle chart_handle;
65         da_handle series_handle;
66         da_user_data_2_chart_data callback;
67         void* user_data;
68         struct _chart_interval_callback* next;
69 } chart_interval_callback;
70
71 typedef struct
72 {
73         int                     timerfd;
74         pthread_t       thread_handle;
75         chart_interval_callback*        callback_list;
76         pthread_mutex_t         list_mutex;
77 } interval_manager;
78
79 typedef struct
80 {
81         int                     chart_handle_index;
82         int                     series_handle_index[MAX_CHART_HANDLE];
83         int                     interval_for_series[MAX_CHART_HANDLE][MAX_SERIES_PER_CHART];
84         interval_manager        interval_10ms;
85         interval_manager        interval_100ms;
86         interval_manager        interval_1s;
87 } chart_handle_maintainer;
88
89 chart_handle_maintainer chm;
90
91 __thread pid_t cur_thread = -1;
92
93
94 // =====================================================================
95 // internal macro definition
96 // =====================================================================
97
98 #define DECLARE_CHART_VARIABLE                                  \
99         da_handle __attribute__((unused)) ret = 0;      \
100         probeInfo_t probeInfo;                                          \
101         log_t log
102
103 #define APPEND_LOG_CHART_RESULT(RESULT)                                                                 \
104         log.length += sprintf(log.data + log.length, "`,%d`,0x%p`,0`,2",        \
105                         RESULT, CALLER_ADDRESS)
106
107 #define APPEND_LOG_CHART(HANDLE, TYPE, TEXT, COLOR, VALUE)                                      \
108         log.length += sprintf(log.data + log.length, "`,`,%d`,%d`,%s`,%d`,%.3f",        \
109                         HANDLE, TYPE, TEXT, COLOR, VALUE)
110
111 // =====================================================================
112 // timer thread routine for callback
113 // =====================================================================
114
115 void* _chart_timerThread(void* data)
116 {
117         DECLARE_CHART_VARIABLE;
118
119         uint64_t exp;
120         ssize_t readsize;
121         chart_interval_callback* cur;
122         float value;
123         sigset_t profsigmask;
124         interval_manager* pmanager = (interval_manager*)data;
125
126         probeBlockStart();
127
128         sigemptyset(&profsigmask);
129         sigaddset(&profsigmask, SIGPROF);
130         pthread_sigmask(SIG_BLOCK, &profsigmask, NULL);
131
132         while((readsize = read(pmanager->timerfd, &exp, sizeof(uint64_t))) > 0)
133         {
134                 pthread_mutex_lock(&pmanager->list_mutex);
135
136                 cur = pmanager->callback_list;
137                 while(cur != NULL)
138                 {
139                         value = cur->callback(cur->user_data);
140
141                         INIT_LOG;
142                         setProbePoint(&probeInfo);
143                         log.length = sprintf(log.data, "%d`,%d`,%s`,%lu`,%d`,%d`,`,`,0x%p`,0`,2`,`,%d`,0`,`,0`,%.3f",
144                                         LC_CUSTOM, probeInfo.eventIndex, __func__, probeInfo.currentTime, probeInfo.pID,
145                                         probeInfo.tID, CALLER_ADDRESS, cur->series_handle, value);
146                         printLog(&log, MSG_LOG);
147
148                         PREPARE_LOCAL_BUF();
149                         PACK_COMMON_BEGIN(MSG_PROBE_CUSTOM, LC_CUSTOM, "", 0);
150                         PACK_COMMON_END(0, 0, 2);
151                         PACK_CUSTOM(cur->series_handle, 0, "", 0, value);
152                         FLUSH_LOCAL_BUF();
153
154                         cur = cur->next;
155                 }
156
157                 pthread_mutex_unlock(&pmanager->list_mutex);
158
159                 sleep(0);
160         }
161
162         probeBlockEnd();
163
164         return NULL;
165 }
166
167 static int start_callback_thread(chart_interval interval)
168 {
169         int* timerfd = NULL;
170         pthread_t* thread_handle = NULL;
171         interval_manager* pman = NULL;
172         struct itimerspec timevalue;
173
174         if(interval == CHART_INTERVAL_10MSEC)
175         {
176                 timerfd = &(chm.interval_10ms.timerfd);
177                 thread_handle = &(chm.interval_10ms.thread_handle);
178                 pman = &(chm.interval_10ms);
179                 timevalue.it_value.tv_sec = 0;
180                 timevalue.it_value.tv_nsec = 10000000L;
181                 timevalue.it_interval.tv_sec = 0;
182                 timevalue.it_interval.tv_nsec = 10000000L;
183         }
184         else if(interval == CHART_INTERVAL_100MSEC)
185         {
186                 timerfd = &(chm.interval_100ms.timerfd);
187                 thread_handle = &(chm.interval_100ms.thread_handle);
188                 pman = &(chm.interval_100ms);
189                 timevalue.it_value.tv_sec = 0;
190                 timevalue.it_value.tv_nsec = 100000000L;
191                 timevalue.it_interval.tv_sec = 0;
192                 timevalue.it_interval.tv_nsec = 100000000L;
193         }
194         else if(interval == CHART_INTERVAL_1SEC)
195         {
196                 timerfd = &(chm.interval_1s.timerfd);
197                 thread_handle = &(chm.interval_1s.thread_handle);
198                 pman = &(chm.interval_1s);
199                 timevalue.it_value.tv_sec = 1;
200                 timevalue.it_value.tv_nsec = 0;
201                 timevalue.it_interval.tv_sec = 1;
202                 timevalue.it_interval.tv_nsec = 0;
203         }
204         else
205         {
206                 return ERR_WRONG_PARAMETER;
207         }
208
209         if(*timerfd != -1 || *thread_handle != -1)
210                 return 0;               // already thread exist
211
212         *timerfd = timerfd_create(CLOCK_REALTIME, 0);
213         if(*timerfd == -1)
214                 return errno;
215
216         if(timerfd_settime(*timerfd, 0, &timevalue, NULL) == -1)
217                 return errno;
218
219         if(pthread_create(thread_handle, NULL, _chart_timerThread, pman) < 0)
220                 return ERR_THREAD_CREATE_FAIL;
221
222         return 0;
223 }
224
225
226 // =====================================================================
227 // internal utility function
228 // =====================================================================
229
230 static void add_to_callback_list(chart_interval interval, da_handle charthandle, da_handle series_handle,
231                 da_user_data_2_chart_data callback, void* user_data)
232 {
233         chart_interval_callback* newelem;
234         
235         newelem = (chart_interval_callback*)malloc(sizeof(chart_interval_callback));
236         newelem->chart_handle = charthandle;
237         newelem->series_handle = series_handle;
238         newelem->callback = callback;
239         newelem->user_data = user_data;
240
241         chm.interval_for_series[charthandle][series_handle % 10] = interval;
242         
243         switch(interval)
244         {
245         case CHART_INTERVAL_10MSEC:
246                 pthread_mutex_lock(&chm.interval_10ms.list_mutex);
247                 newelem->next = chm.interval_10ms.callback_list;
248                 chm.interval_10ms.callback_list = newelem;
249                 pthread_mutex_unlock(&chm.interval_10ms.list_mutex);
250                 __sync_add_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);
251                 break;
252         case CHART_INTERVAL_100MSEC:
253                 pthread_mutex_lock(&chm.interval_100ms.list_mutex);
254                 newelem->next = chm.interval_100ms.callback_list;
255                 chm.interval_100ms.callback_list = newelem;
256                 pthread_mutex_unlock(&chm.interval_100ms.list_mutex);
257                 __sync_add_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);
258                 break;
259         case CHART_INTERVAL_1SEC:
260                 pthread_mutex_lock(&chm.interval_1s.list_mutex);
261                 newelem->next = chm.interval_1s.callback_list;
262                 chm.interval_1s.callback_list = newelem;
263                 pthread_mutex_unlock(&chm.interval_1s.list_mutex);
264                 __sync_add_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);
265                 break;
266         default:
267                 free(newelem);
268                 break;
269         }
270 }
271
272 static void remove_all_callback_list()
273 {
274         chart_interval_callback* cur;
275         
276         pthread_mutex_lock(&chm.interval_10ms.list_mutex);
277         while(chm.interval_10ms.callback_list != NULL)
278         {
279                 cur = chm.interval_10ms.callback_list;
280                 chm.interval_10ms.callback_list = cur->next;
281                 free(cur);
282         }
283         pthread_mutex_unlock(&chm.interval_10ms.list_mutex);
284
285         pthread_mutex_lock(&chm.interval_100ms.list_mutex);
286         while(chm.interval_100ms.callback_list != NULL)
287         {
288                 cur = chm.interval_100ms.callback_list;
289                 chm.interval_100ms.callback_list = cur->next;
290                 free(cur);
291         }
292         pthread_mutex_unlock(&chm.interval_100ms.list_mutex);
293
294         pthread_mutex_lock(&chm.interval_1s.list_mutex);
295         while(chm.interval_1s.callback_list != NULL)
296         {
297                 cur = chm.interval_1s.callback_list;
298                 chm.interval_1s.callback_list = cur->next;
299                 free(cur);
300         }
301         pthread_mutex_unlock(&chm.interval_1s.list_mutex);
302
303         memset(&chm.interval_for_series, 0, sizeof(chm.interval_for_series));
304         __sync_and_and_fetch(&(gTraceInfo.custom_chart_callback_count), 0);
305 }
306
307 static void remove_from_callback_list(da_handle charthandle, da_handle series_handle)
308 {
309         chart_interval_callback *prev, *cur;
310         chart_interval interval;
311
312         interval = chm.interval_for_series[charthandle][series_handle % 10];
313         chm.interval_for_series[charthandle][series_handle % 10] = 0;
314
315         switch(interval)
316         {
317         case CHART_INTERVAL_10MSEC:
318                 pthread_mutex_lock(&chm.interval_10ms.list_mutex);
319
320                 prev = NULL;
321                 cur = chm.interval_10ms.callback_list;
322                 while(cur != NULL)
323                 {
324                         if(cur->chart_handle == charthandle && cur->series_handle == series_handle)
325                         {
326                                 if(prev)
327                                         prev->next = cur->next;
328                                 else
329                                         chm.interval_10ms.callback_list = cur->next;
330
331                                 __sync_sub_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);
332                                 free(cur);
333                                 break;
334                         }
335
336                         prev = cur;
337                         cur = cur->next;
338                 }
339
340                 pthread_mutex_unlock(&chm.interval_10ms.list_mutex);
341                 break;
342         case CHART_INTERVAL_100MSEC:
343                 pthread_mutex_lock(&chm.interval_100ms.list_mutex);
344
345                 prev = NULL;
346                 cur = chm.interval_100ms.callback_list;
347                 while(cur != NULL)
348                 {
349                         if(cur->chart_handle == charthandle && cur->series_handle == series_handle)
350                         {
351                                 if(prev)
352                                         prev->next = cur->next;
353                                 else
354                                         chm.interval_100ms.callback_list = cur->next;
355
356                                 __sync_sub_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);
357                                 free(cur);
358                                 break;
359                         }
360
361                         prev = cur;
362                         cur = cur->next;
363                 }
364
365                 pthread_mutex_unlock(&chm.interval_100ms.list_mutex);
366                 break;
367         case CHART_INTERVAL_1SEC:
368                 pthread_mutex_lock(&chm.interval_1s.list_mutex);
369
370                 prev = NULL;
371                 cur = chm.interval_1s.callback_list;
372                 while(cur != NULL)
373                 {
374                         if(cur->chart_handle == charthandle && cur->series_handle == series_handle)
375                         {
376                                 if(prev)
377                                         prev->next = cur->next;
378                                 else
379                                         chm.interval_1s.callback_list = cur->next;
380
381                                 __sync_sub_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);
382                                 free(cur);
383                                 break;
384                         }
385
386                         prev = cur;
387                         cur = cur->next;
388                 }
389
390                 pthread_mutex_unlock(&chm.interval_1s.list_mutex);
391                 break;
392         default:
393                 break;
394         }
395 }
396
397
398 // =====================================================================
399 // constructor and destructor functions
400 // =====================================================================
401
402 void __attribute__((constructor)) _init_lib()
403 {
404         probeBlockStart();
405
406         memset(&chm, 0, sizeof(chm));
407         chm.interval_10ms.timerfd = -1;
408         chm.interval_100ms.timerfd = -1;
409         chm.interval_1s.timerfd = -1;
410         chm.interval_10ms.thread_handle = -1;
411         chm.interval_100ms.thread_handle = -1;
412         chm.interval_1s.thread_handle = -1;
413         pthread_mutex_init(&chm.interval_10ms.list_mutex, NULL);
414         pthread_mutex_init(&chm.interval_100ms.list_mutex, NULL);
415         pthread_mutex_init(&chm.interval_1s.list_mutex, NULL);
416
417         probeBlockEnd();
418 }
419
420 void __attribute__((destructor)) _fini_lib()
421 {
422         probeBlockStart();
423
424         remove_all_callback_list();
425         if(chm.interval_10ms.timerfd != -1)
426                 close(chm.interval_10ms.timerfd);
427         if(chm.interval_100ms.timerfd != -1)
428                 close(chm.interval_100ms.timerfd);
429         if(chm.interval_1s.timerfd != -1)
430                 close(chm.interval_1s.timerfd);
431
432         if(chm.interval_10ms.thread_handle != -1)
433         {
434                 pthread_join(chm.interval_10ms.thread_handle, NULL);
435         }
436         if(chm.interval_100ms.thread_handle != -1)
437         {
438                 pthread_join(chm.interval_100ms.thread_handle, NULL);
439         }
440         if(chm.interval_1s.thread_handle != -1)
441         {
442                 pthread_join(chm.interval_1s.thread_handle, NULL);
443         }
444
445         probeBlockEnd();
446 }
447
448
449 // =====================================================================
450 // api definition
451 // =====================================================================
452
453 void da_mark(chart_color color, char* mark_text)
454 {
455         DECLARE_CHART_VARIABLE;
456         
457         probeBlockStart();
458         
459         INIT_LOG;
460         setProbePoint(&probeInfo);
461         APPEND_LOG_BASIC(LC_CUSTOM);
462         APPEND_LOG_INPUT("%s", "");
463         APPEND_LOG_CHART_RESULT(0);
464         APPEND_LOG_CHART(0, 0, mark_text, color, 0.0f);
465         printLog(&log, MSG_LOG);
466
467         PREPARE_LOCAL_BUF();
468         PACK_COMMON_BEGIN(MSG_PROBE_CUSTOM, LC_CUSTOM, "dp", color, mark_text);
469         PACK_COMMON_END(0, 0, 2);
470         PACK_CUSTOM(0, 0, mark_text, color, 0.0f);
471         FLUSH_LOCAL_BUF();
472
473         probeBlockEnd();
474 }
475
476 da_handle da_create_chart(char* chart_name)
477 {
478         DECLARE_CHART_VARIABLE;
479
480         // check if there is available chart handle slot
481         if(chm.chart_handle_index + 1 >= MAX_CHART_HANDLE)
482                 return ERR_MAX_CHART_NUMBER;
483                 
484         // check if chart_name is null
485         if(chart_name == NULL)
486                 return ERR_WRONG_PARAMETER;
487                 
488         probeBlockStart();
489         ret = ++(chm.chart_handle_index);
490
491         INIT_LOG;
492         setProbePoint(&probeInfo);
493         APPEND_LOG_BASIC(LC_CUSTOM);
494         APPEND_LOG_INPUT("%s", "");
495         APPEND_LOG_CHART_RESULT(ret);
496         APPEND_LOG_CHART(0, 0, chart_name, 0, 0.0f);
497         printLog(&log, MSG_LOG);
498
499         PREPARE_LOCAL_BUF();
500         PACK_COMMON_BEGIN(MSG_PROBE_CUSTOM, LC_CUSTOM, "p", chart_name);
501         PACK_COMMON_END(ret, 0, 2);
502         PACK_CUSTOM(0, 0, chart_name, 0, 0.0f);
503         FLUSH_LOCAL_BUF();
504         
505         probeBlockEnd();
506         
507         return ret;
508 }
509
510 da_handle da_create_series(da_handle charthandle, char* seriesname,
511                 series_type type, chart_color color)
512 {
513         DECLARE_CHART_VARIABLE;
514         
515         // check if charthandle is valid handle or not
516         if(charthandle <= 0 || charthandle > chm.chart_handle_index)
517                 return ERR_WRONG_HANDLE;
518                 
519         // chech if extra parameter is valid
520         if(seriesname == NULL)
521                 return ERR_WRONG_PARAMETER;
522
523         // check if there is available series spot
524         if(chm.series_handle_index[(int)charthandle] + 1 >= MAX_SERIES_PER_CHART)
525                 return ERR_MAX_CHART_NUMBER;
526         
527         probeBlockStart();
528         ret = ++(chm.series_handle_index[charthandle]);
529         ret += (10 * charthandle);
530         
531         INIT_LOG;
532         setProbePoint(&probeInfo);
533         APPEND_LOG_BASIC(LC_CUSTOM);
534         APPEND_LOG_INPUT("%s", "");
535         APPEND_LOG_CHART_RESULT(ret);
536         APPEND_LOG_CHART(charthandle, type, seriesname, color, 0.0f);
537         printLog(&log, MSG_LOG);
538
539         PREPARE_LOCAL_BUF();
540         PACK_COMMON_BEGIN(MSG_PROBE_CUSTOM, LC_CUSTOM, "dpdd",  charthandle, seriesname, type, color);
541         PACK_COMMON_END(ret, 0, 2);
542         PACK_CUSTOM(charthandle, type, seriesname, color, 0.0f);
543         FLUSH_LOCAL_BUF();
544
545         probeBlockEnd();
546         
547         return ret;
548 }
549                 
550 da_handle da_create_default_series(da_handle charthandle, char* seriesname)
551 {
552         return da_create_series(charthandle, seriesname,
553                         CHART_TYPE_AUTO, CHART_COLOR_AUTO);
554 }
555
556 int da_set_callback(da_handle series_handle, da_user_data_2_chart_data callback,
557                 void* data_addr, chart_interval interval)
558 {
559         int cindex, sindex;
560         cindex = (int)(series_handle / 10);
561         sindex = series_handle % 10;
562         
563         // check series handle
564         if(cindex <= 0 || cindex > chm.chart_handle_index)
565                 return ERR_WRONG_HANDLE;
566         
567         if(sindex > chm.series_handle_index[(int)cindex])
568                 return ERR_WRONG_HANDLE;
569         
570         // check rest parameters
571         if(interval == CHART_NO_CYCLE && callback != NULL)
572                 return ERR_WRONG_PARAMETER;
573
574         probeBlockStart();
575
576         // remove previously registered callback
577         remove_from_callback_list(cindex, series_handle);
578
579         // register new callback
580         if(callback != NULL)
581         {
582                 add_to_callback_list(interval, cindex, series_handle, callback, data_addr);
583                 start_callback_thread(interval);
584         }
585         probeBlockEnd();
586
587         return 0;
588 }
589
590 void da_log(da_handle series_handle, float uservalue)
591 {
592         DECLARE_CHART_VARIABLE;
593         
594         // chech if series handle is valid
595         int cindex, sindex;
596         cindex = (int)(series_handle / 10);
597         sindex = series_handle % 10;
598         
599         if(cindex <= 0 || cindex > chm.chart_handle_index)
600                 return;
601         
602         if(sindex > chm.series_handle_index[(int)cindex])
603                 return;
604         
605         probeBlockStart();
606         
607         INIT_LOG;
608         setProbePoint(&probeInfo);
609         APPEND_LOG_BASIC(LC_CUSTOM);
610         APPEND_LOG_INPUT("%s", "");
611         APPEND_LOG_CHART_RESULT(0);
612         APPEND_LOG_CHART(series_handle, 0, "", 0, uservalue);
613         printLog(&log, MSG_LOG);
614
615         PREPARE_LOCAL_BUF();
616         PACK_COMMON_BEGIN(MSG_PROBE_CUSTOM, LC_CUSTOM, "dw", series_handle, uservalue);
617         PACK_COMMON_END(0, 0, 2);
618         PACK_CUSTOM(series_handle, 0, "", 0, uservalue);
619         FLUSH_LOCAL_BUF();
620         
621         probeBlockEnd();
622 }