[IMPROVE] added wifi consumption
[kernel/swap-modules.git] / energy / debugfs_energy.c
1 /*
2  *  Dynamic Binary Instrumentation Module based on KProbes
3  *  energy/debugfs_energy.c
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  *
19  * Copyright (C) Samsung Electronics, 2013
20  *
21  * 2013         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
22  *
23  */
24
25
26 #include <linux/fs.h>
27 #include <linux/module.h>
28 #include <linux/debugfs.h>
29 #include <linux/math64.h>
30 #include <master/swap_debugfs.h>
31 #include "energy.h"
32 #include "debugfs_energy.h"
33 #include "rational_debugfs.h"
34 #include "lcd/lcd_debugfs.h"
35 #include "lcd/lcd_base.h"
36
37
38 /* CPU running */
39 static DEFINE_RATIONAL(cpu0_running_coef); /* boot core uses distinct coeff */
40 static DEFINE_RATIONAL(cpuN_running_coef);
41
42 static u64 __energy_cpu(enum parameter_energy pe)
43 {
44         u64 times[NR_CPUS] = { 0 };
45         u64 val = 0;
46         int i;
47
48         if (get_parameter_energy(pe, times, sizeof(times)) == 0) {
49                 val = div_u64(times[0] * cpu0_running_coef.num,
50                               cpu0_running_coef.denom);
51                 for (i = 1; i < NR_CPUS; i++)
52                         val += div_u64(times[i] * cpuN_running_coef.num,
53                                        cpuN_running_coef.denom);
54         }
55
56         return val;
57 }
58
59 static u64 cpu_system(void)
60 {
61         return __energy_cpu(PE_TIME_SYSTEM);
62 }
63
64 static u64 cpu_apps(void)
65 {
66         return __energy_cpu(PE_TIME_APPS);
67 }
68
69
70 /* CPU idle */
71 static DEFINE_RATIONAL(cpu_idle_coef);
72
73 static u64 cpu_idle_system(void)
74 {
75         u64 time = 0;
76
77         get_parameter_energy(PE_TIME_IDLE, &time, sizeof(time));
78         return div_u64(time * cpu_idle_coef.num, cpu_idle_coef.denom);
79 }
80
81
82 /* flash read */
83 static DEFINE_RATIONAL(fr_coef);
84
85 static u64 fr_system(void)
86 {
87         u64 byte = 0;
88
89         get_parameter_energy(PE_READ_SYSTEM, &byte, sizeof(byte));
90         return div_u64(byte * fr_coef.num, fr_coef.denom);
91 }
92
93 static u64 fr_apps(void)
94 {
95         u64 byte = 0;
96
97         get_parameter_energy(PE_READ_APPS, &byte, sizeof(byte));
98         return div_u64(byte * fr_coef.num, fr_coef.denom);
99 }
100
101
102 /* flash write */
103 static DEFINE_RATIONAL(fw_coef);
104
105 static u64 fw_system(void)
106 {
107         u64 byte = 0;
108
109         get_parameter_energy(PE_WRITE_SYSTEM, &byte, sizeof(byte));
110         return div_u64(byte * fw_coef.num, fw_coef.denom);
111 }
112
113 static u64 fw_apps(void)
114 {
115         u64 byte = 0;
116
117         get_parameter_energy(PE_WRITE_APPS, &byte, sizeof(byte));
118         return div_u64(byte * fw_coef.num, fw_coef.denom);
119 }
120
121
122 /* wifi recv */
123 static DEFINE_RATIONAL(wf_recv_coef);
124
125 static u64 wf_recv_system(void)
126 {
127         u64 byte = 0;
128
129         get_parameter_energy(PE_WF_RECV_SYSTEM, &byte, sizeof(byte));
130
131         return div_u64(byte * wf_recv_coef.num, wf_recv_coef.denom);
132 }
133
134 static u64 wf_recv_apps(void)
135 {
136         u64 byte = 0;
137
138         get_parameter_energy(PE_WF_RECV_APPS, &byte, sizeof(byte));
139
140         return div_u64(byte * wf_recv_coef.num, wf_recv_coef.denom);
141 }
142
143 /* wifi send */
144 static DEFINE_RATIONAL(wf_send_coef);
145
146 static u64 wf_send_system(void)
147 {
148         u64 byte = 0;
149
150         get_parameter_energy(PE_WF_SEND_SYSTEM, &byte, sizeof(byte));
151
152         return div_u64(byte * wf_send_coef.num, wf_send_coef.denom);
153 }
154
155 static u64 wf_send_apps(void)
156 {
157         u64 byte = 0;
158
159         get_parameter_energy(PE_WF_SEND_APPS, &byte, sizeof(byte));
160
161         return div_u64(byte * wf_send_coef.num, wf_send_coef.denom);
162 }
163
164 /* ============================================================================
165  * ===                             PARAMETERS                               ===
166  * ============================================================================
167  */
168 static int get_func_u64(void *data, u64 *val)
169 {
170         u64 (*func)(void) = data;
171         *val = func();
172         return 0;
173 }
174
175 SWAP_DEFINE_SIMPLE_ATTRIBUTE(fops_get_u64, get_func_u64, NULL, "%llu\n");
176
177
178 struct param_data {
179         char *name;
180         struct rational *coef;
181         u64 (*system)(void);
182         u64 (*apps)(void);
183 };
184
185 static struct dentry *create_parameter(struct dentry *parent,
186                                        struct param_data *param)
187 {
188         struct dentry *name, *system, *apps = NULL;
189
190         name = debugfs_create_dir(param->name, parent);
191         if (name == NULL)
192                 return NULL;
193
194         system = debugfs_create_file("system", 0600, name, param->system,
195                                      &fops_get_u64);
196         if (system == NULL)
197                 goto rm_name;
198
199         if (param->apps) {
200                 apps = debugfs_create_file("apps", 0600, name, param->apps,
201                                            &fops_get_u64);
202                 if (apps == NULL)
203                         goto rm_system;
204         }
205
206         if (create_rational_files(name, param->coef,
207                                   "numerator", "denominator"))
208                 goto rm_apps;
209
210         return name;
211
212 rm_apps:
213         if (param->apps)
214                 debugfs_remove(apps);
215 rm_system:
216         debugfs_remove(system);
217 rm_name:
218         debugfs_remove(name);
219
220         return NULL;
221 }
222
223 struct param_data parameters[] = {
224         {
225                 .name = "cpu_running",
226                 .coef = &cpu0_running_coef,
227                 .system = cpu_system,
228                 .apps = cpu_apps
229         },
230         {
231                 .name = "cpuN_running",
232                 .coef = &cpuN_running_coef,
233                 .system = cpu_system,
234                 .apps = cpu_apps
235         },
236         {
237                 .name = "cpu_idle",
238                 .coef = &cpu_idle_coef,
239                 .system = cpu_idle_system,
240                 .apps = NULL
241         },
242         {
243                 .name = "flash_read",
244                 .coef = &fr_coef,
245                 .system = fr_system,
246                 .apps = fr_apps
247         },
248         {
249                 .name = "flash_write",
250                 .coef = &fw_coef,
251                 .system = fw_system,
252                 .apps = fw_apps
253         },
254         {
255                 .name = "wf_recv",
256                 .coef = &wf_recv_coef,
257                 .system = wf_recv_system,
258                 .apps = wf_recv_apps
259         },
260         {
261                 .name = "wf_send",
262                 .coef = &wf_send_coef,
263                 .system = wf_send_system,
264                 .apps = wf_send_apps
265         }
266 };
267
268 enum {
269         parameters_cnt = sizeof(parameters) / sizeof(struct param_data)
270 };
271
272
273
274
275
276 /* ============================================================================
277  * ===                              INIT/EXIT                               ===
278  * ============================================================================
279  */
280 static struct dentry *energy_dir;
281
282 /**
283  * @brief Destroy debugfs for LCD
284  *
285  * @return Dentry of energy debugfs
286  */
287 struct dentry *get_energy_dir(void)
288 {
289         return energy_dir;
290 }
291
292 /**
293  * @brief Destroy debugfs for energy
294  *
295  * @return Void
296  */
297 void exit_debugfs_energy(void)
298 {
299         lcd_exit();
300         exit_lcd_debugfs();
301
302         if (energy_dir)
303                 debugfs_remove_recursive(energy_dir);
304
305         energy_dir = NULL;
306 }
307
308 /**
309  * @brief Create debugfs for energy
310  *
311  * @return Error code
312  */
313 int init_debugfs_energy(void)
314 {
315         int i;
316         struct dentry *swap_dir, *dentry;
317
318         swap_dir = swap_debugfs_getdir();
319         if (swap_dir == NULL)
320                 return -ENOENT;
321
322         energy_dir = debugfs_create_dir("energy", swap_dir);
323         if (energy_dir == NULL)
324                 return -ENOMEM;
325
326         for (i = 0; i < parameters_cnt; ++i) {
327                 dentry = create_parameter(energy_dir, &parameters[i]);
328                 if (dentry == NULL)
329                         goto fail;
330         }
331
332         if (init_lcd_debugfs(energy_dir))
333                 goto fail;
334
335         /* Actually, the only goal of lcd_init() is to register lcd screen's
336            debugfs, so it is called here. */
337         if (lcd_init()) {
338                 exit_lcd_debugfs();
339         }
340
341         return 0;
342
343 fail:
344         exit_debugfs_energy();
345         return -ENOMEM;
346 }