change Copyright headers, change line endings to Unix format
[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  * 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, LC_CUSTOM, "", 0);
138                         PACK_COMMON_END(0, 0, 2);
139                         PACK_CUSTOM(cur->series_handle, 0, "", 0, value);
140                         FLUSH_LOCAL_BUF();
141
142                         cur = cur->next;
143                 }
144
145                 pthread_mutex_unlock(&pmanager->list_mutex);
146
147                 sleep(0);
148         }
149
150         probeBlockEnd();
151
152         return NULL;
153 }
154
155 static int start_callback_thread(chart_interval interval)
156 {
157         int* timerfd = NULL;
158         pthread_t* thread_handle = NULL;
159         interval_manager* pman = NULL;
160         struct itimerspec timevalue;
161
162         if(interval == CHART_INTERVAL_10MSEC)
163         {
164                 timerfd = &(chm.interval_10ms.timerfd);
165                 thread_handle = &(chm.interval_10ms.thread_handle);
166                 pman = &(chm.interval_10ms);
167                 timevalue.it_value.tv_sec = 0;
168                 timevalue.it_value.tv_nsec = 10000000L;
169                 timevalue.it_interval.tv_sec = 0;
170                 timevalue.it_interval.tv_nsec = 10000000L;
171         }
172         else if(interval == CHART_INTERVAL_100MSEC)
173         {
174                 timerfd = &(chm.interval_100ms.timerfd);
175                 thread_handle = &(chm.interval_100ms.thread_handle);
176                 pman = &(chm.interval_100ms);
177                 timevalue.it_value.tv_sec = 0;
178                 timevalue.it_value.tv_nsec = 100000000L;
179                 timevalue.it_interval.tv_sec = 0;
180                 timevalue.it_interval.tv_nsec = 100000000L;
181         }
182         else if(interval == CHART_INTERVAL_1SEC)
183         {
184                 timerfd = &(chm.interval_1s.timerfd);
185                 thread_handle = &(chm.interval_1s.thread_handle);
186                 pman = &(chm.interval_1s);
187                 timevalue.it_value.tv_sec = 1;
188                 timevalue.it_value.tv_nsec = 0;
189                 timevalue.it_interval.tv_sec = 1;
190                 timevalue.it_interval.tv_nsec = 0;
191         }
192         else
193         {
194                 return ERR_WRONG_PARAMETER;
195         }
196
197         if(*timerfd != -1 || *thread_handle != -1)
198                 return 0;               // already thread exist
199
200         *timerfd = timerfd_create(CLOCK_REALTIME, 0);
201         if(*timerfd == -1)
202                 return errno;
203
204         if(timerfd_settime(*timerfd, 0, &timevalue, NULL) == -1)
205                 return errno;
206
207         if(pthread_create(thread_handle, NULL, _chart_timerThread, pman) < 0)
208                 return ERR_THREAD_CREATE_FAIL;
209
210         return 0;
211 }
212
213
214 // =====================================================================
215 // internal utility function
216 // =====================================================================
217
218 static void add_to_callback_list(chart_interval interval, da_handle charthandle, da_handle series_handle,
219                 da_user_data_2_chart_data callback, void* user_data)
220 {
221         chart_interval_callback* newelem;
222         
223         newelem = (chart_interval_callback*)malloc(sizeof(chart_interval_callback));
224         newelem->chart_handle = charthandle;
225         newelem->series_handle = series_handle;
226         newelem->callback = callback;
227         newelem->user_data = user_data;
228
229         chm.interval_for_series[charthandle][series_handle % 10] = interval;
230         
231         switch(interval)
232         {
233         case CHART_INTERVAL_10MSEC:
234                 pthread_mutex_lock(&chm.interval_10ms.list_mutex);
235                 newelem->next = chm.interval_10ms.callback_list;
236                 chm.interval_10ms.callback_list = newelem;
237                 pthread_mutex_unlock(&chm.interval_10ms.list_mutex);
238                 __sync_add_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);
239                 break;
240         case CHART_INTERVAL_100MSEC:
241                 pthread_mutex_lock(&chm.interval_100ms.list_mutex);
242                 newelem->next = chm.interval_100ms.callback_list;
243                 chm.interval_100ms.callback_list = newelem;
244                 pthread_mutex_unlock(&chm.interval_100ms.list_mutex);
245                 __sync_add_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);
246                 break;
247         case CHART_INTERVAL_1SEC:
248                 pthread_mutex_lock(&chm.interval_1s.list_mutex);
249                 newelem->next = chm.interval_1s.callback_list;
250                 chm.interval_1s.callback_list = newelem;
251                 pthread_mutex_unlock(&chm.interval_1s.list_mutex);
252                 __sync_add_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);
253                 break;
254         default:
255                 free(newelem);
256                 break;
257         }
258 }
259
260 static void remove_all_callback_list()
261 {
262         chart_interval_callback* cur;
263         
264         pthread_mutex_lock(&chm.interval_10ms.list_mutex);
265         while(chm.interval_10ms.callback_list != NULL)
266         {
267                 cur = chm.interval_10ms.callback_list;
268                 chm.interval_10ms.callback_list = cur->next;
269                 free(cur);
270         }
271         pthread_mutex_unlock(&chm.interval_10ms.list_mutex);
272
273         pthread_mutex_lock(&chm.interval_100ms.list_mutex);
274         while(chm.interval_100ms.callback_list != NULL)
275         {
276                 cur = chm.interval_100ms.callback_list;
277                 chm.interval_100ms.callback_list = cur->next;
278                 free(cur);
279         }
280         pthread_mutex_unlock(&chm.interval_100ms.list_mutex);
281
282         pthread_mutex_lock(&chm.interval_1s.list_mutex);
283         while(chm.interval_1s.callback_list != NULL)
284         {
285                 cur = chm.interval_1s.callback_list;
286                 chm.interval_1s.callback_list = cur->next;
287                 free(cur);
288         }
289         pthread_mutex_unlock(&chm.interval_1s.list_mutex);
290
291         memset(&chm.interval_for_series, 0, sizeof(chm.interval_for_series));
292         __sync_and_and_fetch(&(gTraceInfo.custom_chart_callback_count), 0);
293 }
294
295 static void remove_from_callback_list(da_handle charthandle, da_handle series_handle)
296 {
297         chart_interval_callback *prev, *cur;
298         chart_interval interval;
299
300         interval = chm.interval_for_series[charthandle][series_handle % 10];
301         chm.interval_for_series[charthandle][series_handle % 10] = 0;
302
303         switch(interval)
304         {
305         case CHART_INTERVAL_10MSEC:
306                 pthread_mutex_lock(&chm.interval_10ms.list_mutex);
307
308                 prev = NULL;
309                 cur = chm.interval_10ms.callback_list;
310                 while(cur != NULL)
311                 {
312                         if(cur->chart_handle == charthandle && cur->series_handle == series_handle)
313                         {
314                                 if(prev)
315                                         prev->next = cur->next;
316                                 else
317                                         chm.interval_10ms.callback_list = cur->next;
318
319                                 __sync_sub_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);
320                                 free(cur);
321                                 break;
322                         }
323
324                         prev = cur;
325                         cur = cur->next;
326                 }
327
328                 pthread_mutex_unlock(&chm.interval_10ms.list_mutex);
329                 break;
330         case CHART_INTERVAL_100MSEC:
331                 pthread_mutex_lock(&chm.interval_100ms.list_mutex);
332
333                 prev = NULL;
334                 cur = chm.interval_100ms.callback_list;
335                 while(cur != NULL)
336                 {
337                         if(cur->chart_handle == charthandle && cur->series_handle == series_handle)
338                         {
339                                 if(prev)
340                                         prev->next = cur->next;
341                                 else
342                                         chm.interval_100ms.callback_list = cur->next;
343
344                                 __sync_sub_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);
345                                 free(cur);
346                                 break;
347                         }
348
349                         prev = cur;
350                         cur = cur->next;
351                 }
352
353                 pthread_mutex_unlock(&chm.interval_100ms.list_mutex);
354                 break;
355         case CHART_INTERVAL_1SEC:
356                 pthread_mutex_lock(&chm.interval_1s.list_mutex);
357
358                 prev = NULL;
359                 cur = chm.interval_1s.callback_list;
360                 while(cur != NULL)
361                 {
362                         if(cur->chart_handle == charthandle && cur->series_handle == series_handle)
363                         {
364                                 if(prev)
365                                         prev->next = cur->next;
366                                 else
367                                         chm.interval_1s.callback_list = cur->next;
368
369                                 __sync_sub_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);
370                                 free(cur);
371                                 break;
372                         }
373
374                         prev = cur;
375                         cur = cur->next;
376                 }
377
378                 pthread_mutex_unlock(&chm.interval_1s.list_mutex);
379                 break;
380         default:
381                 break;
382         }
383 }
384
385
386 // =====================================================================
387 // constructor and destructor functions
388 // =====================================================================
389
390 void memory_initialize_hook(void);
391 void (*__malloc_initialize_hook) (void) = memory_initialize_hook;
392
393 void __attribute__((constructor)) _init_lib()
394 {
395         probeBlockStart();
396
397         memset(&chm, 0, sizeof(chm));
398         chm.interval_10ms.timerfd = -1;
399         chm.interval_100ms.timerfd = -1;
400         chm.interval_1s.timerfd = -1;
401         chm.interval_10ms.thread_handle = -1;
402         chm.interval_100ms.thread_handle = -1;
403         chm.interval_1s.thread_handle = -1;
404         pthread_mutex_init(&chm.interval_10ms.list_mutex, NULL);
405         pthread_mutex_init(&chm.interval_100ms.list_mutex, NULL);
406         pthread_mutex_init(&chm.interval_1s.list_mutex, NULL);
407
408         probeBlockEnd();
409 }
410
411 void __attribute__((destructor)) _fini_lib()
412 {
413         probeBlockStart();
414
415         remove_all_callback_list();
416         if(chm.interval_10ms.timerfd != -1)
417                 close(chm.interval_10ms.timerfd);
418         if(chm.interval_100ms.timerfd != -1)
419                 close(chm.interval_100ms.timerfd);
420         if(chm.interval_1s.timerfd != -1)
421                 close(chm.interval_1s.timerfd);
422
423         if(chm.interval_10ms.thread_handle != -1)
424         {
425                 pthread_join(chm.interval_10ms.thread_handle, NULL);
426         }
427         if(chm.interval_100ms.thread_handle != -1)
428         {
429                 pthread_join(chm.interval_100ms.thread_handle, NULL);
430         }
431         if(chm.interval_1s.thread_handle != -1)
432         {
433                 pthread_join(chm.interval_1s.thread_handle, NULL);
434         }
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, LC_CUSTOM, "dp", color, mark_text);
454         PACK_COMMON_END(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, LC_CUSTOM, "p", chart_name);
480         PACK_COMMON_END(ret, 0, 2);
481         PACK_CUSTOM(0, 0, chart_name, 0, 0.0f);
482         FLUSH_LOCAL_BUF();
483         
484         probeBlockEnd();
485         
486         return ret;
487 }
488
489 da_handle da_create_series(da_handle charthandle, char* seriesname,
490                 series_type type, chart_color color)
491 {
492         DECLARE_CHART_VARIABLE;
493         
494         // check if charthandle is valid handle or not
495         if(charthandle <= 0 || charthandle > chm.chart_handle_index)
496                 return ERR_WRONG_HANDLE;
497                 
498         // chech if extra parameter is valid
499         if(seriesname == NULL)
500                 return ERR_WRONG_PARAMETER;
501
502         // check if there is available series spot
503         if(chm.series_handle_index[(int)charthandle] + 1 >= MAX_SERIES_PER_CHART)
504                 return ERR_MAX_CHART_NUMBER;
505         
506         probeBlockStart();
507         ret = ++(chm.series_handle_index[charthandle]);
508         ret += (10 * charthandle);
509         
510         setProbePoint(&probeInfo);
511
512         PREPARE_LOCAL_BUF();
513         PACK_COMMON_BEGIN(MSG_PROBE_CUSTOM, LC_CUSTOM, "dpdd",  charthandle, seriesname, type, color);
514         PACK_COMMON_END(ret, 0, 2);
515         PACK_CUSTOM(charthandle, type, seriesname, color, 0.0f);
516         FLUSH_LOCAL_BUF();
517
518         probeBlockEnd();
519         
520         return ret;
521 }
522                 
523 da_handle da_create_default_series(da_handle charthandle, char* seriesname)
524 {
525         return da_create_series(charthandle, seriesname,
526                         CHART_TYPE_AUTO, CHART_COLOR_AUTO);
527 }
528
529 int da_set_callback(da_handle series_handle, da_user_data_2_chart_data callback,
530                 void* data_addr, chart_interval interval)
531 {
532         int cindex, sindex;
533         cindex = (int)(series_handle / 10);
534         sindex = series_handle % 10;
535         
536         // check series handle
537         if(cindex <= 0 || cindex > chm.chart_handle_index)
538                 return ERR_WRONG_HANDLE;
539         
540         if(sindex > chm.series_handle_index[(int)cindex])
541                 return ERR_WRONG_HANDLE;
542         
543         // check rest parameters
544         if(interval == CHART_NO_CYCLE && callback != NULL)
545                 return ERR_WRONG_PARAMETER;
546
547         probeBlockStart();
548
549         // remove previously registered callback
550         remove_from_callback_list(cindex, series_handle);
551
552         // register new callback
553         if(callback != NULL)
554         {
555                 add_to_callback_list(interval, cindex, series_handle, callback, data_addr);
556                 start_callback_thread(interval);
557         }
558         probeBlockEnd();
559
560         return 0;
561 }
562
563 void da_log(da_handle series_handle, float uservalue)
564 {
565         DECLARE_CHART_VARIABLE;
566         
567         // chech if series handle is valid
568         int cindex, sindex;
569         cindex = (int)(series_handle / 10);
570         sindex = series_handle % 10;
571         
572         if(cindex <= 0 || cindex > chm.chart_handle_index)
573                 return;
574         
575         if(sindex > chm.series_handle_index[(int)cindex])
576                 return;
577         
578         probeBlockStart();
579         
580         setProbePoint(&probeInfo);
581
582         PREPARE_LOCAL_BUF();
583         PACK_COMMON_BEGIN(MSG_PROBE_CUSTOM, LC_CUSTOM, "dw", series_handle, uservalue);
584         PACK_COMMON_END(0, 0, 2);
585         PACK_CUSTOM(series_handle, 0, "", 0, uservalue);
586         FLUSH_LOCAL_BUF();
587         
588         probeBlockEnd();
589 }