Index: uspace/app/top/screen.c
===================================================================
--- uspace/app/top/screen.c	(revision f682f5a7a15b208afa1a1c5c291d774164968db9)
+++ uspace/app/top/screen.c	(revision b8d6783a99ca20a9a760d0859f69a1b5a920212a)
@@ -44,4 +44,5 @@
 #include <stats.h>
 #include <inttypes.h>
+#include <macros.h>
 #include "screen.h"
 #include "top.h"
@@ -327,4 +328,10 @@
 
 	printf("Other keys:");
+	screen_newline();
+	
+	printf(" s .. choose column to sort by");
+	screen_newline();
+	
+	printf(" r .. toggle reversed sorting");
 	screen_newline();
 	
@@ -440,4 +447,27 @@
 }
 
+static inline void print_sort(table_t *table)
+{
+	sysarg_t cols;
+	sysarg_t rows;
+	screen_get_size(&cols, &rows);
+	
+	sysarg_t col;
+	sysarg_t row;
+	screen_get_pos(&col, &row);
+
+	size_t num = min(table->num_columns, rows - row);
+	for (size_t i = 0; i < num; i++) {
+		printf("%c - %s", table->columns[i].key, table->columns[i].name);
+		screen_newline();
+		row++;
+	}
+	
+	while (row < rows) {
+		screen_newline();
+		row++;
+	}
+}
+
 static inline void print_warning(void)
 {
@@ -469,4 +499,7 @@
 		print_table(&data->table);
 		break;
+	case SCREEN_SORT:
+		print_sort(&data->table);
+		break;
 	case SCREEN_HELP:
 		print_help_head();
Index: uspace/app/top/top.c
===================================================================
--- uspace/app/top/top.c	(revision f682f5a7a15b208afa1a1c5c291d774164968db9)
+++ uspace/app/top/top.c	(revision b8d6783a99ca20a9a760d0859f69a1b5a920212a)
@@ -61,9 +61,4 @@
 } op_mode_t;
 
-screen_mode_t screen_mode = SCREEN_TABLE;
-static op_mode_t op_mode = OP_TASKS;
-sort_mode_t sort_mode = SORT_TASK_CYCLES;
-static bool excs_all = false;
-
 static const column_t task_columns[] = {
 	{"taskid",   't',  8},
@@ -131,4 +126,10 @@
 };
 
+screen_mode_t screen_mode = SCREEN_TABLE;
+static op_mode_t op_mode = OP_TASKS;
+static size_t sort_column = TASK_COL_PERCENT_USER;
+static int sort_reverse = -1;
+static bool excs_all = false;
+
 static const char *read_data(data_t *target)
 {
@@ -139,5 +140,4 @@
 	target->tasks = NULL;
 	target->tasks_perc = NULL;
-	target->tasks_map = NULL;
 	target->threads = NULL;
 	target->exceptions = NULL;
@@ -195,9 +195,4 @@
 		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));
@@ -366,29 +361,46 @@
 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;
-	
+	field_t *fa = (field_t *)a + sort_column;
+	field_t *fb = (field_t *)b + sort_column;
+	
+	if (fa->type > fb->type)
+		return 1 * sort_reverse;
+
+	if (fa->type < fb->type)
+		return -1 * sort_reverse;
+
+	switch (fa->type) {
+		case FIELD_EMPTY:
+			return 0;
+		case FIELD_UINT_SUFFIX_BIN: /* fallthrough */
+		case FIELD_UINT_SUFFIX_DEC: /* fallthrough */
+		case FIELD_UINT:
+			if (fa->uint > fb->uint)
+				return 1 * sort_reverse;
+			if (fa->uint < fb->uint)
+				return -1 * sort_reverse;
+			return 0;
+		case FIELD_PERCENT:
+			if (fa->fixed.upper * fb->fixed.lower
+			    > fb->fixed.upper * fa->fixed.lower)
+				return 1 * sort_reverse;
+			if (fa->fixed.upper * fb->fixed.lower
+			    < fb->fixed.upper * fa->fixed.lower)
+				return -1 * sort_reverse;
+			return 0;
+		case FIELD_STRING:
+			return str_cmp(fa->string, fb->string) * sort_reverse;
+	}
+
 	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);
