source: mainline/uspace/app/top/top.c@ e9c02b7

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

new async framework with integrated exchange tracking

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