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