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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since f4f866c was 9e05055, checked in by Martin Decky <martin@…>, 15 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
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 "screen.h"
47#include "input.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
58int operation_type;
59
60static const char *read_data(data_t *target)
61{
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 */
72 struct timeval time;
73 if (gettimeofday(&time, NULL) != EOK)
74 return "Cannot get time of day";
75
76 target->hours = (time.tv_sec % DAY) / HOUR;
77 target->minutes = (time.tv_sec % HOUR) / MINUTE;
78 target->seconds = time.tv_sec % MINUTE;
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;
123}
124
125/** Computes percentage differencies from old_data to new_data
126 *
127 * @param old_data Pointer to old data strucutre.
128 * @param new_data Pointer to actual data where percetages are stored.
129 *
130 */
131static const char *compute_percentages(data_t *old_data, data_t *new_data)
132{
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;
154 uint64_t sum = idle + busy;
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);
158 }
159
160 /* For all tasks compute sum and differencies of all cycles */
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) {
179 /* This is newly borned task, ignore it */
180 ucycles_diff[i] = 0;
181 kcycles_diff[i] = 0;
182 continue;
183 }
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;
191 ucycles_total += ucycles_diff[i];
192 kcycles_total += kcycles_diff[i];
193 }
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);
204 }
205
206 /* Cleanup */
207
208 free(ucycles_diff);
209 free(kcycles_diff);
210
211 return NULL;
212}
213
214static void free_data(data_t *target)
215{
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);
236}
237
238int main(int argc, char *argv[])
239{
240 data_t data;
241 data_t data_prev;
242 const char *ret = NULL;
243
244 screen_init();
245 printf("Reading initial data...\n");
246
247 if ((ret = read_data(&data_prev)) != NULL)
248 goto out;
249
250 /* Compute some rubbish to have initialised values */
251 if ((ret = compute_percentages(&data_prev, &data_prev)) != NULL)
252 goto out;
253
254 /* And paint screen until death */
255 operation_type = OP_TASKS;
256 while (true) {
257 int c = tgetchar(UPDATE_INTERVAL);
258 if (c < 0) {
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
273 continue;
274 }
275
276 switch (c) {
277 case 'q':
278 goto out;
279 case 'i':
280 print_warning("Showing IPC statistics");
281 operation_type = OP_IPC;
282 break;
283 case 't':
284 print_warning("Showing task statistics");
285 operation_type = OP_TASKS;
286 break;
287 default:
288 print_warning("Unknown command: %c", c);
289 break;
290 }
291 }
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
302 return 0;
303}
304
305/** @}
306 */
Note: See TracBrowser for help on using the repository browser.