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