top.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2010 Stanislav Kozina
00003  * Copyright (c) 2010 Martin Decky
00004  * All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  *
00010  * - Redistributions of source code must retain the above copyright
00011  *   notice, this list of conditions and the following disclaimer.
00012  * - Redistributions in binary form must reproduce the above copyright
00013  *   notice, this list of conditions and the following disclaimer in the
00014  *   documentation and/or other materials provided with the distribution.
00015  * - The name of the author may not be used to endorse or promote products
00016  *   derived from this software without specific prior written permission.
00017  *
00018  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00019  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00020  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00021  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00022  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00023  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00024  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00025  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00026  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00027  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00028  */
00029 
00038 #include <stdio.h>
00039 #include <stdlib.h>
00040 #include <unistd.h>
00041 #include <task.h>
00042 #include <thread.h>
00043 #include <sys/time.h>
00044 #include <arch/barrier.h>
00045 #include <errno.h>
00046 #include <sort.h>
00047 #include "screen.h"
00048 #include "input.h"
00049 #include "top.h"
00050 
00051 #define NAME  "top"
00052 
00053 #define UPDATE_INTERVAL  1
00054 
00055 #define DAY     86400
00056 #define HOUR    3600
00057 #define MINUTE  60
00058 
00059 op_mode_t op_mode = OP_TASKS;
00060 sort_mode_t sort_mode = SORT_TASK_CYCLES;
00061 bool excs_all = false;
00062 
00063 static const char *read_data(data_t *target)
00064 {
00065         /* Initialize data */
00066         target->load = NULL;
00067         target->cpus = NULL;
00068         target->cpus_perc = NULL;
00069         target->tasks = NULL;
00070         target->tasks_perc = NULL;
00071         target->tasks_map = NULL;
00072         target->threads = NULL;
00073         target->exceptions = NULL;
00074         target->exceptions_perc = NULL;
00075         target->physmem = NULL;
00076         target->ucycles_diff = NULL;
00077         target->kcycles_diff = NULL;
00078         target->ecycles_diff = NULL;
00079         target->ecount_diff = NULL;
00080         
00081         /* Get current time */
00082         struct timeval time;
00083         if (gettimeofday(&time, NULL) != EOK)
00084                 return "Cannot get time of day";
00085         
00086         target->hours = (time.tv_sec % DAY) / HOUR;
00087         target->minutes = (time.tv_sec % HOUR) / MINUTE;
00088         target->seconds = time.tv_sec % MINUTE;
00089         
00090         /* Get uptime */
00091         sysarg_t uptime = stats_get_uptime();
00092         target->udays = uptime / DAY;
00093         target->uhours = (uptime % DAY) / HOUR;
00094         target->uminutes = (uptime % HOUR) / MINUTE;
00095         target->useconds = uptime % MINUTE;
00096         
00097         /* Get load */
00098         target->load = stats_get_load(&(target->load_count));
00099         if (target->load == NULL)
00100                 return "Cannot get system load";
00101         
00102         /* Get CPUs */
00103         target->cpus = stats_get_cpus(&(target->cpus_count));
00104         if (target->cpus == NULL)
00105                 return "Cannot get CPUs";
00106         
00107         target->cpus_perc =
00108             (perc_cpu_t *) calloc(target->cpus_count, sizeof(perc_cpu_t));
00109         if (target->cpus_perc == NULL)
00110                 return "Not enough memory for CPU utilization";
00111         
00112         /* Get tasks */
00113         target->tasks = stats_get_tasks(&(target->tasks_count));
00114         if (target->tasks == NULL)
00115                 return "Cannot get tasks";
00116         
00117         target->tasks_perc =
00118             (perc_task_t *) calloc(target->tasks_count, sizeof(perc_task_t));
00119         if (target->tasks_perc == NULL)
00120                 return "Not enough memory for task utilization";
00121         
00122         target->tasks_map =
00123             (size_t *) calloc(target->tasks_count, sizeof(size_t));
00124         if (target->tasks_map == NULL)
00125                 return "Not enough memory for task map";
00126         
00127         /* Get threads */
00128         target->threads = stats_get_threads(&(target->threads_count));
00129         if (target->threads == NULL)
00130                 return "Cannot get threads";
00131         
00132         /* Get Exceptions */
00133         target->exceptions = stats_get_exceptions(&(target->exceptions_count));
00134         if (target->exceptions == NULL)
00135                 return "Cannot get exceptions";
00136         
00137         target->exceptions_perc =
00138             (perc_exc_t *) calloc(target->exceptions_count, sizeof(perc_exc_t));
00139         if (target->exceptions_perc == NULL)
00140                 return "Not enough memory for exception utilization";
00141         
00142         /* Get physical memory */
00143         target->physmem = stats_get_physmem();
00144         if (target->physmem == NULL)
00145                 return "Cannot get physical memory";
00146         
00147         target->ucycles_diff = calloc(target->tasks_count,
00148             sizeof(uint64_t));
00149         if (target->ucycles_diff == NULL)
00150                 return "Not enough memory for user utilization";
00151         
00152         /* Allocate memory for computed values */
00153         target->kcycles_diff = calloc(target->tasks_count,
00154             sizeof(uint64_t));
00155         if (target->kcycles_diff == NULL)
00156                 return "Not enough memory for kernel utilization";
00157         
00158         target->ecycles_diff = calloc(target->exceptions_count,
00159             sizeof(uint64_t));
00160         if (target->ecycles_diff == NULL)
00161                 return "Not enough memory for exception cycles utilization";
00162         
00163         target->ecount_diff = calloc(target->exceptions_count,
00164             sizeof(uint64_t));
00165         if (target->ecount_diff == NULL)
00166                 return "Not enough memory for exception count utilization";
00167         
00168         return NULL;
00169 }
00170 
00177 static void compute_percentages(data_t *old_data, data_t *new_data)
00178 {
00179         /* For each CPU: Compute total cycles and divide it between
00180            user and kernel */
00181         
00182         size_t i;
00183         for (i = 0; i < new_data->cpus_count; i++) {
00184                 uint64_t idle =
00185                     new_data->cpus[i].idle_cycles - old_data->cpus[i].idle_cycles;
00186                 uint64_t busy =
00187                     new_data->cpus[i].busy_cycles - old_data->cpus[i].busy_cycles;
00188                 uint64_t sum = idle + busy;
00189                 
00190                 FRACTION_TO_FLOAT(new_data->cpus_perc[i].idle, idle * 100, sum);
00191                 FRACTION_TO_FLOAT(new_data->cpus_perc[i].busy, busy * 100, sum);
00192         }
00193         
00194         /* For all tasks compute sum and differencies of all cycles */
00195         
00196         uint64_t virtmem_total = 0;
00197         uint64_t resmem_total = 0;
00198         uint64_t ucycles_total = 0;
00199         uint64_t kcycles_total = 0;
00200         
00201         for (i = 0; i < new_data->tasks_count; i++) {
00202                 /* Match task with the previous instance */
00203                 
00204                 bool found = false;
00205                 size_t j;
00206                 for (j = 0; j < old_data->tasks_count; j++) {
00207                         if (new_data->tasks[i].task_id == old_data->tasks[j].task_id) {
00208                                 found = true;
00209                                 break;
00210                         }
00211                 }
00212                 
00213                 if (!found) {
00214                         /* This is newly borned task, ignore it */
00215                         new_data->ucycles_diff[i] = 0;
00216                         new_data->kcycles_diff[i] = 0;
00217                         continue;
00218                 }
00219                 
00220                 new_data->ucycles_diff[i] =
00221                     new_data->tasks[i].ucycles - old_data->tasks[j].ucycles;
00222                 new_data->kcycles_diff[i] =
00223                     new_data->tasks[i].kcycles - old_data->tasks[j].kcycles;
00224                 
00225                 virtmem_total += new_data->tasks[i].virtmem;
00226                 resmem_total += new_data->tasks[i].resmem;
00227                 ucycles_total += new_data->ucycles_diff[i];
00228                 kcycles_total += new_data->kcycles_diff[i];
00229         }
00230         
00231         /* For each task compute percential change */
00232         
00233         for (i = 0; i < new_data->tasks_count; i++) {
00234                 FRACTION_TO_FLOAT(new_data->tasks_perc[i].virtmem,
00235                     new_data->tasks[i].virtmem * 100, virtmem_total);
00236                 FRACTION_TO_FLOAT(new_data->tasks_perc[i].resmem,
00237                     new_data->tasks[i].resmem * 100, resmem_total);
00238                 FRACTION_TO_FLOAT(new_data->tasks_perc[i].ucycles,
00239                     new_data->ucycles_diff[i] * 100, ucycles_total);
00240                 FRACTION_TO_FLOAT(new_data->tasks_perc[i].kcycles,
00241                     new_data->kcycles_diff[i] * 100, kcycles_total);
00242         }
00243         
00244         /* For all exceptions compute sum and differencies of cycles */
00245         
00246         uint64_t ecycles_total = 0;
00247         uint64_t ecount_total = 0;
00248         
00249         for (i = 0; i < new_data->exceptions_count; i++) {
00250                 /*
00251                  * March exception with the previous instance.
00252                  * This is quite paranoid since exceptions do not
00253                  * usually disappear, but it does not hurt.
00254                  */
00255                 
00256                 bool found = false;
00257                 size_t j;
00258                 for (j = 0; j < old_data->exceptions_count; j++) {
00259                         if (new_data->exceptions[i].id == old_data->exceptions[j].id) {
00260                                 found = true;
00261                                 break;
00262                         }
00263                 }
00264                 
00265                 if (!found) {
00266                         /* This is a new exception, ignore it */
00267                         new_data->ecycles_diff[i] = 0;
00268                         new_data->ecount_diff[i] = 0;
00269                         continue;
00270                 }
00271                 
00272                 new_data->ecycles_diff[i] =
00273                     new_data->exceptions[i].cycles - old_data->exceptions[j].cycles;
00274                 new_data->ecount_diff[i] =
00275                     new_data->exceptions[i].count - old_data->exceptions[i].count;
00276                 
00277                 ecycles_total += new_data->ecycles_diff[i];
00278                 ecount_total += new_data->ecount_diff[i];
00279         }
00280         
00281         /* For each exception compute percential change */
00282         
00283         for (i = 0; i < new_data->exceptions_count; i++) {
00284                 FRACTION_TO_FLOAT(new_data->exceptions_perc[i].cycles,
00285                     new_data->ecycles_diff[i] * 100, ecycles_total);
00286                 FRACTION_TO_FLOAT(new_data->exceptions_perc[i].count,
00287                     new_data->ecount_diff[i] * 100, ecount_total);
00288         }
00289 }
00290 
00291 static int cmp_data(void *a, void *b, void *arg)
00292 {
00293         size_t ia = *((size_t *) a);
00294         size_t ib = *((size_t *) b);
00295         data_t *data = (data_t *) arg;
00296         
00297         uint64_t acycles = data->ucycles_diff[ia] + data->kcycles_diff[ia];
00298         uint64_t bcycles = data->ucycles_diff[ib] + data->kcycles_diff[ib];
00299         
00300         if (acycles > bcycles)
00301                 return -1;
00302         
00303         if (acycles < bcycles)
00304                 return 1;
00305         
00306         return 0;
00307 }
00308 
00309 static void sort_data(data_t *data)
00310 {
00311         size_t i;
00312         
00313         for (i = 0; i < data->tasks_count; i++)
00314                 data->tasks_map[i] = i;
00315         
00316         qsort((void *) data->tasks_map, data->tasks_count,
00317             sizeof(size_t), cmp_data, (void *) data);
00318 }
00319 
00320 static void free_data(data_t *target)
00321 {
00322         if (target->load != NULL)
00323                 free(target->load);
00324         
00325         if (target->cpus != NULL)
00326                 free(target->cpus);
00327         
00328         if (target->cpus_perc != NULL)
00329                 free(target->cpus_perc);
00330         
00331         if (target->tasks != NULL)
00332                 free(target->tasks);
00333         
00334         if (target->tasks_perc != NULL)
00335                 free(target->tasks_perc);
00336         
00337         if (target->threads != NULL)
00338                 free(target->threads);
00339         
00340         if (target->exceptions != NULL)
00341                 free(target->exceptions);
00342         
00343         if (target->exceptions_perc != NULL)
00344                 free(target->exceptions_perc);
00345         
00346         if (target->physmem != NULL)
00347                 free(target->physmem);
00348         
00349         if (target->ucycles_diff != NULL)
00350                 free(target->ucycles_diff);
00351         
00352         if (target->kcycles_diff != NULL)
00353                 free(target->kcycles_diff);
00354         
00355         if (target->ecycles_diff != NULL)
00356                 free(target->ecycles_diff);
00357         
00358         if (target->ecount_diff != NULL)
00359                 free(target->ecount_diff);
00360 }
00361 
00362 int main(int argc, char *argv[])
00363 {
00364         data_t data;
00365         data_t data_prev;
00366         const char *ret = NULL;
00367         
00368         screen_init();
00369         printf("Reading initial data...\n");
00370         
00371         if ((ret = read_data(&data_prev)) != NULL)
00372                 goto out;
00373         
00374         /* Compute some rubbish to have initialised values */
00375         compute_percentages(&data_prev, &data_prev);
00376         
00377         /* And paint screen until death */
00378         while (true) {
00379                 int c = tgetchar(UPDATE_INTERVAL);
00380                 if (c < 0) {
00381                         if ((ret = read_data(&data)) != NULL) {
00382                                 free_data(&data);
00383                                 goto out;
00384                         }
00385                         
00386                         compute_percentages(&data_prev, &data);
00387                         sort_data(&data);
00388                         print_data(&data);
00389                         free_data(&data_prev);
00390                         data_prev = data;
00391                         
00392                         continue;
00393                 }
00394                 
00395                 switch (c) {
00396                         case 't':
00397                                 print_warning("Showing task statistics");
00398                                 op_mode = OP_TASKS;
00399                                 break;
00400                         case 'i':
00401                                 print_warning("Showing IPC statistics");
00402                                 op_mode = OP_IPC;
00403                                 break;
00404                         case 'e':
00405                                 print_warning("Showing exception statistics");
00406                                 op_mode = OP_EXCS;
00407                                 break;
00408                         case 'h':
00409                                 print_warning("Showing help");
00410                                 op_mode = OP_HELP;
00411                                 break;
00412                         case 'q':
00413                                 goto out;
00414                         case 'a':
00415                                 if (op_mode == OP_EXCS) {
00416                                         excs_all = !excs_all;
00417                                         if (excs_all)
00418                                                 print_warning("Showing all exceptions");
00419                                         else
00420                                                 print_warning("Showing only hot exceptions");
00421                                         break;
00422                                 }
00423                         default:
00424                                 print_warning("Unknown command \"%c\", use \"h\" for help", c);
00425                                 break;
00426                 }
00427         }
00428         
00429 out:
00430         screen_done();
00431         free_data(&data_prev);
00432         
00433         if (ret != NULL) {
00434                 fprintf(stderr, "%s: %s\n", NAME, ret);
00435                 return 1;
00436         }
00437         
00438         return 0;
00439 }
00440 

Generated on Thu Jun 2 07:45:43 2011 for HelenOS/USB by  doxygen 1.4.7