Index: kernel/generic/src/console/cmd.c
===================================================================
--- kernel/generic/src/console/cmd.c	(revision 5ba201d1b59ac56658a3f14dd383a51abae28b5e)
+++ kernel/generic/src/console/cmd.c	(revision 88dea9d01a9bc5e8482c1ceafa6e6531ac50cb4f)
@@ -1049,5 +1049,6 @@
 	ipl_t ipl = interrupts_disable();
 	spinlock_lock(&TASK->lock);
-	uint64_t t0 = task_get_accounting(TASK);
+	uint64_t ucycles0, kcycles0;
+	task_get_accounting(TASK, &ucycles0, &kcycles0);
 	spinlock_unlock(&TASK->lock);
 	interrupts_restore(ipl);
@@ -1058,15 +1059,18 @@
 	
 	/* Update and read thread accounting */
+	uint64_t ucycles1, kcycles1; 
 	ipl = interrupts_disable();
 	spinlock_lock(&TASK->lock);
-	uint64_t dt = task_get_accounting(TASK) - t0;
+	task_get_accounting(TASK, &ucycles1, &kcycles1);
 	spinlock_unlock(&TASK->lock);
 	interrupts_restore(ipl);
 	
-	uint64_t cycles;
-	char suffix;
-	order(dt, &cycles, &suffix);
-		
-	printf("Time: %" PRIu64 "%c cycles\n", cycles, suffix);
+	uint64_t ucycles, kcycles;
+	char usuffix, ksuffix;
+	order(ucycles1 - ucycles0, &ucycles, &usuffix);
+	order(kcycles1 - kcycles0, &kcycles, &ksuffix);
+		
+	printf("Time: %" PRIu64 "%c user cycles, %" PRIu64 "%c kernel cycles\n",
+			ucycles, usuffix, kcycles, ksuffix);
 	
 	if (ret == NULL) {
@@ -1083,6 +1087,6 @@
 	uint32_t i;
 	bool ret = true;
-	uint64_t cycles;
-	char suffix;
+	uint64_t ucycles, kcycles;
+	char usuffix, ksuffix;
 	
 	if (cnt < 1)
@@ -1102,5 +1106,6 @@
 		ipl_t ipl = interrupts_disable();
 		spinlock_lock(&TASK->lock);
-		uint64_t t0 = task_get_accounting(TASK);
+		uint64_t ucycles0, kcycles0;
+		task_get_accounting(TASK, &ucycles0, &kcycles0);
 		spinlock_unlock(&TASK->lock);
 		interrupts_restore(ipl);
@@ -1113,8 +1118,9 @@
 		ipl = interrupts_disable();
 		spinlock_lock(&TASK->lock);
-		uint64_t dt = task_get_accounting(TASK) - t0;
+		uint64_t ucycles1, kcycles1;
+		task_get_accounting(TASK, &ucycles1, &kcycles1);
 		spinlock_unlock(&TASK->lock);
 		interrupts_restore(ipl);
-		
+
 		if (ret != NULL) {
 			printf("%s\n", ret);
@@ -1123,7 +1129,9 @@
 		}
 		
-		data[i] = dt;
-		order(dt, &cycles, &suffix);
-		printf("OK (%" PRIu64 "%c cycles)\n", cycles, suffix);
+		data[i] = ucycles1 - ucycles0 + kcycles1 - kcycles0;
+		order(ucycles1 - ucycles0, &ucycles, &usuffix);
+		order(kcycles1 - kcycles0, &kcycles, &ksuffix);
+		printf("OK (%" PRIu64 "%c user cycles, %" PRIu64 "%c kernel cycles)\n",
+				ucycles, usuffix, kcycles, ksuffix);
 	}
 	
@@ -1137,6 +1145,6 @@
 		}
 		
-		order(sum / (uint64_t) cnt, &cycles, &suffix);
-		printf("Average\t\t%" PRIu64 "%c\n", cycles, suffix);
+		order(sum / (uint64_t) cnt, &ucycles, &usuffix);
+		printf("Average\t\t%" PRIu64 "%c\n", ucycles, usuffix);
 	}
 	
Index: kernel/generic/src/cpu/cpu.c
===================================================================
--- kernel/generic/src/cpu/cpu.c	(revision 5ba201d1b59ac56658a3f14dd383a51abae28b5e)
+++ kernel/generic/src/cpu/cpu.c	(revision 88dea9d01a9bc5e8482c1ceafa6e6531ac50cb4f)
@@ -48,4 +48,5 @@
 #include <adt/list.h>
 #include <print.h>
+#include <sysinfo/sysinfo.h>
 
 cpu_t *cpus;
@@ -74,4 +75,6 @@
 			
 			cpus[i].id = i;
+			cpus[i].idle_ticks = 0;
+			cpus[i].busy_ticks = 0;
 			
 			spinlock_initialize(&cpus[i].lock, "cpu_t.lock");
@@ -94,4 +97,6 @@
 	cpu_identify();
 	cpu_arch_init();
