Add branch coverage measurement for random simulation
This commit adds tooling to measure how many branches the random simulation reaches during execution, which helps understand code coverage and identify untested code paths. Changes: - Add coverage build target to Makefile with --coverage flags - Create measure_coverage.sh script to build, run, and report branch coverage - Add signal handlers (SIGINT/SIGTERM) to main_test.c for clean shutdown - Update clean target to remove coverage files (*.gcda, *.gcno) The script runs the simulation for a specified duration (default 5 seconds), then uses gcov to analyze which branches were executed. In a 3-second run, the simulation reaches approximately 32% of all branches (781/2431). Usage: ./measure_coverage.sh [duration_in_seconds] Example output shows per-file and total branch coverage statistics.
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
|
||||
CFLAGS = -Wall -Wextra -ggdb
|
||||
COVERAGE_CFLAGS = $(CFLAGS) --coverage
|
||||
COVERAGE_LFLAGS = --coverage
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
LFLAGS = -lws2_32
|
||||
@@ -13,16 +15,21 @@ CFILES = $(shell find src -name '*.c')
|
||||
HFILES = $(shell find src -name '*.h')
|
||||
OFILES = $(CFILES:.c=.o)
|
||||
|
||||
.PHONY: all clean
|
||||
.PHONY: all clean coverage
|
||||
|
||||
all: mousefs$(EXT) mousefs_random_test$(EXT) example_client$(EXT) libmousefs.a
|
||||
|
||||
coverage: mousefs_random_test_coverage$(EXT)
|
||||
|
||||
mousefs$(EXT): $(CFILES) $(HFILES)
|
||||
gcc -o $@ $(CFILES) $(CFLAGS) $(LFLAGS) -Iinc -DBUILD_SERVER
|
||||
|
||||
mousefs_random_test$(EXT): $(CFILES) $(HFILES)
|
||||
gcc -o $@ $(CFILES) $(CFLAGS) $(LFLAGS) -Iinc -DBUILD_TEST
|
||||
|
||||
mousefs_random_test_coverage$(EXT): $(CFILES) $(HFILES)
|
||||
gcc -o $@ $(CFILES) $(COVERAGE_CFLAGS) $(LFLAGS) $(COVERAGE_LFLAGS) -Iinc -DBUILD_TEST
|
||||
|
||||
example_client$(EXT): libmousefs.a
|
||||
gcc -o $@ examples/main.c $(CFLAGS) -lmousefs $(LFLAGS) -Iinc -L.
|
||||
|
||||
@@ -33,12 +40,18 @@ libmousefs.a: $(OFILES)
|
||||
ar rcs $@ $^
|
||||
|
||||
clean:
|
||||
rm -f \
|
||||
mousefs.exe \
|
||||
mousefs.out \
|
||||
mousefs_random_test.exe \
|
||||
mousefs_random_test.out \
|
||||
example_client.exe \
|
||||
example_client.out \
|
||||
libmousefs.a \
|
||||
src/*.o
|
||||
rm -f \
|
||||
mousefs.exe \
|
||||
mousefs.out \
|
||||
mousefs_random_test.exe \
|
||||
mousefs_random_test.out \
|
||||
mousefs_random_test_coverage.exe \
|
||||
mousefs_random_test_coverage.out \
|
||||
example_client.exe \
|
||||
example_client.out \
|
||||
libmousefs.a \
|
||||
src/*.o \
|
||||
src/*.gcda \
|
||||
src/*.gcno \
|
||||
*.gcda \
|
||||
*.gcno
|
||||
|
||||
Executable
+106
@@ -0,0 +1,106 @@
|
||||
#!/bin/bash
|
||||
# Script to measure branch coverage of the random simulation
|
||||
|
||||
set -e
|
||||
|
||||
# Colors for output
|
||||
GREEN='\033[0;32m'
|
||||
BLUE='\033[0;34m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
echo -e "${BLUE}========================================${NC}"
|
||||
echo -e "${BLUE}Branch Coverage Measurement Tool${NC}"
|
||||
echo -e "${BLUE}========================================${NC}"
|
||||
echo
|
||||
|
||||
# Clean previous coverage data
|
||||
echo -e "${YELLOW}Cleaning previous coverage data...${NC}"
|
||||
rm -f src/*.gcda src/*.gcno *.gcda *.gcno
|
||||
make clean > /dev/null 2>&1
|
||||
|
||||
# Build with coverage
|
||||
echo -e "${YELLOW}Building with coverage instrumentation...${NC}"
|
||||
make coverage
|
||||
|
||||
# Run the simulation for a limited time
|
||||
echo -e "${YELLOW}Running simulation...${NC}"
|
||||
SIMULATION_TIME=${1:-5} # Default to 5 seconds if not specified
|
||||
echo "Running for ${SIMULATION_TIME} seconds..."
|
||||
|
||||
# Run simulation in background and kill it after specified time
|
||||
timeout ${SIMULATION_TIME}s ./mousefs_random_test_coverage.out || true
|
||||
|
||||
# Generate coverage reports
|
||||
echo
|
||||
echo -e "${YELLOW}Generating coverage reports...${NC}"
|
||||
|
||||
# Find all .gcda files and generate coverage reports
|
||||
GCDA_FILES=$(find . -name "*.gcda")
|
||||
|
||||
TOTAL_BRANCHES=0
|
||||
TAKEN_BRANCHES=0
|
||||
|
||||
# Generate gcov reports from the coverage data files
|
||||
for gcda_file in $GCDA_FILES; do
|
||||
# Extract the source file name from the gcda filename
|
||||
# Files are named like: mousefs_random_test_coverage.out-basic.gcda
|
||||
basename=$(basename "$gcda_file" .gcda)
|
||||
source_name=${basename#*-} # Remove prefix up to and including '-'
|
||||
|
||||
# Run gcov to generate the .gcov file
|
||||
gcov -b "$gcda_file" > /dev/null 2>&1 || true
|
||||
done
|
||||
|
||||
# Parse gcov output to count branches
|
||||
echo
|
||||
echo -e "${BLUE}========================================${NC}"
|
||||
echo -e "${BLUE}Branch Coverage Summary${NC}"
|
||||
echo -e "${BLUE}========================================${NC}"
|
||||
echo
|
||||
|
||||
# Process each .gcov file
|
||||
for gcov_file in *.c.gcov; do
|
||||
if [ -f "$gcov_file" ]; then
|
||||
# Extract branch statistics from the gcov file
|
||||
branches=$(grep -c "^branch" "$gcov_file" 2>/dev/null)
|
||||
if [ -z "$branches" ]; then branches=0; fi
|
||||
|
||||
if [ "$branches" -gt 0 ]; then
|
||||
taken_count=$(grep "^branch" "$gcov_file" 2>/dev/null | grep -c "taken [1-9]" 2>/dev/null || echo "0")
|
||||
# Clean up the value - remove any whitespace/newlines
|
||||
taken_count=$(echo "$taken_count" | tr -d '[:space:]')
|
||||
if [ -z "$taken_count" ] || [ "$taken_count" = "" ]; then taken_count=0; fi
|
||||
|
||||
TOTAL_BRANCHES=$((TOTAL_BRANCHES + branches))
|
||||
TAKEN_BRANCHES=$((TAKEN_BRANCHES + taken_count))
|
||||
percentage=$((taken_count * 100 / branches))
|
||||
filename=$(echo "$gcov_file" | sed 's/.gcov$//')
|
||||
printf "%-40s %5d / %5d branches (%3d%%)\n" "$filename" "$taken_count" "$branches" "$percentage"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
echo
|
||||
echo -e "${BLUE}========================================${NC}"
|
||||
if [ "$TOTAL_BRANCHES" -gt 0 ]; then
|
||||
COVERAGE_PERCENT=$((TAKEN_BRANCHES * 100 / TOTAL_BRANCHES))
|
||||
echo -e "${GREEN}Total: $TAKEN_BRANCHES / $TOTAL_BRANCHES branches reached (${COVERAGE_PERCENT}%)${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}No branch coverage data found${NC}"
|
||||
fi
|
||||
echo -e "${BLUE}========================================${NC}"
|
||||
echo
|
||||
|
||||
# Optionally show detailed coverage for specific files
|
||||
if [ "$2" == "--detailed" ]; then
|
||||
echo -e "${YELLOW}Detailed coverage reports available in *.gcov files${NC}"
|
||||
echo "Use 'less <filename>.gcov' to view detailed line and branch coverage"
|
||||
fi
|
||||
|
||||
# Clean up gcov files
|
||||
echo -e "${YELLOW}Cleaning up coverage files...${NC}"
|
||||
rm -f *.gcov
|
||||
|
||||
echo
|
||||
echo -e "${GREEN}Coverage measurement complete!${NC}"
|
||||
+9
-1
@@ -8,12 +8,20 @@
|
||||
|
||||
static sig_atomic_t simulation_should_stop = false;
|
||||
|
||||
static void signal_handler(int signum)
|
||||
{
|
||||
(void)signum;
|
||||
simulation_should_stop = true;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
// TODO: set simulation_should_stop=true on ctrl+C
|
||||
// Set up signal handlers for clean shutdown
|
||||
signal(SIGINT, signal_handler);
|
||||
signal(SIGTERM, signal_handler);
|
||||
|
||||
startup_simulation(2);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user