Index: common/cmd_time.c |
diff --git a/common/cmd_time.c b/common/cmd_time.c |
new file mode 100644 |
index 0000000000000000000000000000000000000000..689b671e45a8842ba55570fcfebe53d09562392f |
--- /dev/null |
+++ b/common/cmd_time.c |
@@ -0,0 +1,134 @@ |
+/* |
+ * Copyright (c) 2011 The Chromium OS Authors. All rights reserved. |
+ * Use of this source code is governed by a BSD-style license that can be |
+ * found in the LICENSE file. |
+ * |
+ * Alternatively, this software may be distributed under the terms of the |
+ * GNU General Public License ("GPL") version 2 as published by the Free |
+ * Software Foundation. |
+ */ |
+ |
+/* time - run a command and report its run time */ |
+ |
+#include <common.h> |
+#include <command.h> |
+ |
+#define ABSDIFF(u, v) ({ \ |
+ const unsigned long int __u = (u), __v = (v); \ |
+ __u > __v ? __u - __v : __v - __u; \ |
+}) |
+ |
+static void report_time(unsigned long int cycles) |
+{ |
+#ifdef CONFIG_SYS_HZ |
+ unsigned long int minutes, seconds, milliseconds; |
+ unsigned long int total_seconds, remainder, guess, err, err2; |
+ |
+ total_seconds = cycles / CONFIG_SYS_HZ; |
+ minutes = total_seconds / 60; |
+ seconds = total_seconds % 60; |
+ |
+ /* |
+ * We could approximate millisecond value through |
+ * milliseconds = rounding(1000.0 * remainder / CONFIG_SYS_HZ) |
+ * where |
+ * remainder = cycles % CONFIG_SYS_HZ, |
+ * which minimizes the error |
+ * fabs(((float) remainder) / CONFIG_SYS_HZ - milliseconds / 1000.0). |
+ * |
+ * Nevertheless, this approximation, though precise, is undesirable |
+ * for its use of floating-point arithmetic. |
+ * |
+ * So instead we approximate the millisecond value through a 2-step |
+ * method that only uses integer arithmetic. |
+ * |
+ * First, we compute an initial guess |
+ * guess = remainder * 1000 / CONFIG_SYS_HZ. |
+ * |
+ * Then, we adjust the initial guess to form a better guess by |
+ * trying guess - 1 and guess + 1. |
+ * |
+ * My experiment showed that in most cases this 2-step approximation |
+ * is as good as the floating-point approximation method above. |
+ * |
+ * Note: We compute the error using |
+ * abs(remainder * 1000 - milliseconds * CONFIG_SYS_HZ) |
+ * to avoid divisions (and truncation errors). |
+ */ |
+ |
+ /* initial guess */ |
+ remainder = cycles % CONFIG_SYS_HZ; |
+ milliseconds = guess = remainder * 1000 / CONFIG_SYS_HZ; |
sjg
2011/04/05 01:21:44
I think it is good enough if you just stop here. D
Che-Liang Chiou
2011/04/06 08:48:40
Thanks. This is better.
|
+ err = ABSDIFF(remainder * 1000, guess * CONFIG_SYS_HZ); |
+ |
+ /* try guess - 1 */ |
+ if (guess > 0) { |
+ err2 = ABSDIFF(remainder * 1000, (guess - 1) * CONFIG_SYS_HZ); |
+ if (err2 < err) { |
+ milliseconds = guess - 1; |
+ err = err2; |
+ } |
+ } |
+ |
+ /* try guess + 1 */ |
+ if (guess < 999) { |
+ err2 = ABSDIFF(remainder * 1000, (guess + 1) * CONFIG_SYS_HZ); |
+ if (err2 < err) { |
+ milliseconds = guess + 1; |
+ err = err2; |
+ } |
+ } |
+ |
+ printf("time:"); |
+ if (minutes) |
+ printf(" %lu minutes and", minutes); |
sjg
2011/04/05 01:21:44
It might be easier for a test system to parse if y
Che-Liang Chiou
2011/04/06 08:48:40
Done.
|
+ printf(" %lu.%03lu seconds, or", seconds, milliseconds); |
+ printf(" %lu ticks\n", cycles); |
+#else |
+ printf("CONFIG_SYS_HZ not defined\n"); |
+ printf("time: %lu ticks\n", cycles); |
+#endif |
+} |
+ |
+int do_time(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
+{ |
+ const int target_argc = argc - 1; |
+ int retval = 0; |
+ unsigned long int cycles = 0; |
+ cmd_tbl_t *target_cmdtp = NULL; |
+ |
+ if (argc == 1) { |
+ printf("no command provided\n"); |
+ return 128; |
sjg
2011/04/05 01:21:44
What is the significance of 128? Is it argument er
Che-Liang Chiou
2011/04/06 08:48:40
I thought that we might be able to know either it
|
+ } |
+ |
+ /* parse command */ |
+ target_cmdtp = find_cmd(argv[1]); |
+ if (!target_cmdtp) { |
+ printf("command not found: %s\n", argv[1]); |
+ return 128; |
+ } |
+ |
+ if (target_argc > target_cmdtp->maxargs) { |
+ printf("maxarags exceeded: %d > %d\n", target_argc, |
+ target_cmdtp->maxargs); |
+ return 128; |
+ } |
+ |
+ /* run the command and report run time */ |
+ cycles = get_timer_masked(); |
+ retval = target_cmdtp->cmd(target_cmdtp, 0, target_argc, argv + 1); |
+ cycles = get_timer_masked() - cycles; |
+ |
+ putc('\n'); |
+ report_time(cycles); |
+ |
+ return retval; |
+} |
+ |
+U_BOOT_CMD(time, CONFIG_SYS_MAXARGS, 0, do_time, |
+ "run a command and report its run time", |
+ "command [args...]\n" |
+ "the return value of time is the return value of " |
+ "the command it executed, " |
+ "or 128 if there is an internal error of time.\n"); |