source: mainline/uspace/app/top/top.c@ 0b07acd

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

statistics: provide resident (actually used) memory of tasks

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