Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions HOWTO.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4216,6 +4216,16 @@ Steady state
Collect bandwidth data and calculate the least squares regression
slope. Stop the job if the slope falls below the specified limit.

**lat**
Collect completion latency data and calculate the maximum mean
deviation. Stop the job if the deviation falls below the specified
limit.

**lat_slope**
Collect completion latency data and calculate the least squares
regression slope. Stop the job if the slope falls below the
specified limit.

.. option:: steadystate_duration=time, ss_dur=time

A rolling window of this duration will be used to judge whether steady
Expand Down
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -643,6 +643,7 @@ clean: FORCE
@rm -f .depend $(FIO_OBJS) $(GFIO_OBJS) $(OBJS) $(T_OBJS) $(UT_OBJS) $(PROGS) $(T_PROGS) $(T_TEST_PROGS) core.* core gfio unittests/unittest FIO-VERSION-FILE *.[do] lib/*.d oslib/*.[do] crc/*.d engines/*.[do] engines/*.so profiles/*.[do] t/*.[do] t/*/*.[do] unittests/*.[do] unittests/*/*.[do] config-host.mak config-host.h y.tab.[ch] lex.yy.c exp/*.[do] lexer.h
@rm -f t/fio-btrace2fio t/io_uring t/read-to-pipe-async
@rm -rf doc/output
@$(MAKE) -C mock-tests clean

distclean: clean FORCE
@rm -f cscope.out fio.pdf fio_generate_plots.pdf fio2gnuplot.pdf fiologparser_hist.pdf
Expand All @@ -662,6 +663,10 @@ doc: tools/plot/fio2gnuplot.1
test: fio
./fio --minimal --thread --exitall_on_error --runtime=1s --name=nulltest --ioengine=null --rw=randrw --iodepth=2 --norandommap --random_generator=tausworthe64 --size=16T --name=verifyfstest --filename=fiotestfile.tmp --unlink=1 --rw=write --verify=crc32c --verify_state_save=0 --size=16K


mock-tests:
$(MAKE) -C mock-tests test

fulltest:
sudo modprobe null_blk && \
if [ ! -e /usr/include/libzbc/zbc.h ]; then \
Expand Down
4 changes: 4 additions & 0 deletions client.c
Original file line number Diff line number Diff line change
Expand Up @@ -1079,6 +1079,7 @@ static void convert_ts(struct thread_stat *dst, struct thread_stat *src)
for (i = 0; i < dst->ss_dur; i++ ) {
dst->ss_iops_data[i] = le64_to_cpu(src->ss_iops_data[i]);
dst->ss_bw_data[i] = le64_to_cpu(src->ss_bw_data[i]);
dst->ss_lat_data[i] = le64_to_cpu(src->ss_lat_data[i]);
}
}

Expand Down Expand Up @@ -1888,6 +1889,9 @@ int fio_handle_client(struct fio_client *client)

offset = le64_to_cpu(p->ts.ss_bw_data_offset);
p->ts.ss_bw_data = (uint64_t *)((char *)p + offset);

offset = le64_to_cpu(p->ts.ss_lat_data_offset);
p->ts.ss_lat_data = (uint64_t *)((char *)p + offset);
}

convert_ts(&p->ts, &p->ts);
Expand Down
19 changes: 17 additions & 2 deletions configure
Original file line number Diff line number Diff line change
Expand Up @@ -2348,8 +2348,23 @@ print_config "DAOS File System (dfs) Engine" "$dfs"
if test "$libnfs" != "no" ; then
if $(pkg-config libnfs > /dev/null 2>&1); then
libnfs="yes"
libnfs_cflags=$(pkg-config --cflags libnfs gnutls)
libnfs_libs=$(pkg-config --libs libnfs gnutls)
libnfs_cflags=$(pkg-config --cflags libnfs)
libnfs_libs=$(pkg-config --libs libnfs)

# libnfs >= 6.0.0 requires gnutls for TLS support
libnfs_version=$(pkg-config --modversion libnfs 2>/dev/null)
if test -n "$libnfs_version" ; then
libnfs_major=$(echo $libnfs_version | cut -d. -f1)
if test "$libnfs_major" -ge 6 ; then
if $(pkg-config gnutls > /dev/null 2>&1); then
libnfs_cflags="$libnfs_cflags $(pkg-config --cflags gnutls)"
libnfs_libs="$libnfs_libs $(pkg-config --libs gnutls)"
else
feature_not_found "gnutls" "gnutls (required for libnfs >= 6.0.0)"
libnfs="no"
fi
fi
fi
else
if test "$libnfs" = "yes" ; then
feature_not_found "libnfs" "libnfs"
Expand Down
47 changes: 47 additions & 0 deletions example_latency_steadystate.fio
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Example FIO job file demonstrating latency steady state detection
# This example shows how to use FIO's latency steady state detection
# to automatically terminate workloads when latency stabilizes
#
# Based on SNIA SSD Performance Test Specification requirements:
# - Steady state is achieved when latency measurements don't change more than
# 20% for 5 measurement windows and remain within 5% of a line with 10% slope
# - This example uses more conservative 5% deviation threshold for demonstration

[global]
# Basic I/O parameters
ioengine=libaio
iodepth=32
bs=4k
direct=1
rw=randread
numjobs=1
time_based=1
runtime=3600 # Max runtime: 1 hour (will terminate early if steady state reached)

# Steady state detection parameters
steadystate=lat:5% # Stop when latency mean deviation < 5% of average
steadystate_duration=300 # Use 5-minute rolling window for measurements
steadystate_ramp_time=60 # Wait 1 minute before starting measurements
steadystate_check_interval=10 # Take measurements every 10 seconds

# Output options
write_lat_log=lat_steadystate
log_avg_msec=10000 # Log average latency every 10 seconds

[latency_steady_test]
filename=/dev/nvme3n1
size=10G

# Alternative steady state configurations (uncomment to try):

# Use slope-based detection instead of deviation:
# steadystate=lat_slope:0.1%

# More aggressive detection (faster convergence):
# steadystate=lat:2%
# steadystate_duration=120 # 2-minute window
# steadystate_check_interval=5 # Check every 5 seconds

# More conservative detection (slower convergence):
# steadystate=lat:10%
# steadystate_duration=600 # 10-minute window
80 changes: 80 additions & 0 deletions mock-tests/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# Makefile for FIO mock tests
#
# These tests validate specific algorithmic improvements and edge cases
# using isolated mock implementations.

CC ?= gcc
CFLAGS = -Wall -Wextra -O2 -g -I. -I.. -lm
TEST_DIR = tests
LIB_DIR = lib
BUILD_DIR = build

# List of test programs
TESTS = test_latency_precision

# Build paths
TEST_SRCS = $(addprefix $(TEST_DIR)/, $(addsuffix .c, $(TESTS)))
TEST_BINS = $(addprefix $(BUILD_DIR)/, $(TESTS))

# TAP test runner
TAP_RUNNER = prove

.PHONY: all clean test help

all: $(BUILD_DIR) $(TEST_BINS)

$(BUILD_DIR):
@mkdir -p $(BUILD_DIR)

$(BUILD_DIR)/%: $(TEST_DIR)/%.c $(LIB_DIR)/tap.h
$(CC) $(CFLAGS) -o $@ $<

test: all
@echo "Running FIO mock tests..."
@echo "========================="
@failed=0; \
for test in $(TEST_BINS); do \
echo "Running $$test..."; \
./$$test; \
if [ $$? -ne 0 ]; then \
failed=$$((failed + 1)); \
fi; \
echo; \
done; \
if [ $$failed -gt 0 ]; then \
echo "FAILED: $$failed test(s) failed"; \
exit 1; \
else \
echo "SUCCESS: All tests passed"; \
fi

# Run tests with TAP harness if available
test-tap: all
@if command -v $(TAP_RUNNER) >/dev/null 2>&1; then \
$(TAP_RUNNER) -v $(TEST_BINS); \
else \
echo "TAP runner '$(TAP_RUNNER)' not found, running tests directly..."; \
$(MAKE) test; \
fi

# Run a specific test
test-%: $(BUILD_DIR)/%
./$(BUILD_DIR)/$*

clean:
rm -rf $(BUILD_DIR)

help:
@echo "FIO Mock Tests"
@echo "=============="
@echo ""
@echo "Available targets:"
@echo " make all - Build all tests"
@echo " make test - Run all tests"
@echo " make test-tap - Run tests with TAP harness (if available)"
@echo " make test-NAME - Run specific test (e.g., make test-latency_precision)"
@echo " make clean - Remove build artifacts"
@echo " make help - Show this help message"
@echo ""
@echo "Available tests:"
@for test in $(TESTS); do echo " - $$test"; done
166 changes: 166 additions & 0 deletions mock-tests/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
# FIO Mock Tests

## Overview

The FIO mock test suite provides isolated unit testing for specific algorithms,
calculations, and edge cases within FIO. These tests use mock implementations
to validate correctness without requiring the full FIO infrastructure.

## Purpose and Goals

### Why Mock Tests?

1. **Isolation**: Test specific algorithms without full system dependencies
2. **Precision**: Validate numerical calculations and edge cases precisely
3. **Speed**: Run quickly without I/O operations or system calls
4. **Clarity**: Each test focuses on a single aspect with clear documentation
5. **Regression Prevention**: Catch subtle bugs in mathematical operations

### What Mock Tests Are NOT

- Not integration tests (use `make test` for that)
- Not performance benchmarks (use FIO itself)
- Not I/O path testing (requires real FIO execution)

## Structure

```
mock-tests/
├── lib/ # Common test infrastructure
│ └── tap.h # TAP (Test Anything Protocol) output support
├── tests/ # Individual test programs
│ └── test_*.c # Test source files
├── build/ # Build artifacts (created by make)
└── Makefile # Build system for mock tests
```

## Running Tests

### Run all mock tests:
```bash
make mock-tests
```

### Run tests from the mock-tests directory:
```bash
cd mock-tests
make test # Run all tests
make test-tap # Run with TAP harness (if prove is installed)
make test-latency_precision # Run specific test
```

### Clean build artifacts:
```bash
make clean # From mock-tests directory
# or
make clean # From main FIO directory (cleans everything)
```

## TAP Output Format

Tests produce TAP (Test Anything Protocol) output for easy parsing:

```
TAP version 13
1..12
ok 1 - Microsecond latency: 123456000 == 123456000
ok 2 - Millisecond latency: 1234567890000 == 1234567890000
not ok 3 - Some failing test
# All tests passed
```

This format is understood by many test harnesses and CI systems.

## Writing New Mock Tests

### 1. Create test file in `tests/`:

```c
#include "../lib/tap.h"

int main(void) {
tap_init();
tap_plan(3); // Number of tests

tap_ok(1 == 1, "Basic equality");
tap_ok(2 + 2 == 4, "Addition works");
tap_skip("Not implemented yet");

return tap_done();
}
```

### 2. Add to Makefile:

Edit `mock-tests/Makefile` and add your test name to the `TESTS` variable.

### 3. Document your test:

Each test should have a comprehensive header comment explaining:
- Purpose of the test
- Background on what's being tested
- Why this test matters
- What specific cases are covered

## Available Tests

### test_latency_precision

**Purpose**: Validates numerical precision improvements in steady state latency calculations.

**Background**: When calculating total latency from mean and sample count, large values
can cause precision loss or overflow. This test validates the improvement from:
```c
// Before: potential precision loss
total = (uint64_t)(mean * samples);

// After: explicit double precision
total = (uint64_t)(mean * (double)samples);
```

**Test Cases**:
- Normal operating ranges (microseconds to seconds)
- Edge cases near uint64_t overflow
- Zero sample defensive programming
- Precision in accumulation across threads
- Fractional nanosecond preservation

## Design Principles

1. **Isolation**: Mock only what's needed, test one thing at a time
2. **Clarity**: Clear test names and diagnostic messages
3. **Coverage**: Test normal cases, edge cases, and error conditions
4. **Documentation**: Explain WHY each test exists
5. **Reproducibility**: Deterministic tests with no random elements

## Integration with CI

The TAP output format makes these tests easy to integrate with CI systems:

```bash
# In CI script
make mock-tests || exit 1
```

Or with TAP parsing for better reports:

```bash
prove -v mock-tests/build/*
```

## Future Enhancements

Potential areas for expansion:
- Mock tests for parsing algorithms
- Edge case validation for statistical calculations
- Overflow detection in various calculations
- Precision validation for other numerical operations

## Contributing

When adding new mock tests:
1. Follow the existing patterns
2. Document thoroughly
3. Use meaningful test descriptions
4. Include both positive and negative test cases
5. Test edge cases and boundary conditions
Loading
Loading