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

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

return value from tgetchar() must be "int" ("char" is unsigned on some platforms)

  • Property mode set to 100644
File size: 7.7 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>
[5c058d50]46#include "screen.h"
47#include "input.h"
[79edc36]48#include "top.h"
49
[dec16a2]50#define NAME "top"
[79edc36]51
[dec16a2]52#define UPDATE_INTERVAL 1
53
54#define DAY 86400
55#define HOUR 3600
56#define MINUTE 60
[79edc36]57
[bdfd3c97]58int operation_type;
59
[dec16a2]60static const char *read_data(data_t *target)
[79edc36]61{
[dec16a2]62 /* Initialize data */
63 target->load = NULL;
64 target->cpus = NULL;
65 target->cpus_perc = NULL;
66 target->tasks = NULL;
67 target->tasks_perc = NULL;
68 target->threads = NULL;
69 target->physmem = NULL;
70
71 /* Get current time */
[79edc36]72 struct timeval time;
[dec16a2]73 if (gettimeofday(&time, NULL) != EOK)
74 return "Cannot get time of day";
75
[79edc36]76 target->hours = (time.tv_sec % DAY) / HOUR;
77 target->minutes = (time.tv_sec % HOUR) / MINUTE;
78 target->seconds = time.tv_sec % MINUTE;
[dec16a2]79
80 /* Get uptime */
81 sysarg_t uptime = stats_get_uptime();
82 target->udays = uptime / DAY;
83 target->uhours = (uptime % DAY) / HOUR;
84 target->uminutes = (uptime % HOUR) / MINUTE;
85 target->useconds = uptime % MINUTE;
86
87 /* Get load */
88 target->load = stats_get_load(&(target->load_count));
89 if (target->load == NULL)
90 return "Cannot get system load";
91
92 /* Get CPUs */
93 target->cpus = stats_get_cpus(&(target->cpus_count));
94 if (target->cpus == NULL)
95 return "Cannot get CPUs";
96
97 target->cpus_perc =
98 (perc_cpu_t *) calloc(target->cpus_count, sizeof(perc_cpu_t));
99 if (target->cpus_perc == NULL)
100 return "Not enough memory for CPU utilization";
101
102 /* Get tasks */
103 target->tasks = stats_get_tasks(&(target->tasks_count));
104 if (target->tasks == NULL)
105 return "Cannot get tasks";
106
107 target->tasks_perc =
108 (perc_task_t *) calloc(target->tasks_count, sizeof(perc_task_t));
109 if (target->tasks_perc == NULL)
110 return "Not enough memory for task utilization";
111
112 /* Get threads */
113 target->threads = stats_get_threads(&(target->threads_count));
114 if (target->threads == NULL)
115 return "Cannot get threads";
116
117 /* Get physical memory */
118 target->physmem = stats_get_physmem();
119 if (target->physmem == NULL)
120 return "Cannot get physical memory";
121
122 return NULL;
[8b2aba5]123}
124
[ee35ba0b]125/** Computes percentage differencies from old_data to new_data
126 *
[dec16a2]127 * @param old_data Pointer to old data strucutre.
128 * @param new_data Pointer to actual data where percetages are stored.
[ee35ba0b]129 *
130 */
[dec16a2]131static const char *compute_percentages(data_t *old_data, data_t *new_data)
[ee35ba0b]132{
[dec16a2]133 /* Allocate memory */
134
135 uint64_t *ucycles_diff = calloc(new_data->tasks_count, sizeof(uint64_t));
136 if (ucycles_diff == NULL)
137 return "Not enough memory for user utilization";
138
139 uint64_t *kcycles_diff = calloc(new_data->tasks_count, sizeof(uint64_t));
140 if (kcycles_diff == NULL) {
141 free(ucycles_diff);
142 return "Not enough memory for kernel utilization";
143 }
144
145 /* For each CPU: Compute total ticks and divide it between
146 user and kernel */
147
148 size_t i;
149 for (i = 0; i < new_data->cpus_count; i++) {
150 uint64_t idle =
151 new_data->cpus[i].idle_ticks - old_data->cpus[i].idle_ticks;
152 uint64_t busy =
153 new_data->cpus[i].busy_ticks - old_data->cpus[i].busy_ticks;
[ee35ba0b]154 uint64_t sum = idle + busy;
[dec16a2]155
156 FRACTION_TO_FLOAT(new_data->cpus_perc[i].idle, idle * 100, sum);
157 FRACTION_TO_FLOAT(new_data->cpus_perc[i].busy, busy * 100, sum);
[ee35ba0b]158 }
[dec16a2]159
[452268a1]160 /* For all tasks compute sum and differencies of all cycles */
[dec16a2]161
162 uint64_t virtmem_total = 1; /* Must NOT be zero */
163 uint64_t ucycles_total = 1; /* Must NOT be zero */
164 uint64_t kcycles_total = 1; /* Must NOT be zero */
165
166 for (i = 0; i < new_data->tasks_count; i++) {
167 /* Match task with the previous instance */
168
169 bool found = false;
170 size_t j;
171 for (j = 0; j < old_data->tasks_count; j++) {
172 if (new_data->tasks[i].task_id == old_data->tasks[j].task_id) {
173 found = true;
174 break;
175 }
176 }
177
178 if (!found) {
[452268a1]179 /* This is newly borned task, ignore it */
180 ucycles_diff[i] = 0;
181 kcycles_diff[i] = 0;
182 continue;
183 }
[dec16a2]184
185 ucycles_diff[i] =
186 new_data->tasks[i].ucycles - old_data->tasks[j].ucycles;
187 kcycles_diff[i] =
188 new_data->tasks[i].kcycles - old_data->tasks[j].kcycles;
189
190 virtmem_total += new_data->tasks[i].virtmem;
[452268a1]191 ucycles_total += ucycles_diff[i];
192 kcycles_total += kcycles_diff[i];
193 }
[dec16a2]194
195 /* For each task: Compute percential change */
196
197 for (i = 0; i < new_data->tasks_count; i++) {
198 FRACTION_TO_FLOAT(new_data->tasks_perc[i].virtmem,
199 new_data->tasks[i].virtmem * 100, virtmem_total);
200 FRACTION_TO_FLOAT(new_data->tasks_perc[i].ucycles,
201 ucycles_diff[i] * 100, ucycles_total);
202 FRACTION_TO_FLOAT(new_data->tasks_perc[i].kcycles,
203 kcycles_diff[i] * 100, kcycles_total);
[452268a1]204 }
[dec16a2]205
206 /* Cleanup */
207
[452268a1]208 free(ucycles_diff);
209 free(kcycles_diff);
[dec16a2]210
211 return NULL;
[ee35ba0b]212}
213
[8b2aba5]214static void free_data(data_t *target)
215{
[dec16a2]216 if (target->load != NULL)
217 free(target->load);
218
219 if (target->cpus != NULL)
220 free(target->cpus);
221
222 if (target->cpus_perc != NULL)
223 free(target->cpus_perc);
224
225 if (target->tasks != NULL)
226 free(target->tasks);
227
228 if (target->tasks_perc != NULL)
229 free(target->tasks_perc);
230
231 if (target->threads != NULL)
232 free(target->threads);
233
234 if (target->physmem != NULL)
235 free(target->physmem);
[8b2aba5]236}
237
[5c058d50]238int main(int argc, char *argv[])
239{
[dec16a2]240 data_t data;
241 data_t data_prev;
242 const char *ret = NULL;
243
[ee35ba0b]244 screen_init();
[79edc36]245 printf("Reading initial data...\n");
[dec16a2]246
247 if ((ret = read_data(&data_prev)) != NULL)
248 goto out;
249
[ee35ba0b]250 /* Compute some rubbish to have initialised values */
[dec16a2]251 if ((ret = compute_percentages(&data_prev, &data_prev)) != NULL)
252 goto out;
253
254 /* And paint screen until death */
[bdfd3c97]255 operation_type = OP_TASKS;
[5c058d50]256 while (true) {
[9e05055]257 int c = tgetchar(UPDATE_INTERVAL);
[5c058d50]258 if (c < 0) {
[dec16a2]259 if ((ret = read_data(&data)) != NULL) {
260 free_data(&data);
261 goto out;
262 }
263
264 if ((ret = compute_percentages(&data_prev, &data)) != NULL) {
265 free_data(&data);
266 goto out;
267 }
268
269 print_data(&data);
270 free_data(&data_prev);
271 data_prev = data;
272
[5c058d50]273 continue;
274 }
[dec16a2]275
[5c058d50]276 switch (c) {
277 case 'q':
[dec16a2]278 goto out;
[bdfd3c97]279 case 'i':
[dec16a2]280 print_warning("Showing IPC statistics");
[bdfd3c97]281 operation_type = OP_IPC;
282 break;
283 case 't':
[dec16a2]284 print_warning("Showing task statistics");
[bdfd3c97]285 operation_type = OP_TASKS;
286 break;
[5c058d50]287 default:
[dec16a2]288 print_warning("Unknown command: %c", c);
[5c058d50]289 break;
290 }
291 }
[dec16a2]292
293out:
294 screen_done();
295 free_data(&data_prev);
296
297 if (ret != NULL) {
298 fprintf(stderr, "%s: %s\n", NAME, ret);
299 return 1;
300 }
301
[5c058d50]302 return 0;
303}
304
305/** @}
306 */
Note: See TracBrowser for help on using the repository browser.