+
+	sysinfo_set_item_val("cpu.count", NULL, config.cpu_count);
 }
 
Index: kernel/generic/src/interrupt/interrupt.c
===================================================================
--- kernel/generic/src/interrupt/interrupt.c	(revision 5ba201d1b59ac56658a3f14dd383a51abae28b5e)
+++ kernel/generic/src/interrupt/interrupt.c	(revision 88dea9d01a9bc5e8482c1ceafa6e6531ac50cb4f)
@@ -51,4 +51,5 @@
 #include <print.h>
 #include <symtab.h>
+#include <proc/thread.h>
 
 static struct {
@@ -91,4 +92,8 @@
 	ASSERT(n < IVT_ITEMS);
 
+	/* Account user cycles */
+	if (THREAD)
+		thread_update_accounting(true);
+
 #ifdef CONFIG_UDEBUG
 	if (THREAD) THREAD->udebug.uspace_state = istate;
@@ -104,4 +109,7 @@
 	if (THREAD && THREAD->interrupted && istate_from_uspace(istate))
 		thread_exit();
+
+	if (THREAD)
+		thread_update_accounting(false);
 }
 
Index: kernel/generic/src/ipc/ipc.c
===================================================================
--- kernel/generic/src/ipc/ipc.c	(revision 5ba201d1b59ac56658a3f14dd383a51abae28b5e)
+++ kernel/generic/src/ipc/ipc.c	(revision 88dea9d01a9bc5e8482c1ceafa6e6531ac50cb4f)
@@ -219,4 +219,9 @@
 	bool do_lock = ((!selflocked) || callerbox != (&TASK->answerbox));
 
+	/* Count sent answer */
+	spinlock_lock(&TASK->lock);
+	TASK->ipc_info.answer_sent++;
+	spinlock_unlock(&TASK->lock);
+
 	call->flags |= IPC_CALL_ANSWERED;
 
