source: mainline/uspace/app/stats/stats.c@ a6302ae

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a6302ae was a6302ae, checked in by Martin Decky <martin@…>, 6 years ago

add basic support for IPC statistics

Dumping of phone connections is supported right now.

  • Property mode set to 100644
File size: 8.6 KB
Line 
1/*
2 * Copyright (c) 2010 Stanislav Kozina
3 * Copyright (c) 2010 Martin Decky
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/** @addtogroup stats
31 * @{
32 */
33/**
34 * @file
35 */
36
37#include <stdio.h>
38#include <task.h>
39#include <stats.h>
40#include <errno.h>
41#include <stdlib.h>
42#include <stdlib.h>
43#include <inttypes.h>
44#include <stdbool.h>
45#include <str.h>
46#include <arg_parse.h>
47
48#define NAME "stats"
49
50#define DAY 86400
51#define HOUR 3600
52#define MINUTE 60
53
54typedef enum {
55 LIST_TASKS,
56 LIST_THREADS,
57 LIST_IPCCS,
58 LIST_CPUS,
59 LIST_LOAD,
60 LIST_UPTIME
61} list_toggle_t;
62
63static void list_tasks(void)
64{
65 size_t count;
66 stats_task_t *stats_tasks = stats_get_tasks(&count);
67
68 if (stats_tasks == NULL) {
69 fprintf(stderr, "%s: Unable to get tasks\n", NAME);
70 return;
71 }
72
73 printf("[taskid] [thrds] [resident] [virtual] [ucycles]"
74 " [kcycles] [name\n");
75
76 for (size_t i = 0; i < count; i++) {
77 uint64_t resmem;
78 uint64_t virtmem;
79 uint64_t ucycles;
80 uint64_t kcycles;
81 const char *resmem_suffix;
82 const char *virtmem_suffix;
83 char usuffix;
84 char ksuffix;
85
86 bin_order_suffix(stats_tasks[i].resmem, &resmem, &resmem_suffix, true);
87 bin_order_suffix(stats_tasks[i].virtmem, &virtmem, &virtmem_suffix, true);
88 order_suffix(stats_tasks[i].ucycles, &ucycles, &usuffix);
89 order_suffix(stats_tasks[i].kcycles, &kcycles, &ksuffix);
90
91 printf("%-8" PRIu64 " %7zu %7" PRIu64 "%s %6" PRIu64 "%s"
92 " %8" PRIu64 "%c %8" PRIu64 "%c %s\n",
93 stats_tasks[i].task_id, stats_tasks[i].threads,
94 resmem, resmem_suffix, virtmem, virtmem_suffix,
95 ucycles, usuffix, kcycles, ksuffix, stats_tasks[i].name);
96 }
97
98 free(stats_tasks);
99}
100
101static void list_threads(task_id_t task_id, bool all)
102{
103 size_t count;
104 stats_thread_t *stats_threads = stats_get_threads(&count);
105
106 if (stats_threads == NULL) {
107 fprintf(stderr, "%s: Unable to get threads\n", NAME);
108 return;
109 }
110
111 printf("[taskid] [threadid] [state ] [prio] [cpu ] [ucycles] [kcycles]\n");
112
113 for (size_t i = 0; i < count; i++) {
114 if ((all) || (stats_threads[i].task_id == task_id)) {
115 uint64_t ucycles, kcycles;
116 char usuffix, ksuffix;
117
118 order_suffix(stats_threads[i].ucycles, &ucycles, &usuffix);
119 order_suffix(stats_threads[i].kcycles, &kcycles, &ksuffix);
120
121 printf("%-8" PRIu64 " %-10" PRIu64 " %-8s %6d ",
122 stats_threads[i].task_id, stats_threads[i].thread_id,
123 thread_get_state(stats_threads[i].state),
124 stats_threads[i].priority);
125
126 if (stats_threads[i].on_cpu)
127 printf("%6u ", stats_threads[i].cpu);
128 else
129 printf("(none) ");
130
131 printf("%8" PRIu64 "%c %8" PRIu64 "%c\n",
132 ucycles, usuffix, kcycles, ksuffix);
133 }
134 }
135
136 free(stats_threads);
137}
138
139static void list_ipccs(task_id_t task_id, bool all)
140{
141 size_t count;
142 stats_ipcc_t *stats_ipccs = stats_get_ipccs(&count);
143
144 if (stats_ipccs == NULL) {
145 fprintf(stderr, "%s: Unable to get IPC connections\n", NAME);
146 return;
147 }
148
149 printf("[caller] [callee]\n");
150
151 for (size_t i = 0; i < count; i++) {
152 if ((all) || (stats_ipccs[i].caller == task_id)) {
153 printf("%-8" PRIu64 " %-8" PRIu64 "\n",
154 stats_ipccs[i].caller, stats_ipccs[i].callee);
155 }
156 }
157
158 free(stats_ipccs);
159}
160
161static void list_cpus(void)
162{
163 size_t count;
164 stats_cpu_t *cpus = stats_get_cpus(&count);
165
166 if (cpus == NULL) {
167 fprintf(stderr, "%s: Unable to get CPU statistics\n", NAME);
168 return;
169 }
170
171 printf("[id] [MHz ] [busy cycles] [idle cycles]\n");
172
173 for (size_t i = 0; i < count; i++) {
174 printf("%-4u ", cpus[i].id);
175 if (cpus[i].active) {
176 uint64_t bcycles, icycles;
177 char bsuffix, isuffix;
178
179 order_suffix(cpus[i].busy_cycles, &bcycles, &bsuffix);
180 order_suffix(cpus[i].idle_cycles, &icycles, &isuffix);
181
182 printf("%10" PRIu16 " %12" PRIu64 "%c %12" PRIu64 "%c\n",
183 cpus[i].frequency_mhz, bcycles, bsuffix,
184 icycles, isuffix);
185 } else
186 printf("inactive\n");
187 }
188
189 free(cpus);
190}
191
192static void print_load(void)
193{
194 size_t count;
195 load_t *load = stats_get_load(&count);
196
197 if (load == NULL) {
198 fprintf(stderr, "%s: Unable to get load\n", NAME);
199 return;
200 }
201
202 printf("%s: Load average: ", NAME);
203
204 for (size_t i = 0; i < count; i++) {
205 if (i > 0)
206 printf(" ");
207
208 stats_print_load_fragment(load[i], 2);
209 }
210
211 printf("\n");
212
213 free(load);
214}
215
216static void print_uptime(void)
217{
218 struct timespec uptime;
219 getuptime(&uptime);
220
221 printf("%s: Up %lld days, %lld hours, %lld minutes, %lld seconds\n",
222 NAME, uptime.tv_sec / DAY, (uptime.tv_sec % DAY) / HOUR,
223 (uptime.tv_sec % HOUR) / MINUTE, uptime.tv_sec % MINUTE);
224}
225
226static void usage(const char *name)
227{
228 printf(
229 "Usage: %s [-t task_id] [-i task_id] [-at] [-ai] [-c] [-l] [-u]\n"
230 "\n"
231 "Options:\n"
232 "\t-t task_id\n"
233 "\t--task=task_id\n"
234 "\t\tList threads of the given task\n"
235 "\n"
236 "\t-i task_id\n"
237 "\t--ipcc=task_id\n"
238 "\t\tList IPC connections of the given task\n"
239 "\n"
240 "\t-at\n"
241 "\t--all-threads\n"
242 "\t\tList all threads\n"
243 "\n"
244 "\t-ai\n"
245 "\t--all-ipccs\n"
246 "\t\tList all IPC connections\n"
247 "\n"
248 "\t-c\n"
249 "\t--cpus\n"
250 "\t\tList CPUs\n"
251 "\n"
252 "\t-l\n"
253 "\t--load\n"
254 "\t\tPrint system load\n"
255 "\n"
256 "\t-u\n"
257 "\t--uptime\n"
258 "\t\tPrint system uptime\n"
259 "\n"
260 "\t-h\n"
261 "\t--help\n"
262 "\t\tPrint this usage information\n"
263 "\n"
264 "Without any options all tasks are listed\n",
265 name);
266}
267
268int main(int argc, char *argv[])
269{
270 list_toggle_t list_toggle = LIST_TASKS;
271 bool toggle_all = false;
272 task_id_t task_id = 0;
273
274 for (int i = 1; i < argc; i++) {
275 int off;
276
277 /* Usage */
278 if ((off = arg_parse_short_long(argv[i], "-h", "--help")) != -1) {
279 usage(argv[0]);
280 return 0;
281 }
282
283 /* All IPC connections */
284 if ((off = arg_parse_short_long(argv[i], "-ai", "--all-ipccs")) != -1) {
285 list_toggle = LIST_IPCCS;
286 toggle_all = true;
287 continue;
288 }
289
290 /* All threads */
291 if ((off = arg_parse_short_long(argv[i], "-at", "--all-threads")) != -1) {
292 list_toggle = LIST_THREADS;
293 toggle_all = true;
294 continue;
295 }
296
297 /* IPC connections */
298 if ((off = arg_parse_short_long(argv[i], "-i", "--ipcc=")) != -1) {
299 // TODO: Support for 64b range
300 int tmp;
301 errno_t ret = arg_parse_int(argc, argv, &i, &tmp, off);
302 if (ret != EOK) {
303 printf("%s: Malformed task id '%s'\n", NAME, argv[i]);
304 return -1;
305 }
306
307 task_id = tmp;
308
309 list_toggle = LIST_IPCCS;
310 continue;
311 }
312
313 /* Tasks */
314 if ((off = arg_parse_short_long(argv[i], "-t", "--task=")) != -1) {
315 // TODO: Support for 64b range
316 int tmp;
317 errno_t ret = arg_parse_int(argc, argv, &i, &tmp, off);
318 if (ret != EOK) {
319 printf("%s: Malformed task id '%s'\n", NAME, argv[i]);
320 return -1;
321 }
322
323 task_id = tmp;
324
325 list_toggle = LIST_THREADS;
326 continue;
327 }
328
329 /* CPUs */
330 if ((off = arg_parse_short_long(argv[i], "-c", "--cpus")) != -1) {
331 list_toggle = LIST_CPUS;
332 continue;
333 }
334
335 /* Load */
336 if ((off = arg_parse_short_long(argv[i], "-l", "--load")) != -1) {
337 list_toggle = LIST_LOAD;
338 continue;
339 }
340
341 /* Uptime */
342 if ((off = arg_parse_short_long(argv[i], "-u", "--uptime")) != -1) {
343 list_toggle = LIST_UPTIME;
344 continue;
345 }
346 }
347
348 switch (list_toggle) {
349 case LIST_TASKS:
350 list_tasks();
351 break;
352 case LIST_THREADS:
353 list_threads(task_id, toggle_all);
354 break;
355 case LIST_IPCCS:
356 list_ipccs(task_id, toggle_all);
357 break;
358 case LIST_CPUS:
359 list_cpus();
360 break;
361 case LIST_LOAD:
362 print_load();
363 break;
364 case LIST_UPTIME:
365 print_uptime();
366 break;
367 }
368
369 return 0;
370}
371
372/** @}
373 */
Note: See TracBrowser for help on using the repository browser.