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