Index: uspace/app/top/top.c
===================================================================
--- uspace/app/top/top.c	(revision 9e050558f6fae9d4875108d79011987377ff23fe)
+++ uspace/app/top/top.c	(revision 172aad63f50c7c155cabbf9d2f577f1d906b7262)
@@ -44,4 +44,5 @@
 #include <arch/barrier.h>
 #include <errno.h>
+#include <sort.h>
 #include "screen.h"
 #include "input.h"
@@ -56,5 +57,7 @@
 #define MINUTE  60
 
-int operation_type;
+op_mode_t op_mode = OP_TASKS;
+sort_mode_t sort_mode = SORT_TASK_CYCLES;
+bool excs_all = false;
 
 static const char *read_data(data_t *target)
@@ -66,6 +69,13 @@
 	target->tasks = NULL;
 	target->tasks_perc = NULL;
+	target->tasks_map = NULL;
 	target->threads = NULL;
+	target->exceptions = NULL;
+	target->exceptions_perc = NULL;
 	target->physmem = NULL;
+	target->ucycles_diff = NULL;
+	target->kcycles_diff = NULL;
+	target->ecycles_diff = NULL;
+	target->ecount_diff = NULL;
 	
 	/* Get current time */
@@ -110,4 +120,9 @@
 		return "Not enough memory for task utilization";
 	
+	target->tasks_map =
+	    (size_t *) calloc(target->tasks_count, sizeof(size_t));
+	if (target->tasks_map == NULL)
+		return "Not enough memory for task map";
+	
 	/* Get threads */
 	target->threads = stats_get_threads(&(target->threads_count));
@@ -115,8 +130,39 @@
 		return "Cannot get threads";
 	
+	/* Get Exceptions */
+	target->exceptions = stats_get_exceptions(&(target->exceptions_count));
+	if (target->exceptions == NULL)
+		return "Cannot get exceptions";
+	
+	target->exceptions_perc =
+	    (perc_exc_t *) calloc(target->exceptions_count, sizeof(perc_exc_t));
+	if (target->exceptions_perc == NULL)
+		return "Not enough memory for exception utilization";
+	
 	/* Get physical memory */
 	target->physmem = stats_get_physmem();
 	if (target->physmem == NULL)
 		return "Cannot get physical memory";
+	
+	target->ucycles_diff = calloc(target->tasks_count,
+	    sizeof(uint64_t));
+	if (target->ucycles_diff == NULL)
+		return "Not enough memory for user utilization";
+	
+	/* Allocate memory for computed values */
+	target->kcycles_diff = calloc(target->tasks_count,
+	    sizeof(uint64_t));
+	if (target->kcycles_diff == NULL)
+		return "Not enough memory for kernel utilization";
+	
+	target->ecycles_diff = calloc(target->exceptions_count,
+	    sizeof(uint64_t));
+	if (target->ecycles_diff == NULL)
+		return "Not enough memory for exception cycles utilization";
+	
+	target->ecount_diff = calloc(target->exceptions_count,
+	    sizeof(uint64_t));
+	if (target->ecount_diff == NULL)
+		return "Not enough memory for exception count utilization";
 	
 	return NULL;
@@ -129,19 +175,7 @@
  *
  */
