tizen 2.3 release
[framework/system/deviced.git] / src / logd_grabber / nlproc-stat.c
1 #define _GNU_SOURCE
2 #include <ctype.h>
3 #include <dirent.h>
4 #include <Eina.h>
5 #include <errno.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <unistd.h>
10
11 #include "core/log.h"
12 #include "config.h"
13 #include "logd-db.h"
14 #include "logd-taskstats.h"
15 #include "macro.h"
16 #include "nlproc-stat.h"
17 #include "proc-events.h"
18 #include "proc-stat.h"
19 #include "task-stats.h"
20
21 #define LOGD_INTERNAL_PID 3
22
23 struct process_stat {
24         int64_t utime, stime;
25         float utime_power_cons, stime_power_cons;
26         int is_active;
27         time_t duration;
28 };
29
30 static uint64_t power_const_per_uah;
31
32 static int task_stats_sock;
33 static int update_task_stats_sock;
34 static int proc_events_sock;
35
36 static Eina_Hash *active_pids;
37 static Eina_Hash *terminated_stats;
38 static Eina_Hash *total_stats;
39
40 static struct process_stat* find_or_create_statistic(Eina_Hash *table, const char *cmdline);
41 static int proc_state_update(void);
42
43 const char *kernel_threads_name = "[kernel_threads]";
44
45 static int day_of_week()
46 {
47         time_t curr_time;
48         int ret;
49         int day;
50         struct tm *curr_tm = NULL;
51
52         curr_time = time(NULL);
53         if (curr_time == ((time_t) -1)) {
54                 _E("time failed: %s", strerror(errno));
55                 return -EFAULT;
56         }
57         curr_tm = localtime(&curr_time);
58         if (curr_tm == NULL) {
59                 ret = -errno;
60                 _E("time failed: %s", strerror(errno));
61                 return ret;
62         }
63
64         return curr_tm->tm_wday;
65 }
66
67 static Eina_Bool sub_active_from_term_cb(const Eina_Hash *hash, const void *key,
68         void *data, void *fdata)
69 {
70         struct process_stat *statistic;
71         struct process_stat *active_statistic = (struct process_stat *)data;
72         char *cmdline = (char*)key;
73
74         statistic = find_or_create_statistic(terminated_stats, cmdline);
75         if (!statistic) {
76                 _E("find_or_create_statistic failed");
77                 return 1; /* continue to process */
78         }
79
80         statistic->utime -= active_statistic->utime;
81         statistic->stime -= active_statistic->stime;
82         statistic->utime_power_cons -= active_statistic->utime_power_cons;
83         statistic->stime_power_cons -= active_statistic->stime_power_cons;
84         statistic->duration -= active_statistic->duration;
85
86         return 1; /* continue to process */
87 }
88
89
90 int delete_old_proc()
91 {
92         int next_day;
93         int ret;
94
95         _I("delete_old_proc start");
96
97         if (nlproc_stat_store() < 0)
98                 _E("nlproc_stat_store failed");
99
100         /* Already stored into database, so have no reason to keep it */
101         eina_hash_free_buckets(terminated_stats);
102
103         if (!terminated_stats) {
104                 ret = 0;
105                 goto out;
106         }
107
108         /* we have to clear next day stat due to run this function at 23:59:50 */
109         next_day = (day_of_week() + 1) % DAYS_PER_WEEK; /* next day */
110         if (next_day < 0) {
111                 _E("day_of_week failed");
112                 ret = next_day;
113                 goto out;
114         }
115
116         ret = delete_old_power_cons(next_day);
117         if (ret < 0) {
118                 _E("delete_old_power_cons failed");
119                 goto out;
120         }
121         /* It's need to avoid double counting the same data that was
122         already stored into db */
123         proc_state_update();
124         eina_hash_foreach(total_stats, sub_active_from_term_cb, NULL);
125         ret = 0;
126
127 out:
128         return ret;
129 }
130
131 int get_task_stats_sock(void)
132 {
133         return task_stats_sock;
134 }
135
136 int get_proc_events_sock(void)
137 {
138         return proc_events_sock;
139 }
140
141 static int get_cpu_mask(char **mask)
142 {
143         int cpus_number;
144         int ret;
145
146         errno = 0;
147         cpus_number = sysconf(_SC_NPROCESSORS_CONF);
148         if (errno != 0) {
149                 ret = -errno;
150                 _E("sysconf failed: %s", strerror(errno));
151                 return ret;
152         }
153
154         if (asprintf(mask, "0-%d", cpus_number - 1) == -1) {
155                 ret = -errno;
156                 _E("asprintf failed: %s", strerror(errno));
157                 return ret;
158         }
159
160         return 0;
161 }
162
163 static int get_pids_from_proc(Eina_List **pids)
164 {
165         struct dirent *entry = NULL;
166         DIR *dir = NULL;
167         int ret;
168
169         dir = opendir("/proc");
170         if (dir == NULL) {
171                 ret = -errno;
172                 _E("opendir failed: %s", strerror(errno));
173                 return ret;
174         }
175
176         while ((entry = readdir(dir)) != NULL) {
177                 const char *p = entry->d_name;
178                 char buf[30] = { 0, };
179                 FILE *fp = NULL;
180                 char state;
181                 pid_t pid;
182
183                 while (isdigit(*p))
184                         ++p;
185                 if (*p != 0)
186                         continue;
187
188                 pid = atoi(entry->d_name);
189                 sprintf(buf, "/proc/%d/stat", pid);
190                 fp = fopen(buf, "r");
191                 if (!fp) {
192                         _E("fopen failed %s: %s", buf, strerror(errno));
193                         continue;
194                 }
195
196                 ret = fscanf(fp, "%*s %*s %c", &state);
197                 if (ret != 1) {
198                         _E("fscanf failed: %s", strerror(errno));
199                 }
200
201                 if (fclose(fp) != 0) {
202                         _E("fclose failed: %s", strerror(errno));
203                 }
204
205                 if (ret == 1 && state != 'Z') {
206                         *pids = eina_list_append(*pids, (void*)pid);
207                         if (eina_error_get()) {
208                                 _E("eina_list_append failed: %s", eina_error_msg_get(eina_error_get()));
209                         }
210                 }
211         }
212
213         if (closedir(dir) < 0) {
214                 ret = -errno;
215                 _E("closedir failed: %s", strerror(errno));
216                 return ret;
217         }
218
219         return 0;
220 }
221
222 static int get_cmdline_by_pid(pid_t pid, char *cmdline)
223 {
224         FILE *fp;
225         char path[30];
226         char buf[PATH_MAX + 1] = { 0, }; /* "+1" for readlink */
227         int ret;
228
229         ret = snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
230         if (ret < 0 || ret == sizeof(buf)) {
231                 _E("snprintf failed or output was truncated");
232                 return ret;
233         }
234         fp = fopen(path, "r");
235         if (fp != NULL) {
236                 if (fscanf(fp, "%s", buf) != 1) {
237                         buf[0] = '\0';
238                 }
239                 if (fclose(fp) != 0) {
240                         _E("fclose failed: %s", strerror(errno));
241                 }
242                 if (buf[0] == '/') {
243                         strcpy(cmdline, buf);
244                         return 0;
245                 }
246         }
247
248         bzero(path, sizeof(path));
249         ret = snprintf(path, sizeof(path), "/proc/%d/exe", pid);
250         if (ret < 0 || ret == sizeof(path)) {
251                 _E("snprintf failed or output was truncated");
252                 return ret;
253         }
254
255         bzero(buf, sizeof(buf));
256         if (readlink(path, buf, sizeof(buf) - 1) < 0) {
257                 ret = snprintf(path, sizeof(path), "/proc/%d/comm", pid);
258                 if (ret < 0 || ret == sizeof(path)) {
259                         _E("snprintf failed or output was truncated");
260                         return ret;
261                 }
262                 if (access(path, R_OK) < 0) {
263                         ret = -errno;
264                         return ret;
265                 }
266                 strcpy(cmdline, kernel_threads_name);
267                 return 0;
268         }
269
270         strcpy(cmdline, buf);
271
272         return 0;
273 }
274
275 static struct process_stat* find_or_create_statistic(Eina_Hash *table, const char *cmdline)
276 {
277         struct process_stat* statistic =
278                 eina_hash_find(table, cmdline);
279
280         if (!statistic) {
281                 statistic = (struct process_stat *)
282                         calloc(1, sizeof(struct process_stat));
283                 if (!statistic) {
284                         _E("calloc failed: %s", strerror(errno));
285                         return NULL;
286                 }
287
288                 if (eina_hash_add(table, cmdline,
289                         statistic) == EINA_FALSE) {
290                         _E("eina_hash_add failed: %s", eina_error_msg_get(eina_error_get()));
291                         free((void*)cmdline);
292                         free(statistic);
293                         return NULL;
294                 }
295         }
296
297         return statistic;
298 }
299
300 int proc_terminated(struct taskstats *t, void *user_data)
301 {
302         pid_t pid = t->ac_pid;
303         uint64_t s_time = t->ac_stime;
304         uint64_t u_time = t->ac_utime;
305         float u_time_power_cons = (float)t->ac_utime_power_cons / power_const_per_uah;
306         float s_time_power_cons = (float)t->ac_stime_power_cons / power_const_per_uah;
307
308         if (t->ac_stime || t->ac_utime) {
309                 struct process_stat *statistic;
310                 const char *cmdline = eina_hash_find(active_pids, &pid);
311
312                 if (!cmdline)
313                         return 0;
314                 statistic = find_or_create_statistic(terminated_stats, cmdline);
315                 if (!statistic) {
316                         _E("find_or_create_statistic failed");
317                         return -ENOMEM;
318                 }
319
320                 statistic->utime += u_time;
321                 statistic->stime += s_time;
322                 statistic->utime_power_cons += u_time_power_cons;
323                 statistic->stime_power_cons += s_time_power_cons;
324                 statistic->duration += t->ac_etime / USEC_PER_SEC;
325         }
326
327         return 0;
328 }
329
330 static enum logd_db_query load_stat_cb(const struct proc_power_cons *pc, void *user_data)
331 {
332         struct process_stat *statistic;
333         if (!user_data) {
334                 _E("Wrong hash table");
335                 return LOGD_DB_QUERY_STOP;
336         }
337
338         statistic = find_or_create_statistic((Eina_Hash *)user_data, pc->appid);
339         if (!statistic) {
340                 _E("find_or_create_statistic failed");
341                 return -ENOMEM;
342         }
343
344         /* TODO: remove useless utime, stime - need only power consumption */
345         statistic->utime_power_cons += pc->power_cons;
346         statistic->duration += pc->duration;
347
348         return LOGD_DB_QUERY_CONTINUE;
349 }
350
351 int nlproc_stat_init(void)
352 {
353         char *cpus_mask = NULL;
354         Eina_List *pids = NULL;
355         Eina_List *l;
356         int ret;
357         int day;
358         void *pid;
359
360         power_const_per_uah = config_get_int("power_const_per_uah", 3213253205ll, NULL);
361
362         task_stats_sock = create_netlink_socket(NETLINK_GENERIC, 0, 0);
363         if (task_stats_sock < 0) {
364                 _E("create_netlink_sock failed (task_stats_sock)");
365                 return task_stats_sock;
366         }
367
368         update_task_stats_sock = create_netlink_socket(NETLINK_GENERIC, 0, 0);
369         if (update_task_stats_sock < 0) {
370                 _E("create_netlink_sock failed (update_task_stats_sock)");
371                 return update_task_stats_sock;
372         }
373
374         ret = get_cpu_mask(&cpus_mask);
375         if (ret < 0) {
376                 _E("get_cpu_mask failed");
377                 return ret;
378         }
379
380         ret = reg_task_stats_cpu_mask(task_stats_sock, cpus_mask);
381         if (ret < 0) {
382                 _E("reg_task_stats_cpu_mask failed");
383                 return ret;
384         }
385         free(cpus_mask);
386         proc_events_sock = create_netlink_socket(NETLINK_CONNECTOR, CN_IDX_PROC, getpid());
387         if (proc_events_sock < 0) {
388                 _E("create_netlink_sock failed (proc_events_sock)");
389                 return proc_events_sock;
390         }
391
392         ret = subscribe_on_proc_events(proc_events_sock);
393         if (ret < 0) {
394                 _E("subscribe_on_proc_events failed");
395                 return ret;
396         }
397
398         ret = get_pids_from_proc(&pids);
399         if (ret < 0) {
400                 _E("get_pids_from_proc failed");
401                 return ret;
402         }
403
404         active_pids = eina_hash_int32_new(free);
405         if (!active_pids) {
406                 _E("eina_hash_pointer_new failed");
407                 return -ENOMEM;
408         }
409
410         EINA_LIST_FOREACH(pids, l, pid) {
411                 char cmdline[PATH_MAX];
412                 char *tmp;
413
414                 ret = get_cmdline_by_pid((int)pid, cmdline);
415                 if (ret < 0) {
416                         continue;
417                 }
418
419                 tmp = strdup(cmdline);
420                 if (!tmp) {
421                         _E("strdup failed: %s", strerror(errno));
422                         continue;
423                 }
424                 if (eina_hash_add(active_pids, &pid, tmp) == EINA_FALSE) {
425                         _E("eina_hash_add failed: %s", eina_error_msg_get(eina_error_get()));
426                         return -ENOMEM;
427                 }
428         }
429
430         eina_list_free(pids);
431
432         terminated_stats = eina_hash_string_superfast_new(free);
433         if (!terminated_stats) {
434                 _E("eina_hash_string_superfast_new failed");
435                 return -ENOMEM;
436
437         }
438
439         day = day_of_week();
440         if (day < 0) {
441                 _E("day_of_week failed");
442                 day = 0;
443         }
444
445         total_stats = eina_hash_string_superfast_new(free);
446         if (!total_stats) {
447                 _E("eina_hash_string_superfast_new failed");
448                 return -ENOMEM;
449         }
450
451         /* ignore statistic before logd started */
452         proc_state_update();
453         eina_hash_foreach(total_stats, sub_active_from_term_cb, NULL);
454
455         if (foreach_proc_power_cons(load_stat_cb, day, terminated_stats) < 0)
456                 _E("foreach_proc_power_cons failed");
457
458
459         return 0;
460 }
461
462 int proc_forked(struct proc_event *e, void *user_data)
463 {
464         int pid;
465         char cmdline[PATH_MAX];
466         char *old_cmdline;
467         int ret;
468         char *tmp;
469
470         if (e->what == PROC_EVENT_FORK) {
471                 pid = e->event_data.fork.child_pid;
472         } else if (e->what == PROC_EVENT_EXEC) {
473                 pid = e->event_data.exec.process_pid;
474         } else if (e->what == PROC_EVENT_EXIT) {
475                 pid = e->event_data.exit.process_pid;
476                 if (eina_hash_find(active_pids, &pid)) {
477                         if (eina_hash_del(active_pids, &pid, NULL) == EINA_FALSE) {
478                                 _E("eina_hash_del failed %d", pid);
479                                 return -EINVAL;
480                         }
481                 }
482                 return 0;
483         } else
484                 return 0;
485
486         ret = get_cmdline_by_pid(pid, cmdline);
487         if (ret < 0) {
488                 return ret;
489         }
490
491         tmp = strdup(cmdline);
492         if (!tmp) {
493                 _E("strdup failed: %s", strerror(errno));
494                 return -ENOMEM;
495         }
496
497         old_cmdline = eina_hash_set(active_pids, &pid, tmp);
498         if (old_cmdline)
499                 free(old_cmdline);
500         else if (eina_error_get()) {
501                 _E("eina_hash_set failed: %s", eina_error_msg_get(eina_error_get()));
502                 return -ENOMEM;
503         }
504
505         return 0;
506 }
507
508 int add_active_proc(struct taskstats *t, void *user_data)
509 {
510         const char *launchpad_cmdline = "/usr/bin/launchpad_preloading_preinitializing_daemon";
511         int ret;
512         pid_t pid = t->ac_pid;
513         uint64_t s_time = t->ac_stime;
514         uint64_t u_time = t->ac_utime;
515         float u_time_power_cons = (float)t->ac_utime_power_cons / power_const_per_uah;
516         float s_time_power_cons = (float)t->ac_stime_power_cons / power_const_per_uah;
517
518         if (t->ac_stime || t->ac_utime) {
519                 char *cmdline = eina_hash_find(active_pids, &pid);
520                 struct process_stat *statistic;
521                 char buf[PATH_MAX];
522
523                 if (!cmdline) {
524                         ret = get_cmdline_by_pid(pid, buf);
525                         if (ret < 0) {
526                                 return ret;
527                         }
528                         cmdline = strdup(buf);
529                         if (!cmdline) {
530                                 _E("strdup failed: %s", strerror(errno));
531                                 return -ENOMEM;
532                         }
533
534                         if (eina_hash_add(active_pids, &pid, cmdline) == EINA_FALSE) {
535                                 _E("eina_hash_add failed: %s", eina_error_msg_get(eina_error_get()));
536                                 free((void*)cmdline);
537                                 return -ENOMEM;
538                         }
539                 } else {
540                         if (strcmp(cmdline, launchpad_cmdline) == 0) {
541                                 char *old_cmdline = NULL;
542                                 ret = get_cmdline_by_pid(pid, buf);
543                                 if (ret < 0) {
544                                         return ret;
545                                 }
546                                 cmdline = strdup(buf);
547                                 if (!cmdline) {
548                                         _E("strdup failed: %s", strerror(errno));
549                                         return -ENOMEM;
550                                 }
551                                 old_cmdline = eina_hash_modify(active_pids,
552                                         &pid, cmdline);
553                                 if (!old_cmdline) {
554                                         _E("eina_hash_modify failed: %s", eina_error_msg_get(eina_error_get()));
555                                         return -EINVAL;
556                                 }
557                                 free(old_cmdline);
558                         }
559                 }
560
561                 statistic = find_or_create_statistic(total_stats, cmdline);
562                 if (!statistic) {
563                         _E("find_or_create_statistic failed");
564                         return -ENOMEM;
565                 }
566
567                 statistic->utime += u_time;
568                 statistic->stime += s_time;
569                 statistic->utime_power_cons += u_time_power_cons;
570                 statistic->stime_power_cons += s_time_power_cons;
571                 statistic->duration += t->ac_etime / USEC_PER_SEC;
572                 statistic->is_active = 1;
573         }
574
575         return 0;
576 }
577
578 static Eina_Bool update_total_stat_cb(const Eina_Hash *hash, const void *key,
579         void *data, void *fdata)
580 {
581         struct process_stat *statistic;
582         struct process_stat *new_statistic = (struct process_stat *)data;
583         char *cmdline = (char*)key;
584
585         statistic = find_or_create_statistic(total_stats, cmdline);
586         if (!statistic) {
587                 _E("find_or_create_statistic failed");
588                 return 1; /* continue to process */
589         }
590
591         statistic->utime += new_statistic->utime;
592         statistic->stime += new_statistic->stime;
593         statistic->utime_power_cons += new_statistic->utime_power_cons;
594         statistic->stime_power_cons += new_statistic->stime_power_cons;
595         statistic->duration += new_statistic->duration;
596
597         return 1; /* continue to process */
598 }
599
600 Eina_Bool update_active_pids_cb(const Eina_Hash *hash, const void *key,
601         void *data, void *fdata)
602 {
603         int pid = *(int*)key;
604         int ret;
605
606         ret = request_stat_by_pid(update_task_stats_sock, (int)pid);
607         if (ret < 0) {
608                 _E("request_stat_by_pid failed (pid=%d)", (int)pid);
609                 return 1; /* continue to process */
610         }
611         ret = process_task_stats_answer(update_task_stats_sock,
612                 add_active_proc, NULL);
613         if (ret < 0) {
614                 _E("process_task_stats_answer failed (pid=%d)", (int)pid);
615                 return 1; /* continue to process */
616         }
617
618         return 1; /* continue to process */
619 }
620
621 static int proc_state_update(void)
622 {
623         eina_hash_free_buckets(total_stats);
624
625         eina_hash_foreach(active_pids, update_active_pids_cb, NULL);
626         eina_hash_foreach(terminated_stats, update_total_stat_cb, NULL);
627
628         return 0;
629 }
630
631 static int send_one_stat(const struct logd_proc_stat *statistics, int sock)
632 {
633         const char *cmdline = (const char *)statistics->application;
634         int len = strlen(cmdline);
635         int ret;
636
637         if (send(sock, (void*)&len, sizeof(len), 0) < 0) {
638                 goto err;
639         }
640         if (send(sock, cmdline, len, 0) < 0) {
641                 goto err;
642         }
643         if (send(sock, &statistics->utime, sizeof(statistics->utime), 0) < 0) {
644                 goto err;
645         }
646         if (send(sock, &statistics->stime, sizeof(statistics->stime), 0) < 0) {
647                 goto err;
648         }
649         if (send(sock, &statistics->utime_power_cons,
650                 sizeof(statistics->utime_power_cons), 0) < 0) {
651                 goto err;
652         }
653         if (send(sock, &statistics->stime_power_cons,
654                 sizeof(statistics->stime_power_cons), 0) < 0) {
655                 goto err;
656         }
657         if (send(sock, &statistics->is_active,
658                 sizeof(statistics->is_active), 0) < 0) {
659                 goto err;
660         }
661
662         return 0;
663 err:
664         ret = -errno;
665         if (errno != EPIPE)
666                 _E("send failed: %s", strerror(errno));
667         return ret;
668 }
669
670 static int sort_stat_cb(void *d1, void *d2)
671 {
672         const struct logd_proc_stat *s1 = d1;
673         const struct logd_proc_stat *s2 = d2;
674
675         if(!d1) return(1);
676         if(!d2) return(-1);
677
678         if (s1->utime_power_cons + s1->stime_power_cons <
679                 s2->utime_power_cons + s2->stime_power_cons)
680                 return 1;
681         else if (s1->utime_power_cons + s1->stime_power_cons >
682                 s2->utime_power_cons + s2->stime_power_cons)
683                 return -1;
684         return 0;
685 }
686
687 int send_proc_stat(int sock)
688 {
689         int count = eina_hash_population(total_stats);
690         int day = day_of_week();
691         Eina_List *sorted_stat = NULL;
692         Eina_List *l;
693         Eina_Iterator *it;
694         void *data;
695         int ret;
696         int i;
697
698         ret = proc_state_update();
699         if (ret < 0) {
700                 _E("proc_stat_update failed");
701                 return ret;
702         }
703
704         for (i = 0; i < DAYS_PER_WEEK; ++i) {
705                 /* stat for current day stored in activ/terminated hash tables */
706                 if (i == day)
707                         continue;
708                 if (foreach_proc_power_cons(load_stat_cb, i, total_stats) < 0)
709                         _E("foreach_proc_power_cons failed");
710         }
711
712         it = eina_hash_iterator_tuple_new(total_stats);
713         if (!it) {
714                 _E("eina_hash_iterator_tuple_new failed");
715                 return -ENOMEM;
716         }
717
718         while (eina_iterator_next(it, &data)) {
719                 Eina_Hash_Tuple *t = data;
720                 char *cmdline = (char*)t->key;
721                 const struct process_stat *statistic = t->data;
722                 struct logd_proc_stat *ps =
723                         (struct logd_proc_stat*) malloc(sizeof(struct logd_proc_stat));
724
725                 if (!ps) {
726                         ret = -ENOMEM;
727                         _E("malloc failed: %s", strerror(errno));
728                         goto out_free;
729                 }
730                 ps->application = cmdline;
731                 ps->utime = statistic->utime;
732                 ps->stime = statistic->stime;
733                 ps->utime_power_cons = statistic->utime_power_cons;
734                 ps->stime_power_cons = statistic->stime_power_cons;
735                 ps->is_active = statistic->is_active;
736
737                 sorted_stat = eina_list_sorted_insert(sorted_stat,
738                         EINA_COMPARE_CB(sort_stat_cb), ps);
739                 if (eina_error_get()) {
740                         _E("eina_list_sorted_insert failed: %s", eina_error_msg_get(eina_error_get()));
741                 }
742
743         }
744
745         if (send(sock, &count, sizeof(count), 0) < 0) {
746                 ret = -errno;
747                 _E("send failed: %s", strerror(errno));
748                 goto out_free;
749         }
750
751         EINA_LIST_FOREACH(sorted_stat, l, data) {
752                 ret = send_one_stat(data, sock);
753                 if (ret < 0) {
754                         if (ret != -EPIPE)
755                                 _E("send_one_stat failed");
756                         break;
757                 }
758         }
759
760         EINA_LIST_FOREACH(sorted_stat, l, data) {
761                 free(data);
762         }
763
764         eina_iterator_free(it);
765
766         eina_list_free(sorted_stat);
767
768         return 0;
769
770 out_free:
771         if (sorted_stat) {
772                 EINA_LIST_FOREACH(sorted_stat, l, data) {
773                         free(data);
774                 }
775         }
776
777         if (it)
778                 eina_iterator_free(it);
779
780         if (sorted_stat)
781                 eina_list_free(sorted_stat);
782         return ret;
783 }
784
785 int nlproc_stat_store(void)
786 {
787         Eina_Iterator *it;
788         void *data;
789         int ret;
790         int day;
791
792         _I("nlproc_stat_store start");
793
794         ret = proc_state_update();
795         if (ret < 0) {
796                 _E("proc_state_update failed");
797                 goto out;
798         }
799
800         it = eina_hash_iterator_tuple_new(total_stats);
801         if (!it) {
802                 _E("eina_hash_iterator_tuple_new failed");
803                 ret = -ENOMEM;
804                 goto out;
805         }
806
807         day = day_of_week();
808         if (day < 0) {
809                 _E("day_of_week failed");
810                 day = 0;
811         }
812
813         while (eina_iterator_next(it, &data)) {
814                 struct proc_power_cons pc;
815                 Eina_Hash_Tuple *t = data;
816                 const char *cmdline = t->key;
817                 const struct process_stat *statistic = t->data;
818
819                 pc.appid = cmdline;
820                 pc.power_cons = statistic->stime_power_cons + statistic->utime_power_cons;
821                 pc.duration = statistic->duration;
822
823                 update_proc_power_cons(&pc, day);
824         }
825         eina_iterator_free(it);
826         ret = 0;
827
828 out:
829         return ret;
830 }
831
832 int nlproc_stat_exit()
833 {
834         if (active_pids)
835                 eina_hash_free(active_pids);
836         /* TODO: free terminated keys */
837
838         return 0;
839 }