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