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 |