Skip to content

Commit 20a47bc

Browse files
committed
test-case: latency-metrics: introduce latency tests
Introduce latency tests using `JACK` Audio Connection Kit: run `jackd` audio service, connect ports with loopback and run `jack_iodelay` to collect latency measurements, detect xrun-s, calculate and save statistics into a json report file. Optionally, run in 'trial' mode repeating measurements with gradually reduced buffers to find the smallest latency possible. Signed-off-by: Dmitrii Golovanov <dmitrii.golovanov@intel.com>
1 parent 863ab70 commit 20a47bc

File tree

6 files changed

+424
-1
lines changed

6 files changed

+424
-1
lines changed

case-lib/jack_iodelay_metrics.awk

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#!/usr/bin/gawk -f
2+
3+
# SPDX-License-Identifier: BSD-3-Clause
4+
# Copyright(c) 2025 Intel Corporation. All rights reserved.
5+
6+
# Process `jack_iodelay` output to extract latency measurements,
7+
# and calculate some general statistics: min, max, avg, stddev.
8+
# The resulting output is a json dictionary.
9+
10+
@include "lib.awk"
11+
12+
/^[ ]*[0-9.]+ frames[ ]+[0-9.]+ ms total roundtrip latency/ {
13+
sum_frames+=$1
14+
sum_ms+=$3
15+
latency_frames[NR]=$1
16+
latency_ms[NR]=$3
17+
}
18+
19+
END {
20+
if (length(latency_frames) !=0 && length(latency_ms) != 0) {
21+
printf("\"metric_name\":\"roundtrip latency\", ")
22+
printf("\"probes\":%d, ", length(latency_frames))
23+
printf("\"avg_frames\":%0.3f, ", (length(latency_frames) ? sum(latency_frames) / length(latency_frames) : 0))
24+
printf("\"min_frames\":%0.3f, \"max_frames\":%0.3f, ", min(latency_frames), max(latency_frames))
25+
printf("\"avg_ms\":%0.3f, ", (length(latency_ms) ? sum(latency_ms) / length(latency_ms) : 0))
26+
printf("\"min_ms\":%0.3f, \"max_ms\":%0.3f, ", min(latency_ms), max(latency_ms))
27+
printf("\"stdev_frames\":%0.6f, \"stdev_ms\":%0.6f", stddev(latency_frames), stddev(latency_ms))
28+
fflush()
29+
}
30+
}

case-lib/jackd_events.awk

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#!/usr/bin/gawk -f
2+
3+
# SPDX-License-Identifier: BSD-3-Clause
4+
# Copyright(c) 2025 Intel Corporation. All rights reserved.
5+
6+
# Process `jackd` output to count XRun's.
7+
8+
/JackEngine::XRun: client = jack_delay/ {
9+
xrun_cnt+=1
10+
}
11+
12+
END {
13+
printf("\"xruns\":%d", xrun_cnt)
14+
fflush()
15+
}

case-lib/lib.awk

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#!/usr/bin/gawk -f
2+
3+
# SPDX-License-Identifier: BSD-3-Clause
4+
# Copyright(c) 2025 Intel Corporation. All rights reserved.
5+
6+
# A library of functions to re-use in AWK scripts.
7+
8+
function min(in_array, min_value,idx)
9+
{
10+
min_value = "N/A"
11+
if (! isarray(in_array) || length(in_array) == 0) return min_value
12+
for(idx in in_array) {
13+
if (min_value == "N/A" || in_array[idx] < min_value) {
14+
min_value = in_array[idx]
15+
}
16+
}
17+
return min_value
18+
}
19+
20+
function max(in_array, max_value,idx)
21+
{
22+
max_value = "N/A"
23+
if (! isarray(in_array) || length(in_array) == 0) return max_value
24+
for(idx in in_array) {
25+
if (max_value == "N/A" || in_array[idx] > max_value) {
26+
max_value = in_array[idx]
27+
}
28+
}
29+
return max_value
30+
}
31+
32+
function sum(in_array, sum_items,idx)
33+
{
34+
if (! isarray(in_array) || length(in_array) == 0) return 0
35+
sum_items=0
36+
for(idx in in_array) {
37+
sum_items += in_array[idx]
38+
}
39+
return sum_items
40+
}
41+
42+
function stddev(in_array, sum_items,cnt_items,idx,avg,dev)
43+
{
44+
if (! isarray(in_array) || length(in_array) == 0) return -1
45+
sum_items=0
46+
cnt_items=0
47+
for(idx in in_array) {
48+
sum_items += in_array[idx]
49+
cnt_items += 1
50+
}
51+
avg = sum_items / cnt_items
52+
dev = 0
53+
for(idx in in_array) dev += (in_array[idx] - avg)^2
54+
return sqrt(dev/(cnt_items - 1))
55+
}

case-lib/opt.sh

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#!/bin/bash
22

33
# SPDX-License-Identifier: BSD-3-Clause
4-
# Copyright(c) 2021 Intel Corporation. All rights reserved.
4+
# Copyright(c) 2021-2025 Intel Corporation. All rights reserved.
55

66
# These four arrays are used to define script options, and they should
77
# be indexed by a character [a-zA-Z], which is the option short name.
@@ -26,6 +26,17 @@ add_common_options()
2626
OPT_DESC['h']='show help information'
2727
}
2828

29+
# Convert options to a json dictionary.
30+
options2json()
31+
{
32+
local items_=()
33+
for idx_ in "${!OPT_NAME[@]}" ; do
34+
items_+=("\"${OPT_NAME[$idx_]}\":\"${OPT_VAL[$idx_]}\"")
35+
done
36+
# NOTE: use [*] to join array elements into a string, so IFS is applied.
37+
echo "$(IFS=',' ; printf "%s" "${items_[*]}")"
38+
}
39+
2940
# validate command line options, override default option value,
3041
# and dump help
3142
func_opt_parse_option()

env-check.sh

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,18 @@ main "$@"
8181

8282
out_str="" check_res=0
8383
printf "Checking for some OS packages:\t\t"
84+
func_check_pkg gawk
8485
func_check_pkg expect
8586
func_check_pkg aplay
8687
func_check_pkg sox
8788
func_check_pkg tinycap
8889
func_check_pkg tinyplay
90+
# JACK Audio Connection Kit
91+
func_check_pkg jackd
92+
func_check_pkg jack_iodelay
93+
func_check_pkg jack_lsp
94+
func_check_pkg jack_connect
95+
#
8996
func_check_pkg python3
9097
# jq is command-line json parser
9198
func_check_pkg jq

0 commit comments

Comments
 (0)