Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 /* | |
| 2 * Copyright (c) 2011 The Chromium OS Authors. All rights reserved. | |
| 3 * Use of this source code is governed by a BSD-style license that can be | |
| 4 * found in the LICENSE file. | |
| 5 * | |
| 6 * Alternatively, this software may be distributed under the terms of the | |
| 7 * GNU General Public License ("GPL") version 2 as published by the Free | |
| 8 * Software Foundation. | |
| 9 */ | |
| 10 | |
| 11 /* time - run a command and report its run time */ | |
| 12 | |
| 13 #include <common.h> | |
| 14 #include <command.h> | |
| 15 | |
| 16 #define ABSDIFF(u, v) ({ \ | |
| 17 const unsigned long int __u = (u), __v = (v); \ | |
| 18 __u > __v ? __u - __v : __v - __u; \ | |
| 19 }) | |
| 20 | |
| 21 static void report_time(unsigned long int cycles) | |
| 22 { | |
| 23 #ifdef CONFIG_SYS_HZ | |
| 24 unsigned long int minutes, seconds, milliseconds; | |
| 25 unsigned long int total_seconds, remainder, guess, err, err2; | |
| 26 | |
| 27 total_seconds = cycles / CONFIG_SYS_HZ; | |
| 28 minutes = total_seconds / 60; | |
| 29 seconds = total_seconds % 60; | |
| 30 | |
| 31 /* | |
| 32 * We could approximate millisecond value through | |
| 33 * milliseconds = rounding(1000.0 * remainder / CONFIG_SYS_HZ) | |
| 34 * where | |
| 35 * remainder = cycles % CONFIG_SYS_HZ, | |
| 36 * which minimizes the error | |
| 37 * fabs(((float) remainder) / CONFIG_SYS_HZ - milliseconds / 1000.0). | |
| 38 * | |
| 39 * Nevertheless, this approximation, though precise, is undesirable | |
| 40 * for its use of floating-point arithmetic. | |
| 41 * | |
| 42 * So instead we approximate the millisecond value through a 2-step | |
| 43 * method that only uses integer arithmetic. | |
| 44 * | |
| 45 * First, we compute an initial guess | |
| 46 * guess = remainder * 1000 / CONFIG_SYS_HZ. | |
| 47 * | |
| 48 * Then, we adjust the initial guess to form a better guess by | |
| 49 * trying guess - 1 and guess + 1. | |
| 50 * | |
| 51 * My experiment showed that in most cases this 2-step approximation | |
| 52 * is as good as the floating-point approximation method above. | |
| 53 * | |
| 54 * Note: We compute the error using | |
| 55 * abs(remainder * 1000 - milliseconds * CONFIG_SYS_HZ) | |
| 56 * to avoid divisions (and truncation errors). | |
| 57 */ | |
| 58 | |
| 59 /* initial guess */ | |
| 60 remainder = cycles % CONFIG_SYS_HZ; | |
| 61 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.
| |
| 62 err = ABSDIFF(remainder * 1000, guess * CONFIG_SYS_HZ); | |
| 63 | |
| 64 /* try guess - 1 */ | |
| 65 if (guess > 0) { | |
| 66 err2 = ABSDIFF(remainder * 1000, (guess - 1) * CONFIG_SYS_HZ); | |
| 67 if (err2 < err) { | |
| 68 milliseconds = guess - 1; | |
| 69 err = err2; | |
| 70 } | |
| 71 } | |
| 72 | |
| 73 /* try guess + 1 */ | |
| 74 if (guess < 999) { | |
| 75 err2 = ABSDIFF(remainder * 1000, (guess + 1) * CONFIG_SYS_HZ); | |
| 76 if (err2 < err) { | |
| 77 milliseconds = guess + 1; | |
| 78 err = err2; | |
| 79 } | |
| 80 } | |
| 81 | |
| 82 printf("time:"); | |
| 83 if (minutes) | |
| 84 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.
| |
| 85 printf(" %lu.%03lu seconds, or", seconds, milliseconds); | |
| 86 printf(" %lu ticks\n", cycles); | |
| 87 #else | |
| 88 printf("CONFIG_SYS_HZ not defined\n"); | |
| 89 printf("time: %lu ticks\n", cycles); | |
| 90 #endif | |
| 91 } | |
| 92 | |
| 93 int do_time(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) | |
| 94 { | |
| 95 const int target_argc = argc - 1; | |
| 96 int retval = 0; | |
| 97 unsigned long int cycles = 0; | |
| 98 cmd_tbl_t *target_cmdtp = NULL; | |
| 99 | |
| 100 if (argc == 1) { | |
| 101 printf("no command provided\n"); | |
| 102 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
| |
| 103 } | |
| 104 | |
| 105 /* parse command */ | |
| 106 target_cmdtp = find_cmd(argv[1]); | |
| 107 if (!target_cmdtp) { | |
| 108 printf("command not found: %s\n", argv[1]); | |
| 109 return 128; | |
| 110 } | |
| 111 | |
| 112 if (target_argc > target_cmdtp->maxargs) { | |
| 113 printf("maxarags exceeded: %d > %d\n", target_argc, | |
| 114 target_cmdtp->maxargs); | |
| 115 return 128; | |
| 116 } | |
| 117 | |
| 118 /* run the command and report run time */ | |
| 119 cycles = get_timer_masked(); | |
| 120 retval = target_cmdtp->cmd(target_cmdtp, 0, target_argc, argv + 1); | |
| 121 cycles = get_timer_masked() - cycles; | |
| 122 | |
| 123 putc('\n'); | |
| 124 report_time(cycles); | |
| 125 | |
| 126 return retval; | |
| 127 } | |
| 128 | |
| 129 U_BOOT_CMD(time, CONFIG_SYS_MAXARGS, 0, do_time, | |
| 130 "run a command and report its run time", | |
| 131 "command [args...]\n" | |
| 132 "the return value of time is the return value of " | |
| 133 "the command it executed, " | |
| 134 "or 128 if there is an internal error of time.\n"); | |
| OLD | NEW |