@@ -276,4 +281,9 @@
 static void _ipc_call(phone_t *phone, answerbox_t *box, call_t *call)
 {
+	/* Count sent ipc call */
+	spinlock_lock(&TASK->lock);
+	TASK->ipc_info.call_sent++;
+	spinlock_unlock(&TASK->lock);
+
 	if (!(call->flags & IPC_CALL_FORWARDED)) {
 		atomic_inc(&phone->active_calls);
@@ -376,4 +386,9 @@
 int ipc_forward(call_t *call, phone_t *newphone, answerbox_t *oldbox, int mode)
 {
+	/* Count forwarded calls */
+	spinlock_lock(&TASK->lock);
+	TASK->ipc_info.forwarded++;
+	spinlock_unlock(&TASK->lock);
+
 	spinlock_lock(&oldbox->lock);
 	list_remove(&call->link);
@@ -416,4 +431,10 @@
 	spinlock_lock(&box->lock);
 	if (!list_empty(&box->irq_notifs)) {
+
+		/* Count recieved IRQ notification */
+		spinlock_lock(&TASK->lock);
+		TASK->ipc_info.irq_notif_recieved++;
+		spinlock_unlock(&TASK->lock);
+
 		ipl = interrupts_disable();
 		spinlock_lock(&box->irq_lock);
@@ -425,4 +446,9 @@
 		interrupts_restore(ipl);
 	} else if (!list_empty(&box->answers)) {
+		/* Count recieved answer */
+		spinlock_lock(&TASK->lock);
+		TASK->ipc_info.answer_recieved++;
+		spinlock_unlock(&TASK->lock);
+
 		/* Handle asynchronous answers */
 		request = list_get_instance(box->answers.next, call_t, link);
@@ -430,4 +456,9 @@
 		atomic_dec(&request->data.phone->active_calls);
 	} else if (!list_empty(&box->calls)) {
+		/* Count recieved call */
+		spinlock_lock(&TASK->lock);
+		TASK->ipc_info.call_recieved++;
+		spinlock_unlock(&TASK->lock);
+
 		/* Handle requests */
 		request = list_get_instance(box->calls.next, call_t, link);
Index: kernel/generic/src/main/kinit.c
===================================================================
--- kernel/generic/src/main/kinit.c	(revision 5ba201d1b59ac56658a3f14dd383a51abae28b5e)
+++ kernel/generic/src/main/kinit.c	(revision 88dea9d01a9bc5e8482c1ceafa6e6531ac50cb4f)
@@ -67,4 +67,5 @@
 #include <debug.h>
 #include <str.h>
+#include <ps/load.h>
 
 #ifdef CONFIG_SMP
@@ -163,4 +164,11 @@
 #endif /* CONFIG_KCONSOLE */
 	
+	/* Start thread computing system load */
+	thread = thread_create(kload_thread, NULL, TASK, 0, "kload", false);
+	if (thread != NULL)
+		thread_ready(thread);
+	else
+		printf("Unable to create kload thread\n");
+
 	interrupts_enable();
 	
Index: kernel/generic/src/main/main.c
===================================================================
--- kernel/generic/src/main/main.c	(revision 5ba201d1b59ac56658a3f14dd383a51abae28b5e)
+++ kernel/generic/src/main/main.c	(revision 88dea9d01a9bc5e8482c1ceafa6e6531ac50cb4f)
@@ -226,5 +226,5 @@
 	printf("Detected %" PRIs " CPU(s), %" PRIu64" MiB free memory\n",
 	    config.cpu_count, SIZE2MB(zone_total_size()));
-	
+
 	LOG_EXEC(cpu_init());
 	
Index: kernel/generic/src/mm/frame.c
===================================================================
--- kernel/generic/src/mm/frame.c	(revision 5ba201d1b59ac56658a3f14dd383a51abae28b5e)
+++ kernel/generic/src/mm/frame.c	(revision 88dea9d01a9bc5e8482c1ceafa6e6531ac50cb4f)
@@ -1218,4 +1218,26 @@
 }
 
+void zone_busy_and_free(uint64_t *out_busy, uint64_t *out_free)
+{
+	ipl_t ipl = interrupts_disable();
+	spinlock_lock(&zones.lock);
+
+	uint64_t busy = 0, free = 0;
+	size_t i;
+	for (i = 0; i < zones.count; i++) {
+		bool available = zone_flags_available(zones.info[i].flags);
+		/* Do not count reserved memory */
+		if (available) {
+			busy += (uint64_t) FRAMES2SIZE(zones.info[i].busy_count);
+			free += (uint64_t) FRAMES2SIZE(zones.info[i].free_count);
+		}
+	}
+
+	spinlock_unlock(&zones.lock);
+	interrupts_restore(ipl);
+	*out_busy = busy;
+	*out_free = free;
+}
+
 /** Prints list of zones. */
 void zone_print_list(void)
Index: kernel/generic/src/proc/scheduler.c
===================================================================
--- kernel/generic/src/proc/scheduler.c	(revision 5ba201d1b59ac56658a3f14dd383a51abae28b5e)
+++ kernel/generic/src/proc/scheduler.c	(revision 88dea9d01a9bc5e8482c1ceafa6e6531ac50cb4f)
@@ -202,4 +202,7 @@
 		 */
 
+		 spinlock_lock(&CPU->lock);
+		 CPU->idle = true;
+		 spinlock_unlock(&CPU->lock);
 		 cpu_sleep();
 		 goto loop;
@@ -313,6 +316,6 @@
 		spinlock_lock(&THREAD->lock);
 		
-		/* Update thread accounting */
-		THREAD->cycles += get_cycle() - THREAD->last_cycle;
+		/* Update thread kernel accounting */
+		THREAD->kcycles += get_cycle() - THREAD->last_cycle;
 		
 #ifndef CONFIG_FPU_LAZY
Index: kernel/generic/src/proc/task.c
===================================================================
--- kernel/generic/src/proc/task.c	(revision 5ba201d1b59ac56658a3f14dd383a51abae28b5e)
+++ kernel/generic/src/proc/task.c	(revision 88dea9d01a9bc5e8482c1ceafa6e6531ac50cb4f)
@@ -186,6 +186,14 @@
 	ta->context = CONTEXT;
 	ta->capabilities = 0;
-	ta->cycles = 0;
-	
+	ta->ucycles = 0;
+	ta->kcycles = 0;
+
+	ta->ipc_info.call_sent = 0;
+	ta->ipc_info.call_recieved = 0;
+	ta->ipc_info.answer_sent = 0;
+	ta->ipc_info.answer_recieved = 0;
+	ta->ipc_info.irq_notif_recieved = 0;
+	ta->ipc_info.forwarded = 0;
+
 #ifdef CONFIG_UDEBUG
 	/* Init debugging stuff */
@@ -324,14 +332,14 @@
  * already disabled.
  *
- * @param t Pointer to task.
- *
- * @return Number of cycles used by the task and all its threads
- *         so far.
- *
- */
-uint64_t task_get_accounting(task_t *t)
-{
-	/* Accumulated value of task */
-	uint64_t ret = t->cycles;
+ * @param t       Pointer to thread.
+ * @param ucycles Out pointer to sum of all user cycles.
+ * @param kcycles Out pointer to sum of all kernel cycles.
+ *
+ */
+void task_get_accounting(task_t *t, uint64_t *ucycles, uint64_t *kcycles)
+{
+	/* Accumulated values of task */
+	uint64_t uret = t->ucycles;
+	uint64_t kret = t->kcycles;
 	
 	/* Current values of threads */
@@ -345,12 +353,14 @@
 			if (thr == THREAD) {
 				/* Update accounting of current thread */
-				thread_update_accounting();
+				thread_update_accounting(false);
 			} 
-			ret += thr->cycles;
+			uret += thr->ucycles;
+			kret += thr->kcycles;
 		}
 		spinlock_unlock(&thr->lock);
 	}
 	
-	return ret;
+	*ucycles = uret;
+	*kcycles = kret;
 }
 
@@ -419,18 +429,23 @@
 	spinlock_lock(&t->lock);
 	
-	uint64_t cycles;
-	char suffix;
-	order(task_get_accounting(t), &cycles, &suffix);
-	
-#ifdef __32_BITS__
-	printf("%-6" PRIu64 " %-12s %-3" PRIu32 " %10p %10p %9" PRIu64
-	    "%c %7ld %6ld", t->taskid, t->name, t->context, t, t->as, cycles,
-	    suffix, atomic_get(&t->refcount), atomic_get(&t->active_calls));
+	uint64_t ucycles;
+	uint64_t kcycles;
+	char usuffix, ksuffix;
+	task_get_accounting(t, &ucycles, &kcycles);
+	order(ucycles, &ucycles, &usuffix);
+	order(kcycles, &kcycles, &ksuffix);
+	
+#ifdef __32_BITS__	
+	printf("%-6" PRIu64 " %-12s %-3" PRIu32 " %10p %10p %9" PRIu64 "%c %9"
+		PRIu64 "%c %7ld %6ld", t->taskid, t->name, t->context, t, t->as,
+		ucycles, usuffix, kcycles, ksuffix, atomic_get(&t->refcount),
+		atomic_get(&t->active_calls));
 #endif
 	
 #ifdef __64_BITS__
-	printf("%-6" PRIu64 " %-12s %-3" PRIu32 " %18p %18p %9" PRIu64
-	    "%c %7ld %6ld", t->taskid, t->name, t->context, t, t->as, cycles,
-	    suffix, atomic_get(&t->refcount), atomic_get(&t->active_calls));
+	printf("%-6" PRIu64 " %-12s %-3" PRIu32 " %18p %18p %9" PRIu64 "%c %9"
+		PRIu64 "%c %7ld %6ld", t->taskid, t->name, t->context, t, t->as,
+		ucycles, usuffix, kcycles, ksuffix, atomic_get(&t->refcount),
+		atomic_get(&t->active_calls));
 #endif
 	
@@ -455,15 +470,15 @@
 	
 #ifdef __32_BITS__
-	printf("taskid name         ctx address    as         "
-	    "cycles     threads calls  callee\n");
-	printf("------ ------------ --- ---------- ---------- "
-	    "---------- ------- ------ ------>\n");
+	printf("taskid name         ctx address    as        "
+	    " ucycles    kcycles    threads calls  callee\n");
+	printf("------ ------------ --- ---------- ----------"
+	    " ---------- ---------- ------- ------ ------>\n");
 #endif
 	
 #ifdef __64_BITS__
-	printf("taskid name         ctx address            as                 "
-	    "cycles     threads calls  callee\n");
-	printf("------ ------------ --- ------------------ ------------------ "
-	    "---------- ------- ------ ------>\n");
+	printf("taskid name         ctx address            as                "
+	    " ucycles    kcycles    threads calls  callee\n");
+	printf("------ ------------ --- ------------------ ------------------"
+	    " ---------- ---------- ---------- ------- ------ ------>\n");
 #endif
 	
Index: kernel/generic/src/proc/thread.c
===================================================================
--- kernel/generic/src/proc/thread.c	(revision 5ba201d1b59ac56658a3f14dd383a51abae28b5e)
+++ kernel/generic/src/proc/thread.c	(revision 88dea9d01a9bc5e8482c1ceafa6e6531ac50cb4f)
@@ -132,11 +132,15 @@
 	spinlock_lock(&THREAD->lock);
 	if (!THREAD->uncounted) {
-		thread_update_accounting();
-		uint64_t cycles = THREAD->cycles;
-		THREAD->cycles = 0;
+		thread_update_accounting(true);
+		uint64_t ucycles = THREAD->ucycles;
+		THREAD->ucycles = 0;
+		uint64_t kcycles = THREAD->kcycles;
+		THREAD->kcycles = 0;
+
 		spinlock_unlock(&THREAD->lock);
 		
 		spinlock_lock(&TASK->lock);
-		TASK->cycles += cycles;
+		TASK->ucycles += ucycles;
+		TASK->kcycles += kcycles;
 		spinlock_unlock(&TASK->lock);
 	} else
@@ -323,5 +327,6 @@
 	t->thread_arg = arg;
 	t->ticks = -1;
-	t->cycles = 0;
+	t->ucycles = 0;
+	t->kcycles = 0;
 	t->uncounted = uncounted;
 	t->priority = -1;		/* start in rq[0] */
@@ -614,18 +619,21 @@
 	thread_t *t = avltree_get_instance(node, thread_t, threads_tree_node);
 	
-	uint64_t cycles;
-	char suffix;
-	order(t->cycles, &cycles, &suffix);
+	uint64_t ucycles, kcycles;
+	char usuffix, ksuffix;
+	order(t->ucycles, &ucycles, &usuffix);
+	order(t->kcycles, &kcycles, &ksuffix);
 
 #ifdef __32_BITS__
-	printf("%-6" PRIu64" %-10s %10p %-8s %10p %-3" PRIu32 " %10p %10p %9" PRIu64 "%c ",
-	    t->tid, t->name, t, thread_states[t->state], t->task,
-    	t->task->context, t->thread_code, t->kstack, cycles, suffix);
+	printf("%-6" PRIu64" %-10s %10p %-8s %10p %-3" PRIu32 " %10p %10p %9"
+		PRIu64 "%c %9" PRIu64 "%c ", t->tid, t->name, t,
+		thread_states[t->state], t->task, t->task->context, t->thread_code,
+		t->kstack, ucycles, usuffix, kcycles, ksuffix);
 #endif
 
 #ifdef __64_BITS__
-	printf("%-6" PRIu64" %-10s %18p %-8s %18p %-3" PRIu32 " %18p %18p %9" PRIu64 "%c ",
-	    t->tid, t->name, t, thread_states[t->state], t->task,
-    	t->task->context, t->thread_code, t->kstack, cycles, suffix);
+	printf("%-6" PRIu64" %-10s %18p %-8s %18p %-3" PRIu32 " %18p %18p %9"
+		PRIu64 "%c %9" PRIu64 "%c ", t->tid, t->name, t,
+		thread_states[t->state], t->task, t->task->context, t->thread_code,
+		t->kstack, ucycles, usuffix, kcycles, ksuffix);
 #endif
 			
@@ -661,8 +669,8 @@
 #ifdef __32_BITS__	
 	printf("tid    name       address    state    task       "
-		"ctx code       stack      cycles     cpu  "
+		"ctx code       stack      ucycles    kcycles    cpu  "
 		"waitqueue\n");
 	printf("------ ---------- ---------- -------- ---------- "
-		"--- ---------- ---------- ---------- ---- "
+		"--- ---------- ---------- ---------- ---------- ---- "
 		"----------\n");
 #endif
@@ -670,8 +678,8 @@
 #ifdef __64_BITS__
 	printf("tid    name       address            state    task               "
-		"ctx code               stack              cycles     cpu  "
+		"ctx code               stack              ucycles    kcycles    cpu  "
 		"waitqueue\n");
 	printf("------ ---------- ------------------ -------- ------------------ "
-		"--- ------------------ ------------------ ---------- ---- "
+		"--- ------------------ ------------------ ---------- ---------- ---- "
 		"------------------\n");
 #endif
@@ -706,9 +714,14 @@
  * interrupts must be already disabled.
  *
- */
-void thread_update_accounting(void)
+ * @param user	True to update user accounting, false for kernel.
+ */
+void thread_update_accounting(bool user)
 {
 	uint64_t time = get_cycle();
-	THREAD->cycles += time - THREAD->last_cycle;
+	if (user) {
+		THREAD->ucycles += time - THREAD->last_cycle;
+	} else {
+		THREAD->kcycles += time - THREAD->last_cycle;
+	}
 	THREAD->last_cycle = time;
 }
Index: kernel/generic/src/ps/cpu.c
===================================================================
--- kernel/generic/src/ps/cpu.c	(revision 88dea9d01a9bc5e8482c1ceafa6e6531ac50cb4f)
+++ kernel/generic/src/ps/cpu.c	(revision 88dea9d01a9bc5e8482c1ceafa6e6531ac50cb4f)
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2010 Stanislav Kozina
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup genericps
+ * @{
+ */
+
+/**
+ * @file
+ * @brief	CPU listing.
+ */
+
+#include <ps/ps.h>
+#include <ps/cpuinfo.h>
+#include <arch/asm.h>
+#include <cpu.h>
+#include <syscall/copy.h>
+
+#define WRITE_CPU_INFO(dst, i, src) copy_to_uspace(dst+i, src, sizeof(uspace_cpu_info_t))
+
+int sys_ps_get_cpu_info(uspace_cpu_info_t *uspace_cpu)
+{
+	size_t i;
+	uspace_cpu_info_t cpuinfo;
+	ipl_t ipl;
+	ipl = interrupts_disable();
+
+	for (i = 0; i < config.cpu_count; ++i) {
+		spinlock_lock(&cpus[i].lock);
+		cpuinfo.id = cpus[i].id;
+		cpuinfo.frequency_mhz = cpus[i].frequency_mhz;
+		cpuinfo.busy_ticks = cpus[i].busy_ticks;
+		cpuinfo.idle_ticks = cpus[i].idle_ticks;
+		spinlock_unlock(&cpus[i].lock);
+		WRITE_CPU_INFO(uspace_cpu, i, &cpuinfo);
+	}
+
+	interrupts_restore(ipl);
+	return 0;
+}
+
+/** @}
+ */
Index: kernel/generic/src/ps/load.c
===================================================================
--- kernel/generic/src/ps/load.c	(revision 88dea9d01a9bc5e8482c1ceafa6e6531ac50cb4f)
+++ kernel/generic/src/ps/load.c	(revision 88dea9d01a9bc5e8482c1ceafa6e6531ac50cb4f)
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2010 Stanislav Kozina
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup genericload
+ * @{
+ */
+
+/**
+ * @file
+ * @brief	System load computation.
+ */
+
+#include <proc/thread.h>
+#include <ps/load.h>
+#include <arch.h>
+#include <proc/scheduler.h>
+#include <config.h>
+#include <arch/types.h>
+#include <time/clock.h>
+#include <syscall/copy.h>
+
+static size_t get_running_count(void);
+
+unsigned long avenrun[3];
+
+#define FSHIFT   11		/* nr of bits of precision */
+#define FIXED_1  (1<<FSHIFT)	/* 1.0 as fixed-point */
+#define LOAD_FREQ 5		/* 5 sec intervals */
+#define EXP_1  1884		/* 1/exp(5sec/1min) as fixed-point */
+#define EXP_5  2014		/* 1/exp(5sec/5min) */
+#define EXP_15 2037		/* 1/exp(5sec/15min) */
+
+void get_avenrun(unsigned long *loads, int shift)
+{
+	loads[0] = avenrun[0] << shift;
+	loads[1] = avenrun[1] << shift;
+	loads[2] = avenrun[2] << shift;
+}
+
+static inline unsigned long calc_load(unsigned long load, size_t exp, size_t active)
+{
+	load *= exp;
+	load += active * (FIXED_1 - exp);
+	return load >> FSHIFT;
+}
+
+static inline void calc_load_global(void)
+{
+	size_t active;
+
+	active = get_running_count();
+	active = active > 0 ? active * FIXED_1 : 0;
+	avenrun[0] = calc_load(avenrun[0], EXP_1, active);
+	avenrun[1] = calc_load(avenrun[1], EXP_5, active);
+	avenrun[2] = calc_load(avenrun[2], EXP_15, active);
+}
+
+static size_t get_running_count(void)
+{
+	size_t i;
+	size_t result = 0;
+	ipl_t ipl;
+
+	/* run queues should not change during reading */
+	ipl = interrupts_disable();
+
+	for (i = 0; i < config.cpu_active; ++i) {
+		cpu_t *cpu = &cpus[i];
+		int j;
+		for (j = 0; j < RQ_COUNT; ++j) {
+			result += cpu->rq[j].n;
+		}
+	} 
+
+	interrupts_restore(ipl);
+	return result;
+}
+
+/** Load thread main function.
+ *  Thread computes system load every few seconds.
+ *
+ *  @param arg		Generic thread argument (unused).
+ *
+ */
+void kload_thread(void *arg)
+{
+	/* Noone will thread_join us */
+	thread_detach(THREAD);
+	avenrun[0] = 0;
+	avenrun[1] = 0;
+	avenrun[2] = 0;
+
+	while (true) {
+		calc_load_global();
+		thread_sleep(LOAD_FREQ);
+	}
+}
+
+int sys_ps_get_load(unsigned long *user_load)
+{
+	unsigned long loads[3];
+	get_avenrun(loads, 5);
+	copy_to_uspace(user_load, loads, sizeof(loads));
+	return 0;
+}
+
+
+/** @}
+ */
Index: kernel/generic/src/ps/mem.c
===================================================================
--- kernel/generic/src/ps/mem.c	(revision 88dea9d01a9bc5e8482c1ceafa6e6531ac50cb4f)
+++ kernel/generic/src/ps/mem.c	(revision 88dea9d01a9bc5e8482c1ceafa6e6531ac50cb4f)
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2010 Stanislav Kozina
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup genericps
+ * @{
+ */
+
+/**
+ * @file
+ * @brief	Mem info
+ */
+
+#include <ps/meminfo.h>
+#include <ps/ps.h>
+#include <syscall/copy.h>
+#include <mm/frame.h>
+#include <arch.h>
+
+int sys_ps_get_mem_info(uspace_mem_info_t *uspace_mem)
+{
+	uspace_mem_info_t meminfo;
+	ipl_t ipl;
+	ipl = interrupts_disable();
+
+	meminfo.total = zone_total_size();
+	zone_busy_and_free(&meminfo.used, &meminfo.free);
+	interrupts_restore(ipl);
+
+	copy_to_uspace(uspace_mem, &meminfo, sizeof(uspace_mem_info_t));
+	return 0;
+}
+
+/** @}
+ */
Index: kernel/generic/src/ps/ps.c
===================================================================
--- kernel/generic/src/ps/ps.c	(revision 88dea9d01a9bc5e8482c1ceafa6e6531ac50cb4f)
+++ kernel/generic/src/ps/ps.c	(revision 88dea9d01a9bc5e8482c1ceafa6e6531ac50cb4f)
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2010 Stanislav Kozina
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup genericps
+ * @{
+ */
+
+/**
+ * @file
+ * @brief	Process listing.
+ */
+
+#include <proc/task.h>
+#include <proc/thread.h>
+#include <ps/ps.h>
+#include <ps/taskinfo.h>
+#include <adt/avl.h>
+#include <synch/waitq.h>
+#include <syscall/copy.h>
+#include <atomic.h>
+#include <errno.h>
+
+static size_t count;
+static size_t max_count;
+
+#define WRITE_TASK_ID(dst, i, src) copy_to_uspace(dst + i, src, sizeof(task_id_t))
+#define WRITE_THREAD_INFO(dst, i, src) copy_to_uspace(dst+i, src, sizeof(thread_info_t))
+
+static bool task_walker(avltree_node_t *node, void *arg)
+{
+	task_t *t = avltree_get_instance(node, task_t, tasks_tree_node);
+	task_id_t *ids = (task_id_t *)arg;
+
+	spinlock_lock(&t->lock);
+
+	++count;
+	if (count > max_count) {
+		spinlock_unlock(&t->lock);
+		return false;
+	}
+
+	WRITE_TASK_ID(ids, count - 1, &t->taskid);
+
+	spinlock_unlock(&t->lock);
+	return true;
+}
+
+size_t sys_ps_get_tasks(task_id_t *uspace_ids, size_t size)
+{
+	ipl_t ipl;
+	
+	/* Messing with task structures, avoid deadlock */
+	ipl = interrupts_disable();
+	spinlock_lock(&tasks_lock);
+
+	count = 0;
+	max_count = size / sizeof(task_id_t);
+	avltree_walk(&tasks_tree, task_walker, uspace_ids);
+
+	spinlock_unlock(&tasks_lock);
+	interrupts_restore(ipl);
+	
+	return count;
+}
+
+static uint64_t get_task_memory(as_t *as)
+{
+	mutex_lock(&as->lock);
+
+	size_t result = 0;
+	
+	link_t *cur;
+	for (cur = as->as_area_btree.leaf_head.next;
+	    cur != &as->as_area_btree.leaf_head; cur = cur->next) {
+		btree_node_t *node;
+		
+		node = list_get_instance(cur, btree_node_t, leaf_link);
+		
+		unsigned int i;
+		for (i = 0; i < node->keys; i++) {
+			as_area_t *area = node->value[i];
+		
+			mutex_lock(&area->lock);
+			result += area->pages;
+			mutex_unlock(&area->lock);
+		}
+	}
+	
+	mutex_unlock(&as->lock);
+	
+	return result * PAGE_SIZE;
+}
+
+int sys_ps_get_task_info(task_id_t *uspace_id, task_info_t *uspace_info)
+{
+	ipl_t ipl;
+	ipl = interrupts_disable();
+
+	task_id_t id;
+	copy_from_uspace(&id, uspace_id, sizeof(task_id_t));
+
+	spinlock_lock(&tasks_lock);
+	task_t *t = task_find_by_id(id);
+	if (!t) {
+		spinlock_unlock(&tasks_lock);
+		return ENOENT;
+	}
+	spinlock_lock(&t->lock);
+	spinlock_unlock(&tasks_lock);
+
+	copy_to_uspace(&uspace_info->taskid, &t->taskid, sizeof(task_id_t));
+	copy_to_uspace(uspace_info->name, t->name, sizeof(t->name));
+
+	uint64_t ucycles;
+	uint64_t kcycles;
+	task_get_accounting(t, &ucycles, &kcycles);
+	copy_to_uspace(&uspace_info->ucycles, &ucycles, sizeof(uint64_t));
+	copy_to_uspace(&uspace_info->kcycles, &kcycles, sizeof(uint64_t));
+
+	task_ipc_info_t ipc_info;
+	ipc_info.call_sent = t->ipc_info.call_sent;
+	ipc_info.call_recieved = t->ipc_info.call_recieved;
+	ipc_info.answer_sent = t->ipc_info.answer_sent;
+	ipc_info.answer_recieved = t->ipc_info.answer_recieved;
+	ipc_info.irq_notif_recieved = t->ipc_info.irq_notif_recieved;
+	ipc_info.forwarded = t->ipc_info.forwarded;
+	copy_to_uspace(&uspace_info->ipc_info, &ipc_info, sizeof(task_ipc_info_t));
+
+	uint64_t memory = get_task_memory(t->as);
+	copy_to_uspace(&uspace_info->virt_mem, &memory, sizeof(memory));
+
+	int thread_count = atomic_get(&t->refcount);
+	copy_to_uspace(&uspace_info->thread_count, &thread_count, sizeof(thread_count));
+	
+	spinlock_unlock(&t->lock);
+	interrupts_restore(ipl);
+	return 0;
+}
+
+static bool thread_walker(avltree_node_t *node, void *arg)
+{
+	thread_t *t = avltree_get_instance(node, thread_t, threads_tree_node);
+	thread_info_t *infos = (thread_info_t *)arg;
+	thread_info_t result;
+
+	spinlock_lock(&t->lock);
+
+	++count;
+	if (count > max_count) {
+		spinlock_unlock(&t->lock);
+		return false;
+	}
+	
+	result.tid = t->tid;
+	ASSERT(t->task);
+	result.taskid = t->task->taskid;
+	result.state = t->state;
+	result.priority = t->priority;
+	result.ucycles = t->ucycles;
+	result.kcycles = t->kcycles;
+
+	if (t->cpu)
+		result.cpu = t->cpu->id;
+	else
+		result.cpu = -1;
+
+	WRITE_THREAD_INFO(infos, count - 1, &result);
+
+	spinlock_unlock(&t->lock);
+	return true;
+}
+
+int sys_ps_get_threads(thread_info_t *uspace_infos, size_t size)
+{
+	ipl_t ipl;
+	ipl = interrupts_disable();
+	spinlock_lock(&threads_lock);
+
+	count = 0;
+	max_count = size / sizeof(thread_info_t);
+	avltree_walk(&threads_tree, thread_walker, uspace_infos);
+
+	spinlock_unlock(&threads_lock);
+	interrupts_restore(ipl);
+	return count;
+}
+
+/** @}
+ */
Index: kernel/generic/src/ps/uptime.c
===================================================================
--- kernel/generic/src/ps/uptime.c	(revision 88dea9d01a9bc5e8482c1ceafa6e6531ac50cb4f)
+++ kernel/generic/src/ps/uptime.c	(revision 88dea9d01a9bc5e8482c1ceafa6e6531ac50cb4f)
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2010 Stanislav Kozina
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup genericuptime
+ * @{
+ */
+
+/**
+ * @file
+ * @brief	Get system uptime.
+ */
+
+#include <time/clock.h>
+#include <syscall/copy.h>
+#include <ps/uptime.h>
+
+int sys_ps_get_uptime(uint64_t *user_uptime)
+{
+	uint64_t seconds = uptime->seconds1;
+	copy_to_uspace(user_uptime, &seconds, sizeof(uint64_t));
+	return 0;
+}
+
+
+/** @}
+ */
Index: kernel/generic/src/synch/waitq.c
===================================================================
--- kernel/generic/src/synch/waitq.c	(revision 5ba201d1b59ac56658a3f14dd383a51abae28b5e)
+++ kernel/generic/src/synch/waitq.c	(revision 88dea9d01a9bc5e8482c1ceafa6e6531ac50cb4f)
@@ -54,4 +54,5 @@
 #include <context.h>
 #include <adt/list.h>
+#include <arch/cycle.h>
 
 static void waitq_sleep_timed_out(void *data);
@@ -373,4 +374,5 @@
 		if (!context_save(&THREAD->sleep_interruption_context)) {
 			/* Short emulation of scheduler() return code. */
+			THREAD->last_cycle = get_cycle();
 			spinlock_unlock(&THREAD->lock);
 			return ESYNCH_INTERRUPTED;
@@ -385,4 +387,5 @@
 		if (!context_save(&THREAD->sleep_timeout_context)) {
 			/* Short emulation of scheduler() return code. */
+			THREAD->last_cycle = get_cycle();
 			spinlock_unlock(&THREAD->lock);
 			return ESYNCH_TIMEOUT;
Index: kernel/generic/src/syscall/syscall.c
===================================================================
--- kernel/generic/src/syscall/syscall.c	(revision 5ba201d1b59ac56658a3f14dd383a51abae28b5e)
+++ kernel/generic/src/syscall/syscall.c	(revision 88dea9d01a9bc5e8482c1ceafa6e6531ac50cb4f)
@@ -54,4 +54,7 @@
 #include <console/console.h>
 #include <udebug/udebug.h>
+#include <ps/ps.h>
+#include <ps/load.h>
+#include <ps/uptime.h>
 
 /** Dispatch system call */
@@ -60,4 +63,7 @@
 {
 	unative_t rc;
+
+	/* Do userpace accounting */
+	thread_update_accounting(true);
 
 #ifdef CONFIG_UDEBUG
@@ -95,4 +101,7 @@
 	}
 #endif
+
+	/* Do kernel accounting */
+	thread_update_accounting(false);
 	
 	return rc;
@@ -161,4 +170,13 @@
 	(syshandler_t) sys_debug_enable_console,
 	(syshandler_t) sys_debug_disable_console,
+
+	/* Ps calls */
+	(syshandler_t) sys_ps_get_cpu_info,
+	(syshandler_t) sys_ps_get_mem_info,
+	(syshandler_t) sys_ps_get_tasks,
+	(syshandler_t) sys_ps_get_task_info,
+	(syshandler_t) sys_ps_get_threads,
+	(syshandler_t) sys_ps_get_uptime,
+	(syshandler_t) sys_ps_get_load,
 	
 	(syshandler_t) sys_ipc_connect_kbox
Index: kernel/generic/src/time/clock.c
===================================================================
--- kernel/generic/src/time/clock.c	(revision 5ba201d1b59ac56658a3f14dd383a51abae28b5e)
+++ kernel/generic/src/time/clock.c	(revision 88dea9d01a9bc5e8482c1ceafa6e6531ac50cb4f)
@@ -137,4 +137,13 @@
 	size_t missed_clock_ticks = CPU->missed_clock_ticks;
 	unsigned int i;
+
+	/* Account lost ticks to CPU usage */
+	if (CPU->idle) {
+		ASSERT(missed_clock_ticks == 0);
+		CPU->idle_ticks++;
+	} else {
+		CPU->busy_ticks += missed_clock_ticks + 1;
+	}
+	CPU->idle = false;
 
 	/*
