-
Notifications
You must be signed in to change notification settings - Fork 31
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix the max precision of the 'time' keyword #72
Conversation
1748f4e
to
68740bf
Compare
@JohnoKing, wondering if you have taken into account the following existing code that pertains to $SECONDS: Lines 571 to 628 in 84e2f6d
|
The $ echo $SECONDS
1547.796 If $ echo $SECONDS; sleep .002; echo $SECONDS
18.420
18.420 I'll update my gist to implement microsecond precision for |
c8fb934
to
c64cce1
Compare
I was not worried about the lesser precision (.01) when the OS cannot provide it. When I reviewed your code, you used names of variables and such that had already been defined elsewhere (might want to check out the alarm.c and timers.c as well). As far as changing
ksh currently limits the output of variable
If one wishes the
|
The sleep builtin in ksh93v- handles microseconds just fine, indicating a bugfix to backport. This can be demonstrated by running the following loop in ksh93u+ and ksh93v-: $ cat ./loop.sh
for ((i = 0; i != 10000; i++)) do
sleep PT100U
done
# The results below are inflated due to overhead from the for loop,
# but the time elapsed should be at least one second. In ksh93u+ the
# time elapsed is much lower because microseconds are ignored.
$ time ksh93u+ ./loop.sh
real 0m0.06s
user 0m0.04s
sys 0m0.02s
$ time ksh93v- ./loop.sh
real 0m1.58s
user 0m0.07s
sys 0m0.00s |
Very nice find on the sleep builtin! Also, thank you for improving ksh93 as working on the time keyword was on my todo list. What's more, my systems are so much slower than yours.
|
Nice work. However, after applying, ksh no longer uses the locale's radix point ( Test command: $ LC_ALL=nl_NL.UTF-8 TIMEFORMAT=$'\nreal\t%3R\tuser\t%3U\tsys\t%3S' ksh -c 'time sleep 1.235' Output before:
Output after:
Unsurprisingly, ksh2020 has this problem as well. |
The locale's radix point is now used when |
This commit backports the required fixes from ksh2020 for using millisecond precision with the 'time' keyword. The bugfix refactors a decent amount of code to rely on the BSD 'timeradd' and 'timersub' macros for calculating the total amount of time elapsed (as these aren't standard, they are selectively implemented in an iffe feature test for platforms without them). getrusage(3) is now preferred since it usually has higher precision than times(3) (the latter is used as a fallback). This patch can be extended with support for microsecond precision, although that is better left for a separate feature branch. There are three other fixes as well: src/lib/libast/features/time: - Test for getrusage with an iffe feature test rather than assume _sys_times == _lib_getrusage. src/cmd/ksh93/sh/xec.c: - A single percent at the end of a format specifier is now treated as a literal '%' (like in Bash). - Zero-pad seconds if seconds < 10. This was already done for the times builtin in commit 5c677a4, although it wasn't applied to the time keyword. - Backport the ksh2020 bugfix for the time keyword by using timeradd and timersub with gettimeofday (which is used with a timeofday macro). Prefer getrusage when it is available. src/cmd/ksh93/features/time: - Implement feature tests for the 'timeradd' and 'timersub' macros. - Do a feature test for getrusage like in the libast time test. src/cmd/ksh93/tests/basic.sh: - Add two tests for millisecond precision and the handling of '%' at the end of a format specifier.
src/cmd/ksh93/sh/xec.c: - Allow compiling without the 'timeofday' ifdef for better portability. This is the order of priority for getting the elapsed time: 1) getrusage (most precise) 2) times + gettimeofday (best fallback) 3) only times (doesn't support millisecond precision) This was tested by using debug '#undef' statements in xec.c.
src/cmd/ksh93/sh/xec.c: - Restore some old code for the fallback when _lib_getrusage and timeofday aren't defined to fix a bus error.
b07d114
to
07121af
Compare
src/cmd/ksh93/sh/xec.c: - In subshells, getrusage must be run after forking. If it isn't, 'time' can return negative user and system times. src/cmd/ksh93/tests/basic.sh: - Modify the radix regression test to check for negative numbers as well.
02a117e
to
7f0d569
Compare
The change from att/ast@27777b3d has been reverted because it caused a regression in command substitutions. The user and system time were intermittently returning negative numbers because $ t=$(time sleep 0)
real 0m00.00s
user 0m-1.99s
sys 0m-1.99s |
I'm getting this regression test failure:
You probably want |
I have changed |
Yes, it's very strange. I've tried using variants of |
Anyway, that's not directly relevant to this pull request. It looks good to me now. Are you still doing tests? Let me know when you consider it ready to merge. |
Actually, what is your method of testing the fallback that uses times(3) (with neither timeofday() nor getrusage(3) available)? I can't seem to get there without triggering a segfault. |
Here is a debug patch: --- a/src/cmd/ksh93/sh/xec.c
+++ b/src/cmd/ksh93/sh/xec.c
@@ -64,6 +64,16 @@
static pid_t sh_ntfork(Shell_t*,const Shnode_t*,char*[],int*,int);
#endif /* SHOPT_SPAWN */
+/* Note: If _lib_getrusage is defined then timeofday must be defined as well.
+ This forces the standalone times(3) fallback. */
+#if SHOPT_ONLY_TIMES
+#undef _lib_getrusage
+#undef timeofday
+#elif SHOPT_TIMES_WITH_GETTIMEOFDAY
+/* Fallback to times + gettimeofday without getrusage */
+#undef _lib_getrusage
+#endif
+
static void sh_funct(Shell_t *,Namval_t*, int, char*[], struct argnod*,int);
static void coproc_init(Shell_t*, int pipes[]);
|
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Also, thanks for the patch for microsecond precision; it appears to be working nicely. I'll add that to my post-release todo list. :) |
This commit backports the main changes to sh_delay from ksh93v- and ksh2020, which fixes the following bugs: - Microsecond amounts of less than one millisecond are no longer ignored. The following loop will now take a minimum of one second to complete: for ((i = 0; i != 10000; i++)) do sleep PT100U done - 'sleep 30' no longer adds an extra 30 milliseconds to the total amount of time to sleep. This bug is hard to notice since 30 milliseconds can be considered within the margin of error. The only reason why longer delays weren't affected is because the old code masked the bug when the interval is greater than 30 seconds: else if(n > 30) { sleep(n); t -= n; } This caused 'sleep -s' to break with intervals greater than 30 seconds, so an actual fix is used instead of a workaround. - 'sleep -s' now functions correctly with intervals of more than 30 seconds as the new code doesn't need the old workaround. This is done by handling '-s' in sh_delay. src/cmd/ksh93/bltins/sleep.c: - Remove the replacement for sleep(3) from the sleep builtin. - Replace the old sh_delay function with the newer one from ksh2020. The new function uses tvsleep, which uses nanosleep(3) internally. src/cmd/ksh93/include/shell.h, src/cmd/ksh93/edit/edit.c, src/cmd/ksh93/sh/jobs.c, src/cmd/ksh93/sh/xec.c, src/cmd/ksh93/shell.3: - Update sh_delay documentation and usage since the function now requires two arguments. src/cmd/ksh93/tests/builtins.sh: - Add a regression test for 'sleep -s' when the interval is greater than 30 seconds. The other bugs can't be tested for in a feasible manner across all systems: ksh93#72 (comment)
This commit backports the main changes to sh_delay from ksh93v- and ksh2020, which fixes the following bugs: - Microsecond amounts of less than one millisecond are no longer ignored. The following loop will now take a minimum of one second to complete: for ((i = 0; i != 10000; i++)) do sleep PT100U done - 'sleep 30' no longer adds an extra 30 milliseconds to the total amount of time to sleep. This bug is hard to notice since 30 milliseconds can be considered within the margin of error. The only reason why longer delays weren't affected is because the old code masked the bug when the interval is greater than 30 seconds: else if(n > 30) { sleep(n); t -= n; } This caused 'sleep -s' to break with intervals greater than 30 seconds, so an actual fix is used instead of a workaround. - 'sleep -s' now functions correctly with intervals of more than 30 seconds as the new code doesn't need the old workaround. This is done by handling '-s' in sh_delay. src/cmd/ksh93/bltins/sleep.c: - Remove the replacement for sleep(3) from the sleep builtin. - Replace the old sh_delay function with the newer one from ksh2020. The new function uses tvsleep, which uses nanosleep(3) internally. src/cmd/ksh93/include/shell.h, src/cmd/ksh93/edit/edit.c, src/cmd/ksh93/sh/jobs.c, src/cmd/ksh93/sh/xec.c, src/cmd/ksh93/shell.3: - Update sh_delay documentation and usage since the function now requires two arguments. src/cmd/ksh93/tests/builtins.sh: - Add a regression test for 'sleep -s' when the interval is greater than 30 seconds. The other bugs can't be tested for in a feasible manner across all systems: ksh93#72 (comment)
This commit backports the main changes to sh_delay from ksh93v- and ksh2020, which fixes the following bugs: - Microsecond amounts of less than one millisecond are no longer ignored. The following loop will now take a minimum of one second to complete: for ((i = 0; i != 10000; i++)) do sleep PT100U done - 'sleep 30' no longer adds an extra 30 milliseconds to the total amount of time to sleep. This bug is hard to notice since 30 milliseconds can be considered within the margin of error. The only reason why longer delays weren't affected is because the old code masked the bug when the interval is greater than 30 seconds: else if(n > 30) { sleep(n); t -= n; } This caused 'sleep -s' to break with intervals greater than 30 seconds, so an actual fix is used instead of a workaround. - 'sleep -s' now functions correctly with intervals of more than 30 seconds as the new code doesn't need the old workaround. This is done by handling '-s' in sh_delay. src/cmd/ksh93/bltins/sleep.c: - Remove the replacement for sleep(3) from the sleep builtin. - Replace the old sh_delay function with the newer one from ksh2020. The new function uses tvsleep, which uses nanosleep(3) internally. src/cmd/ksh93/include/shell.h, src/cmd/ksh93/edit/edit.c, src/cmd/ksh93/sh/jobs.c, src/cmd/ksh93/sh/xec.c, src/cmd/ksh93/shell.3: - Update sh_delay documentation and usage since the function now requires two arguments. src/cmd/ksh93/tests/builtins.sh: - Add a regression test for 'sleep -s' when the interval is greater than 30 seconds. The other bugs can't be tested for in a feasible manner across all systems: ksh93#72 (comment)
This commit backports the main changes to sh_delay from ksh93v- and ksh2020, which fixes the following bugs: - Microsecond amounts of less than one millisecond are no longer ignored. The following loop will now take a minimum of one second to complete: for ((i = 0; i != 10000; i++)) do sleep PT100U done - 'sleep 30' no longer adds an extra 30 milliseconds to the total amount of time to sleep. This bug is hard to notice since 30 milliseconds can be considered within the margin of error. The only reason why longer delays weren't affected is because the old code masked the bug when the interval is greater than 30 seconds: else if(n > 30) { sleep(n); t -= n; } This caused 'sleep -s' to break with intervals greater than 30 seconds, so an actual fix is used instead of a workaround. - 'sleep -s' now functions correctly with intervals of more than 30 seconds as the new code doesn't need the old workaround. This is done by handling '-s' in sh_delay. src/cmd/ksh93/bltins/sleep.c: - Remove the replacement for sleep(3) from the sleep builtin. - Replace the old sh_delay function with the newer one from ksh2020. The new function uses tvsleep, which uses nanosleep(3) internally. src/cmd/ksh93/include/shell.h, src/cmd/ksh93/edit/edit.c, src/cmd/ksh93/sh/jobs.c, src/cmd/ksh93/sh/xec.c, src/cmd/ksh93/shell.3: - Update sh_delay documentation and usage since the function now requires two arguments. src/cmd/ksh93/tests/builtins.sh: - Add a regression test for 'sleep -s' when the interval is greater than 30 seconds. The other bugs can't be tested for in a feasible manner across all systems: ksh93#72 (comment)
This commit backports the main changes to sh_delay from ksh93v- and ksh2020, which fixes the following bugs: - Microsecond amounts of less than one millisecond are no longer ignored. The following loop will now take a minimum of one second to complete: for ((i = 0; i != 10000; i++)) do sleep PT100U done - 'sleep 30' no longer adds an extra 30 milliseconds to the total amount of time to sleep. This bug is hard to notice since 30 milliseconds can be considered within the margin of error. The only reason why longer delays weren't affected is because the old code masked the bug when the interval is greater than 30 seconds: else if(n > 30) { sleep(n); t -= n; } This caused 'sleep -s' to break with intervals greater than 30 seconds, so an actual fix is used instead of a workaround. - 'sleep -s' now functions correctly with intervals of more than 30 seconds as the new code doesn't need the old workaround. This is done by handling '-s' in sh_delay. src/cmd/ksh93/bltins/sleep.c: - Remove the replacement for sleep(3) from the sleep builtin. - Replace the old sh_delay function with the newer one from ksh2020. The new function uses tvsleep, which uses nanosleep(3) internally. src/cmd/ksh93/include/shell.h, src/cmd/ksh93/edit/edit.c, src/cmd/ksh93/sh/jobs.c, src/cmd/ksh93/sh/xec.c, src/cmd/ksh93/shell.3: - Update sh_delay documentation and usage since the function now requires two arguments. src/cmd/ksh93/tests/builtins.sh: - Add a regression test for 'sleep -s' when the interval is greater than 30 seconds. The other bugs can't be tested for in a feasible manner across all systems: ksh93#72 (comment)
This commit backports the main changes to sh_delay from ksh93v- and ksh2020, which fixes the following bugs: - Microsecond amounts of less than one millisecond are no longer ignored. The following loop will now take a minimum of one second to complete: for ((i = 0; i != 10000; i++)) do sleep PT100U done - 'sleep 30' no longer adds an extra 30 milliseconds to the total amount of time to sleep. This bug is hard to notice since 30 milliseconds can be considered within the margin of error. The only reason why longer delays weren't affected is because the old code masked the bug when the interval is greater than 30 seconds: else if(n > 30) { sleep(n); t -= n; } This caused 'sleep -s' to break with intervals greater than 30 seconds, so an actual fix is used instead of a workaround. - 'sleep -s' now functions correctly with intervals of more than 30 seconds as the new code doesn't need the old workaround. This is done by handling '-s' in sh_delay. src/cmd/ksh93/bltins/sleep.c: - Remove the replacement for sleep(3) from the sleep builtin. - Replace the old sh_delay function with the newer one from ksh2020. The new function uses tvsleep, which uses nanosleep(3) internally. src/cmd/ksh93/include/shell.h, src/cmd/ksh93/edit/edit.c, src/cmd/ksh93/sh/jobs.c, src/cmd/ksh93/sh/xec.c, src/cmd/ksh93/shell.3: - Update sh_delay documentation and usage since the function now requires two arguments. src/cmd/ksh93/tests/builtins.sh: - Add a regression test for 'sleep -s' when the interval is greater than 30 seconds. The other bugs can't be tested for in a feasible manner across all systems: #72 (comment)
This pull request makes the following changes:
The
time
keyword now prioritizesgetrusage
to fix the bug reported at "time" builtin does not correctly report a third decimal digit ksh-community/ksh#7. Reproducer:TIMEFORMAT=$'\nreal\t%3R\tuser\t%3U\tsys\t%3S'; time sleep 1.235 # → real 1.240 user 0.000 sys 0.000
This bugfix is based on the following ksh2020 commits:
att/ast@48230e61
att/ast@2e18c672
att/ast@27777b3d(that commit breaks command substitutions, now reverted)getrusage
,timeradd
andtimersub
are detected withiffe
feature tests. Thetimes
function is used as a fallback ifgetrusage
isn't available.A single percent at the end of a format specifier is now treated as a literal '%' (like in Bash and ksh2020). The following command no longer causes a syntax error:
TIMEFORMAT='%3S%'; time sleep .1
The default output from
time
now zero-pads seconds. This change was made for consistency with thetimes
builtin, which also zero-pads seconds as of commit 5c677a4.Fixed one instance of
getrusage
in libast that was missing an ifdef for_lib_getrusage
.This patch can be extended with support for microsecond precision,
which I put in a separate gistedit: now in a downstream branch (since that isn't a bugfix):JohnoKing@d97b64e