Skip to content

Commit 3d1a25c

Browse files
committed
ZTS: Add L2ARC DWPD and parallel writes tests
Add four new functional tests to validate L2ARC DWPD rate limiting and parallel write features: - l2arc_dwpd_ratelimit_pos: Verifies DWPD rate limiting with different values (0, 100, 1000, 10000) and ordering - l2arc_dwpd_reimport_pos: Verifies DWPD rate limiting persists after pool export/import - l2arc_multidev_scaling_pos: Verifies parallel write scaling ratio (dual devices achieve ~2× single device throughput) - l2arc_multidev_throughput_pos: Verifies absolute parallel write throughput scales with device count (~32MB/s per device) Signed-off-by: Ameer Hamza <ahamza@ixsystems.com>
1 parent bfa870d commit 3d1a25c

File tree

9 files changed

+540
-3
lines changed

9 files changed

+540
-3
lines changed

tests/runfiles/common.run

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1130,7 +1130,8 @@ tags = ['functional', 'log_spacemap']
11301130

11311131
[tests/functional/l2arc]
11321132
tests = ['l2arc_arcstats_pos', 'l2arc_mfuonly_pos', 'l2arc_l2miss_pos',
1133-
'persist_l2arc_001_pos', 'persist_l2arc_002_pos',
1133+
'l2arc_dwpd_ratelimit_pos', 'l2arc_dwpd_reimport_pos', 'l2arc_multidev_scaling_pos',
1134+
'l2arc_multidev_throughput_pos', 'persist_l2arc_001_pos', 'persist_l2arc_002_pos',
11341135
'persist_l2arc_003_neg', 'persist_l2arc_004_pos', 'persist_l2arc_005_pos']
11351136
tags = ['functional', 'l2arc']
11361137

tests/zfs-tests/include/tunables.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,12 @@ INITIALIZE_CHUNK_SIZE initialize_chunk_size zfs_initialize_chunk_size
4646
INITIALIZE_VALUE initialize_value zfs_initialize_value
4747
KEEP_LOG_SPACEMAPS_AT_EXPORT keep_log_spacemaps_at_export zfs_keep_log_spacemaps_at_export
4848
LUA_MAX_MEMLIMIT lua.max_memlimit zfs_lua_max_memlimit
49+
L2ARC_DWPD_LIMIT l2arc.dwpd_limit l2arc_dwpd_limit
4950
L2ARC_MFUONLY l2arc.mfuonly l2arc_mfuonly
5051
L2ARC_NOPREFETCH l2arc.noprefetch l2arc_noprefetch
5152
L2ARC_REBUILD_BLOCKS_MIN_L2SIZE l2arc.rebuild_blocks_min_l2size l2arc_rebuild_blocks_min_l2size
5253
L2ARC_REBUILD_ENABLED l2arc.rebuild_enabled l2arc_rebuild_enabled
5354
L2ARC_TRIM_AHEAD l2arc.trim_ahead l2arc_trim_ahead
54-
L2ARC_WRITE_BOOST l2arc.write_boost l2arc_write_boost
5555
L2ARC_WRITE_MAX l2arc.write_max l2arc_write_max
5656
LIVELIST_CONDENSE_NEW_ALLOC livelist.condense.new_alloc zfs_livelist_condense_new_alloc
5757
LIVELIST_CONDENSE_SYNC_CANCEL livelist.condense.sync_cancel zfs_livelist_condense_sync_cancel

tests/zfs-tests/tests/Makefile.am

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1660,6 +1660,10 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
16601660
functional/l2arc/l2arc_arcstats_pos.ksh \
16611661
functional/l2arc/l2arc_l2miss_pos.ksh \
16621662
functional/l2arc/l2arc_mfuonly_pos.ksh \
1663+
functional/l2arc/l2arc_dwpd_ratelimit_pos.ksh \
1664+
functional/l2arc/l2arc_dwpd_reimport_pos.ksh \
1665+
functional/l2arc/l2arc_multidev_scaling_pos.ksh \
1666+
functional/l2arc/l2arc_multidev_throughput_pos.ksh \
16631667
functional/l2arc/persist_l2arc_001_pos.ksh \
16641668
functional/l2arc/persist_l2arc_002_pos.ksh \
16651669
functional/l2arc/persist_l2arc_003_neg.ksh \

tests/zfs-tests/tests/functional/cache/cache_012_pos.ksh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,15 @@ function cleanup
5555

5656
log_must set_tunable32 L2ARC_WRITE_MAX $write_max
5757
log_must set_tunable32 L2ARC_NOPREFETCH $noprefetch
58+
log_must set_tunable32 L2ARC_DWPD_LIMIT $dwpd_limit
5859
}
5960
log_onexit cleanup
6061

