[PROTO] MSG_PROBE: replace return by return type, return value pair
[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('p', 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 __attribute__((constructor)) _init_lib()
397 {
398         probeBlockStart();
399
400         memset(&chm, 0, sizeof(chm));
401         chm.interval_10ms.timerfd = -1;
402         chm.interval_100ms.timerfd = -1;
403         chm.interval_1s.timerfd = -1;
404         chm.interval_10ms.thread_handle = -1;
405         chm.interval_100ms.thread_handle = -1;
406         chm.interval_1s.thread_handle = -1;
407         pthread_mutex_init(&chm.interval_10ms.list_mutex, NULL);
408         pthread_mutex_init(&chm.interval_100ms.list_mutex, NULL);
409         pthread_mutex_init(&chm.interval_1s.list_mutex, NULL);
410
411         probeBlockEnd();
412 }
413
414 void __attribute__((destructor)) _fini_lib()
415 {
416         probeBlockStart();
417
418         remove_all_callback_list();
419         if (chm.interval_10ms.timerfd != -1)
420                 close(chm.interval_10ms.timerfd);
421         if (chm.interval_100ms.timerfd != -1)
422                 close(chm.interval_100ms.timerfd);
423         if (chm.interval_1s.timerfd != -1)
424                 close(chm.interval_1s.timerfd);
425         /*! Bad. Ugly. Unportable */
426         if (chm.interval_10ms.thread_handle != (pthread_t) -1)
427                 pthread_join(chm.interval_10ms.thread_handle, NULL);
428         if (chm.interval_100ms.thread_handle != (pthread_t) -1)
429                 pthread_join(chm.interval_100ms.thread_handle, NULL);
430         if (chm.interval_1s.thread_handle != (pthread_t) -1)
431                 pthread_join(chm.interval_1s.thread_handle, NULL);
432
433         probeBlockEnd();
434 }
435
436
437 // =====================================================================
438 // api definition
439 // =====================================================================
440
441 void da_mark(chart_color color, char* mark_text)
442 {
443         DECLARE_CHART_VARIABLE;
444
445         probeBlockStart();
446
447         setProbePoint(&probeInfo);
448
449         PREPARE_LOCAL_BUF();
450         PACK_COMMON_BEGIN(MSG_PROBE_CUSTOM,
451                           API_ID_da_mark,
452                           "dp", color, voidp_to_uint64(mark_text));
453         PACK_COMMON_END('v', 0, 0, 2);
454         PACK_CUSTOM(0, 0, mark_text, color, 0.0f);
455         FLUSH_LOCAL_BUF();
456
457         probeBlockEnd();
458 }
459
460 da_handle da_create_chart(char* chart_name)
461 {
462         DECLARE_CHART_VARIABLE;
463
464         // check if there is available chart handle slot
465         if(chm.chart_handle_index + 1 >= MAX_CHART_HANDLE)
466                 return ERR_MAX_CHART_NUMBER;
467
468         // check if chart_name is null
469         if(chart_name == NULL)
470                 return ERR_WRONG_PARAMETER;
471
472         probeBlockStart();
473         ret = ++(chm.chart_handle_index);
474
475         setProbePoint(&probeInfo);
476
477         PREPARE_LOCAL_BUF();
478         PACK_COMMON_BEGIN(MSG_PROBE_CUSTOM,
479                           API_ID_da_create_chart,
480                           "p", voidp_to_uint64(chart_name));
481         PACK_COMMON_END('d', ret, 0, 2);
482         PACK_CUSTOM(0, 0, chart_name, 0, 0.0f);
483         FLUSH_LOCAL_BUF();
484
485         probeBlockEnd();
486
487         return ret;
488 }
489
490 da_handle da_create_series(da_handle charthandle, char* seriesname,
491                 series_type type, chart_color color)
492 {
493         DECLARE_CHART_VARIABLE;
494
495         // check if charthandle is valid handle or not
496         if(charthandle <= 0 || charthandle > chm.chart_handle_index)
497                 return ERR_WRONG_HANDLE;
498
499         // chech if extra parameter is valid
500         if(seriesname == NULL)
501                 return ERR_WRONG_PARAMETER;
502
503         // check if there is available series spot
504         if(chm.series_handle_index[(int)charthandle] + 1 >= MAX_SERIES_PER_CHART)
505                 return ERR_MAX_CHART_NUMBER;
506
507         probeBlockStart();
508         ret = ++(chm.series_handle_index[charthandle]);
509         ret += (10 * charthandle);
510
511         setProbePoint(&probeInfo);
512
513         PREPARE_LOCAL_BUF();
514         PACK_COMMON_BEGIN(MSG_PROBE_CUSTOM,
515                           API_ID_da_create_series,
516                           "dpdd",  charthandle, voidp_to_uint64(seriesname),
517                           type, color);
518         PACK_COMMON_END('d', ret, 0, 2);
519         PACK_CUSTOM(charthandle, type, seriesname, color, 0.0f);
520         FLUSH_LOCAL_BUF();
521
522         probeBlockEnd();
523
524         return ret;
525 }
526
527 da_handle da_create_default_series(da_handle charthandle, char* seriesname)
528 {
529         return da_create_series(charthandle, seriesname,
530                         CHART_TYPE_AUTO, CHART_COLOR_AUTO);
531 }
532
533 int da_set_callback(da_handle series_handle, da_user_data_2_chart_data callback,
534                 void* data_addr, chart_interval interval)
535 {
536         int cindex, sindex;
537         cindex = (int)(series_handle / 10);
538         sindex = series_handle % 10;
539
540         // check series handle
541         if(cindex <= 0 || cindex > chm.chart_handle_index)
542                 return ERR_WRONG_HANDLE;
543
544         if(sindex > chm.series_handle_index[(int)cindex])
545                 return ERR_WRONG_HANDLE;
546
547         // check rest parameters
548         if(interval == CHART_NO_CYCLE && callback != NULL)
549                 return ERR_WRONG_PARAMETER;
550
551         probeBlockStart();
552
553         // remove previously registered callback
554         remove_from_callback_list(cindex, series_handle);
555
556         // register new callback
557         if(callback != NULL)
558         {
559                 int re;
560                 add_to_callback_list(interval, cindex, series_handle, callback, data_addr);
561                 re = start_callback_thread(interval);
562                 LOG("start callback thread return %d\n", re);
563         }
564         probeBlockEnd();
565
566         return 0;
567 }
568
569 void da_log(da_handle series_handle, float uservalue)
570 {
571         DECLARE_CHART_VARIABLE;
572
573         // chech if series handle is valid
574         int cindex, sindex;
575         cindex = (int)(series_handle / 10);
576         sindex = series_handle % 10;
577
578         if(cindex <= 0 || cindex > chm.chart_handle_index)
579                 return;
580
581         if(sindex > chm.series_handle_index[(int)cindex])
582                 return;
583
584         probeBlockStart();
585
586         setProbePoint(&probeInfo);
587
588         PREPARE_LOCAL_BUF();
589         PACK_COMMON_BEGIN(MSG_PROBE_CUSTOM,
590                           API_ID_da_log,
591                           "df", series_handle, uservalue);
592         PACK_COMMON_END('v', 0, 0, 2);
593         PACK_CUSTOM(series_handle, 0, "", 0, uservalue);
594         FLUSH_LOCAL_BUF();
595
596         probeBlockEnd();
597 }