blob: 7b69dbbdb7a283c1faa88bdfefff6da350833950 [file] [log] [blame]
Thara Gopinath9cee8a52017-07-14 13:25:18 -04001/*
2 * Powerdebug : power debugging tool
3 *
4 * Copyright (C) 2016, Linaro Limited.
5 *
6 * Author:
7 * Thara Gopinath <thara.gopinath@linaro.org>
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 */
19#define DEBUGFS_GENPD "/sys/kernel/debug/pm_genpd"
20#define NAME_MAX 16
21#define DEVICE_NAME_MAX 256
22
23#define _GNU_SOURCE
24#include <stdio.h>
25#undef _GNU_SOURCE
26#include <sys/types.h>
27#include <stdbool.h>
28#include <dirent.h>
29#include <string.h>
30#include <stdlib.h>
31#include <unistd.h>
32
33#include "display.h"
34#include "powerdebug.h"
35#include "tree.h"
36#include "utils.h"
37
38struct genpd_idle_state {
39 char name[NAME_MAX];
40 long long idle_time;
41};
42
43struct genpd_info {
44 long long active_time;
45 long long total_idle_time;
46 char current_state[NAME_MAX];
47 struct genpd_idle_state *idle_states;
48 char (*devices)[DEVICE_NAME_MAX];
49 char (*sub_domains)[NAME_MAX];
50 int nr_devices;
51 int nr_subdomains;
52 int nr_states;
53};
54
55static struct tree *genpd_tree;
56
57static struct genpd_info *genpd_alloc(void)
58{
59 struct genpd_info *genpd;
60
61 genpd = malloc(sizeof(*genpd));
62 if (genpd)
63 memset(genpd, 0, sizeof(*genpd));
64
65 return genpd;
66}
67
68static int genpd_filter_cb(const char *name)
69{
70 /* Ignore the summary directory */
71 if (!strcmp(name, "pm_genpd_summary"))
72 return -1;
73 if (!strcmp(name, "pm_genpd"))
74 return -1;
75
76 return 0;
77}
78
79static int genpd_dump_cb(struct tree *t, void *data)
80{
81 struct genpd_info *genpd = t->private;
82 int i;
83
84 if (!t->parent)
85 return 0;
86
87 printf("\n%s:\n", t->name);
88 printf("current_state: %s\n", genpd->current_state);
89 printf("active_time: %lld ms\n", genpd->active_time);
90 printf("total_idle_time: %lld ms\n", genpd->total_idle_time);
91 printf("Idle States:\n");
92 for (i = 0; i < genpd->nr_states; i++) {
93 struct genpd_idle_state state = genpd->idle_states[i];
94
95 if (!i)
96 printf("%*s State %*s Time\n", 12, "", 10, "");
97 printf("%*s %-16s %lld\n", 12, "", state.name,
98 state.idle_time);
99 }
100 printf("Devices:\n");
101 for (i = 0; i < genpd->nr_devices; i++)
102 printf("%*s %s\n", 8, "", genpd->devices[i]);
103 printf("Subdomains:\n");
104 for (i = 0; i < genpd->nr_subdomains; i++)
105 printf("%*s %s\n", 11, "", genpd->sub_domains[i]);
106
107 return 0;
108}
109
110static int genpd_display_cb(struct tree *t, void *data)
111{
112 struct genpd_info *genpd = t->private;
113 int *line = data;
114 int nr_states = 0, nr_devices = 0, nr_domains = 0, i = 0;
115 char *buf;
116
117 if (!t->parent)
118 return 0;
119
120 while (1) {
121 char *state_buf, *device_buf, *domain_buf;
122
123 if ((i) && (nr_states == genpd->nr_states) &&
124 (nr_devices == genpd->nr_devices) &&
125 (nr_domains == genpd->nr_subdomains)) {
126 display_print_line(GENPD, *line, " ", 1, t);
127 (*line)++;
128 break;
129 }
130
131 if (nr_states < genpd->nr_states) {
132 if (asprintf(&state_buf, "%-10s %lld",
133 genpd->idle_states[nr_states].name,
134 genpd->idle_states[nr_states].idle_time) < 0)
135 return -1;
136 nr_states++;
137 } else {
138 if (asprintf(&state_buf, "%s", "") < 0)
139 return -1;
140 }
141
142 if (nr_devices < genpd->nr_devices) {
143 if (asprintf(&device_buf, "%s",
144 genpd->devices[nr_devices]) < 0)
145 return -1;
146 nr_devices++;
147 } else {
148 if (asprintf(&device_buf, "%s", "") < 0)
149 return -1;
150 }
151
152 if (nr_domains < genpd->nr_subdomains) {
153 if (asprintf(&domain_buf, "%s",
154 genpd->sub_domains[nr_domains]) < 0)
155 return -1;
156 nr_domains++;
157 } else {
158 if (asprintf(&domain_buf, "%s", "") < 0)
159 return -1;
160 }
161
162 if (!i) {
163 if (asprintf(&buf, "%-9s %-18s %-20lld %-24lld %-34s "
164 "%-50s %-15s", t->name, genpd->current_state,
165 genpd->active_time, genpd->total_idle_time,
166 state_buf, device_buf, domain_buf) < 0)
167 return -1;
168 } else {
169 if (asprintf(&buf, "%-74s %-34s %-50s %-15s",
170 "", state_buf, device_buf, domain_buf) < 0)
171 return -1;
172 }
173
174 display_print_line(GENPD, *line, buf, 1, t);
175 (*line)++;
176 free(buf);
177 free(state_buf);
178 free(device_buf);
179 free(domain_buf);
180 i++;
181 }
182
183 return 0;
184}
185
186static int genpd_print_header(void)
187{
188 char *buf;
189 int ret;
190
191 if (asprintf(&buf, "%-9s %-18s %-20s %-24s %-34s %-50s %-15s", "Name",
192 "Current State", "Active Time(ms)", "Total Idle Time(ms)",
193 "Idle States(State,Time ms)", "Devices", "Subdomains") < 0)
194 return -1;
195
196 ret = display_column_name(buf);
197 free(buf);
198
199 return ret;
200}
201
202static int genpd_print_info(struct tree *t)
203{
204 int ret, line = 0;
205
206 display_reset_cursor(GENPD);
207
208 genpd_print_header();
209
210 ret = tree_for_each(t, genpd_display_cb, &line);
211
212 display_refresh_pad(GENPD);
213
214 return ret;
215}
216
217static int read_genpd_cb(struct tree *t, void *data)
218{
219 struct genpd_info *genpd = t->private;
220 FILE *fp;
221 char line[256];
222 int nr_states = 0, nr_devices = 0, nr_sub_domains = 0;
223
224 file_read_value(t->path, "active_time", "%lld", &genpd->active_time);
225 file_read_value(t->path, "total_idle_time", "%lld",
226 &genpd->total_idle_time);
227 file_read_value(t->path, "current_state", "%s", &genpd->current_state);
228 file_open(&fp, t->path, "idle_states", "r");
229 while (!(file_read_line(&fp, line, sizeof(line)))) {
230 if (!strncmp(line, "State", 5))
231 continue;
232
233 genpd->idle_states = realloc(genpd->idle_states,
234 sizeof(struct genpd_idle_state) * (nr_states + 1));
235 if (!genpd->idle_states)
236 continue;
237 sscanf(line, "%s %lld", genpd->idle_states[nr_states].name,
238 &(genpd->idle_states[nr_states].idle_time));
239
240 nr_states++;
241 }
242 file_close(&fp);
243
244 file_open(&fp, t->path, "devices", "r");
245 while (!(file_read_line(&fp, line, sizeof(line)))) {
246 int len;
247
248 genpd->devices = realloc(genpd->devices,
249 sizeof(*(genpd->devices)) * (nr_devices + 1));
250 if (!genpd->devices)
251 continue;
252
253 len = strlen(line);
254 line[len - 1] = '\0';
255 strcpy(genpd->devices[nr_devices], line);
256 nr_devices++;
257 }
258 file_close(&fp);
259
260 file_open(&fp, t->path, "sub_domains", "r");
261 while (!(file_read_line(&fp, line, sizeof(line)))) {
262 int len;
263
264 genpd->sub_domains = realloc(genpd->sub_domains,
265 sizeof(*(genpd->sub_domains)) * (nr_sub_domains + 1));
266 if (!genpd->sub_domains)
267 continue;
268
269 len = strlen(line);
270 line[len - 1] = '\0';
271 strcpy(genpd->sub_domains[nr_sub_domains], line);
272 nr_sub_domains++;
273 }
274
275 genpd->nr_states = nr_states;
276 genpd->nr_devices = nr_devices;
277 genpd->nr_subdomains = nr_sub_domains;
278
279 return 0;
280}
281
282static int read_genpd_info(struct tree *t)
283{
284 return tree_for_each(t, read_genpd_cb, NULL);
285}
286
287static int fill_genpd_cb(struct tree *t, void *data)
288{
289 struct genpd_info *genpd;
290
291 genpd = genpd_alloc();
292 if (!genpd) {
293 printf("error: unable to allocate memory for genpd\n");
294 return -1;
295 }
296
297 t->private = genpd;
298
299 return read_genpd_cb(t, data);
300}
301
302static int fill_genpd_tree(void)
303{
304 return tree_for_each(genpd_tree, fill_genpd_cb, NULL);
305}
306
307static int genpd_info_load(void)
308{
309 if (genpd_tree)
310 return 0;
311
312 genpd_tree = tree_load(DEBUGFS_GENPD, genpd_filter_cb, false);
313 if (!genpd_tree)
314 return -1;
315
316 if (fill_genpd_tree())
317 return -1;
318
319 return 0;
320}
321
322int genpd_dump(void)
323{
324 if (!genpd_tree)
325 genpd_info_load();
326 else
327 read_genpd_info(genpd_tree);
328
329 return tree_for_each(genpd_tree, genpd_dump_cb, NULL);
330
331 return 0;
332}
333
334static int genpd_display(bool refresh)
335{
336 if (genpd_info_load()) {
337 display_print_error(GENPD, 0, "Failed to read genpd info");
338 return 0;
339 }
340
341 if (refresh && read_genpd_info(genpd_tree))
342 return -1;
343
344 return genpd_print_info(genpd_tree);
345}
346
347static struct display_ops genpd_ops = {
348 .display = genpd_display,
349};
350
351int genpd_init(struct powerdebug_options *options)
352{
353 if (!(options->flags & GENPD_OPTION))
354 return 0;
355
356 return display_register(GENPD, &genpd_ops);
357}
358