6162
typeset write_max=$(get_tunable L2ARC_WRITE_MAX)
6263
typeset noprefetch=$(get_tunable L2ARC_NOPREFETCH)
64+
typeset dwpd_limit=$(get_tunable L2ARC_DWPD_LIMIT)
6365
log_must set_tunable32 L2ARC_NOPREFETCH 0
66+
log_must set_tunable32 L2ARC_DWPD_LIMIT 0
6467

6568
typeset VDEV="$VDIR/vdev.disk"
6669
typeset VDEV_SZ=$(( 4 * 1024 * 1024 * 1024 ))
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
#!/bin/ksh -p
2+
# SPDX-License-Identifier: CDDL-1.0
3+
#
4+
# CDDL HEADER START
5+
#
6+
# This file and its contents are supplied under the terms of the
7+
# Common Development and Distribution License ("CDDL"), version 1.0.
8+
# You may only use this file in accordance with the terms of version
9+
# 1.0 of the CDDL.
10+
#
11+
# A full copy of the text of the CDDL should have accompanied this
12+
# source. A copy of the CDDL is also available via the Internet at
13+
# http://www.illumos.org/license/CDDL.
14+
#
15+
# CDDL HEADER END
16+
#
17+
18+
#
19+
# Copyright (c) 2024. All rights reserved.
20+
#
21+
22+
. $STF_SUITE/include/libtest.shlib
23+
. $STF_SUITE/tests/functional/l2arc/l2arc.cfg
24+
25+
#
26+
# DESCRIPTION:
27+
# L2ARC DWPD rate limiting correctly limits write rate.
28+
#
29+
# STRATEGY:
30+
# 1. Set DWPD limit before creating pool.
31+
# 2. Create pool with cache device (arc_max = 1.5 * cache_size).
32+
# 3. Fill L2ARC to complete first pass.
33+
# 4. Measure writes over test period.
34+
# 5. Repeat 1-4 for DWPD values 0, 100, 1000, 10000.
35+
# 6. Verify DWPD=0 > DWPD=10000 > DWPD=1000 > DWPD=100.
36+
#
37+
38+
verify_runnable "global"
39+
40+
log_assert "L2ARC DWPD rate limiting correctly limits write rate."
41+
42+
function cleanup
43+
{
44+
if poolexists $TESTPOOL ; then
45+
destroy_pool $TESTPOOL
46+
fi
47+
48+
restore_tunable L2ARC_WRITE_MAX
49+
restore_tunable L2ARC_NOPREFETCH
50+
restore_tunable L2ARC_DWPD_LIMIT
51+
restore_tunable ARC_MIN
52+
restore_tunable ARC_MAX
53+
}
54+
log_onexit cleanup
55+
56+
# Save original tunables
57+
save_tunable L2ARC_WRITE_MAX
58+
save_tunable L2ARC_NOPREFETCH
59+
save_tunable L2ARC_DWPD_LIMIT
60+
save_tunable ARC_MIN
61+
save_tunable ARC_MAX
62+
63+
# Test parameters
64+
typeset cache_sz=900
65+
typeset fill_mb=1200
66+
typeset test_time=15
67+
68+
# Configure arc_max = 1.8 * cache_size for continuous L2ARC feed
69+
log_must set_tunable64 ARC_MIN $((cache_sz * 8 / 10 * 1024 * 1024))
70+
log_must set_tunable64 ARC_MAX $((cache_sz * 18 / 10 * 1024 * 1024))
71+
log_must set_tunable32 L2ARC_NOPREFETCH 0
72+
log_must set_tunable32 L2ARC_WRITE_MAX $((200 * 1024 * 1024))
73+
74+
# Create larger main vdev to accommodate fill data
75+
log_must truncate -s 5G $VDEV
76+
log_must truncate -s ${cache_sz}M $VDEV_CACHE
77+
78+
typeset -A results
79+
80+
# Test each DWPD value with fresh pool to measure first-pass fill
81+
for dwpd in 0 10000 1000 100; do
82+
log_must set_tunable32 L2ARC_DWPD_LIMIT $dwpd
83+
84+
if poolexists $TESTPOOL; then
85+
destroy_pool $TESTPOOL
86+
fi
87+
log_must zpool create -f $TESTPOOL $VDEV cache $VDEV_CACHE
88+
89+
# Fill first pass and wait for L2ARC writes to stabilize
90+
log_must dd if=/dev/urandom of=/$TESTPOOL/file1 bs=1M count=$fill_mb
91+
log_must sleep 10
92+
93+
# Take baseline after first pass completes
94+
baseline=$(kstat arcstats.l2_write_bytes)
95+
log_note "Baseline for DWPD=$dwpd: ${baseline}"
96+
97+
# Generate continuous workload to measure DWPD-limited L2ARC writes
98+
# Write 2GB to ensure continuous L2ARC feed pressure throughout measurement
99+
dd if=/dev/urandom of=/$TESTPOOL/file2 bs=1M count=2000 >/dev/null 2>&1 &
100+
dd_pid=$!
101+
log_must sleep $test_time
102+
kill $dd_pid 2>/dev/null
103+
wait $dd_pid 2>/dev/null
104+
log_must sleep 2
105+
end=$(kstat arcstats.l2_write_bytes)
106+
107+
results[$dwpd]=$((end - baseline))
108+
log_note "DWPD=$dwpd: delta=$((results[$dwpd] / 1024))KB"
109+
done
110+
111+
# Verify ordering: higher DWPD = more writes, 0 = unlimited
112+
if [[ ${results[0]} -le ${results[10000]} ]]; then
113+
log_fail "DWPD=0 (unlimited) should write more than DWPD=10000"
114+
fi
115+
if [[ ${results[10000]} -le ${results[1000]} ]]; then
116+
log_fail "DWPD=10000 should write more than DWPD=1000"
117+
fi
118+
if [[ ${results[1000]} -le ${results[100]} ]]; then
119+
log_fail "DWPD=1000 should write more than DWPD=100"
120+
fi
121+
122+
log_must zpool destroy $TESTPOOL
123+
124+
log_pass "L2ARC DWPD rate limiting correctly limits write rate."
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
#!/bin/ksh -p
2+
# SPDX-License-Identifier: CDDL-1.0
3+
#
4+
# CDDL HEADER START
5+
#
6+
# This file and its contents are supplied under the terms of the
7+
# Common Development and Distribution License ("CDDL"), version 1.0.
8+
# You may only use this file in accordance with the terms of version
9+
# 1.0 of the CDDL.
10+
#
11+
# A full copy of the text of the CDDL should have accompanied this
12+
# source. A copy of the CDDL is also available via the Internet at
13+
# http://www.illumos.org/license/CDDL.
14+
#
15+
# CDDL HEADER END
16+
#
17+
18+
#
19+
# Copyright (c) 2024. All rights reserved.
20+
#
21+
22+
. $STF_SUITE/include/libtest.shlib
23+
. $STF_SUITE/tests/functional/l2arc/l2arc.cfg
24+
25+
#
26+
# DESCRIPTION:
27+
# L2ARC DWPD rate limiting works after pool export/import.
28+
#
29+
# STRATEGY:
30+
# 1. Set DWPD limit before creating pool.
31+
# 2. Create pool with 900MB cache device.
32+
# 3. Fill L2ARC and wait for first pass to complete.
33+
# 4. Measure DWPD-limited writes with continuous workload.
34+
# 5. Export and import pool.
35+
# 6. Wait for rebuild, then fill L2ARC and wait for first pass to complete.
36+
# 7. Measure DWPD-limited writes again.
37+
# 8. Verify rate limiting still works after import (non-zero writes).
38+
#
39+
40+
verify_runnable "global"
41+
42+
log_assert "L2ARC DWPD rate limiting works after pool export/import."
43+
44+
function cleanup
45+
{
46+
if poolexists $TESTPOOL ; then
47+
destroy_pool $TESTPOOL
48+
fi
49+
50+
restore_tunable L2ARC_WRITE_MAX
51+
restore_tunable L2ARC_NOPREFETCH
52+
restore_tunable L2ARC_DWPD_LIMIT
53+
restore_tunable L2ARC_REBUILD_BLOCKS_MIN_L2SIZE
54+
restore_tunable ARC_MIN
55+
restore_tunable ARC_MAX
56+
}
57+
log_onexit cleanup
58+
59+
# Save original tunables
60+
save_tunable L2ARC_WRITE_MAX
61+
save_tunable L2ARC_NOPREFETCH
62+
save_tunable L2ARC_DWPD_LIMIT
63+
save_tunable L2ARC_REBUILD_BLOCKS_MIN_L2SIZE
64+
save_tunable ARC_MIN
65+
save_tunable ARC_MAX
66+
67+
# Test parameters
68+
typeset cache_sz=900
69+
typeset fill_mb=900
70+
typeset test_time=15
71+
72+
# Set DWPD before pool creation (10000 = 100 DWPD)
73+
log_must set_tunable32 L2ARC_DWPD_LIMIT 10000
74+
log_must set_tunable32 L2ARC_REBUILD_BLOCKS_MIN_L2SIZE 0
75+
76+
# Configure arc_max = 1.8 * cache_size for continuous L2ARC feed
77+
log_must set_tunable64 ARC_MIN $((cache_sz * 8 / 10 * 1024 * 1024))
78+
log_must set_tunable64 ARC_MAX $((cache_sz * 18 / 10 * 1024 * 1024))
79+
log_must set_tunable32 L2ARC_NOPREFETCH 0
80+
log_must set_tunable32 L2ARC_WRITE_MAX $((200 * 1024 * 1024))
81+
82+
# Create larger main vdev to accommodate fill data
83+
log_must truncate -s 5G $VDEV
84+
log_must truncate -s ${cache_sz}M $VDEV_CACHE
85+
86+
log_must zpool create -f $TESTPOOL $VDEV cache $VDEV_CACHE
87+
88+
# Fill first pass and wait for L2ARC writes to complete
89+
log_must dd if=/dev/urandom of=/$TESTPOOL/file1 bs=1M count=$fill_mb
90+
arcstat_quiescence_noecho l2_size
91+
92+
# Verify L2ARC is populated before export
93+
typeset l2_size_before=$(kstat arcstats.l2_size)
94+
log_note "L2ARC size before export: $((l2_size_before / 1024 / 1024))MB"
95+
if [[ $l2_size_before -eq 0 ]]; then
96+
log_fail "L2ARC not populated before export"
97+
fi
98+
99+
# Measure DWPD-limited writes before export
100+
baseline1=$(kstat arcstats.l2_write_bytes)
101+
log_note "Baseline before export: ${baseline1}"
102+
dd if=/dev/urandom of=/$TESTPOOL/file2 bs=1M count=2000 >/dev/null 2>&1 &
103+
dd_pid=$!
104+
log_must sleep $test_time
105+
kill $dd_pid 2>/dev/null
106+
wait $dd_pid 2>/dev/null
107+
log_must sleep 2
108+
end1=$(kstat arcstats.l2_write_bytes)
109+
typeset writes_before=$((end1 - baseline1))
110+
111+
log_note "Writes before export: $((writes_before / 1024))KB"
112+
113+
# Verify L2ARC actually wrote data
114+
if [[ $writes_before -eq 0 ]]; then
115+
log_fail "No L2ARC writes before export - DWPD may be too restrictive"
116+
fi
117+
118+
# Export and import pool
119+
log_must zpool export $TESTPOOL
120+
log_must zpool import -d $VDIR $TESTPOOL
121+
122+
# Wait for rebuild to complete
123+
log_must sleep 5
124+
125+
# Verify L2ARC is populated after import
126+
typeset l2_size_after=$(kstat arcstats.l2_size)
127+
log_note "L2ARC size after import: $((l2_size_after / 1024 / 1024))MB"
128+
if [[ $l2_size_after -eq 0 ]]; then
129+
log_fail "L2ARC not populated after import"
130+
fi
131+
132+
# Fill first pass again after import and wait for L2ARC writes to complete
133+
log_must dd if=/dev/urandom of=/$TESTPOOL/file3 bs=1M count=$fill_mb
134+
log_must sleep 10
135+
136+
# Verify L2ARC is still populated after refill
137+
l2_size=$(kstat arcstats.l2_size)
138+
log_note "L2ARC size after refill: $((l2_size / 1024 / 1024))MB"
139+
140+
# Measure DWPD-limited writes after import
141+
baseline2=$(kstat arcstats.l2_write_bytes)
142+
log_note "Baseline after import: ${baseline2}"
143+
dd if=/dev/urandom of=/$TESTPOOL/file4 bs=1M count=2000 >/dev/null 2>&1 &
144+
dd_pid=$!
145+
log_must sleep $test_time
146+
kill $dd_pid 2>/dev/null
147+
wait $dd_pid 2>/dev/null
148+
log_must sleep 2
149+
end2=$(kstat arcstats.l2_write_bytes)
150+
typeset writes_after=$((end2 - baseline2))
151+
152+
log_note "Writes after import: $((writes_after / 1024))KB"
153+
154+
# Verify rate limiting persists after import
155+
if [[ $writes_after -eq 0 ]]; then
156+
log_fail "No writes after import - rate limiting may be broken"
157+
fi
158+
159+
log_must zpool destroy $TESTPOOL
160+
161+
log_pass "L2ARC DWPD rate limiting works after pool export/import."

0 commit comments

Comments
 (0)