tizen 2.3 release
[framework/system/deviced.git] / src / logd / src / liblogd-db / padvisor.c
1 #define _GNU_SOURCE
2 #include <errno.h>
3 #include <stdio.h>
4 #include <sqlite3.h>
5 #include <stdlib.h>
6 #include <string.h>
7
8 #include "padvisor.h"
9 #include "db.h"
10 #include "devices.h"
11 #include "macro.h"
12
13 static sqlite3_stmt *load_mostused_apps_stmt;
14 static sqlite3_stmt *get_enabled_devices_stmt;
15 static sqlite3_stmt *load_dev_working_time_stmt;
16
17 static sqlite3 *db;
18
19 struct logd_device_ratio {
20         enum logd_object device;
21         float coefficient;
22 };
23
24 static struct logd_device_ratio ratio[] = {
25         /* HW devices */
26         {LOGD_ACCELEROMETER, 0},
27         {LOGD_BAROMETER, 0},
28         {LOGD_BT, 0.22},
29         {LOGD_DISPLAY, 1.86}, /* brightness 80% */
30         {LOGD_GEOMAGNETIC, 0},
31         {LOGD_GPS, 0.54},
32         {LOGD_GYROSCOPE, 0},
33         {LOGD_LIGHT, 0},
34         {LOGD_NFC, 0},
35         {LOGD_PROXIMITY, 0},
36         {LOGD_THERMOMETER, 0},
37         {LOGD_WIFI, 0.11},
38         {LOGD_MMC, 0},
39         /* Battery */
40         {LOGD_BATTERY_SOC, 0},
41         {LOGD_CHARGER, 0},
42         /* Apps */
43         {LOGD_FOREGRD_APP, 0},
44         /* Function */
45         {LOGD_AUTOROTATE, 0},
46         {LOGD_MOTION, 0},
47         {LOGD_POWER_MODE, 0},
48 };
49
50 STATIC_ASSERT(sizeof(ratio)/sizeof(ratio[0]) == LOGD_OBJECT_MAX, number_of_ratio_\
51 elements_must_be_equal_LOGD_OBJECT_MAX);
52
53 #define GET_ENABLED_DEVICES_SQL "SELECT object, MAX(time_stamp) \
54 FROM events GROUP BY object HAVING action!=%d"
55
56 #define LOAD_DEV_WORKING_TIME_SQL "SELECT device, SUM(time) AS time \
57 FROM device_working_time WHERE time_stamp>=? AND time_stamp<=? \
58 GROUP BY device"
59
60 int padvisor_init()
61 {
62         int ret;
63         char *get_enabled_devices;
64
65         db = logd_get_db();
66
67         ret = asprintf(&get_enabled_devices, GET_ENABLED_DEVICES_SQL, LOGD_OFF);
68         if (ret == -1) {
69                 fprintf(stderr, "Cannot create statement\n");
70                 return -errno;
71         }
72
73         PREPARE_STMT(load_dev_working_time_stmt, LOAD_DEV_WORKING_TIME_SQL);
74         PREPARE_STMT(get_enabled_devices_stmt, get_enabled_devices);
75
76         free(get_enabled_devices);
77
78         return 0;
79 }
80
81 int padvisor_finalize()
82 {
83         FINALIZE_STMT(load_dev_working_time_stmt);
84         FINALIZE_STMT(load_mostused_apps_stmt);
85         FINALIZE_STMT(get_enabled_devices_stmt);
86
87         return 0;
88 }
89
90 static int compare_device_power_cons(const void *dev1, const void *dev2)
91 {
92         float coeff1 = ratio[((struct logd_idle_device*)dev1)->device].coefficient;
93         float coeff2 = ratio[((struct logd_idle_device*)dev2)->device].coefficient;
94
95         if (coeff1 < coeff2)
96                 return 1;
97         else if (coeff1 > coeff2)
98                 return -1;
99
100         return 0;
101 }
102
103 static enum logd_db_query mostused_apps_cb(const struct logd_proc_stat *proc_stat, void *user_data)
104 {
105         static int i = 0;
106         struct logd_power_advisor *lpa = (struct logd_power_advisor*) user_data;
107
108         lpa->procs[i].application = strdup(proc_stat->application);
109         lpa->procs[i].utime = proc_stat->utime;
110         lpa->procs[i].stime = proc_stat->stime;
111         lpa->procs[i].utime_power_cons = proc_stat->utime_power_cons;
112         lpa->procs[i].stime_power_cons = proc_stat->stime_power_cons;
113         lpa->proc_stat_used_num++;
114
115         if (++i < LOGD_ADVISOR_MAX)
116                 return LOGD_DB_QUERY_CONTINUE;
117
118         i = 0;
119         return LOGD_DB_QUERY_STOP;
120 }
121
122 API struct logd_power_advisor *logd_get_power_advisor(void)
123 {
124         int i;
125         int ret;
126         struct logd_power_advisor *lpa;
127         int total_power_cons = 0;
128
129         lpa = calloc(1, sizeof(struct logd_power_advisor));
130         if (lpa == NULL) {
131                 _E("Can't calloc logd_power_advisor");
132                 return NULL;
133         }
134
135         for (i = 0; i < LOGD_ADVISOR_MAX; i++) {
136                 if (sqlite3_step(get_enabled_devices_stmt) != SQLITE_ROW) {
137                         break;
138                 }
139
140                 lpa->idle_devices[i].device =
141                         sqlite3_column_int(get_enabled_devices_stmt, 0);
142                 lpa->idle_devices[i].idle_time =
143                         sqlite3_column_int64(get_enabled_devices_stmt, 1);
144                 lpa->idle_devices_used_num++;
145         }
146         qsort(lpa->idle_devices, lpa->idle_devices_used_num,
147                 sizeof(struct logd_idle_device), compare_device_power_cons);
148
149         ret = sqlite3_reset(get_enabled_devices_stmt);
150         if (ret != SQLITE_OK) {
151                 _E("cannot reset statement: %s", sqlite3_errmsg(db));
152                 free(lpa);
153                 return NULL;
154         }
155
156         logd_foreach_proc_stat(&mostused_apps_cb, lpa);
157
158         for (i = 0; i < lpa->proc_stat_used_num; i++) {
159                 total_power_cons += lpa->procs[i].utime_power_cons + lpa->procs[i].stime_power_cons;
160         }
161
162         for (i = 0; i < lpa->proc_stat_used_num; ++i)
163                 lpa->procs[i].percentage =
164                         (float)(lpa->procs[i].utime_power_cons + lpa->procs[i].stime_power_cons) /
165                                 total_power_cons;
166
167         return lpa;
168 }
169
170 API void logd_free_power_advisor(struct logd_power_advisor *lpa)
171 {
172         int i;
173
174         if (!lpa)
175                 return;
176
177         for (i = 0; i < lpa->proc_stat_used_num; i++) {
178                 free(lpa->procs[i].application);
179         }
180
181         free(lpa);
182 }
183
184 API struct device_power_consumption *
185 logd_get_device_power_cons(time_t from, time_t to)
186 {
187         struct device_power_consumption *pcons;
188         float scaled_time = 0;
189
190         if (sqlite3_bind_int(load_dev_working_time_stmt, 1, from) !=
191                 SQLITE_OK) {
192                 _E("Can't bind argument: %s", sqlite3_errmsg(db));
193                 return NULL;
194         }
195         if (sqlite3_bind_int(load_dev_working_time_stmt, 2, to) !=
196                 SQLITE_OK) {
197                 _E("Can't bind argument: %s", sqlite3_errmsg(db));
198                 return NULL;
199         }
200
201         pcons = calloc(1, sizeof(struct device_power_consumption));
202         if (!pcons) {
203                 _E("Can't calloc device_power_consumption");
204                 return NULL;
205         }
206
207         while (sqlite3_step(load_dev_working_time_stmt) == SQLITE_ROW)
208         {
209                 int devid = sqlite3_column_int(load_dev_working_time_stmt, 0);
210                 int dev_time = sqlite3_column_int(load_dev_working_time_stmt, 1);
211
212                 if (devid < 0 || LOGD_OBJECT_MAX <= devid) {
213                         _E("wrong device id: %d", devid);
214                         free(pcons);
215                         return NULL;
216                 }
217                 pcons->device_cons[devid].time = dev_time;
218                 pcons->total_time += dev_time;
219                 scaled_time += ratio[devid].coefficient * dev_time;
220         }
221
222         if (pcons->total_time) {
223                 for (int i = 0; i < LOGD_OBJECT_MAX; ++i) {
224                         pcons->device_cons[i].percentage = ratio[i].coefficient *
225                                 pcons->device_cons[i].time / scaled_time;
226                 }
227         }
228         if (sqlite3_reset(load_dev_working_time_stmt) != SQLITE_OK) {
229                 _E("Can't reset statement: %s", sqlite3_errmsg(db));
230                 free(pcons);
231                 return NULL;
232         }
233
234         return pcons;
235 }
236
237 API void logd_free_device_power_cons(struct device_power_consumption *pcons)
238 {
239         if (pcons)
240                 free(pcons);
241 }
242