+static void sort_table(table_t *table)
+{
+	if (sort_column >= table->num_columns)
+		sort_column = 0;
+	/* stable sort is probably best, so we use gsort */
+	gsort((void *) table->fields, table->num_fields / table->num_columns,
+	    sizeof(field_t) * table->num_columns, cmp_data, NULL);
 }
 
@@ -406,6 +418,6 @@
 	field_t *field = data->table.fields;
 	for (size_t i = 0; i < data->tasks_count; i++) {
-		stats_task_t *task = data->tasks + data->tasks_map[i];
-		perc_task_t *perc = data->tasks_perc + data->tasks_map[i];
+		stats_task_t *task = &data->tasks[i];
+		perc_task_t *perc = &data->tasks_perc[i];
 		field[TASK_COL_ID].type = FIELD_UINT;
 		field[TASK_COL_ID].uint = task->task_id;
@@ -583,33 +595,56 @@
 		int c = tgetchar(UPDATE_INTERVAL);
 
+		if (c < 0) { /* timeout */
+			data_prev = data;
+			if ((ret = read_data(&data)) != NULL) {
+				free_data(&data_prev);
+				goto out;
+			}
+			
+			compute_percentages(&data_prev, &data);
+			free_data(&data_prev);
+
+			c = -1;
+		}
+
+		if (screen_mode == SCREEN_HELP && c >= 0) {
+			if (c == 'h' || c == '?')
+				c = -1;
+			/* go back to table and handle the key */
+			screen_mode = SCREEN_TABLE;
+		}
+
+		if (screen_mode == SCREEN_SORT && c >= 0) {
+			for (size_t i = 0; i < data.table.num_columns; i++) {
+				if (data.table.columns[i].key == c) {
+					sort_column = i;
+					screen_mode = SCREEN_TABLE;
+				}
+			}
+
+			c = -1;
+		}
+
 		switch (c) {
-			case -1: /* timeout */
-				data_prev = data;
-				if ((ret = read_data(&data)) != NULL) {
-					free_data(&data_prev);
-					goto out;
-				}
-				
-				compute_percentages(&data_prev, &data);
-				free_data(&data_prev);
+			case -1: /* do nothing */
 				break;
 			case 't':
-				screen_mode = SCREEN_TABLE;
 				op_mode = OP_TASKS;
 				break;
 			case 'i':
-				screen_mode = SCREEN_TABLE;
 				op_mode = OP_IPC;
 				break;
 			case 'e':
-				screen_mode = SCREEN_TABLE;
 				op_mode = OP_EXCS;
+				break;
+			case 's':
+				screen_mode = SCREEN_SORT;
+				break;
+			case 'r':
+				sort_reverse = -sort_reverse;
 				break;
 			case 'h':
 			case '?':
-				if (screen_mode == SCREEN_HELP)
-					screen_mode = SCREEN_TABLE;
-				else
-					screen_mode = SCREEN_HELP;
+				screen_mode = SCREEN_HELP;
 				break;
 			case 'q':
@@ -617,5 +652,4 @@
 			case 'a':
 				if (op_mode == OP_EXCS) {
-					screen_mode = SCREEN_TABLE;
 					excs_all = !excs_all;
 					if (excs_all)
@@ -631,8 +665,8 @@
 		}
 
-		sort_data(&data);
 		if ((ret = fill_table(&data)) != NULL) {
 			goto out;
 		}
+		sort_table(&data.table);
 		print_data(&data);
 	}
Index: uspace/app/top/top.h
===================================================================
--- uspace/app/top/top.h	(revision f682f5a7a15b208afa1a1c5c291d774164968db9)
+++ uspace/app/top/top.h	(revision b8d6783a99ca20a9a760d0859f69a1b5a920212a)
@@ -52,13 +52,9 @@
 typedef enum {
 	SCREEN_TABLE,
+	SCREEN_SORT,
 	SCREEN_HELP,
 } screen_mode_t;
 
-typedef enum {
-	SORT_TASK_CYCLES
-} sort_mode_t;
-
 extern screen_mode_t screen_mode;
-extern sort_mode_t sort_mode;
 
 typedef struct {
@@ -132,5 +128,4 @@
 	stats_task_t *tasks;
 	perc_task_t *tasks_perc;
-	size_t *tasks_map;
 	
 	size_t threads_count;
