source: mainline/uspace/app/top/top.c@ 3a8370c

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

do not provide general access to kernel headers from uspace, only allow specific headers to be accessed or shared
externalize headers which serve as kernel/uspace API/ABI into a special tree

  • Property mode set to 100644
File size: 11.5 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 top
31 * @brief Top utility.
32 * @{
33 */
34/**
35 * @file
36 */
37
38#include <stdio.h>
39#include <stdlib.h>
40#include <unistd.h>
41#include <task.h>
42#include <thread.h>
43#include <sys/time.h>
44#include <errno.h>
45#include <sort.h>
46#include "screen.h"
47#include "top.h"
48
49#define NAME "top"
50
51#define UPDATE_INTERVAL 1
52
53#define DAY 86400
54#define HOUR 3600
55#define MINUTE 60
56
57op_mode_t op_mode = OP_TASKS;
58sort_mode_t sort_mode = SORT_TASK_CYCLES;
59bool excs_all = false;
60
61static const char *read_data(data_t *target)
62{
63 /* Initialize data */
64 target->load = NULL;
65 target->cpus = NULL;
66 target->cpus_perc = NULL;
67 target->tasks = NULL;
68 target->tasks_perc = NULL;
69 target->tasks_map = NULL;
70 target->threads = NULL;
71 target->exceptions = NULL;
72 target->exceptions_perc = NULL;
73 target->physmem = NULL;
74 target->ucycles_diff = NULL;
75 target->kcycles_diff = NULL;
76 target->ecycles_diff = NULL;
77 target->ecount_diff = NULL;
78
79 /* Get current time */
80 struct timeval time;
81 if (gettimeofday(&time, NULL) != EOK)
82 return "Cannot get time of day";
83
84 target->hours = (time.tv_sec % DAY) / HOUR;
85 target->minutes = (time.tv_sec % HOUR) / MINUTE;
86 target->seconds = time.tv_sec % MINUTE;
87
88 /* Get uptime */
89 sysarg_t uptime = stats_get_uptime();
90 target->udays = uptime / DAY;
91 target->uhours = (uptime % DAY) / HOUR;
92 target->uminutes = (uptime % HOUR) / MINUTE;
93 target->useconds = uptime % MINUTE;
94
95 /* Get load */
96 target->load = stats_get_load(&(target->load_count));
97 if (target->load == NULL)
98 return "Cannot get system load";
99
100 /* Get CPUs */
101 target->cpus = stats_get_cpus(&(target->cpus_count));
102 if (target->cpus == NULL)
103 return "Cannot get CPUs";
104
105 target->cpus_perc =
106 (perc_cpu_t *) calloc(target->cpus_count, sizeof(perc_cpu_t));
107 if (target->cpus_perc == NULL)
108 return "Not enough memory for CPU utilization";
109
110 /* Get tasks */
111 target->tasks = stats_get_tasks(&(target->tasks_count));
112 if (target->tasks == NULL)
113 return "Cannot get tasks";
114
115 target->tasks_perc =
116 (perc_task_t *) calloc(target->tasks_count, sizeof(perc_task_t));
117 if (target->tasks_perc == NULL)
118 return "Not enough memory for task utilization";
119
120 target->tasks_map =
121 (size_t *) calloc(target->tasks_count, sizeof(size_t));
122 if (target->tasks_map == NULL)
123 return "Not enough memory for task map";
124
125 /* Get threads */
126 target->threads = stats_get_threads(&(target->threads_count));
127 if (target->threads == NULL)
128 return "Cannot get threads";
129
130 /* Get Exceptions */
131 target->exceptions = stats_get_exceptions(&(target->exceptions_count));
132 if (target->exceptions == NULL)
133 return "Cannot get exceptions";
134
135 target->exceptions_perc =
136 (perc_exc_t *) calloc(target->exceptions_count, sizeof(perc_exc_t));
137 if (target->exceptions_perc == NULL)
138 return "Not enough memory for exception utilization";
139
140 /* Get physical memory */
141 target->physmem = stats_get_physmem();
142 if (target->physmem == NULL)
143 return "Cannot get physical memory";
144
145 target->ucycles_diff = calloc(target->tasks_count,
146 sizeof(uint64_t));
147 if (target->ucycles_diff == NULL)
148 return "Not enough memory for user utilization";
149
150 /* Allocate memory for computed values */
151 target->kcycles_diff = calloc(target->tasks_count,
152 sizeof(uint64_t));
153 if (target->kcycles_diff == NULL)
154 return "Not enough memory for kernel utilization";
155
156 target->ecycles_diff = calloc(target->exceptions_count,
157 sizeof(uint64_t));
158 if (target->ecycles_diff == NULL)
159 return "Not enough memory for exception cycles utilization";
160
161 target->ecount_diff = calloc(target->exceptions_count,
162 sizeof(uint64_t));
163 if (target->ecount_diff == NULL)
164 return "Not enough memory for exception count utilization";
165
166 return NULL;
167}
168
169/** Computes percentage differencies from old_data to new_data
170 *
171 * @param old_data Pointer to old data strucutre.
172 * @param new_data Pointer to actual data where percetages are stored.
173 *
174 */
175static void compute_percentages(data_t *old_data, data_t *new_data)
176{
177 /* For each CPU: Compute total cycles and divide it between
178 user and kernel */
179
180 size_t i;
181 for (i = 0; i < new_data->cpus_count; i++) {
182 uint64_t idle =
183 new_data->cpus[i].idle_cycles - old_data->cpus[i].idle_cycles;
184 uint64_t busy =
185 new_data->cpus[i].busy_cycles - old_data->cpus[i].busy_cycles;
186 uint64_t sum = idle + busy;
187
188 FRACTION_TO_FLOAT(new_data->cpus_perc[i].idle, idle * 100, sum);
189 FRACTION_TO_FLOAT(new_data->cpus_perc[i].busy, busy * 100, sum);
190 }
191
192 /* For all tasks compute sum and differencies of all cycles */
193
194 uint64_t virtmem_total = 0;
195 uint64_t resmem_total = 0;
196 uint64_t ucycles_total = 0;
197 uint64_t kcycles_total = 0;
198
199 for (i = 0; i < new_data->tasks_count; i++) {
200 /* Match task with the previous instance */
201
202 bool found = false;
203 size_t j;
204 for (j = 0; j < old_data->tasks_count; j++) {
205 if (new_data->tasks[i].task_id == old_data->tasks[j].task_id) {
206 found = true;
207 break;
208 }
209 }
210
211 if (!found) {
212 /* This is newly borned task, ignore it */
213 new_data->ucycles_diff[i] = 0;
214 new_data->kcycles_diff[i] = 0;
215 continue;
216 }
217
218 new_data->ucycles_diff[i] =
219 new_data->tasks[i].ucycles - old_data->tasks[j].ucycles;
220 new_data->kcycles_diff[i] =
221 new_data->tasks[i].kcycles - old_data->tasks[j].kcycles;
222
223 virtmem_total += new_data->tasks[i].virtmem;
224 resmem_total += new_data->tasks[i].resmem;
225 ucycles_total += new_data->ucycles_diff[i];
226 kcycles_total += new_data->kcycles_diff[i];
227 }
228
229 /* For each task compute percential change */
230
231 for (i = 0; i < new_data->tasks_count; i++) {
232 FRACTION_TO_FLOAT(new_data->tasks_perc[i].virtmem,
233 new_data->tasks[i].virtmem * 100, virtmem_total);
234 FRACTION_TO_FLOAT(new_data->tasks_perc[i].resmem,
235 new_data->tasks[i].resmem * 100, resmem_total);
236 FRACTION_TO_FLOAT(new_data->tasks_perc[i].ucycles,
237 new_data->ucycles_diff[i] * 100, ucycles_total);
238 FRACTION_TO_FLOAT(new_data->tasks_perc[i].kcycles,
239 new_data->kcycles_diff[i] * 100, kcycles_total);
240 }
241
242 /* For all exceptions compute sum and differencies of cycles */
243
244 uint64_t ecycles_total = 0;
245 uint64_t ecount_total = 0;
246
247 for (i = 0; i < new_data->exceptions_count; i++) {
248 /*
249 * March exception with the previous instance.
250 * This is quite paranoid since exceptions do not
251 * usually disappear, but it does not hurt.
252 */
253
254 bool found = false;
255 size_t j;
256 for (j = 0; j < old_data->exceptions_count; j++) {
257 if (new_data->exceptions[i].id == old_data->exceptions[j].id) {
258 found = true;
259 break;
260 }
261 }
262
263 if (!found) {
264 /* This is a new exception, ignore it */
265 new_data->ecycles_diff[i] = 0;
266 new_data->ecount_diff[i] = 0;
267 continue;
268 }
269
270 new_data->ecycles_diff[i] =
271 new_data->exceptions[i].cycles - old_data->exceptions[j].cycles;
272 new_data->ecount_diff[i] =
273 new_data->exceptions[i].count - old_data->exceptions[i].count;
274
275 ecycles_total += new_data->ecycles_diff[i];
276 ecount_total += new_data->ecount_diff[i];
277 }
278
279 /* For each exception compute percential change */
280
281 for (i = 0; i < new_data->exceptions_count; i++) {
282 FRACTION_TO_FLOAT(new_data->exceptions_perc[i].cycles,
283 new_data->ecycles_diff[i] * 100, ecycles_total);
284 FRACTION_TO_FLOAT(new_data->exceptions_perc[i].count,
285 new_data->ecount_diff[i] * 100, ecount_total);
286 }
287}
288
289static int cmp_data(void *a, void *b, void *arg)
290{
291 size_t ia = *((size_t *) a);
292 size_t ib = *((size_t *) b);
293 data_t *data = (data_t *) arg;
294
295 uint64_t acycles = data->ucycles_diff[ia] + data->kcycles_diff[ia];
296 uint64_t bcycles = data->ucycles_diff[ib] + data->kcycles_diff[ib];
297
298 if (acycles > bcycles)
299 return -1;
300
301 if (acycles < bcycles)
302 return 1;
303
304 return 0;
305}
306
307static void sort_data(data_t *data)
308{
309 size_t i;
310
311 for (i = 0; i < data->tasks_count; i++)
312 data->tasks_map[i] = i;
313
314 qsort((void *) data->tasks_map, data->tasks_count,
315 sizeof(size_t), cmp_data, (void *) data);
316}
317
318static void free_data(data_t *target)
319{
320 if (target->load != NULL)
321 free(target->load);
322
323 if (target->cpus != NULL)
324 free(target->cpus);
325
326 if (target->cpus_perc != NULL)
327 free(target->cpus_perc);
328
329 if (target->tasks != NULL)
330 free(target->tasks);
331
332 if (target->tasks_perc != NULL)
333 free(target->tasks_perc);
334
335 if (target->threads != NULL)
336 free(target->threads);
337
338 if (target->exceptions != NULL)
339 free(target->exceptions);
340
341 if (target->exceptions_perc != NULL)
342 free(target->exceptions_perc);
343
344 if (target->physmem != NULL)
345 free(target->physmem);
346
347 if (target->ucycles_diff != NULL)
348 free(target->ucycles_diff);
349
350 if (target->kcycles_diff != NULL)
351 free(target->kcycles_diff);
352
353 if (target->ecycles_diff != NULL)
354 free(target->ecycles_diff);
355
356 if (target->ecount_diff != NULL)
357 free(target->ecount_diff);
358}
359
360int main(int argc, char *argv[])
361{
362 data_t data;
363 data_t data_prev;
364 const char *ret = NULL;
365
366 screen_init();
367 printf("Reading initial data...\n");
368
369 if ((ret = read_data(&data_prev)) != NULL)
370 goto out;
371
372 /* Compute some rubbish to have initialised values */
373 compute_percentages(&data_prev, &data_prev);
374
375 /* And paint screen until death */
376 while (true) {
377 int c = tgetchar(UPDATE_INTERVAL);
378 if (c < 0) {
379 if ((ret = read_data(&data)) != NULL) {
380 free_data(&data);
381 goto out;
382 }
383
384 compute_percentages(&data_prev, &data);
385 sort_data(&data);
386 print_data(&data);
387 free_data(&data_prev);
388 data_prev = data;
389
390 continue;
391 }
392
393 switch (c) {
394 case 't':
395 print_warning("Showing task statistics");
396 op_mode = OP_TASKS;
397 break;
398 case 'i':
399 print_warning("Showing IPC statistics");
400 op_mode = OP_IPC;
401 break;
402 case 'e':
403 print_warning("Showing exception statistics");
404 op_mode = OP_EXCS;
405 break;
406 case 'h':
407 print_warning("Showing help");
408 op_mode = OP_HELP;
409 break;
410 case 'q':
411 goto out;
412 case 'a':
413 if (op_mode == OP_EXCS) {
414 excs_all = !excs_all;
415 if (excs_all)
416 print_warning("Showing all exceptions");
417 else
418 print_warning("Showing only hot exceptions");
419 break;
420 }
421 default:
422 print_warning("Unknown command \"%c\", use \"h\" for help", c);
423 break;
424 }
425 }
426
427out:
428 screen_done();
429 free_data(&data_prev);
430
431 if (ret != NULL) {
432 fprintf(stderr, "%s: %s\n", NAME, ret);
433 return 1;
434 }
435
436 return 0;
437}
438
439/** @}
440 */
Note: See TracBrowser for help on using the repository browser.