serialbench 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/config/ci.yml ADDED
@@ -0,0 +1,22 @@
1
+ # Configuration for CI/GitHub Actions - Memory-safe settings
2
+ # Only runs small data sizes to avoid memory constraints
3
+
4
+ data_sizes:
5
+ - small
6
+
7
+ formats:
8
+ - xml
9
+ - json
10
+ - yaml
11
+ - toml
12
+
13
+ iterations:
14
+ small: 20
15
+ medium: 5
16
+ large: 2
17
+
18
+ # Disable memory profiling in CI to reduce memory usage
19
+ memory_profiling: false
20
+
21
+ # Reduce warmup iterations for faster CI
22
+ warmup_iterations: 2
data/config/full.yml ADDED
@@ -0,0 +1,30 @@
1
+ # Configuration for comprehensive benchmarks - Full testing with all data sizes
2
+ # Used by Docker script for complete performance analysis
3
+
4
+ data_sizes:
5
+ - small
6
+ - medium
7
+ - large
8
+
9
+ formats:
10
+ - xml
11
+ - json
12
+ - yaml
13
+ - toml
14
+
15
+ iterations:
16
+ small: 20
17
+ medium: 5
18
+ large: 2
19
+
20
+ # Enable memory profiling for comprehensive analysis
21
+ memory_profiling: true
22
+
23
+ # Standard warmup iterations
24
+ warmup_iterations: 3
25
+
26
+ # Enable streaming benchmarks where supported
27
+ streaming_benchmarks: true
28
+
29
+ # Generate detailed reports
30
+ detailed_reports: true
@@ -0,0 +1,31 @@
1
+ # Multi-stage Dockerfile for Ruby serialization benchmarks
2
+ # Supports multiple Ruby versions for comprehensive testing
3
+
4
+ ARG RUBY_VERSION=3.3
5
+ FROM ruby:${RUBY_VERSION}
6
+
7
+ # Install system dependencies for XML libraries
8
+ RUN apt-get update && apt-get install -y \
9
+ libxml2-dev \
10
+ libxslt1-dev \
11
+ build-essential \
12
+ && rm -rf /var/lib/apt/lists/*
13
+
14
+ # Set working directory
15
+ WORKDIR /app
16
+
17
+ # Copy the entire application (gemspec needs full context)
18
+ COPY . .
19
+
20
+ # Update bundler and configure bundle for cross-platform compatibility
21
+ RUN gem install bundler:2.5.22 && \
22
+ bundle config set --local deployment 'false' && \
23
+ bundle config set --local path '/usr/local/bundle' && \
24
+ bundle config set --local force_ruby_platform true && \
25
+ bundle install --jobs 4 --retry 3
26
+
27
+ # Create results directory
28
+ RUN mkdir -p /app/results
29
+
30
+ # Default command runs parsing and generation benchmarks (memory benchmarks disabled due to hanging in Docker)
31
+ CMD ["bundle", "exec", "ruby", "exe/serialbench", "benchmark", "--formats", "xml", "json", "yaml", "toml", "--iterations", "1", "--warmup", "0", "--parsing_only"]
data/docker/README.md ADDED
@@ -0,0 +1,214 @@
1
+ # Serialbench Docker Setup
2
+
3
+ This directory contains Docker infrastructure for running Serialbench across multiple Ruby versions in isolated environments.
4
+
5
+ ## Files
6
+
7
+ - `Dockerfile.benchmark` - Multi-stage Dockerfile for building benchmark environments
8
+ - `run-benchmarks.sh` - Automated script for running benchmarks across multiple Ruby versions
9
+
10
+ ## Quick Start
11
+
12
+ ### Prerequisites
13
+
14
+ - Docker installed and running
15
+ - Bash shell (Linux/macOS/WSL)
16
+
17
+ ### Running Multi-Ruby Benchmarks
18
+
19
+ ```bash
20
+ # From the project root directory
21
+ ./docker/run-benchmarks.sh
22
+ ```
23
+
24
+ This will:
25
+ 1. Build Docker images for Ruby 3.1, 3.2, 3.3, and 3.4 (skipping existing images)
26
+ 2. Run comprehensive benchmarks in each environment
27
+ 3. Merge results from all Ruby versions
28
+ 4. Generate GitHub Pages with comparative results
29
+
30
+ #### Force Rebuild Images
31
+
32
+ To force rebuild all Docker images (even if they already exist):
33
+
34
+ ```bash
35
+ # Force rebuild all images
36
+ ./docker/run-benchmarks.sh --force-rebuild
37
+
38
+ # Or use the short form
39
+ ./docker/run-benchmarks.sh -f
40
+ ```
41
+
42
+ This is useful when:
43
+ - Dependencies have been updated
44
+ - Dockerfile has been modified
45
+ - You want to ensure fresh builds
46
+ - Troubleshooting build-related issues
47
+
48
+ #### Command Line Options
49
+
50
+ ```bash
51
+ # Show help and available options
52
+ ./docker/run-benchmarks.sh --help
53
+
54
+ # Available options:
55
+ # --force-rebuild, -f Force rebuild of Docker images even if they exist
56
+ # --help, -h Show help message
57
+ ```
58
+
59
+ ### Results
60
+
61
+ Results are saved in `docker-results/`:
62
+ ```
63
+ docker-results/
64
+ ├── ruby-3.1/ # Ruby 3.1 results
65
+ ├── ruby-3.2/ # Ruby 3.2 results
66
+ ├── ruby-3.3/ # Ruby 3.3 results
67
+ ├── ruby-3.4/ # Ruby 3.4 results
68
+ ├── merged/ # Merged results from all versions
69
+ └── docs/ # GitHub Pages site
70
+ ```
71
+
72
+ ## Manual Docker Usage
73
+
74
+ ### Build Image for Specific Ruby Version
75
+
76
+ ```bash
77
+ docker build \
78
+ --build-arg RUBY_VERSION=3.3 \
79
+ -t serialbench:ruby-3.3 \
80
+ -f docker/Dockerfile.benchmark \
81
+ .
82
+ ```
83
+
84
+ ### Run Benchmarks
85
+
86
+ ```bash
87
+ # Create results directory
88
+ mkdir -p results
89
+
90
+ # Run benchmarks
91
+ docker run \
92
+ --rm \
93
+ -v $(pwd)/results:/app/results \
94
+ serialbench:ruby-3.3
95
+ ```
96
+
97
+ ### Custom Configuration
98
+
99
+ ```bash
100
+ # Use custom config file
101
+ docker run \
102
+ --rm \
103
+ -v $(pwd)/results:/app/results \
104
+ -v $(pwd)/config:/app/config \
105
+ serialbench:ruby-3.3 \
106
+ bundle exec serialbench benchmark --config config/ci.yml
107
+ ```
108
+
109
+ ## Supported Ruby Versions
110
+
111
+ - Ruby 3.1
112
+ - Ruby 3.2
113
+ - Ruby 3.3
114
+ - Ruby 3.4
115
+
116
+ ## Environment Variables
117
+
118
+ The Docker images support these environment variables:
119
+
120
+ - `BUNDLE_PATH` - Bundle installation path
121
+ - `BUNDLE_BIN` - Bundle binary path
122
+ - `PATH` - System PATH including bundle binaries
123
+
124
+ ## Troubleshooting
125
+
126
+ ### Build Failures
127
+
128
+ Check build logs in `docker-results/build-ruby-X.X.log`:
129
+
130
+ ```bash
131
+ cat docker-results/build-ruby-3.3.log
132
+ ```
133
+
134
+ ### Runtime Failures
135
+
136
+ Check benchmark logs in `docker-results/ruby-X.X/benchmark.log`:
137
+
138
+ ```bash
139
+ cat docker-results/ruby-3.3/benchmark.log
140
+ ```
141
+
142
+ ### Docker Issues
143
+
144
+ Ensure Docker is running:
145
+ ```bash
146
+ docker info
147
+ ```
148
+
149
+ Clean up Docker resources:
150
+ ```bash
151
+ # Remove all serialbench images
152
+ docker rmi $(docker images serialbench -q)
153
+
154
+ # Remove all containers
155
+ docker container prune
156
+ ```
157
+
158
+ ## Customization
159
+
160
+ ### Adding Ruby Versions
161
+
162
+ Edit `RUBY_VERSIONS` array in `run-benchmarks.sh`:
163
+
164
+ ```bash
165
+ RUBY_VERSIONS=("3.1" "3.2" "3.3" "3.4" "head")
166
+ ```
167
+
168
+ ### Custom Benchmark Configuration
169
+
170
+ Create custom config files in `config/` directory and reference them:
171
+
172
+ ```bash
173
+ # In run-benchmarks.sh
174
+ CONFIG_FILE="config/custom.yml"
175
+ ```
176
+
177
+ ### Output Directory
178
+
179
+ Change the output directory:
180
+
181
+ ```bash
182
+ # In run-benchmarks.sh
183
+ OUTPUT_DIR="my-results"
184
+ ```
185
+
186
+ ## Integration with CI/CD
187
+
188
+ The Docker setup integrates with GitHub Actions. See `.github/workflows/benchmark.yml` for automated benchmark runs.
189
+
190
+ ### GitHub Actions Usage
191
+
192
+ ```yaml
193
+ - name: Run Docker Benchmarks
194
+ run: ./docker/run-benchmarks.sh
195
+
196
+ - name: Upload Results
197
+ uses: actions/upload-artifact@v3
198
+ with:
199
+ name: benchmark-results
200
+ path: docker-results/
201
+ ```
202
+
203
+ ## Performance Considerations
204
+
205
+ - Each Ruby version runs in isolation
206
+ - Results are automatically merged for comparison
207
+ - Memory profiling is enabled by default
208
+ - Build caching optimizes subsequent runs
209
+
210
+ ## Security
211
+
212
+ - Containers run with minimal privileges
213
+ - No network access required during benchmarks
214
+ - Results are written to mounted volumes only
@@ -0,0 +1,356 @@
1
+ #!/bin/bash
2
+
3
+ # Serialbench Docker Multi-Ruby Version Benchmark Runner
4
+ # Runs comprehensive benchmarks across multiple Ruby versions using Docker
5
+
6
+ set -e
7
+
8
+ # Configuration
9
+ RUBY_VERSIONS=("3.0" "3.1" "3.2" "3.3" "3.4")
10
+ OUTPUT_DIR="docker-results"
11
+ CONFIG_FILE="config/full.yml"
12
+ DOCKERFILE="docker/Dockerfile.benchmark"
13
+ FORCE_REBUILD=false
14
+
15
+ # Colors for output
16
+ RED='\033[0;31m'
17
+ GREEN='\033[0;32m'
18
+ YELLOW='\033[1;33m'
19
+ BLUE='\033[0;34m'
20
+ NC='\033[0m' # No Color
21
+
22
+ # Helper functions
23
+ log_info() {
24
+ echo -e "${BLUE}[INFO]${NC} $1"
25
+ }
26
+
27
+ log_success() {
28
+ echo -e "${GREEN}[SUCCESS]${NC} $1"
29
+ }
30
+
31
+ log_warning() {
32
+ echo -e "${YELLOW}[WARNING]${NC} $1"
33
+ }
34
+
35
+ log_error() {
36
+ echo -e "${RED}[ERROR]${NC} $1"
37
+ }
38
+
39
+ # Show usage information
40
+ show_usage() {
41
+ echo "Usage: $0 [OPTIONS]"
42
+ echo
43
+ echo "Run comprehensive benchmarks across multiple Ruby versions using Docker"
44
+ echo
45
+ echo "OPTIONS:"
46
+ echo " --force-rebuild, -f Force rebuild of Docker images even if they exist"
47
+ echo " --help, -h Show this help message"
48
+ echo
49
+ echo "EXAMPLES:"
50
+ echo " $0 Run benchmarks (skip building existing images)"
51
+ echo " $0 --force-rebuild Run benchmarks and rebuild all images"
52
+ echo " $0 -f Same as --force-rebuild"
53
+ echo
54
+ }
55
+
56
+ # Parse command line arguments
57
+ parse_arguments() {
58
+ while [[ $# -gt 0 ]]; do
59
+ case $1 in
60
+ --force-rebuild|-f)
61
+ FORCE_REBUILD=true
62
+ log_info "Force rebuild enabled - will rebuild all Docker images"
63
+ shift
64
+ ;;
65
+ --help|-h)
66
+ show_usage
67
+ exit 0
68
+ ;;
69
+ *)
70
+ log_error "Unknown option: $1"
71
+ show_usage
72
+ exit 1
73
+ ;;
74
+ esac
75
+ done
76
+ }
77
+
78
+ # Check if Docker is available
79
+ check_docker() {
80
+ if ! command -v docker &> /dev/null; then
81
+ log_error "Docker is not installed or not in PATH"
82
+ exit 1
83
+ fi
84
+
85
+ if ! docker info &> /dev/null; then
86
+ log_error "Docker daemon is not running"
87
+ exit 1
88
+ fi
89
+
90
+ log_success "Docker is available"
91
+ }
92
+
93
+ # Clean up previous results
94
+ cleanup_results() {
95
+ if [ -d "$OUTPUT_DIR" ]; then
96
+ log_info "Cleaning up previous results in $OUTPUT_DIR"
97
+ rm -rf "$OUTPUT_DIR"
98
+ fi
99
+ mkdir -p "$OUTPUT_DIR"
100
+ }
101
+
102
+ # Build Docker image for specific Ruby version
103
+ build_image() {
104
+ local ruby_version=$1
105
+ local image_name="serialbench:ruby-${ruby_version}"
106
+
107
+ # Check if image already exists (unless force rebuild is enabled)
108
+ if [ "$FORCE_REBUILD" = false ] && docker image inspect "${image_name}" >/dev/null 2>&1; then
109
+ log_success "Image ${image_name} already exists, skipping build"
110
+ return 0
111
+ fi
112
+
113
+ if [ "$FORCE_REBUILD" = true ] && docker image inspect "${image_name}" >/dev/null 2>&1; then
114
+ log_info "Force rebuild enabled, removing existing image ${image_name}..."
115
+ docker rmi "${image_name}" >/dev/null 2>&1 || true
116
+ fi
117
+
118
+ log_info "Building Docker image for Ruby ${ruby_version}..."
119
+
120
+ if docker build \
121
+ --build-arg RUBY_VERSION="${ruby_version}" \
122
+ -t "${image_name}" \
123
+ -f "${DOCKERFILE}" \
124
+ . > "${OUTPUT_DIR}/build-ruby-${ruby_version}.log" 2>&1; then
125
+ log_success "Built image ${image_name}"
126
+ return 0
127
+ else
128
+ log_error "Failed to build image for Ruby ${ruby_version}"
129
+ log_error "Check ${OUTPUT_DIR}/build-ruby-${ruby_version}.log for details"
130
+ return 1
131
+ fi
132
+ }
133
+
134
+ # Run benchmarks for specific Ruby version
135
+ run_benchmark() {
136
+ local ruby_version=$1
137
+ local image_name="serialbench:ruby-${ruby_version}"
138
+ local container_name="serialbench-ruby-${ruby_version}"
139
+ local result_dir="${OUTPUT_DIR}/ruby-${ruby_version}"
140
+
141
+ log_info "Running benchmarks for Ruby ${ruby_version}..."
142
+
143
+ # Create result directory
144
+ mkdir -p "${result_dir}"
145
+
146
+ # Run container with benchmark
147
+ if docker run \
148
+ --name "${container_name}" \
149
+ --rm \
150
+ -v "$(pwd)/${result_dir}:/app/results" \
151
+ "${image_name}" \
152
+ > "${result_dir}/benchmark.log" 2>&1; then
153
+ log_success "Completed benchmarks for Ruby ${ruby_version}"
154
+ return 0
155
+ else
156
+ log_error "Failed to run benchmarks for Ruby ${ruby_version}"
157
+ log_error "Check ${result_dir}/benchmark.log for details"
158
+ return 1
159
+ fi
160
+ }
161
+
162
+ # Merge results from all Ruby versions
163
+ merge_results() {
164
+ log_info "Merging results from all Ruby versions..."
165
+
166
+ local input_dirs=""
167
+ for version in "${RUBY_VERSIONS[@]}"; do
168
+ local result_dir="${OUTPUT_DIR}/ruby-${version}"
169
+ if [ -d "${result_dir}" ] && [ -f "${result_dir}/data/results.json" ]; then
170
+ input_dirs="${input_dirs} ${result_dir}"
171
+ else
172
+ log_warning "No results found for Ruby ${version}"
173
+ fi
174
+ done
175
+
176
+ if [ -n "$input_dirs" ]; then
177
+ if bundle exec serialbench merge_results ${input_dirs} "${OUTPUT_DIR}/merged"; then
178
+ log_success "Results merged successfully"
179
+ else
180
+ log_error "Failed to merge results"
181
+ return 1
182
+ fi
183
+ else
184
+ log_error "No valid results to merge"
185
+ return 1
186
+ fi
187
+ }
188
+
189
+ # Generate GitHub Pages
190
+ generate_github_pages() {
191
+ log_info "Generating GitHub Pages..."
192
+
193
+ local input_dirs=""
194
+ for version in "${RUBY_VERSIONS[@]}"; do
195
+ local result_dir="${OUTPUT_DIR}/ruby-${version}"
196
+ if [ -d "${result_dir}" ] && [ -f "${result_dir}/data/results.json" ]; then
197
+ input_dirs="${input_dirs} ${result_dir}"
198
+ fi
199
+ done
200
+
201
+ if [ -n "$input_dirs" ]; then
202
+ if bundle exec serialbench github_pages ${input_dirs} "${OUTPUT_DIR}/docs"; then
203
+ log_success "GitHub Pages generated successfully"
204
+ log_info "Open ${OUTPUT_DIR}/docs/index.html to view results"
205
+ else
206
+ log_error "Failed to generate GitHub Pages"
207
+ return 1
208
+ fi
209
+ else
210
+ log_error "No valid results for GitHub Pages generation"
211
+ return 1
212
+ fi
213
+ }
214
+
215
+ # Build all Docker images (fail fast)
216
+ build_all_images() {
217
+ local failed_builds=()
218
+
219
+ for version in "${RUBY_VERSIONS[@]}"; do
220
+ if ! build_image "${version}"; then
221
+ failed_builds+=("${version}")
222
+ fi
223
+ done
224
+
225
+ if [ ${#failed_builds[@]} -gt 0 ]; then
226
+ log_error "Failed to build images for Ruby versions: ${failed_builds[*]}"
227
+ log_error "Aborting benchmark run due to build failures"
228
+ exit 1
229
+ fi
230
+
231
+ log_success "All Docker images built successfully"
232
+ }
233
+
234
+ # Run benchmarks on all built images
235
+ run_all_benchmarks() {
236
+ local successful_runs=0
237
+ local failed_runs=()
238
+
239
+ for version in "${RUBY_VERSIONS[@]}"; do
240
+ if run_benchmark "${version}"; then
241
+ ((successful_runs++))
242
+ else
243
+ failed_runs+=("${version}")
244
+ log_warning "Benchmark failed for Ruby ${version}"
245
+ fi
246
+ done
247
+
248
+ log_info "Benchmark runs completed: ${successful_runs}/${#RUBY_VERSIONS[@]} successful"
249
+
250
+ if [ ${#failed_runs[@]} -gt 0 ]; then
251
+ log_warning "Failed benchmark runs for Ruby versions: ${failed_runs[*]}"
252
+ fi
253
+
254
+ # Store results for processing phase
255
+ echo "${successful_runs}" > "${OUTPUT_DIR}/.successful_runs"
256
+ }
257
+
258
+ # Process results (fail if no successful runs)
259
+ process_results() {
260
+ local successful_runs
261
+ if [ -f "${OUTPUT_DIR}/.successful_runs" ]; then
262
+ successful_runs=$(cat "${OUTPUT_DIR}/.successful_runs")
263
+ else
264
+ successful_runs=0
265
+ fi
266
+
267
+ if [ "${successful_runs}" -eq 0 ]; then
268
+ log_error "No successful benchmark runs to process"
269
+ exit 1
270
+ fi
271
+
272
+ log_info "Processing ${successful_runs} successful benchmark results..."
273
+
274
+ if ! merge_results; then
275
+ log_error "Failed to merge results"
276
+ exit 1
277
+ fi
278
+
279
+ if ! generate_github_pages; then
280
+ log_error "Failed to generate GitHub Pages"
281
+ exit 1
282
+ fi
283
+
284
+ log_success "Results processed successfully"
285
+ }
286
+
287
+ # Print summary
288
+ print_summary() {
289
+ echo
290
+ echo "=========================================="
291
+ echo "Serialbench Docker Benchmark Summary"
292
+ echo "=========================================="
293
+ echo
294
+
295
+ for version in "${RUBY_VERSIONS[@]}"; do
296
+ local result_dir="${OUTPUT_DIR}/ruby-${version}"
297
+ if [ -f "${result_dir}/data/results.json" ]; then
298
+ echo "✅ Ruby ${version}: Completed"
299
+ else
300
+ echo "❌ Ruby ${version}: Failed"
301
+ fi
302
+ done
303
+
304
+ echo
305
+ if [ -f "${OUTPUT_DIR}/merged/merged_results.json" ]; then
306
+ echo "📊 Merged results: ${OUTPUT_DIR}/merged/merged_results.json"
307
+ fi
308
+
309
+ if [ -f "${OUTPUT_DIR}/docs/index.html" ]; then
310
+ echo "🌐 GitHub Pages: ${OUTPUT_DIR}/docs/index.html"
311
+ echo
312
+ echo "To view results, open: file://$(pwd)/${OUTPUT_DIR}/docs/index.html"
313
+ fi
314
+
315
+ echo
316
+ }
317
+
318
+ # Main execution
319
+ main() {
320
+ # Parse command line arguments first
321
+ parse_arguments "$@"
322
+
323
+ echo "=========================================="
324
+ echo "Serialbench Docker Multi-Ruby Benchmarks"
325
+ echo "=========================================="
326
+ echo
327
+
328
+ # Check prerequisites
329
+ check_docker
330
+
331
+ # Clean up
332
+ cleanup_results
333
+
334
+ # Phase 1: Build all images (fail fast)
335
+ echo
336
+ log_info "Phase 1: Building all Docker images..."
337
+ build_all_images
338
+
339
+ # Phase 2: Run all benchmarks
340
+ echo
341
+ log_info "Phase 2: Running benchmarks on all images..."
342
+ run_all_benchmarks
343
+
344
+ # Phase 3: Process results (fail if no successful runs)
345
+ echo
346
+ log_info "Phase 3: Processing results..."
347
+ process_results
348
+
349
+ # Print summary
350
+ print_summary
351
+
352
+ log_success "Docker benchmark run completed!"
353
+ }
354
+
355
+ # Run main function
356
+ main "$@"