mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-03-10 20:36:21 +03:00
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) Reviewed-by: Alexander Motin <alexander.motin@TrueNAS.com> Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Signed-off-by: Ameer Hamza <ahamza@ixsystems.com> Closes #18093
This commit is contained in:
parent
48d3f7fac9
commit
13552d754f
@ -1130,7 +1130,8 @@ tags = ['functional', 'log_spacemap']
|
||||
|
||||
[tests/functional/l2arc]
|
||||
tests = ['l2arc_arcstats_pos', 'l2arc_mfuonly_pos', 'l2arc_l2miss_pos',
|
||||
'persist_l2arc_001_pos', 'persist_l2arc_002_pos',
|
||||
'l2arc_dwpd_ratelimit_pos', 'l2arc_dwpd_reimport_pos', 'l2arc_multidev_scaling_pos',
|
||||
'l2arc_multidev_throughput_pos', 'persist_l2arc_001_pos', 'persist_l2arc_002_pos',
|
||||
'persist_l2arc_003_neg', 'persist_l2arc_004_pos', 'persist_l2arc_005_pos']
|
||||
tags = ['functional', 'l2arc']
|
||||
|
||||
|
||||
@ -46,12 +46,12 @@ INITIALIZE_CHUNK_SIZE initialize_chunk_size zfs_initialize_chunk_size
|
||||
INITIALIZE_VALUE initialize_value zfs_initialize_value
|
||||
KEEP_LOG_SPACEMAPS_AT_EXPORT keep_log_spacemaps_at_export zfs_keep_log_spacemaps_at_export
|
||||
LUA_MAX_MEMLIMIT lua.max_memlimit zfs_lua_max_memlimit
|
||||
L2ARC_DWPD_LIMIT l2arc.dwpd_limit l2arc_dwpd_limit
|
||||
L2ARC_MFUONLY l2arc.mfuonly l2arc_mfuonly
|
||||
L2ARC_NOPREFETCH l2arc.noprefetch l2arc_noprefetch
|
||||
L2ARC_REBUILD_BLOCKS_MIN_L2SIZE l2arc.rebuild_blocks_min_l2size l2arc_rebuild_blocks_min_l2size
|
||||
L2ARC_REBUILD_ENABLED l2arc.rebuild_enabled l2arc_rebuild_enabled
|
||||
L2ARC_TRIM_AHEAD l2arc.trim_ahead l2arc_trim_ahead
|
||||
L2ARC_WRITE_BOOST l2arc.write_boost l2arc_write_boost
|
||||
L2ARC_WRITE_MAX l2arc.write_max l2arc_write_max
|
||||
LIVELIST_CONDENSE_NEW_ALLOC livelist.condense.new_alloc zfs_livelist_condense_new_alloc
|
||||
LIVELIST_CONDENSE_SYNC_CANCEL livelist.condense.sync_cancel zfs_livelist_condense_sync_cancel
|
||||
|
||||
@ -1660,6 +1660,10 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
|
||||
functional/l2arc/l2arc_arcstats_pos.ksh \
|
||||
functional/l2arc/l2arc_l2miss_pos.ksh \
|
||||
functional/l2arc/l2arc_mfuonly_pos.ksh \
|
||||
functional/l2arc/l2arc_dwpd_ratelimit_pos.ksh \
|
||||
functional/l2arc/l2arc_dwpd_reimport_pos.ksh \
|
||||
functional/l2arc/l2arc_multidev_scaling_pos.ksh \
|
||||
functional/l2arc/l2arc_multidev_throughput_pos.ksh \
|
||||
functional/l2arc/persist_l2arc_001_pos.ksh \
|
||||
functional/l2arc/persist_l2arc_002_pos.ksh \
|
||||
functional/l2arc/persist_l2arc_003_neg.ksh \
|
||||
|
||||
@ -55,12 +55,15 @@ function cleanup
|
||||
|
||||
log_must set_tunable32 L2ARC_WRITE_MAX $write_max
|
||||
log_must set_tunable32 L2ARC_NOPREFETCH $noprefetch
|
||||
log_must set_tunable32 L2ARC_DWPD_LIMIT $dwpd_limit
|
||||
}
|
||||
log_onexit cleanup
|
||||
|
||||
typeset write_max=$(get_tunable L2ARC_WRITE_MAX)
|
||||
typeset noprefetch=$(get_tunable L2ARC_NOPREFETCH)
|
||||
typeset dwpd_limit=$(get_tunable L2ARC_DWPD_LIMIT)
|
||||
log_must set_tunable32 L2ARC_NOPREFETCH 0
|
||||
log_must set_tunable32 L2ARC_DWPD_LIMIT 0
|
||||
|
||||
typeset VDEV="$VDIR/vdev.disk"
|
||||
typeset VDEV_SZ=$(( 4 * 1024 * 1024 * 1024 ))
|
||||
|
||||
@ -25,7 +25,8 @@ export SIZE=1G
|
||||
export VDIR=$TESTDIR/disk.l2arc
|
||||
export VDEV="$VDIR/a"
|
||||
export VDEV_CACHE="$VDIR/b"
|
||||
export VDEV1="$VDIR/c"
|
||||
export VDEV_CACHE2="$VDIR/c"
|
||||
export VDEV1="$VDIR/d"
|
||||
|
||||
# fio options
|
||||
export DIRECTORY=/$TESTPOOL
|
||||
|
||||
138
tests/zfs-tests/tests/functional/l2arc/l2arc_dwpd_ratelimit_pos.ksh
Executable file
138
tests/zfs-tests/tests/functional/l2arc/l2arc_dwpd_ratelimit_pos.ksh
Executable file
@ -0,0 +1,138 @@
|
||||
#!/bin/ksh -p
|
||||
# SPDX-License-Identifier: CDDL-1.0
|
||||
#
|
||||
# CDDL HEADER START
|
||||
#
|
||||
# This file and its contents are supplied under the terms of the
|
||||
# Common Development and Distribution License ("CDDL"), version 1.0.
|
||||
# You may only use this file in accordance with the terms of version
|
||||
# 1.0 of the CDDL.
|
||||
#
|
||||
# A full copy of the text of the CDDL should have accompanied this
|
||||
# source. A copy of the CDDL is also available via the Internet at
|
||||
# http://www.illumos.org/license/CDDL.
|
||||
#
|
||||
# CDDL HEADER END
|
||||
#
|
||||
|
||||
#
|
||||
# Copyright (c) 2024. All rights reserved.
|
||||
#
|
||||
|
||||
. $STF_SUITE/include/libtest.shlib
|
||||
. $STF_SUITE/tests/functional/l2arc/l2arc.cfg
|
||||
|
||||
#
|
||||
# DESCRIPTION:
|
||||
# L2ARC DWPD rate limiting correctly limits write rate.
|
||||
#
|
||||
# STRATEGY:
|
||||
# 1. Set DWPD limit before creating pool.
|
||||
# 2. Create pool with cache device (L2ARC >= arc_c_max * 2).
|
||||
# 3. Populate L2ARC to complete first pass - DWPD only limits writes
|
||||
# after first pass, so we must fill L2ARC first.
|
||||
# 4. Delete the file to free ARC and invalidate L2ARC entries.
|
||||
# 5. Write fresh data - now DWPD rate limiting controls refill rate.
|
||||
# 6. Measure L2ARC writes over test period.
|
||||
# 7. Repeat 1-6 for DWPD values 0, 10000, 5000, 1800.
|
||||
# 8. Verify DWPD=0 > DWPD=10000 > DWPD=5000 > DWPD=1800.
|
||||
#
|
||||
|
||||
verify_runnable "global"
|
||||
|
||||
log_assert "L2ARC DWPD rate limiting correctly limits write rate."
|
||||
|
||||
function cleanup
|
||||
{
|
||||
if poolexists $TESTPOOL ; then
|
||||
destroy_pool $TESTPOOL
|
||||
fi
|
||||
|
||||
restore_tunable L2ARC_WRITE_MAX
|
||||
restore_tunable L2ARC_NOPREFETCH
|
||||
restore_tunable L2ARC_DWPD_LIMIT
|
||||
restore_tunable ARC_MIN
|
||||
restore_tunable ARC_MAX
|
||||
}
|
||||
log_onexit cleanup
|
||||
|
||||
# Save original tunables
|
||||
save_tunable L2ARC_WRITE_MAX
|
||||
save_tunable L2ARC_NOPREFETCH
|
||||
save_tunable L2ARC_DWPD_LIMIT
|
||||
save_tunable ARC_MIN
|
||||
save_tunable ARC_MAX
|
||||
|
||||
# Test parameters
|
||||
typeset cache_sz=900
|
||||
typeset fill_mb=1500
|
||||
typeset test_time=15
|
||||
|
||||
# Configure arc_max = 400MB so L2ARC (900MB) >= arc_c_max * 2 threshold
|
||||
log_must set_tunable64 ARC_MAX $((400 * 1024 * 1024))
|
||||
log_must set_tunable64 ARC_MIN $((200 * 1024 * 1024))
|
||||
log_must set_tunable32 L2ARC_NOPREFETCH 0
|
||||
log_must set_tunable32 L2ARC_WRITE_MAX $((200 * 1024 * 1024))
|
||||
|
||||
# Create larger main vdev to accommodate fill data
|
||||
log_must truncate -s 5G $VDEV
|
||||
log_must truncate -s ${cache_sz}M $VDEV_CACHE
|
||||
|
||||
typeset -A results
|
||||
|
||||
# Test each DWPD value with fresh pool.
|
||||
# Minimum DWPD=1800 (18 DWPD) gives ~192KB/s (900MB*18/86400), enough to
|
||||
# write one block (128KB) + log overhead (64KB) without accumulating budget.
|
||||
for dwpd in 0 10000 5000 1800; do
|
||||
log_must set_tunable32 L2ARC_DWPD_LIMIT $dwpd
|
||||
|
||||
if poolexists $TESTPOOL; then
|
||||
destroy_pool $TESTPOOL
|
||||
fi
|
||||
log_must zpool create -f $TESTPOOL $VDEV cache $VDEV_CACHE
|
||||
|
||||
# Populate L2ARC in chunks to complete first pass
|
||||
# (DWPD only limits after first pass)
|
||||
log_must dd if=/dev/urandom of=/$TESTPOOL/fill1 bs=1M count=$((fill_mb/3))
|
||||
log_must sleep 5
|
||||
log_must dd if=/dev/urandom of=/$TESTPOOL/fill2 bs=1M count=$((fill_mb/3))
|
||||
log_must sleep 5
|
||||
log_must dd if=/dev/urandom of=/$TESTPOOL/fill3 bs=1M count=$((fill_mb/3))
|
||||
log_must sleep 5
|
||||
|
||||
# Delete files to free ARC and invalidate L2ARC entries
|
||||
log_must rm /$TESTPOOL/fill1 /$TESTPOOL/fill2 /$TESTPOOL/fill3
|
||||
log_must sync
|
||||
|
||||
# Take baseline - L2ARC now has space for fresh data
|
||||
baseline=$(kstat arcstats.l2_write_bytes)
|
||||
log_note "Baseline for DWPD=$dwpd: ${baseline}"
|
||||
|
||||
# Write fresh data - DWPD rate limiting now controls refill rate
|
||||
# Write arc_max worth of data since that's what flows through ARC
|
||||
dd if=/dev/urandom of=/$TESTPOOL/test bs=1M count=400 &
|
||||
dd_pid=$!
|
||||
log_must sleep $test_time
|
||||
kill $dd_pid 2>/dev/null
|
||||
wait $dd_pid 2>/dev/null
|
||||
log_must sleep 2
|
||||
end=$(kstat arcstats.l2_write_bytes)
|
||||
|
||||
results[$dwpd]=$((end - baseline))
|
||||
log_note "DWPD=$dwpd: delta=$((results[$dwpd] / 1024))KB"
|
||||
done
|
||||
|
||||
# Verify ordering: higher DWPD = more writes, 0 = unlimited
|
||||
if [[ ${results[0]} -le ${results[10000]} ]]; then
|
||||
log_fail "DWPD=0 (unlimited) should write more than DWPD=10000"
|
||||
fi
|
||||
if [[ ${results[10000]} -le ${results[5000]} ]]; then
|
||||
log_fail "DWPD=10000 should write more than DWPD=5000"
|
||||
fi
|
||||
if [[ ${results[5000]} -le ${results[1800]} ]]; then
|
||||
log_fail "DWPD=5000 should write more than DWPD=1800"
|
||||
fi
|
||||
|
||||
log_must zpool destroy $TESTPOOL
|
||||
|
||||
log_pass "L2ARC DWPD rate limiting correctly limits write rate."
|
||||
169
tests/zfs-tests/tests/functional/l2arc/l2arc_dwpd_reimport_pos.ksh
Executable file
169
tests/zfs-tests/tests/functional/l2arc/l2arc_dwpd_reimport_pos.ksh
Executable file
@ -0,0 +1,169 @@
|
||||
#!/bin/ksh -p
|
||||
# SPDX-License-Identifier: CDDL-1.0
|
||||
#
|
||||
# CDDL HEADER START
|
||||
#
|
||||
# This file and its contents are supplied under the terms of the
|
||||
# Common Development and Distribution License ("CDDL"), version 1.0.
|
||||
# You may only use this file in accordance with the terms of version
|
||||
# 1.0 of the CDDL.
|
||||
#
|
||||
# A full copy of the text of the CDDL should have accompanied this
|
||||
# source. A copy of the CDDL is also available via the Internet at
|
||||
# http://www.illumos.org/license/CDDL.
|
||||
#
|
||||
# CDDL HEADER END
|
||||
#
|
||||
|
||||
#
|
||||
# Copyright (c) 2024. All rights reserved.
|
||||
#
|
||||
|
||||
. $STF_SUITE/include/libtest.shlib
|
||||
. $STF_SUITE/tests/functional/l2arc/l2arc.cfg
|
||||
|
||||
#
|
||||
# DESCRIPTION:
|
||||
# L2ARC DWPD rate limiting works after pool export/import.
|
||||
#
|
||||
# STRATEGY:
|
||||
# 1. Set DWPD limit before creating pool.
|
||||
# 2. Create pool with cache device (L2ARC >= arc_c_max * 2).
|
||||
# 3. Fill L2ARC with staged writes and wait for first pass to complete.
|
||||
# 4. Measure DWPD-limited writes with continuous workload.
|
||||
# 5. Export and import pool.
|
||||
# 6. Wait for rebuild, then fill L2ARC with staged writes.
|
||||
# 7. Measure DWPD-limited writes again.
|
||||
# 8. Verify rate limiting still works after import (non-zero writes).
|
||||
#
|
||||
|
||||
verify_runnable "global"
|
||||
|
||||
log_assert "L2ARC DWPD rate limiting works after pool export/import."
|
||||
|
||||
function cleanup
|
||||
{
|
||||
if poolexists $TESTPOOL ; then
|
||||
destroy_pool $TESTPOOL
|
||||
fi
|
||||
|
||||
restore_tunable L2ARC_WRITE_MAX
|
||||
restore_tunable L2ARC_NOPREFETCH
|
||||
restore_tunable L2ARC_DWPD_LIMIT
|
||||
restore_tunable L2ARC_REBUILD_BLOCKS_MIN_L2SIZE
|
||||
restore_tunable ARC_MIN
|
||||
restore_tunable ARC_MAX
|
||||
}
|
||||
log_onexit cleanup
|
||||
|
||||
# Save original tunables
|
||||
save_tunable L2ARC_WRITE_MAX
|
||||
save_tunable L2ARC_NOPREFETCH
|
||||
save_tunable L2ARC_DWPD_LIMIT
|
||||
save_tunable L2ARC_REBUILD_BLOCKS_MIN_L2SIZE
|
||||
save_tunable ARC_MIN
|
||||
save_tunable ARC_MAX
|
||||
|
||||
# Test parameters
|
||||
typeset cache_sz=900
|
||||
typeset fill_mb=1500
|
||||
typeset test_time=15
|
||||
|
||||
# Set DWPD before pool creation (10000 = 100 DWPD)
|
||||
log_must set_tunable32 L2ARC_DWPD_LIMIT 10000
|
||||
log_must set_tunable32 L2ARC_REBUILD_BLOCKS_MIN_L2SIZE 0
|
||||
|
||||
# Configure arc_max = 400MB so L2ARC (900MB) >= arc_c_max * 2 threshold
|
||||
log_must set_tunable64 ARC_MAX $((400 * 1024 * 1024))
|
||||
log_must set_tunable64 ARC_MIN $((200 * 1024 * 1024))
|
||||
log_must set_tunable32 L2ARC_NOPREFETCH 0
|
||||
log_must set_tunable32 L2ARC_WRITE_MAX $((200 * 1024 * 1024))
|
||||
|
||||
# Create larger main vdev to accommodate fill data
|
||||
log_must truncate -s 8G $VDEV
|
||||
log_must truncate -s ${cache_sz}M $VDEV_CACHE
|
||||
|
||||
log_must zpool create -f $TESTPOOL $VDEV cache $VDEV_CACHE
|
||||
|
||||
# Staged fills to allow L2ARC to drain between writes
|
||||
log_must dd if=/dev/urandom of=/$TESTPOOL/file1a bs=1M count=$((fill_mb/3))
|
||||
log_must sleep 5
|
||||
log_must dd if=/dev/urandom of=/$TESTPOOL/file1b bs=1M count=$((fill_mb/3))
|
||||
log_must sleep 5
|
||||
log_must dd if=/dev/urandom of=/$TESTPOOL/file1c bs=1M count=$((fill_mb/3))
|
||||
log_must sleep 5
|
||||
|
||||
# Verify L2ARC is populated before export
|
||||
typeset l2_size_before=$(kstat arcstats.l2_size)
|
||||
log_note "L2ARC size before export: $((l2_size_before / 1024 / 1024))MB"
|
||||
if [[ $l2_size_before -eq 0 ]]; then
|
||||
log_fail "L2ARC not populated before export"
|
||||
fi
|
||||
|
||||
# Measure DWPD-limited writes before export
|
||||
baseline1=$(kstat arcstats.l2_write_bytes)
|
||||
log_note "Baseline before export: ${baseline1}"
|
||||
dd if=/dev/urandom of=/$TESTPOOL/file2 bs=1M count=2000 >/dev/null 2>&1 &
|
||||
dd_pid=$!
|
||||
log_must sleep $test_time
|
||||
kill $dd_pid 2>/dev/null
|
||||
wait $dd_pid 2>/dev/null
|
||||
log_must sleep 2
|
||||
end1=$(kstat arcstats.l2_write_bytes)
|
||||
typeset writes_before=$((end1 - baseline1))
|
||||
|
||||
log_note "Writes before export: $((writes_before / 1024))KB"
|
||||
|
||||
# Verify L2ARC actually wrote data
|
||||
if [[ $writes_before -eq 0 ]]; then
|
||||
log_fail "No L2ARC writes before export - DWPD may be too restrictive"
|
||||
fi
|
||||
|
||||
# Export and import pool
|
||||
log_must zpool export $TESTPOOL
|
||||
log_must zpool import -d $VDIR $TESTPOOL
|
||||
|
||||
# Wait for rebuild to complete
|
||||
log_must sleep 5
|
||||
|
||||
# Verify L2ARC is populated after import
|
||||
typeset l2_size_after=$(kstat arcstats.l2_size)
|
||||
log_note "L2ARC size after import: $((l2_size_after / 1024 / 1024))MB"
|
||||
if [[ $l2_size_after -eq 0 ]]; then
|
||||
log_fail "L2ARC not populated after import"
|
||||
fi
|
||||
|
||||
# Staged fills again after import
|
||||
log_must dd if=/dev/urandom of=/$TESTPOOL/file3a bs=1M count=$((fill_mb/3))
|
||||
log_must sleep 5
|
||||
log_must dd if=/dev/urandom of=/$TESTPOOL/file3b bs=1M count=$((fill_mb/3))
|
||||
log_must sleep 5
|
||||
log_must dd if=/dev/urandom of=/$TESTPOOL/file3c bs=1M count=$((fill_mb/3))
|
||||
log_must sleep 5
|
||||
|
||||
# Verify L2ARC is still populated after refill
|
||||
l2_size=$(kstat arcstats.l2_size)
|
||||
log_note "L2ARC size after refill: $((l2_size / 1024 / 1024))MB"
|
||||
|
||||
# Measure DWPD-limited writes after import
|
||||
baseline2=$(kstat arcstats.l2_write_bytes)
|
||||
log_note "Baseline after import: ${baseline2}"
|
||||
dd if=/dev/urandom of=/$TESTPOOL/file4 bs=1M count=2000 >/dev/null 2>&1 &
|
||||
dd_pid=$!
|
||||
log_must sleep $test_time
|
||||
kill $dd_pid 2>/dev/null
|
||||
wait $dd_pid 2>/dev/null
|
||||
log_must sleep 2
|
||||
end2=$(kstat arcstats.l2_write_bytes)
|
||||
typeset writes_after=$((end2 - baseline2))
|
||||
|
||||
log_note "Writes after import: $((writes_after / 1024))KB"
|
||||
|
||||
# Verify rate limiting persists after import
|
||||
if [[ $writes_after -eq 0 ]]; then
|
||||
log_fail "No writes after import - rate limiting may be broken"
|
||||
fi
|
||||
|
||||
log_must zpool destroy $TESTPOOL
|
||||
|
||||
log_pass "L2ARC DWPD rate limiting works after pool export/import."
|
||||
162
tests/zfs-tests/tests/functional/l2arc/l2arc_multidev_scaling_pos.ksh
Executable file
162
tests/zfs-tests/tests/functional/l2arc/l2arc_multidev_scaling_pos.ksh
Executable file
@ -0,0 +1,162 @@
|
||||
#!/bin/ksh -p
|
||||
# SPDX-License-Identifier: CDDL-1.0
|
||||
#
|
||||
# CDDL HEADER START
|
||||
#
|
||||
# This file and its contents are supplied under the terms of the
|
||||
# Common Development and Distribution License ("CDDL"), version 1.0.
|
||||
# You may only use this file in accordance with the terms of version
|
||||
# 1.0 of the CDDL.
|
||||
#
|
||||
# A full copy of the text of the CDDL should have accompanied this
|
||||
# source. A copy of the CDDL is also available via the Internet at
|
||||
# http://www.illumos.org/license/CDDL.
|
||||
#
|
||||
# CDDL HEADER END
|
||||
#
|
||||
|
||||
#
|
||||
# Copyright (c) 2024. All rights reserved.
|
||||
#
|
||||
|
||||
. $STF_SUITE/include/libtest.shlib
|
||||
. $STF_SUITE/tests/functional/l2arc/l2arc.cfg
|
||||
|
||||
#
|
||||
# DESCRIPTION:
|
||||
# L2ARC parallel writes scale with number of cache devices.
|
||||
#
|
||||
# STRATEGY:
|
||||
# 1. Configure L2ARC write rate to 16MB/s per device.
|
||||
# 2. Disable DWPD rate limiting to test pure parallel throughput.
|
||||
# 3. Create pool with single 2100MB cache device.
|
||||
# 4. Generate continuous writes, wait for L2ARC activity, measure over 25s.
|
||||
# 5. Verify single-device throughput ~400MB (16MB/s × 25s).
|
||||
# 6. Recreate pool with dual 2100MB cache devices.
|
||||
# 7. Generate continuous writes, wait for L2ARC activity, measure over 25s.
|
||||
# 8. Verify dual-device throughput ~800MB (2×16MB/s × 25s).
|
||||
#
|
||||
|
||||
verify_runnable "global"
|
||||
|
||||
log_assert "L2ARC parallel writes scale with number of cache devices."
|
||||
|
||||
function cleanup
|
||||
{
|
||||
if poolexists $TESTPOOL ; then
|
||||
destroy_pool $TESTPOOL
|
||||
fi
|
||||
|
||||
restore_tunable L2ARC_WRITE_MAX
|
||||
restore_tunable L2ARC_NOPREFETCH
|
||||
restore_tunable L2ARC_DWPD_LIMIT
|
||||
restore_tunable ARC_MIN
|
||||
restore_tunable ARC_MAX
|
||||
}
|
||||
log_onexit cleanup
|
||||
|
||||
# Save original tunables
|
||||
save_tunable L2ARC_WRITE_MAX
|
||||
save_tunable L2ARC_NOPREFETCH
|
||||
save_tunable L2ARC_DWPD_LIMIT
|
||||
save_tunable ARC_MIN
|
||||
save_tunable ARC_MAX
|
||||
|
||||
# Test parameters
|
||||
typeset cache_sz=1000
|
||||
typeset fill_mb=2500 # 2.5GB initial data
|
||||
typeset test_time=12 # Measurement window: 16MB/s × 12s = ~200MB per device
|
||||
|
||||
# Disable DWPD to test pure parallel throughput
|
||||
log_must set_tunable32 L2ARC_DWPD_LIMIT 0
|
||||
|
||||
# Set L2ARC_WRITE_MAX to 16MB/s to test parallel scaling
|
||||
log_must set_tunable32 L2ARC_WRITE_MAX $((16 * 1024 * 1024))
|
||||
log_must set_tunable32 L2ARC_NOPREFETCH 0
|
||||
|
||||
# Configure arc_max so L2ARC >= arc_c_max * 2 threshold for persistent markers
|
||||
log_must set_tunable64 ARC_MAX $((400 * 1024 * 1024))
|
||||
log_must set_tunable64 ARC_MIN $((200 * 1024 * 1024))
|
||||
|
||||
# Single device test
|
||||
log_must truncate -s 4G $VDEV
|
||||
log_must truncate -s ${cache_sz}M $VDEV_CACHE
|
||||
log_must zpool create -f $TESTPOOL $VDEV cache $VDEV_CACHE
|
||||
|
||||
# Generate data in background
|
||||
dd if=/dev/urandom of=/$TESTPOOL/file1 bs=1M count=$fill_mb &
|
||||
typeset dd_pid=$!
|
||||
|
||||
# Wait for L2ARC to start writing
|
||||
typeset l2_size=0
|
||||
for i in {1..30}; do
|
||||
l2_size=$(kstat arcstats.l2_size)
|
||||
[[ $l2_size -gt 0 ]] && break
|
||||
sleep 1
|
||||
done
|
||||
if [[ $l2_size -eq 0 ]]; then
|
||||
kill $dd_pid 2>/dev/null
|
||||
log_fail "L2ARC did not start writing (single device)"
|
||||
fi
|
||||
|
||||
# Measure single-device write throughput
|
||||
typeset start=$(kstat arcstats.l2_write_bytes)
|
||||
log_must sleep $test_time
|
||||
typeset end=$(kstat arcstats.l2_write_bytes)
|
||||
kill $dd_pid 2>/dev/null
|
||||
wait $dd_pid 2>/dev/null
|
||||
typeset single_writes=$((end - start))
|
||||
|
||||
# expected = 16MB/s * 1 device * 25s = 400MB
|
||||
typeset single_expected=$((16 * 1024 * 1024 * test_time))
|
||||
log_note "Single-device writes: $((single_writes / 1024 / 1024))MB (expected ~$((single_expected / 1024 / 1024))MB)"
|
||||
|
||||
# Dual device test
|
||||
log_must zpool destroy $TESTPOOL
|
||||
log_must truncate -s ${cache_sz}M $VDEV_CACHE
|
||||
log_must truncate -s ${cache_sz}M $VDEV_CACHE2
|
||||
|
||||
log_must zpool create -f $TESTPOOL $VDEV cache $VDEV_CACHE $VDEV_CACHE2
|
||||
|
||||
# Generate data in background
|
||||
dd if=/dev/urandom of=/$TESTPOOL/file2 bs=1M count=$fill_mb &
|
||||
dd_pid=$!
|
||||
|
||||
# Wait for L2ARC to start writing
|
||||
l2_size=0
|
||||
for i in {1..30}; do
|
||||
l2_size=$(kstat arcstats.l2_size)
|
||||
[[ $l2_size -gt 0 ]] && break
|
||||
sleep 1
|
||||
done
|
||||
if [[ $l2_size -eq 0 ]]; then
|
||||
kill $dd_pid 2>/dev/null
|
||||
log_fail "L2ARC did not start writing (dual device)"
|
||||
fi
|
||||
|
||||
# Measure parallel write throughput (2 feed threads active)
|
||||
start=$(kstat arcstats.l2_write_bytes)
|
||||
log_must sleep $test_time
|
||||
end=$(kstat arcstats.l2_write_bytes)
|
||||
kill $dd_pid 2>/dev/null
|
||||
wait $dd_pid 2>/dev/null
|
||||
typeset dual_writes=$((end - start))
|
||||
|
||||
# expected = 16MB/s * 2 devices * 25s = 800MB
|
||||
typeset dual_expected=$((16 * 1024 * 1024 * 2 * test_time))
|
||||
log_note "Dual-device writes: $((dual_writes / 1024 / 1024))MB (expected ~$((dual_expected / 1024 / 1024))MB)"
|
||||
|
||||
# Verify writes are within expected range (80-150%)
|
||||
typeset single_min=$((single_expected * 80 / 100))
|
||||
typeset dual_min=$((dual_expected * 80 / 100))
|
||||
|
||||
if [[ $single_writes -lt $single_min ]]; then
|
||||
log_fail "Single-device writes $((single_writes / 1024 / 1024))MB below minimum $((single_min / 1024 / 1024))MB"
|
||||
fi
|
||||
if [[ $dual_writes -lt $dual_min ]]; then
|
||||
log_fail "Dual-device writes $((dual_writes / 1024 / 1024))MB below minimum $((dual_min / 1024 / 1024))MB"
|
||||
fi
|
||||
|
||||
log_must zpool destroy $TESTPOOL
|
||||
|
||||
log_pass "L2ARC parallel writes scale with number of cache devices."
|
||||
133
tests/zfs-tests/tests/functional/l2arc/l2arc_multidev_throughput_pos.ksh
Executable file
133
tests/zfs-tests/tests/functional/l2arc/l2arc_multidev_throughput_pos.ksh
Executable file
@ -0,0 +1,133 @@
|
||||
#!/bin/ksh -p
|
||||
# SPDX-License-Identifier: CDDL-1.0
|
||||
#
|
||||
# CDDL HEADER START
|
||||
#
|
||||
# This file and its contents are supplied under the terms of the
|
||||
# Common Development and Distribution License ("CDDL"), version 1.0.
|
||||
# You may only use this file in accordance with the terms of version
|
||||
# 1.0 of the CDDL.
|
||||
#
|
||||
# A full copy of the text of the CDDL should have accompanied this
|
||||
# source. A copy of the CDDL is also available via the Internet at
|
||||
# http://www.illumos.org/license/CDDL.
|
||||
#
|
||||
# CDDL HEADER END
|
||||
#
|
||||
|
||||
#
|
||||
# Copyright (c) 2024. All rights reserved.
|
||||
#
|
||||
|
||||
. $STF_SUITE/include/libtest.shlib
|
||||
. $STF_SUITE/tests/functional/l2arc/l2arc.cfg
|
||||
|
||||
#
|
||||
# DESCRIPTION:
|
||||
# L2ARC parallel writes scale with number of cache devices.
|
||||
#
|
||||
# STRATEGY:
|
||||
# 1. Disable DWPD rate limiting.
|
||||
# 2. Create pool with 2 cache devices.
|
||||
# 3. Write data and measure L2ARC throughput.
|
||||
# 4. Verify throughput scales with device count (~16MB/s per device).
|
||||
#
|
||||
|
||||
verify_runnable "global"
|
||||
|
||||
log_assert "L2ARC parallel writes scale with number of cache devices."
|
||||
|
||||
function cleanup
|
||||
{
|
||||
if poolexists $TESTPOOL ; then
|
||||
destroy_pool $TESTPOOL
|
||||
fi
|
||||
|
||||
restore_tunable L2ARC_WRITE_MAX
|
||||
restore_tunable L2ARC_NOPREFETCH
|
||||
restore_tunable L2ARC_DWPD_LIMIT
|
||||
restore_tunable ARC_MIN
|
||||
restore_tunable ARC_MAX
|
||||
}
|
||||
log_onexit cleanup
|
||||
|
||||
# Save original tunables
|
||||
save_tunable L2ARC_WRITE_MAX
|
||||
save_tunable L2ARC_NOPREFETCH
|
||||
save_tunable L2ARC_DWPD_LIMIT
|
||||
save_tunable ARC_MIN
|
||||
save_tunable ARC_MAX
|
||||
|
||||
# Test parameters
|
||||
typeset num_devs=2
|
||||
typeset cache_sz=1000 # 2000MB total > 1900MB (arc_max*2) threshold
|
||||
typeset test_time=10
|
||||
typeset fill_mb=1500
|
||||
typeset expected_rate=$((32 * 1024 * 1024)) # 32 MB/s per device
|
||||
|
||||
# Disable DWPD rate limiting
|
||||
log_must set_tunable32 L2ARC_DWPD_LIMIT 0
|
||||
|
||||
# Set L2ARC_WRITE_MAX to 32MB/s per device (64MB/s total with 2 devices)
|
||||
log_must set_tunable32 L2ARC_WRITE_MAX $expected_rate
|
||||
log_must set_tunable32 L2ARC_NOPREFETCH 0
|
||||
|
||||
# Configure arc_max large enough to feed L2ARC
|
||||
log_must set_tunable64 ARC_MAX $((950 * 1024 * 1024))
|
||||
log_must set_tunable64 ARC_MIN $((512 * 1024 * 1024))
|
||||
|
||||
# Create cache devices (using letters e-f to follow cfg naming convention)
|
||||
typeset cache_devs=""
|
||||
for letter in e f; do
|
||||
typeset dev="$VDIR/$letter"
|
||||
log_must truncate -s ${cache_sz}M $dev
|
||||
cache_devs="$cache_devs $dev"
|
||||
done
|
||||
|
||||
log_must truncate -s 2G $VDEV
|
||||
log_must zpool create -f $TESTPOOL $VDEV cache $cache_devs
|
||||
|
||||
# Generate data in background
|
||||
dd if=/dev/urandom of=/$TESTPOOL/file1 bs=1M count=$fill_mb &
|
||||
typeset dd_pid=$!
|
||||
|
||||
# Wait for L2ARC to start writing
|
||||
typeset l2_size=0
|
||||
for i in {1..30}; do
|
||||
l2_size=$(kstat arcstats.l2_size)
|
||||
[[ $l2_size -gt 0 ]] && break
|
||||
sleep 1
|
||||
done
|
||||
if [[ $l2_size -eq 0 ]]; then
|
||||
kill $dd_pid 2>/dev/null
|
||||
log_fail "L2ARC did not start writing"
|
||||
fi
|
||||
|
||||
# Measure L2ARC throughput over test window
|
||||
typeset start=$(kstat arcstats.l2_write_bytes)
|
||||
log_must sleep $test_time
|
||||
typeset end=$(kstat arcstats.l2_write_bytes)
|
||||
kill $dd_pid 2>/dev/null
|
||||
wait $dd_pid 2>/dev/null
|
||||
|
||||
typeset bytes=$((end - start))
|
||||
typeset bytes_mb=$((bytes / 1024 / 1024))
|
||||
# expected = 32MB/s * 2 devices * 10 seconds = 640MB
|
||||
typeset expected=$((expected_rate * num_devs * test_time))
|
||||
typeset expected_mb=$((expected / 1024 / 1024))
|
||||
|
||||
log_note "L2ARC writes: ${bytes_mb}MB (expected ~${expected_mb}MB)"
|
||||
|
||||
# Verify writes are within expected range (75-150%)
|
||||
typeset min_bytes=$((expected * 75 / 100))
|
||||
typeset max_bytes=$((expected * 150 / 100))
|
||||
if [[ $bytes -lt $min_bytes ]]; then
|
||||
log_fail "Writes ${bytes_mb}MB below minimum $((min_bytes/1024/1024))MB"
|
||||
fi
|
||||
if [[ $bytes -gt $max_bytes ]]; then
|
||||
log_fail "Writes ${bytes_mb}MB above maximum $((max_bytes/1024/1024))MB"
|
||||
fi
|
||||
|
||||
log_must zpool destroy $TESTPOOL
|
||||
|
||||
log_pass "L2ARC parallel writes scale with number of cache devices."
|
||||
@ -50,16 +50,19 @@ function cleanup
|
||||
log_must rm -f $VDEVS
|
||||
log_must set_tunable32 L2ARC_TRIM_AHEAD $l2arc_trimahead
|
||||
log_must set_tunable32 L2ARC_WRITE_MAX $l2arc_writemax
|
||||
log_must set_tunable32 L2ARC_DWPD_LIMIT $l2arc_dwpdlimit
|
||||
}
|
||||
log_onexit cleanup
|
||||
|
||||
# The cache device $TRIM_VDEV2 has to be small enough, so that
|
||||
# dev->l2ad_hand loops around and dev->l2ad_first=0. Otherwise
|
||||
# dev->l2ad_hand loops around and dev->l2ad_first=0. Otherwise
|
||||
# l2arc_evict() exits before evicting/trimming.
|
||||
typeset l2arc_trimahead=$(get_tunable L2ARC_TRIM_AHEAD)
|
||||
typeset l2arc_writemax=$(get_tunable L2ARC_WRITE_MAX)
|
||||
typeset l2arc_dwpdlimit=$(get_tunable L2ARC_DWPD_LIMIT)
|
||||
log_must set_tunable32 L2ARC_TRIM_AHEAD 1
|
||||
log_must set_tunable32 L2ARC_WRITE_MAX $((64 * 1024 * 1024))
|
||||
log_must set_tunable32 L2ARC_DWPD_LIMIT 0
|
||||
VDEVS="$TRIM_VDEV1 $TRIM_VDEV2"
|
||||
log_must truncate -s $((MINVDEVSIZE)) $TRIM_VDEV2
|
||||
log_must truncate -s $((4 * MINVDEVSIZE)) $TRIM_VDEV1
|
||||
|
||||
Loading…
Reference in New Issue
Block a user