[STYLE] Remove all trailing whitespaces
[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         if(*timerfd != -1 || *thread_handle != -1)
200                 return 0;               // already thread exist
201
202         *timerfd = timerfd_create(CLOCK_REALTIME, 0);
203         if(*timerfd == -1)
204                 return errno;
205
206         if(timerfd_settime(*timerfd, 0, &timevalue, NULL) == -1)
207                 return errno;
208
209         if(pthread_create(thread_handle, NULL, _chart_timerThread, pman) < 0)
210                 return ERR_THREAD_CREATE_FAIL;
211
212         return 0;
213 }
214
215
216 // =====================================================================
217 // internal utility function
218 // =====================================================================
219
220 static void add_to_callback_list(chart_interval interval, da_handle charthandle, da_handle series_handle,
221                 da_user_data_2_chart_data callback, void* user_data)
222 {
223         chart_interval_callback* newelem;
224
225         newelem = (chart_interval_callback*)malloc(sizeof(chart_interval_callback));
226         newelem->chart_handle = charthandle;
227         newelem->series_handle = series_handle;
228         newelem->callback = callback;
229         newelem->user_data = user_data;
230
231         chm.interval_for_series[charthandle][series_handle % 10] = interval;
232
233         switch(interval)
234         {
235         case CHART_INTERVAL_10MSEC:
236                 pthread_mutex_lock(&chm.interval_10ms.list_mutex);
237                 newelem->next = chm.interval_10ms.callback_list;
238                 chm.interval_10ms.callback_list = newelem;
239                 pthread_mutex_unlock(&chm.interval_10ms.list_mutex);
240                 __sync_add_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);
241                 break;
242         case CHART_INTERVAL_100MSEC:
243                 pthread_mutex_lock(&chm.interval_100ms.list_mutex);
244                 newelem->next = chm.interval_100ms.callback_list;
245                 chm.interval_100ms.callback_list = newelem;
246                 pthread_mutex_unlock(&chm.interval_100ms.list_mutex);
247                 __sync_add_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);
248                 break;
249         case CHART_INTERVAL_1SEC:
250                 pthread_mutex_lock(&chm.interval_1s.list_mutex);
251                 newelem->next = chm.interval_1s.callback_list;
252                 chm.interval_1s.callback_list = newelem;
253                 pthread_mutex_unlock(&chm.interval_1s.list_mutex);
254                 __sync_add_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);
255                 break;
256         default:
257                 free(newelem);
258                 break;
259         }
260 }
261
262 static void remove_all_callback_list()
263 {
264         chart_interval_callback* cur;
265
266         pthread_mutex_lock(&chm.interval_10ms.list_mutex);
267         while(chm.interval_10ms.callback_list != NULL)
268         {
269                 cur = chm.interval_10ms.callback_list;
270                 chm.interval_10ms.callback_list = cur->next;
271                 free(cur);
272         }
273         pthread_mutex_unlock(&chm.interval_10ms.list_mutex);
274
275         pthread_mutex_lock(&chm.interval_100ms.list_mutex);
276         while(chm.interval_100ms.callback_list != NULL)
277         {
278                 cur = chm.interval_100ms.callback_list;
279                 chm.interval_100ms.callback_list = cur->next;
280                 free(cur);
281         }
282         pthread_mutex_unlock(&chm.interval_100ms.list_mutex);
283
284         pthread_mutex_lock(&chm.interval_1s.list_mutex);
285         while(chm.interval_1s.callback_list != NULL)
286         {
287                 cur = chm.interval_1s.callback_list;
288                 chm.interval_1s.callback_list = cur->next;
289                 free(cur);
290         }
291         pthread_mutex_unlock(&chm.interval_1s.list_mutex);
292
293         memset(&chm.interval_for_series, 0, sizeof(chm.interval_for_series));
294         __sync_and_and_fetch(&(gTraceInfo.custom_chart_callback_count), 0);
295 }
296
297 static void remove_from_callback_list(da_handle charthandle, da_handle series_handle)
298 {
299         chart_interval_callback *prev, *cur;
300         chart_interval interval;
301
302         interval = chm.interval_for_series[charthandle][series_handle % 10];
303         chm.interval_for_series[charthandle][series_handle % 10] = 0;
304
305         switch(interval)
306         {
307         case CHART_INTERVAL_10MSEC:
308                 pthread_mutex_lock(&chm.interval_10ms.list_mutex);
309
310                 prev = NULL;
311                 cur = chm.interval_10ms.callback_list;
312                 while(cur != NULL)
313                 {
314                         if(cur->chart_handle == charthandle && cur->series_handle == series_handle)
315                         {
316                                 if(prev)
317                                         prev->next = cur->next;
318                                 else
319                                         chm.interval_10ms.callback_list = cur->next;
320
321                                 __sync_sub_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);
322                                 free(cur);
323                                 break;
324                         }
325
326                         prev = cur;
327                         cur = cur->next;
328                 }
329
330                 pthread_mutex_unlock(&chm.interval_10ms.list_mutex);
331                 break;
332         case CHART_INTERVAL_100MSEC:
333                 pthread_mutex_lock(&chm.interval_100ms.list_mutex);
334
335                 prev = NULL;
336                 cur = chm.interval_100ms.callback_list;
337                 while(cur != NULL)
338                 {
339                         if(cur->chart_handle == charthandle && cur->series_handle == series_handle)
340                         {
341                                 if(prev)
342                                         prev->next = cur->next;
343                                 else
344                                         chm.interval_100ms.callback_list = cur->next;
345
346                                 __sync_sub_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);
347                                 free(cur);
348                                 break;
349                         }
350
351                         prev = cur;
352                         cur = cur->next;
353                 }
354
355                 pthread_mutex_unlock(&chm.interval_100ms.list_mutex);
356                 break;
357         case CHART_INTERVAL_1SEC:
358                 pthread_mutex_lock(&chm.interval_1s.list_mutex);
359
360                 prev = NULL;
361                 cur = chm.interval_1s.callback_list;
362                 while(cur != NULL)
363                 {
364                         if(cur->chart_handle == charthandle && cur->series_handle == series_handle)
365                         {
366                                 if(prev)
367                                         prev->next = cur->next;
368                                 else
369                                         chm.interval_1s.callback_list = cur->next;
370
371                                 __sync_sub_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);
372                                 free(cur);
373                                 break;
374                         }
375
376                         prev = cur;
377                         cur = cur->next;
378                 }
379
380                 pthread_mutex_unlock(&chm.interval_1s.list_mutex);
381                 break;
382         default:
383                 break;
384         }
385 }
386
387
388 // =====================================================================
389 // constructor and destructor functions
390 // =====================================================================
391
392 void memory_initialize_hook(void);
393 void (*__malloc_initialize_hook) (void) = memory_initialize_hook;
394
395 void __attribute__((constructor)) _init_lib()
396 {
397         probeBlockStart();
398
399         memset(&chm, 0, sizeof(chm));
400         chm.interval_10ms.timerfd = -1;
401         chm.interval_100ms.timerfd = -1;
402         chm.interval_1s.timerfd = -1;
403         chm.interval_10ms.thread_handle = -1;
404         chm.interval_100ms.thread_handle = -1;
405         chm.interval_1s.thread_handle = -1;
406         pthread_mutex_init(&chm.interval_10ms.list_mutex, NULL);
407         pthread_mutex_init(&chm.interval_100ms.list_mutex, NULL);
408         pthread_mutex_init(&chm.interval_1s.list_mutex, NULL);
409
410         probeBlockEnd();
411 }
412
413 void __attribute__((destructor)) _fini_lib()
414 {
415         probeBlockStart();
416
417         remove_all_callback_list();
418         if(chm.interval_10ms.timerfd != -1)
419                 close(chm.interval_10ms.timerfd);
420         if(chm.interval_100ms.timerfd != -1)
421                 close(chm.interval_100ms.timerfd);
422         if(chm.interval_1s.timerfd != -1)
423                 close(chm.interval_1s.timerfd);
424
425         if(chm.interval_10ms.thread_handle != -1)
426         {
427                 pthread_join(chm.interval_10ms.thread_handle, NULL);
428         }
429         if(chm.interval_100ms.thread_handle != -1)
430         {
431                 pthread_join(chm.interval_100ms.thread_handle, NULL);
432         }
433         if(chm.interval_1s.thread_handle != -1)
434         {
435                 pthread_join(chm.interval_1s.thread_handle, NULL);
436         }
437
438         probeBlockEnd();
439 }
440
441
442 // =====================================================================
443 // api definition
444 // =====================================================================
445
446 void da_mark(chart_color color, char* mark_text)
447 {
448         DECLARE_CHART_VARIABLE;
449
450         probeBlockStart();
451
452         setProbePoint(&probeInfo);
453
454         PREPARE_LOCAL_BUF();
455         PACK_COMMON_BEGIN(MSG_PROBE_CUSTOM,
456                           API_ID_da_mark,
457                           "dp", color, mark_text);
458         PACK_COMMON_END(0, 0, 2);
459         PACK_CUSTOM(0, 0, mark_text, color, 0.0f);
460         FLUSH_LOCAL_BUF();
461
462         probeBlockEnd();
463 }
464
465 da_handle da_create_chart(char* chart_name)
466 {
467         DECLARE_CHART_VARIABLE;
468
469         // check if there is available chart handle slot
470         if(chm.chart_handle_index + 1 >= MAX_CHART_HANDLE)
471                 return ERR_MAX_CHART_NUMBER;
472
473         // check if chart_name is null
474         if(chart_name == NULL)
475                 return ERR_WRONG_PARAMETER;
476
477         probeBlockStart();
478         ret = ++(chm.chart_handle_index);
479
480         setProbePoint(&probeInfo);
481
482         PREPARE_LOCAL_BUF();
483         PACK_COMMON_BEGIN(MSG_PROBE_CUSTOM,
484                           API_ID_da_create_chart,
485                           "p", chart_name);
486         PACK_COMMON_END(ret, 0, 2);
487         PACK_CUSTOM(0, 0, chart_name, 0, 0.0f);
488         FLUSH_LOCAL_BUF();
489
490         probeBlockEnd();
491
492         return ret;
493 }
494
495 da_handle da_create_series(da_handle charthandle, char* seriesname,
496                 series_type type, chart_color color)
497 {
498         DECLARE_CHART_VARIABLE;
499
500         // check if charthandle is valid handle or not
501         if(charthandle <= 0 || charthandle > chm.chart_handle_index)
502                 return ERR_WRONG_HANDLE;
503
504         // chech if extra parameter is valid
505         if(seriesname == NULL)
506                 return ERR_WRONG_PARAMETER;
507
508         // check if there is available series spot
509         if(chm.series_handle_index[(int)charthandle] + 1 >= MAX_SERIES_PER_CHART)
510                 return ERR_MAX_CHART_NUMBER;
511
512         probeBlockStart();
513         ret = ++(chm.series_handle_index[charthandle]);
514         ret += (10 * charthandle);
515
516         setProbePoint(&probeInfo);
517
518         PREPARE_LOCAL_BUF();
519         PACK_COMMON_BEGIN(MSG_PROBE_CUSTOM,
520                           API_ID_da_create_series,
521                           "dpdd",  charthandle, seriesname, type, color);
522         PACK_COMMON_END(ret, 0, 2);
523         PACK_CUSTOM(charthandle, type, seriesname, color, 0.0f);
524         FLUSH_LOCAL_BUF();
525
526         probeBlockEnd();
527
528         return ret;
529 }
530
531 da_handle da_create_default_series(da_handle charthandle, char* seriesname)
532 {
533         return da_create_series(charthandle, seriesname,
534                         CHART_TYPE_AUTO, CHART_COLOR_AUTO);
535 }
536
537 int da_set_callback(da_handle series_handle, da_user_data_2_chart_data callback,
538                 void* data_addr, chart_interval interval)
539 {
540         int cindex, sindex;
541         cindex = (int)(series_handle / 10);
542         sindex = series_handle % 10;
543
544         // check series handle
545         if(cindex <= 0 || cindex > chm.chart_handle_index)
546                 return ERR_WRONG_HANDLE;
547
548         if(sindex > chm.series_handle_index[(int)cindex])
549                 return ERR_WRONG_HANDLE;
550
551         // check rest parameters
552         if(interval == CHART_NO_CYCLE && callback != NULL)
553                 return ERR_WRONG_PARAMETER;
554
555         probeBlockStart();
556
557         // remove previously registered callback
558         remove_from_callback_list(cindex, series_handle);
559
560         // register new callback
561         if(callback != NULL)
562         {
563                 int re;
564                 add_to_callback_list(interval, cindex, series_handle, callback, data_addr);
565                 re = start_callback_thread(interval);
566                 LOG("start callback thread return %d\n", re);
567         }
568         probeBlockEnd();
569
570         return 0;
571 }
572
573 void da_log(da_handle series_handle, float uservalue)
574 {
575         DECLARE_CHART_VARIABLE;
576
577         // chech if series handle is valid
578         int cindex, sindex;
579         cindex = (int)(series_handle / 10);
580         sindex = series_handle % 10;
581
582         if(cindex <= 0 || cindex > chm.chart_handle_index)
583                 return;
584
585         if(sindex > chm.series_handle_index[(int)cindex])
586                 return;
587
588         probeBlockStart();
589
590         setProbePoint(&probeInfo);
591
592         PREPARE_LOCAL_BUF();
593         PACK_COMMON_BEGIN(MSG_PROBE_CUSTOM,
594                           API_ID_da_log,
595                           "dw", series_handle, uservalue);
596         PACK_COMMON_END(0, 0, 2);
597         PACK_CUSTOM(series_handle, 0, "", 0, uservalue);
598         FLUSH_LOCAL_BUF();
599
600         probeBlockEnd();
601 }