-static const char *compute_percentages(data_t *old_data, data_t *new_data)
-{
-	/* Allocate memory */
-	
-	uint64_t *ucycles_diff = calloc(new_data->tasks_count, sizeof(uint64_t));
-	if (ucycles_diff == NULL)
-		return "Not enough memory for user utilization";
-	
-	uint64_t *kcycles_diff = calloc(new_data->tasks_count, sizeof(uint64_t));
-	if (kcycles_diff == NULL) {
-		free(ucycles_diff);
-		return "Not enough memory for kernel utilization";
-	}
-	
-	/* For each CPU: Compute total ticks and divide it between
+static void compute_percentages(data_t *old_data, data_t *new_data)
+{
+	/* For each CPU: Compute total cycles and divide it between
 	   user and kernel */
 	
@@ -149,7 +183,7 @@
 	for (i = 0; i < new_data->cpus_count; i++) {
 		uint64_t idle =
-		    new_data->cpus[i].idle_ticks - old_data->cpus[i].idle_ticks;
+		    new_data->cpus[i].idle_cycles - old_data->cpus[i].idle_cycles;
 		uint64_t busy =
-		    new_data->cpus[i].busy_ticks - old_data->cpus[i].busy_ticks;
+		    new_data->cpus[i].busy_cycles - old_data->cpus[i].busy_cycles;
 		uint64_t sum = idle + busy;
 		
@@ -160,7 +194,7 @@
 	/* For all tasks compute sum and differencies of all cycles */
 	
-	uint64_t virtmem_total = 1;  /* Must NOT be zero */
-	uint64_t ucycles_total = 1;  /* Must NOT be zero */
-	uint64_t kcycles_total = 1;  /* Must NOT be zero */
+	uint64_t virtmem_total = 0;
+	uint64_t ucycles_total = 0;
+	uint64_t kcycles_total = 0;
 	
 	for (i = 0; i < new_data->tasks_count; i++) {
@@ -178,20 +212,20 @@
 		if (!found) {
 			/* This is newly borned task, ignore it */
-			ucycles_diff[i] = 0;
-			kcycles_diff[i] = 0;
+			new_data->ucycles_diff[i] = 0;
+			new_data->kcycles_diff[i] = 0;
 			continue;
 		}
 		
-		ucycles_diff[i] =
+		new_data->ucycles_diff[i] =
 		    new_data->tasks[i].ucycles - old_data->tasks[j].ucycles;
-		kcycles_diff[i] =
+		new_data->kcycles_diff[i] =
 		    new_data->tasks[i].kcycles - old_data->tasks[j].kcycles;
 		
 		virtmem_total += new_data->tasks[i].virtmem;
-		ucycles_total += ucycles_diff[i];
-		kcycles_total += kcycles_diff[i];
-	}
-	
-	/* For each task: Compute percential change */
+		ucycles_total += new_data->ucycles_diff[i];
+		kcycles_total += new_data->kcycles_diff[i];
+	}
+	
+	/* For each task compute percential change */
 	
 	for (i = 0; i < new_data->tasks_count; i++) {
@@ -199,15 +233,83 @@
 		    new_data->tasks[i].virtmem * 100, virtmem_total);
 		FRACTION_TO_FLOAT(new_data->tasks_perc[i].ucycles,
-		    ucycles_diff[i] * 100, ucycles_total);
+		    new_data->ucycles_diff[i] * 100, ucycles_total);
 		FRACTION_TO_FLOAT(new_data->tasks_perc[i].kcycles,
-		    kcycles_diff[i] * 100, kcycles_total);
-	}
-	
-	/* Cleanup */
-	
-	free(ucycles_diff);
-	free(kcycles_diff);
-	
-	return NULL;
+		    new_data->kcycles_diff[i] * 100, kcycles_total);
+	}
+	
+	/* For all exceptions compute sum and differencies of cycles */
+	
+	uint64_t ecycles_total = 0;
+	uint64_t ecount_total = 0;
+	
+	for (i = 0; i < new_data->exceptions_count; i++) {
+		/*
+		 * March exception with the previous instance.
+		 * This is quite paranoid since exceptions do not
+		 * usually disappear, but it does not hurt.
+		 */
+		
+		bool found = false;
+		size_t j;
+		for (j = 0; j < old_data->exceptions_count; j++) {
+			if (new_data->exceptions[i].id == old_data->exceptions[j].id) {
+				found = true;
+				break;
+			}
+		}
+		
+		if (!found) {
+			/* This is a new exception, ignore it */
+			new_data->ecycles_diff[i] = 0;
+			new_data->ecount_diff[i] = 0;
+			continue;
+		}
+		
+		new_data->ecycles_diff[i] =
+		    new_data->exceptions[i].cycles - old_data->exceptions[j].cycles;
+		new_data->ecount_diff[i] =
+		    new_data->exceptions[i].count - old_data->exceptions[i].count;
+		
+		ecycles_total += new_data->ecycles_diff[i];
+		ecount_total += new_data->ecount_diff[i];
+	}
+	
+	/* For each exception compute percential change */
+	
+	for (i = 0; i < new_data->exceptions_count; i++) {
+		FRACTION_TO_FLOAT(new_data->exceptions_perc[i].cycles,
+		    new_data->ecycles_diff[i] * 100, ecycles_total);
+		FRACTION_TO_FLOAT(new_data->exceptions_perc[i].count,
+		    new_data->ecount_diff[i] * 100, ecount_total);
+	}
+}
+
+static int cmp_data(void *a, void *b, void *arg)
+{
+	size_t ia = *((size_t *) a);
+	size_t ib = *((size_t *) b);
+	data_t *data = (data_t *) arg;
+	
+	uint64_t acycles = data->ucycles_diff[ia] + data->kcycles_diff[ia];
+	uint64_t bcycles = data->ucycles_diff[ib] + data->kcycles_diff[ib];
+	
+	if (acycles > bcycles)
+		return -1;
+	
+	if (acycles < bcycles)
+		return 1;
+	
+	return 0;
+}
+
+static void sort_data(data_t *data)
+{
+	size_t i;
+	
+	for (i = 0; i < data->tasks_count; i++)
+		data->tasks_map[i] = i;
+	
+	qsort((void *) data->tasks_map, data->tasks_count,
+	    sizeof(size_t), cmp_data, (void *) data);
 }
 
