sync with master
[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         interval_manager* pmanager = (interval_manager*)data;\r
122 \r
123         probeBlockStart();\r
124 \r
125         while((readsize = read(pmanager->timerfd, &exp, sizeof(uint64_t))) > 0)\r
126         {\r
127                 pthread_mutex_lock(&pmanager->list_mutex);\r
128 \r
129                 cur = pmanager->callback_list;\r
130                 while(cur != NULL)\r
131                 {\r
132                         value = cur->callback(cur->user_data);\r
133 \r
134                         INIT_LOG;\r
135                         setProbePoint(&probeInfo);\r
136                         log.length = sprintf(log.data, "%d`,%d`,%s`,%lu`,%d`,%d`,`,`,0x%p`,0`,2`,`,%d`,0`,`,0`,%.3f",\r
137                                         LC_CUSTOM, probeInfo.eventIndex, __func__, probeInfo.currentTime, probeInfo.pID,\r
138                                         probeInfo.tID, CALLER_ADDRESS, cur->series_handle, value);\r
139                         printLog(&log, MSG_LOG);\r
140 \r
141                         cur = cur->next;\r
142                 }\r
143 \r
144                 pthread_mutex_unlock(&pmanager->list_mutex);\r
145 \r
146                 sleep(0);\r
147         }\r
148 \r
149         probeBlockEnd();\r
150 \r
151         return NULL;\r
152 }\r
153 \r
154 static int start_callback_thread(chart_interval interval)\r
155 {\r
156         int* timerfd = NULL;\r
157         pthread_t* thread_handle = NULL;\r
158         interval_manager* pman = NULL;\r
159         struct itimerspec timevalue;\r
160 \r
161         if(interval == CHART_INTERVAL_10MSEC)\r
162         {\r
163                 timerfd = &(chm.interval_10ms.timerfd);\r
164                 thread_handle = &(chm.interval_10ms.thread_handle);\r
165                 pman = &(chm.interval_10ms);\r
166                 timevalue.it_value.tv_sec = 0;\r
167                 timevalue.it_value.tv_nsec = 10000000L;\r
168                 timevalue.it_interval.tv_sec = 0;\r
169                 timevalue.it_interval.tv_nsec = 10000000L;\r
170         }\r
171         else if(interval == CHART_INTERVAL_100MSEC)\r
172         {\r
173                 timerfd = &(chm.interval_100ms.timerfd);\r
174                 thread_handle = &(chm.interval_100ms.thread_handle);\r
175                 pman = &(chm.interval_100ms);\r
176                 timevalue.it_value.tv_sec = 0;\r
177                 timevalue.it_value.tv_nsec = 100000000L;\r
178                 timevalue.it_interval.tv_sec = 0;\r
179                 timevalue.it_interval.tv_nsec = 100000000L;\r
180         }\r
181         else if(interval == CHART_INTERVAL_1SEC)\r
182         {\r
183                 timerfd = &(chm.interval_1s.timerfd);\r
184                 thread_handle = &(chm.interval_1s.thread_handle);\r
185                 pman = &(chm.interval_1s);\r
186                 timevalue.it_value.tv_sec = 1;\r
187                 timevalue.it_value.tv_nsec = 0;\r
188                 timevalue.it_interval.tv_sec = 1;\r
189                 timevalue.it_interval.tv_nsec = 0;\r
190         }\r
191         else\r
192         {\r
193                 return ERR_WRONG_PARAMETER;\r
194         }\r
195 \r
196         if(*timerfd != -1 || *thread_handle != -1)\r
197                 return 0;               // already thread exist\r
198 \r
199         *timerfd = timerfd_create(CLOCK_REALTIME, 0);\r
200         if(*timerfd == -1)\r
201                 return errno;\r
202 \r
203         if(timerfd_settime(*timerfd, 0, &timevalue, NULL) == -1)\r
204                 return errno;\r
205 \r
206         if(pthread_create(thread_handle, NULL, _chart_timerThread, pman) < 0)\r
207                 return ERR_THREAD_CREATE_FAIL;\r
208 \r
209         return 0;\r
210 }\r
211 \r
212 \r
213 // =====================================================================\r
214 // internal utility function\r
215 // =====================================================================\r
216 \r
217 static void add_to_callback_list(chart_interval interval, da_handle charthandle, da_handle series_handle,\r
218                 da_user_data_2_chart_data callback, void* user_data)\r
219 {\r
220         chart_interval_callback* newelem;\r
221         \r
222         newelem = (chart_interval_callback*)malloc(sizeof(chart_interval_callback));\r
223         newelem->chart_handle = charthandle;\r
224         newelem->series_handle = series_handle;\r
225         newelem->callback = callback;\r
226         newelem->user_data = user_data;\r
227 \r
228         chm.interval_for_series[charthandle][series_handle % 10] = interval;\r
229         \r
230         switch(interval)\r
231         {\r
232         case CHART_INTERVAL_10MSEC:\r
233                 pthread_mutex_lock(&chm.interval_10ms.list_mutex);\r
234                 newelem->next = chm.interval_10ms.callback_list;\r
235                 chm.interval_10ms.callback_list = newelem;\r
236                 pthread_mutex_unlock(&chm.interval_10ms.list_mutex);\r
237                 __sync_add_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);\r
238                 break;\r
239         case CHART_INTERVAL_100MSEC:\r
240                 pthread_mutex_lock(&chm.interval_100ms.list_mutex);\r
241                 newelem->next = chm.interval_100ms.callback_list;\r
242                 chm.interval_100ms.callback_list = newelem;\r
243                 pthread_mutex_unlock(&chm.interval_100ms.list_mutex);\r
244                 __sync_add_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);\r
245                 break;\r
246         case CHART_INTERVAL_1SEC:\r
247                 pthread_mutex_lock(&chm.interval_1s.list_mutex);\r
248                 newelem->next = chm.interval_1s.callback_list;\r
249                 chm.interval_1s.callback_list = newelem;\r
250                 pthread_mutex_unlock(&chm.interval_1s.list_mutex);\r
251                 __sync_add_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);\r
252                 break;\r
253         default:\r
254                 free(newelem);\r
255                 break;\r
256         }\r
257 }\r
258 \r
259 static void remove_all_callback_list()\r
260 {\r
261         chart_interval_callback* cur;\r
262         \r
263         pthread_mutex_lock(&chm.interval_10ms.list_mutex);\r
264         while(chm.interval_10ms.callback_list != NULL)\r
265         {\r
266                 cur = chm.interval_10ms.callback_list;\r
267                 chm.interval_10ms.callback_list = cur->next;\r
268                 free(cur);\r
269         }\r
270         pthread_mutex_unlock(&chm.interval_10ms.list_mutex);\r
271 \r
272         pthread_mutex_lock(&chm.interval_100ms.list_mutex);\r
273         while(chm.interval_100ms.callback_list != NULL)\r
274         {\r
275                 cur = chm.interval_100ms.callback_list;\r
276                 chm.interval_100ms.callback_list = cur->next;\r
277                 free(cur);\r
278         }\r
279         pthread_mutex_unlock(&chm.interval_100ms.list_mutex);\r
280 \r
281         pthread_mutex_lock(&chm.interval_1s.list_mutex);\r
282         while(chm.interval_1s.callback_list != NULL)\r
283         {\r
284                 cur = chm.interval_1s.callback_list;\r
285                 chm.interval_1s.callback_list = cur->next;\r
286                 free(cur);\r
287         }\r
288         pthread_mutex_unlock(&chm.interval_1s.list_mutex);\r
289 \r
290         memset(&chm.interval_for_series, 0, sizeof(chm.interval_for_series));\r
291         __sync_and_and_fetch(&(gTraceInfo.custom_chart_callback_count), 0);\r
292 }\r
293 \r
294 static void remove_from_callback_list(da_handle charthandle, da_handle series_handle)\r
295 {\r
296         chart_interval_callback *prev, *cur;\r
297         chart_interval interval;\r
298 \r
299         interval = chm.interval_for_series[charthandle][series_handle % 10];\r
300         chm.interval_for_series[charthandle][series_handle % 10] = 0;\r
301 \r
302         switch(interval)\r
303         {\r
304         case CHART_INTERVAL_10MSEC:\r
305                 pthread_mutex_lock(&chm.interval_10ms.list_mutex);\r
306 \r
307                 prev = NULL;\r
308                 cur = chm.interval_10ms.callback_list;\r
309                 while(cur != NULL)\r
310                 {\r
311                         if(cur->chart_handle == charthandle && cur->series_handle == series_handle)\r
312                         {\r
313                                 if(prev)\r
314                                         prev->next = cur->next;\r
315                                 else\r
316                                         chm.interval_10ms.callback_list = cur->next;\r
317 \r
318                                 __sync_sub_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);\r
319                                 free(cur);\r
320                                 break;\r
321                         }\r
322 \r
323                         prev = cur;\r
324                         cur = cur->next;\r
325                 }\r
326 \r
327                 pthread_mutex_unlock(&chm.interval_10ms.list_mutex);\r
328                 break;\r
329         case CHART_INTERVAL_100MSEC:\r
330                 pthread_mutex_lock(&chm.interval_100ms.list_mutex);\r
331 \r
332                 prev = NULL;\r
333                 cur = chm.interval_100ms.callback_list;\r
334                 while(cur != NULL)\r
335                 {\r
336                         if(cur->chart_handle == charthandle && cur->series_handle == series_handle)\r
337                         {\r
338                                 if(prev)\r
339                                         prev->next = cur->next;\r
340                                 else\r
341                                         chm.interval_100ms.callback_list = cur->next;\r
342 \r
343                                 __sync_sub_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);\r
344                                 free(cur);\r
345                                 break;\r
346                         }\r
347 \r
348                         prev = cur;\r
349                         cur = cur->next;\r
350                 }\r
351 \r
352                 pthread_mutex_unlock(&chm.interval_100ms.list_mutex);\r
353                 break;\r
354         case CHART_INTERVAL_1SEC:\r
355                 pthread_mutex_lock(&chm.interval_1s.list_mutex);\r
356 \r
357                 prev = NULL;\r
358                 cur = chm.interval_1s.callback_list;\r
359                 while(cur != NULL)\r
360                 {\r
361                         if(cur->chart_handle == charthandle && cur->series_handle == series_handle)\r
362                         {\r
363                                 if(prev)\r
364                                         prev->next = cur->next;\r
365                                 else\r
366                                         chm.interval_1s.callback_list = cur->next;\r
367 \r
368                                 __sync_sub_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);\r
369                                 free(cur);\r
370                                 break;\r
371                         }\r
372 \r
373                         prev = cur;\r
374                         cur = cur->next;\r
375                 }\r
376 \r
377                 pthread_mutex_unlock(&chm.interval_1s.list_mutex);\r
378                 break;\r
379         default:\r
380                 break;\r
381         }\r
382 }\r
383 \r
384 \r
385 // =====================================================================\r
386 // constructor and destructor functions\r
387 // =====================================================================\r
388 \r
389 void __attribute__((constructor)) _init_lib()\r
390 {\r
391         probeBlockStart();\r
392 \r
393         memset(&chm, 0, sizeof(chm));\r
394         chm.interval_10ms.timerfd = -1;\r
395         chm.interval_100ms.timerfd = -1;\r
396         chm.interval_1s.timerfd = -1;\r
397         chm.interval_10ms.thread_handle = -1;\r
398         chm.interval_100ms.thread_handle = -1;\r
399         chm.interval_1s.thread_handle = -1;\r
400         pthread_mutex_init(&chm.interval_10ms.list_mutex, NULL);\r
401         pthread_mutex_init(&chm.interval_100ms.list_mutex, NULL);\r
402         pthread_mutex_init(&chm.interval_1s.list_mutex, NULL);\r
403 \r
404         probeBlockEnd();\r
405 }\r
406 \r
407 void __attribute__((destructor)) _fini_lib()\r
408 {\r
409         probeBlockStart();\r
410 \r
411         remove_all_callback_list();\r
412         if(chm.interval_10ms.timerfd != -1)\r
413                 close(chm.interval_10ms.timerfd);\r
414         if(chm.interval_100ms.timerfd != -1)\r
415                 close(chm.interval_100ms.timerfd);\r
416         if(chm.interval_1s.timerfd != -1)\r
417                 close(chm.interval_1s.timerfd);\r
418 \r
419         if(chm.interval_10ms.thread_handle != -1)\r
420         {\r
421                 pthread_join(chm.interval_10ms.thread_handle, NULL);\r
422         }\r
423         if(chm.interval_100ms.thread_handle != -1)\r
424         {\r
425                 pthread_join(chm.interval_100ms.thread_handle, NULL);\r
426         }\r
427         if(chm.interval_1s.thread_handle != -1)\r
428         {\r
429                 pthread_join(chm.interval_1s.thread_handle, NULL);\r
430         }\r
431 \r
432         probeBlockEnd();\r
433 }\r
434 \r
435 \r
436 // =====================================================================\r
437 // api definition\r
438 // =====================================================================\r
439 \r
440 void da_mark(chart_color color, char* mark_text)\r
441 {\r
442         DECLARE_CHART_VARIABLE;\r
443         \r
444         probeBlockStart();\r
445         \r
446         INIT_LOG;\r
447         setProbePoint(&probeInfo);\r
448         APPEND_LOG_BASIC(LC_CUSTOM);\r
449         APPEND_LOG_INPUT("%s", "");\r
450         APPEND_LOG_CHART_RESULT(0);\r
451         APPEND_LOG_CHART(0, 0, mark_text, color, 0.0f);\r
452         printLog(&log, MSG_LOG);\r
453         \r
454         probeBlockEnd();\r
455 }\r
456 \r
457 da_handle da_create_chart(char* chart_name)\r
458 {\r
459         DECLARE_CHART_VARIABLE;\r
460 \r
461         // check if there is available chart handle slot\r
462         if(chm.chart_handle_index + 1 >= MAX_CHART_HANDLE)\r
463                 return ERR_MAX_CHART_NUMBER;\r
464                 \r
465         // check if chart_name is null\r
466         if(chart_name == NULL)\r
467                 return ERR_WRONG_PARAMETER;\r
468                 \r
469         probeBlockStart();\r
470         ret = ++(chm.chart_handle_index);\r
471 \r
472         INIT_LOG;\r
473         setProbePoint(&probeInfo);\r
474         APPEND_LOG_BASIC(LC_CUSTOM);\r
475         APPEND_LOG_INPUT("%s", "");\r
476         APPEND_LOG_CHART_RESULT(ret);\r
477         APPEND_LOG_CHART(0, 0, chart_name, 0, 0.0f);\r
478         printLog(&log, MSG_LOG);\r
479         \r
480         probeBlockEnd();\r
481         \r
482         return ret;\r
483 }\r
484 \r
485 da_handle da_create_series(da_handle charthandle, char* seriesname,\r
486                 series_type type, chart_color color)\r
487 {\r
488         DECLARE_CHART_VARIABLE;\r
489         \r
490         // check if charthandle is valid handle or not\r
491         if(charthandle <= 0 || charthandle > chm.chart_handle_index)\r
492                 return ERR_WRONG_HANDLE;\r
493                 \r
494         // chech if extra parameter is valid\r
495         if(seriesname == NULL)\r
496                 return ERR_WRONG_PARAMETER;\r
497 \r
498         // check if there is available series spot\r
499         if(chm.series_handle_index[(int)charthandle] + 1 >= MAX_SERIES_PER_CHART)\r
500                 return ERR_MAX_CHART_NUMBER;\r
501         \r
502         probeBlockStart();\r
503         ret = ++(chm.series_handle_index[charthandle]);\r
504         ret += (10 * charthandle);\r
505         \r
506         INIT_LOG;\r
507         setProbePoint(&probeInfo);\r
508         APPEND_LOG_BASIC(LC_CUSTOM);\r
509         APPEND_LOG_INPUT("%s", "");\r
510         APPEND_LOG_CHART_RESULT(ret);\r
511         APPEND_LOG_CHART(charthandle, type, seriesname, color, 0.0f);\r
512         printLog(&log, MSG_LOG);\r
513 \r
514         probeBlockEnd();\r
515         \r
516         return ret;\r
517 }\r
518                 \r
519 da_handle da_create_default_series(da_handle charthandle, char* seriesname)\r
520 {\r
521         return da_create_series(charthandle, seriesname,\r
522                         CHART_TYPE_AUTO, CHART_COLOR_AUTO);\r
523 }\r
524 \r
525 int da_set_callback(da_handle series_handle, da_user_data_2_chart_data callback,\r
526                 void* data_addr, chart_interval interval)\r
527 {\r
528         int cindex, sindex;\r
529         cindex = (int)(series_handle / 10);\r
530         sindex = series_handle % 10;\r
531         \r
532         // check series handle\r
533         if(cindex <= 0 || cindex > chm.chart_handle_index)\r
534                 return ERR_WRONG_HANDLE;\r
535         \r
536         if(sindex > chm.series_handle_index[(int)cindex])\r
537                 return ERR_WRONG_HANDLE;\r
538         \r
539         // check rest parameters\r
540         if(interval == CHART_NO_CYCLE && callback != NULL)\r
541                 return ERR_WRONG_PARAMETER;\r
542 \r
543         probeBlockStart();\r
544 \r
545         // remove previously registered callback\r
546         remove_from_callback_list(cindex, series_handle);\r
547 \r
548         // register new callback\r
549         if(callback != NULL)\r
550         {\r
551                 add_to_callback_list(interval, cindex, series_handle, callback, data_addr);\r
552                 start_callback_thread(interval);\r
553         }\r
554         probeBlockEnd();\r
555 \r
556         return 0;\r
557 }\r
558 \r
559 void da_log(da_handle series_handle, float uservalue)\r
560 {\r
561         DECLARE_CHART_VARIABLE;\r
562         \r
563         // chech if series handle is valid\r
564         int cindex, sindex;\r
565         cindex = (int)(series_handle / 10);\r
566         sindex = series_handle % 10;\r
567         \r
568         if(cindex <= 0 || cindex > chm.chart_handle_index)\r
569                 return;\r
570         \r
571         if(sindex > chm.series_handle_index[(int)cindex])\r
572                 return;\r
573         \r
574         probeBlockStart();\r
575         \r
576         INIT_LOG;\r
577         setProbePoint(&probeInfo);\r
578         APPEND_LOG_BASIC(LC_CUSTOM);\r
579         APPEND_LOG_INPUT("%s", "");\r
580         APPEND_LOG_CHART_RESULT(0);\r
581         APPEND_LOG_CHART(series_handle, 0, "", 0, uservalue);\r
582         printLog(&log, MSG_LOG);\r
583         \r
584         probeBlockEnd();\r
585 }\r