Skip to content

Commit 3a6d35d

Browse files
authored
Merge pull request #427 from TypedDevs/refactor/improve-clock-performance-2
Improve clock performance
2 parents fd4d277 + 532e322 commit 3a6d35d

File tree

3 files changed

+36
-30
lines changed

3 files changed

+36
-30
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
- Add benchmark feature
1010
- Support placeholder `::ignore::` in snapshots
1111
- Add project overview docs
12+
- Improve clock performance
1213

1314
## [0.20.0](https://github.com/TypedDevs/bashunit/compare/0.19.1...0.20.0) - 2025-06-01
1415

src/clock.sh

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,67 @@
11
#!/usr/bin/env bash
22

33
function clock::now() {
4-
if dependencies::has_perl && perl -MTime::HiRes -e "" > /dev/null 2>&1; then
5-
if perl -MTime::HiRes -e 'printf("%.0f\n",Time::HiRes::time()*1000000000)'; then
6-
return 0
7-
fi
4+
local shell_time
5+
6+
# 1. Try using native shell EPOCHREALTIME (if available)
7+
if shell_time="$(clock::shell_time)"; then
8+
local seconds="${shell_time%%.*}"
9+
local microseconds="${shell_time#*.}"
10+
math::calculate "($seconds * 1000000000) + ($microseconds * 1000)"
11+
return 0
812
fi
913

14+
# 2. Try Perl with Time::HiRes
15+
if dependencies::has_perl && perl -MTime::HiRes -e "" &>/dev/null; then
16+
perl -MTime::HiRes -e 'printf("%.0f\n", Time::HiRes::time() * 1000000000)' && return 0
17+
fi
18+
19+
# 3. Windows fallback with PowerShell
1020
if check_os::is_windows && dependencies::has_powershell; then
11-
powershell -Command "
12-
\$unixEpoch = [DateTime]'1970-01-01 00:00:00';
13-
\$now = [DateTime]::UtcNow;
14-
\$ticksSinceEpoch = (\$now - \$unixEpoch).Ticks;
15-
\$nanosecondsSinceEpoch = \$ticksSinceEpoch * 100;
16-
Write-Output \$nanosecondsSinceEpoch
17-
"
18-
return 0
21+
powershell -Command "
22+
\$unixEpoch = [DateTime]'1970-01-01 00:00:00';
23+
\$now = [DateTime]::UtcNow;
24+
\$ticksSinceEpoch = (\$now - \$unixEpoch).Ticks;
25+
\$nanosecondsSinceEpoch = \$ticksSinceEpoch * 100;
26+
Write-Output \$nanosecondsSinceEpoch
27+
" && return 0
1928
fi
2029

30+
# 4. Unix fallback using `date +%s%N` (if not macOS or Alpine)
2131
if ! check_os::is_macos && ! check_os::is_alpine; then
2232
local result
23-
result=$(date +%s%N)
24-
if [[ "$result" != *N ]] && [[ "$result" -gt 0 ]]; then
33+
result=$(date +%s%N 2>/dev/null)
34+
if [[ "$result" != *N && "$result" =~ ^[0-9]+$ ]]; then
2535
echo "$result"
2636
return 0
2737
fi
2838
fi
2939

30-
local shell_time has_shell_time
31-
shell_time="$(clock::shell_time)"
32-
has_shell_time="$?"
33-
if [[ "$has_shell_time" -eq 0 ]]; then
34-
local seconds microseconds
35-
seconds=$(echo "$shell_time" | cut -f 1 -d '.')
36-
microseconds=$(echo "$shell_time" | cut -f 2 -d '.')
37-
38-
math::calculate "($seconds * 1000000000) + ($microseconds * 1000)"
39-
return 0
40-
fi
41-
40+
# 5. All methods failed
4241
echo ""
4342
return 1
4443
}
4544

4645
function clock::shell_time() {
47-
# Get time directly from the shell rather than a program.
46+
# Get time directly from the shell variable EPOCHREALTIME (Bash 5+)
4847
[[ -n ${EPOCHREALTIME+x} && -n "$EPOCHREALTIME" ]] && LC_ALL=C echo "$EPOCHREALTIME"
4948
}
5049

51-
5250
function clock::total_runtime_in_milliseconds() {
51+
local end_time
5352
end_time=$(clock::now)
5453
if [[ -n $end_time ]]; then
55-
math::calculate "($end_time-$_START_TIME)/1000000"
54+
math::calculate "($end_time - $_START_TIME) / 1000000"
5655
else
5756
echo ""
5857
fi
5958
}
6059

6160
function clock::total_runtime_in_nanoseconds() {
61+
local end_time
6262
end_time=$(clock::now)
6363
if [[ -n $end_time ]]; then
64-
math::calculate "($end_time-$_START_TIME)"
64+
math::calculate "$end_time - $_START_TIME"
6565
else
6666
echo ""
6767
fi

tests/unit/clock_test.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,15 @@ function mock_non_existing_fn() {
1515
}
1616

1717
function test_now_with_perl() {
18+
mock clock::shell_time mock_non_existing_fn
1819
mock perl echo "1720705883457"
1920

2021
assert_same "1720705883457" "$(clock::now)"
2122
}
2223

2324
function test_now_on_linux_unknown() {
2425
mock_unknown_linux_os
26+
mock clock::shell_time mock_non_existing_fn
2527
mock perl mock_non_existing_fn
2628
mock date echo "1720705883457"
2729

@@ -30,6 +32,7 @@ function test_now_on_linux_unknown() {
3032

3133
function test_now_on_linux_alpine() {
3234
mock_alpine_os
35+
mock clock::shell_time mock_non_existing_fn
3336
mock perl echo "1720705883457"
3437

3538
assert_same "1720705883457" "$(clock::now)"
@@ -40,6 +43,7 @@ function test_now_on_windows_without_with_powershell() {
4043
mock dependencies::has_perl mock_false
4144
mock dependencies::has_powershell mock_true
4245
mock powershell echo "1727768183281580800"
46+
mock clock::shell_time mock_non_existing_fn
4347

4448
assert_same "1727768183281580800" "$(clock::now)"
4549
}
@@ -49,6 +53,7 @@ function test_now_on_windows_without_without_powershell() {
4953
mock dependencies::has_perl mock_false
5054
mock dependencies::has_powershell mock_false
5155
mock date echo "1727768951"
56+
mock clock::shell_time mock_non_existing_fn
5257

5358
assert_same "1727768951" "$(clock::now)"
5459
}

0 commit comments

Comments
 (0)