@@ -232,6 +334,24 @@
 		free(target->threads);
 	
+	if (target->exceptions != NULL)
+		free(target->exceptions);
+	
+	if (target->exceptions_perc != NULL)
+		free(target->exceptions_perc);
+	
 	if (target->physmem != NULL)
 		free(target->physmem);
+	
+	if (target->ucycles_diff != NULL)
+		free(target->ucycles_diff);
+	
+	if (target->kcycles_diff != NULL)
+		free(target->kcycles_diff);
+	
+	if (target->ecycles_diff != NULL)
+		free(target->ecycles_diff);
+	
+	if (target->ecount_diff != NULL)
+		free(target->ecount_diff);
 }
 
@@ -249,9 +369,7 @@
 	
 	/* Compute some rubbish to have initialised values */
-	if ((ret = compute_percentages(&data_prev, &data_prev)) != NULL)
-		goto out;
+	compute_percentages(&data_prev, &data_prev);
 	
 	/* And paint screen until death */
-	operation_type = OP_TASKS;
 	while (true) {
 		int c = tgetchar(UPDATE_INTERVAL);
@@ -262,9 +380,6 @@
 			}
 			
-			if ((ret = compute_percentages(&data_prev, &data)) != NULL) {
-				free_data(&data);
-				goto out;
-			}
-			
+			compute_percentages(&data_prev, &data);
+			sort_data(&data);
 			print_data(&data);
 			free_data(&data_prev);
@@ -275,16 +390,33 @@
 		
 		switch (c) {
+			case 't':
+				print_warning("Showing task statistics");
+				op_mode = OP_TASKS;
+				break;
+			case 'i':
+				print_warning("Showing IPC statistics");
+				op_mode = OP_IPC;
+				break;
+			case 'e':
+				print_warning("Showing exception statistics");
+				op_mode = OP_EXCS;
+				break;
+			case 'h':
+				print_warning("Showing help");
+				op_mode = OP_HELP;
+				break;
 			case 'q':
 				goto out;
-			case 'i':
-				print_warning("Showing IPC statistics");
-				operation_type = OP_IPC;
-				break;
-			case 't':
-				print_warning("Showing task statistics");
-				operation_type = OP_TASKS;
-				break;
+			case 'a':
+				if (op_mode == OP_EXCS) {
+					excs_all = !excs_all;
+					if (excs_all)
+						print_warning("Showing all exceptions");
+					else
+						print_warning("Showing only hot exceptions");
+					break;
+				}
 			default:
-				print_warning("Unknown command: %c", c);
+				print_warning("Unknown command \"%c\", use \"h\" for help", c);
 				break;
 		}
