Index: uspace/app/hbench/csv.c
===================================================================
--- uspace/app/hbench/csv.c	(revision 94ebebf259d1d5d83f702d859ff01bffde3a341c)
+++ uspace/app/hbench/csv.c	(revision e7f9a093b00a54747dbfa7e288153beb04d93009)
@@ -62,10 +62,10 @@
  * nothing.
  *
- * @param stopwatch Performance data of the entry.
+ * @param run Performance data of the entry.
  * @param run_index Run index, use negative values for warm-up.
  * @param bench Benchmark information.
  * @param workload_size Workload size.
  */
-void csv_report_add_entry(benchmeter_t *meter, int run_index,
+void csv_report_add_entry(bench_run_t *run, int run_index,
     benchmark_t *bench, uint64_t workload_size)
 {
@@ -76,5 +76,5 @@
 	fprintf(csv_output, "%s,%d,%" PRIu64 ",%lld\n",
 	    bench->name, run_index, workload_size,
-	    (long long) stopwatch_get_nanos(&meter->stopwatch));
+	    (long long) stopwatch_get_nanos(&run->stopwatch));
 }
 
Index: uspace/app/hbench/doc/doxygroups.h
===================================================================
--- uspace/app/hbench/doc/doxygroups.h	(revision 94ebebf259d1d5d83f702d859ff01bffde3a341c)
+++ uspace/app/hbench/doc/doxygroups.h	(revision e7f9a093b00a54747dbfa7e288153beb04d93009)
@@ -19,22 +19,22 @@
  * benchmark function to the benchmark_t.
  *
- * The benchmarking function has to accept four arguments:
- *  @li benchmeter_t: call benchmeter_start and benchmeter_stop around the
+ * The benchmarking function has to accept two arguments:
+ *  @li bench_run_t: call bench_run_start and bench_run_stop around the
  *      actual benchmarking code
  *  @li uint64_t: size of the workload - typically number of inner loops in
  *      your benchmark (used to self-calibrate benchmark size)
- *  @li char * and size_t giving you access to buffer for storing error message
- *  if the benchmark fails (return false from the function itself then)
  *
  * Typically, the structure of the function is following:
  * @code{c}
- * static bool runner(benchmeter_t *meter, uint64_t size,
- *     char *error, size_t error_size)
+ * static bool runner(bench_run_t *run, uint64_t size)
  * {
- * 	benchmeter_start(meter);
+ * 	bench_run_start(run);
  * 	for (uint64_t i = 0; i < size; i++) {
  * 		// measured action
+ * 		if (something_fails) {
+ * 		    return bench_run_fail(run, "oops: %s (%d)", str_error(rc), rc);
+ * 		}
  * 	}
- * 	benchmeter_stop(meter);
+ * 	bench_run_stop(run);
  *
  * 	return true;
Index: uspace/app/hbench/fs/dirread.c
===================================================================
--- uspace/app/hbench/fs/dirread.c	(revision 94ebebf259d1d5d83f702d859ff01bffde3a341c)
+++ uspace/app/hbench/fs/dirread.c	(revision e7f9a093b00a54747dbfa7e288153beb04d93009)
@@ -44,16 +44,14 @@
  * that the corresponding blocks would be cached after first run.
  */
-static bool runner(benchmeter_t *meter, uint64_t size,
-    char *error, size_t error_size)
+static bool runner(bench_run_t *run, uint64_t size)
 {
 	const char *path = bench_param_get("dirname", "/");
 
-	benchmeter_start(meter);
+	bench_run_start(run);
 	for (uint64_t i = 0; i < size; i++) {
 		DIR *dir = opendir(path);
 		if (dir == NULL) {
-			snprintf(error, error_size, "failed to open %s for reading: %s",
+			return bench_run_fail(run, "failed to open %s for reading: %s",
 			    path, str_error(errno));
-			return false;
 		}
 
@@ -65,5 +63,5 @@
 		closedir(dir);
 	}
-	benchmeter_stop(meter);
+	bench_run_stop(run);
 
 	return true;
Index: uspace/app/hbench/fs/fileread.c
===================================================================
--- uspace/app/hbench/fs/fileread.c	(revision 94ebebf259d1d5d83f702d859ff01bffde3a341c)
+++ uspace/app/hbench/fs/fileread.c	(revision e7f9a093b00a54747dbfa7e288153beb04d93009)
@@ -45,6 +45,5 @@
  * corresponding blocks would be cached after first run.
  */
-static bool runner(benchmeter_t *meter, uint64_t size,
-    char *error, size_t error_size)
+static bool runner(bench_run_t *run, uint64_t size)
 {
 	const char *path = bench_param_get("filename", "/data/web/helenos.png");
@@ -52,6 +51,5 @@
 	char *buf = malloc(BUFFER_SIZE);
 	if (buf == NULL) {
-		snprintf(error, error_size, "failed to allocate %dB buffer", BUFFER_SIZE);
-		return false;
+		return bench_run_fail(run, "failed to allocate %dB buffer", BUFFER_SIZE);
 	}
 
@@ -60,5 +58,5 @@
 	FILE *file = fopen(path, "r");
 	if (file == NULL) {
-		snprintf(error, error_size, "failed to open %s for reading: %s",
+		bench_run_fail(run, "failed to open %s for reading: %s",
 		    path, str_error(errno));
 		ret = false;
@@ -66,9 +64,9 @@
 	}
 
-	benchmeter_start(meter);
+	bench_run_start(run);
 	for (uint64_t i = 0; i < size; i++) {
 		int rc = fseek(file, 0, SEEK_SET);
 		if (rc != 0) {
-			snprintf(error, error_size, "failed to rewind %s: %s",
+			bench_run_fail(run, "failed to rewind %s: %s",
 			    path, str_error(errno));
 			ret = false;
@@ -78,5 +76,5 @@
 			fread(buf, 1, BUFFER_SIZE, file);
 			if (ferror(file)) {
-				snprintf(error, error_size, "failed to read from %s: %s",
+				bench_run_fail(run, "failed to read from %s: %s",
 				    path, str_error(errno));
 				ret = false;
@@ -85,5 +83,5 @@
 		}
 	}
-	benchmeter_stop(meter);
+	bench_run_stop(run);
 
 leave_close:
Index: uspace/app/hbench/hbench.h
===================================================================
--- uspace/app/hbench/hbench.h	(revision 94ebebf259d1d5d83f702d859ff01bffde3a341c)
+++ uspace/app/hbench/hbench.h	(revision e7f9a093b00a54747dbfa7e288153beb04d93009)
@@ -38,8 +38,15 @@
 
 #include <errno.h>
+#include <stdarg.h>
 #include <stdbool.h>
+#include <stdio.h>
 #include <perf.h>
 
-/** Simple wrapper around system stopwatch.
+/** Single run information.
+ *
+ * Used to store both performance information (now, only wall-clock
+ * time) as well as information about error.
+ *
+ * Use proper access functions when modifying data inside this structure.
  *
  * Eventually, we could collection of hardware counters etc. without
@@ -48,24 +55,38 @@
 typedef struct {
 	stopwatch_t stopwatch;
-} benchmeter_t;
+	char *error_buffer;
+	size_t error_buffer_size;
+} bench_run_t;
 
-static inline void benchmeter_init(benchmeter_t *meter)
+static inline void bench_run_init(bench_run_t *run, char *error_buffer,
+    size_t error_buffer_size)
 {
-	stopwatch_init(&meter->stopwatch);
+	stopwatch_init(&run->stopwatch);
+	run->error_buffer = error_buffer;
+	run->error_buffer_size = error_buffer_size;
 }
 
-static inline void benchmeter_start(benchmeter_t *meter)
+static inline void bench_run_start(bench_run_t *run)
 {
-	stopwatch_start(&meter->stopwatch);
+	stopwatch_start(&run->stopwatch);
 }
 
-static inline void benchmeter_stop(benchmeter_t *meter)
+static inline void bench_run_stop(bench_run_t *run)
 {
-	stopwatch_stop(&meter->stopwatch);
+	stopwatch_stop(&run->stopwatch);
 }
 
-typedef bool (*benchmark_entry_t)(benchmeter_t *, uint64_t,
-    char *, size_t);
-typedef bool (*benchmark_helper_t)(char *, size_t);
+static inline bool bench_run_fail(bench_run_t *run, const char *fmt, ...)
+{
+	va_list args;
+	va_start(args, fmt);
+	vsnprintf(run->error_buffer, run->error_buffer_size, fmt, args);
+	va_end(args);
+
+	return false;
+}
+
+typedef bool (*benchmark_entry_t)(bench_run_t *, uint64_t);
+typedef bool (*benchmark_helper_t)(bench_run_t *);
 
 typedef struct {
@@ -81,5 +102,5 @@
 
 extern errno_t csv_report_open(const char *);
-extern void csv_report_add_entry(benchmeter_t *, int, benchmark_t *, uint64_t);
+extern void csv_report_add_entry(bench_run_t *, int, benchmark_t *, uint64_t);
 extern void csv_report_close(void);
 
Index: uspace/app/hbench/ipc/ns_ping.c
===================================================================
--- uspace/app/hbench/ipc/ns_ping.c	(revision 94ebebf259d1d5d83f702d859ff01bffde3a341c)
+++ uspace/app/hbench/ipc/ns_ping.c	(revision e7f9a093b00a54747dbfa7e288153beb04d93009)
@@ -38,8 +38,7 @@
 #include "../hbench.h"
 
-static bool runner(benchmeter_t *meter, uint64_t niter,
-    char *error, size_t error_size)
+static bool runner(bench_run_t *run, uint64_t niter)
 {
-	benchmeter_start(meter);
+	bench_run_start(run);
 
 	for (uint64_t count = 0; count < niter; count++) {
@@ -47,12 +46,10 @@
 
 		if (rc != EOK) {
-			snprintf(error, error_size,
-			    "failed sending ping message: %s (%d)",
+			return bench_run_fail(run, "failed sending ping message: %s (%d)",
 			    str_error(rc), rc);
-			return false;
 		}
 	}
 
-	benchmeter_stop(meter);
+	bench_run_stop(run);
 
 	return true;
Index: uspace/app/hbench/ipc/ping_pong.c
===================================================================
--- uspace/app/hbench/ipc/ping_pong.c	(revision 94ebebf259d1d5d83f702d859ff01bffde3a341c)
+++ uspace/app/hbench/ipc/ping_pong.c	(revision e7f9a093b00a54747dbfa7e288153beb04d93009)
@@ -40,12 +40,11 @@
 static ipc_test_t *test = NULL;
 
-static bool setup(char *error, size_t error_size)
+static bool setup(bench_run_t *run)
 {
 	errno_t rc = ipc_test_create(&test);
 	if (rc != EOK) {
-		snprintf(error, error_size,
+		return bench_run_fail(run,
 		    "failed contacting IPC test server (have you run /srv/test/ipc-test?): %s (%d)",
 		    str_error(rc), rc);
-		return false;
 	}
 
@@ -53,5 +52,5 @@
 }
 
-static bool teardown(char *error, size_t error_size)
+static bool teardown(bench_run_t *run)
 {
 	ipc_test_destroy(test);
@@ -59,8 +58,7 @@
 }
 
-static bool runner(benchmeter_t *meter, uint64_t niter,
-    char *error, size_t error_size)
+static bool runner(bench_run_t *run, uint64_t niter)
 {
-	benchmeter_start(meter);
+	bench_run_start(run);
 
 	for (uint64_t count = 0; count < niter; count++) {
@@ -68,12 +66,10 @@
 
 		if (rc != EOK) {
-			snprintf(error, error_size,
-			    "failed sending ping message: %s (%d)",
+			return bench_run_fail(run, "failed sending ping message: %s (%d)",
 			    str_error(rc), rc);
-			return false;
 		}
 	}
 
-	benchmeter_stop(meter);
+	bench_run_stop(run);
 
 	return true;
Index: uspace/app/hbench/main.c
===================================================================
--- uspace/app/hbench/main.c	(revision 94ebebf259d1d5d83f702d859ff01bffde3a341c)
+++ uspace/app/hbench/main.c	(revision e7f9a093b00a54747dbfa7e288153beb04d93009)
@@ -53,15 +53,15 @@
 #define MAX_ERROR_STR_LENGTH 1024
 
-static void short_report(benchmeter_t *meter, int run_index,
+static void short_report(bench_run_t *info, int run_index,
     benchmark_t *bench, uint64_t workload_size)
 {
-	csv_report_add_entry(meter, run_index, bench, workload_size);
-
-	usec_t duration_usec = NSEC2USEC(stopwatch_get_nanos(&meter->stopwatch));
+	csv_report_add_entry(info, run_index, bench, workload_size);
+
+	usec_t duration_usec = NSEC2USEC(stopwatch_get_nanos(&info->stopwatch));
 
 	printf("Completed %" PRIu64 " operations in %llu us",
 	    workload_size, duration_usec);
 	if (duration_usec > 0) {
-		double nanos = stopwatch_get_nanos(&meter->stopwatch);
+		double nanos = stopwatch_get_nanos(&info->stopwatch);
 		double thruput = (double) workload_size / (nanos / 1000000000.0l);
 		printf(", %.0f ops/s.\n", thruput);
@@ -111,5 +111,5 @@
  *
  */
-static void compute_stats(benchmeter_t *meter, size_t stopwatch_count,
+static void compute_stats(bench_run_t *runs, size_t run_count,
     uint64_t workload_size, double precision, double *out_duration_avg,
     double *out_duration_sigma, double *out_thruput_avg)
@@ -119,6 +119,6 @@
 	double nanos_sum2 = 0.0;
 
-	for (size_t i = 0; i < stopwatch_count; i++) {
-		double nanos = stopwatch_get_nanos(&meter[i].stopwatch);
+	for (size_t i = 0; i < run_count; i++) {
+		double nanos = stopwatch_get_nanos(&runs[i].stopwatch);
 		double thruput = (double) workload_size / nanos;
 
@@ -127,17 +127,17 @@
 		nanos_sum2 += nanos * nanos;
 	}
-	*out_duration_avg = nanos_sum / stopwatch_count;
+	*out_duration_avg = nanos_sum / run_count;
 	double sigma2 = (nanos_sum2 - nanos_sum * (*out_duration_avg)) /
-	    ((double) stopwatch_count - 1);
+	    ((double) run_count - 1);
 	// FIXME: implement sqrt properly
 	*out_duration_sigma = estimate_square_root(sigma2, precision);
-	*out_thruput_avg = 1.0 / (inv_thruput_sum / stopwatch_count);
-}
-
-static void summary_stats(benchmeter_t *meter, size_t meter_count,
+	*out_thruput_avg = 1.0 / (inv_thruput_sum / run_count);
+}
+
+static void summary_stats(bench_run_t *runs, size_t run_count,
     benchmark_t *bench, uint64_t workload_size)
 {
 	double duration_avg, duration_sigma, thruput_avg;
-	compute_stats(meter, meter_count, workload_size, 0.001,
+	compute_stats(runs, run_count, workload_size, 0.001,
 	    &duration_avg, &duration_sigma, &thruput_avg);
 
@@ -145,5 +145,5 @@
 	    "%.0f ops/s; Samples: %zu\n",
 	    workload_size, duration_avg / 1000.0, duration_sigma / 1000.0,
-	    thruput_avg * 1000000000.0, meter_count);
+	    thruput_avg * 1000000000.0, run_count);
 }
 
@@ -152,4 +152,8 @@
 	printf("Warm up and determine workload size...\n");
 
+	/*
+	 * We share this buffer across all runs as we know that it is
+	 * used only on failure (and we abort after first error).
+	 */
 	char *error_msg = malloc(MAX_ERROR_STR_LENGTH + 1);
 	if (error_msg == NULL) {
@@ -159,8 +163,11 @@
 	str_cpy(error_msg, MAX_ERROR_STR_LENGTH, "");
 
+	bench_run_t helper_run;
+	bench_run_init(&helper_run, error_msg, MAX_ERROR_STR_LENGTH);
+
 	bool ret = true;
 
 	if (bench->setup != NULL) {
-		ret = bench->setup(error_msg, MAX_ERROR_STR_LENGTH);
+		ret = bench->setup(&helper_run);
 		if (!ret) {
 			goto leave_error;
@@ -180,15 +187,14 @@
 		workload_size = ((uint64_t) 1) << bits;
 
-		benchmeter_t meter;
-		benchmeter_init(&meter);
-
-		bool ok = bench->entry(&meter, workload_size,
-		    error_msg, MAX_ERROR_STR_LENGTH);
+		bench_run_t run;
+		bench_run_init(&run, error_msg, MAX_ERROR_STR_LENGTH);
+
+		bool ok = bench->entry(&run, workload_size);
 		if (!ok) {
 			goto leave_error;
 		}
-		short_report(&meter, -1, bench, workload_size);
-
-		nsec_t duration = stopwatch_get_nanos(&meter.stopwatch);
+		short_report(&run, -1, bench, workload_size);
+
+		nsec_t duration = stopwatch_get_nanos(&run.stopwatch);
 		if (duration > SEC2NSEC(MIN_DURATION_SECS)) {
 			break;
@@ -198,25 +204,24 @@
 	printf("Workload size set to %" PRIu64 ", measuring %d samples.\n", workload_size, NUM_SAMPLES);
 
-	benchmeter_t *meter = calloc(NUM_SAMPLES, sizeof(benchmeter_t));
-	if (meter == NULL) {
+	bench_run_t *runs = calloc(NUM_SAMPLES, sizeof(bench_run_t));
+	if (runs == NULL) {
 		snprintf(error_msg, MAX_ERROR_STR_LENGTH, "failed allocating memory");
 		goto leave_error;
 	}
 	for (int i = 0; i < NUM_SAMPLES; i++) {
-		benchmeter_init(&meter[i]);
-
-		bool ok = bench->entry(&meter[i], workload_size,
-		    error_msg, MAX_ERROR_STR_LENGTH);
+		bench_run_init(&runs[i], error_msg, MAX_ERROR_STR_LENGTH);
+
+		bool ok = bench->entry(&runs[i], workload_size);
 		if (!ok) {
-			free(meter);
+			free(runs);
 			goto leave_error;
 		}
-		short_report(&meter[i], i, bench, workload_size);
-	}
-
-	summary_stats(meter, NUM_SAMPLES, bench, workload_size);
+		short_report(&runs[i], i, bench, workload_size);
+	}
+
+	summary_stats(runs, NUM_SAMPLES, bench, workload_size);
 	printf("\nBenchmark completed\n");
 
-	free(meter);
+	free(runs);
 
 	goto leave;
@@ -228,5 +233,5 @@
 leave:
 	if (bench->teardown != NULL) {
-		bool ok = bench->teardown(error_msg, MAX_ERROR_STR_LENGTH);
+		bool ok = bench->teardown(&helper_run);
 		if (!ok) {
 			printf("Error: %s\n", error_msg);
Index: uspace/app/hbench/malloc/malloc1.c
===================================================================
--- uspace/app/hbench/malloc/malloc1.c	(revision 94ebebf259d1d5d83f702d859ff01bffde3a341c)
+++ uspace/app/hbench/malloc/malloc1.c	(revision e7f9a093b00a54747dbfa7e288153beb04d93009)
@@ -36,19 +36,17 @@
 #include "../hbench.h"
 
-static bool runner(benchmeter_t *meter, uint64_t size,
-    char *error, size_t error_size)
+static bool runner(bench_run_t *run, uint64_t size)
 {
-	benchmeter_start(meter);
+	bench_run_start(run);
 	for (uint64_t i = 0; i < size; i++) {
 		void *p = malloc(1);
 		if (p == NULL) {
-			snprintf(error, error_size,
+			return bench_run_fail(run,
 			    "failed to allocate 1B in run %" PRIu64 " (out of %" PRIu64 ")",
 			    i, size);
-			return false;
 		}
 		free(p);
 	}
-	benchmeter_stop(meter);
+	bench_run_stop(run);
 
 	return true;
Index: uspace/app/hbench/malloc/malloc2.c
===================================================================
--- uspace/app/hbench/malloc/malloc2.c	(revision 94ebebf259d1d5d83f702d859ff01bffde3a341c)
+++ uspace/app/hbench/malloc/malloc2.c	(revision e7f9a093b00a54747dbfa7e288153beb04d93009)
@@ -35,15 +35,12 @@
 #include "../hbench.h"
 
-static bool runner(benchmeter_t *meter, uint64_t niter,
-    char *error, size_t error_size)
+static bool runner(bench_run_t *run, uint64_t niter)
 {
-	benchmeter_start(meter);
+	bench_run_start(run);
 
 	void **p = malloc(niter * sizeof(void *));
 	if (p == NULL) {
-		snprintf(error, error_size,
-		    "failed to allocate backend array (%" PRIu64 "B)",
+		return bench_run_fail(run, "failed to allocate backend array (%" PRIu64 "B)",
 		    niter * sizeof(void *));
-		return false;
 	}
 
@@ -51,12 +48,11 @@
 		p[count] = malloc(1);
 		if (p[count] == NULL) {
-			snprintf(error, error_size,
-			    "failed to allocate 1B in run %" PRIu64 " (out of %" PRIu64 ")",
-			    count, niter);
 			for (uint64_t j = 0; j < count; j++) {
 				free(p[j]);
 			}
 			free(p);
-			return false;
+			return bench_run_fail(run,
+			    "failed to allocate 1B in run %" PRIu64 " (out of %" PRIu64 ")",
+			    count, niter);
 		}
 	}
@@ -67,5 +63,5 @@
 	free(p);
 
-	benchmeter_stop(meter);
+	bench_run_stop(run);
 
 	return true;
Index: uspace/app/hbench/synch/fibril_mutex.c
===================================================================
--- uspace/app/hbench/synch/fibril_mutex.c	(revision 94ebebf259d1d5d83f702d859ff01bffde3a341c)
+++ uspace/app/hbench/synch/fibril_mutex.c	(revision e7f9a093b00a54747dbfa7e288153beb04d93009)
@@ -65,6 +65,5 @@
 }
 
-static bool runner(benchmeter_t *meter, uint64_t size,
-    char *error, size_t error_size)
+static bool runner(bench_run_t *run, uint64_t size)
 {
 	shared_t shared;
@@ -76,5 +75,5 @@
 	fibril_add_ready(other);
 
-	benchmeter_start(meter);
+	bench_run_start(run);
 	for (uint64_t i = 0; i < size; i++) {
 		fibril_mutex_lock(&shared.mutex);
@@ -82,5 +81,5 @@
 		fibril_mutex_unlock(&shared.mutex);
 	}
-	benchmeter_stop(meter);
+	bench_run_stop(run);
 
 	while (!atomic_load(&shared.done)) {
