rails_benchmark_suite 0.2.6 → 0.2.8

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c0ba63e3d45287127a9fe0b288163f0d7bc8e0620a03ef2c9659732a6785e60f
4
- data.tar.gz: 98e7c9a9cb433203ccb4cdaa07435753c7c696ee8dadc2df81d5b2e3b651cf94
3
+ metadata.gz: b4dba673f286e0a526b602537257364dda4b7477eed8698d7f69a0993b3b0ff5
4
+ data.tar.gz: 344f0dd405e3249068746359edff5d9b1578bdf2bb736861f27548283f64d91d
5
5
  SHA512:
6
- metadata.gz: 8c801578bae53257e375fb058ad14015785851bd1def663b1a52c5d271cc243e0af74746e96ffcc007b17f5fdcc5df414d010686e02c35a1816746fff93f23b5
7
- data.tar.gz: 1216ba6595a80999820713962e2e41b01e94ccd662379a3b6c07334c0f2301e1ddd9588bf36f6354f3a958049f2c6ddd95f2280bd18802917d4df974efacdbfe
6
+ metadata.gz: 65ae4cd0975954f2d7ccb3e5b60d25c587eb76d7ea3d3bfc771b1e879c6ccf5b6749b823323506973c500c49c415b2050b12bacdc7b497fc4d3e9791c1ac9943
7
+ data.tar.gz: d1af906dc1e84f78d92b74c27f74156aa8fd25d92016a317d342a084f5657bc72d2eb2f6b6e10a822e46073c71f886a1563e8f52d2ee5f68764b5e68c41a4a35
data/README.md CHANGED
@@ -19,6 +19,12 @@ The Heft Score is a weighted metric representing a machine's ability to handle R
19
19
  | 150+ | 🚀 High Performance | Apple M-series Pro/Max, Ryzen 5000+ |
20
20
  | 300+ | ⚡ Blazing | Server-grade Metal, M3 Ultra |
21
21
 
22
+ ### Quick Start
23
+ ```bash
24
+ ruby --yjit -S bundle exec rails_benchmark_suite
25
+ ```
26
+ **Note:** `bundle exec` is required for Rails environment stability and to prevent Minitest version conflicts.
27
+
22
28
  ## 🛠 Technical Philosophy
23
29
 
24
30
  Rails Benchmark Suite prioritizes **Benchmarking** (via `benchmark-ips`) over **Profiling**.
@@ -28,6 +34,10 @@ Rails Benchmark Suite prioritizes **Benchmarking** (via `benchmark-ips`) over **
28
34
 
29
35
  ## 🚀 Installation & Usage
30
36
 
37
+ ### Requirements
38
+ - **Ruby**: 3.3+ (Ruby with YJIT support highly recommended for accurate performance measurement)
39
+ - **Database**: SQLite3
40
+
31
41
  ### Prerequisites
32
42
  * **Ruby:** 3.4.1+ (Recommended for latest YJIT/Prism performance)
33
43
  * **Database:** SQLite3
@@ -51,17 +61,9 @@ Add to your Gemfile:
51
61
  gem "rails_benchmark_suite", group: :development
52
62
  ```
53
63
 
54
- ## Quick Start
55
-
56
- For the best performance measurement with YJIT enabled:
57
-
58
- ```bash
59
- ruby --yjit -S bundle exec rails_benchmark_suite
60
- ```
61
-
62
64
  ## Usage
63
65
 
64
- To get the most accurate 'Heft' score within a Rails project context, run:
66
+ To get the most accurate 'Heft' score, run with YJIT enabled:
65
67
 
66
68
  ```bash
67
69
  ruby --yjit -S bundle exec rails_benchmark_suite
@@ -88,6 +90,42 @@ ruby --yjit -S bundle exec rails_benchmark_suite --json
88
90
 
89
91
  > **Note:** Use `--skip-rails` to ignore the host application and run in isolated mode.
90
92
 
93
+ ## Performance
94
+
95
+ **Understanding YJIT Status:**
96
+
97
+ If you see `YJIT: Disabled`, this is a result of your Ruby binary build, not the gem itself. The gem will work perfectly fine without YJIT, but performance measurements will be more accurate with YJIT enabled.
98
+
99
+ To enable YJIT, you need Ruby compiled with YJIT support (requires Rust compiler during Ruby installation). See the Troubleshooting section below for installation instructions.
100
+
101
+ ## Troubleshooting
102
+
103
+ ### YJIT Shows "Disabled"
104
+
105
+ If you see `YJIT: Disabled (Requires Ruby with YJIT support for best results)`, it means your Ruby was not compiled with YJIT support. To get the best performance:
106
+
107
+ 1. Ensure `rustc` (Rust compiler) is installed on your system
108
+ 2. Reinstall Ruby with YJIT support:
109
+ ```bash
110
+ # Using rbenv
111
+ RUBY_CONFIGURE_OPTS="--enable-yjit" rbenv install 3.4.1
112
+
113
+ # Using rvm
114
+ rvm install 3.4.1 --enable-yjit
115
+ ```
116
+ 3. Verify YJIT is available: `ruby --yjit -e "puts RubyVM::YJIT.enabled?"`
117
+
118
+ ### SQLite Lock Errors
119
+
120
+ If you encounter `SQLite3::BusyException` or "database table is locked" errors, ensure you're running the latest version of the gem (v0.2.7+) which includes automatic concurrency retries with smart backoff.
121
+
122
+ **v0.2.7+** includes:
123
+ - Automatic retry logic with sleep backoff
124
+ - Per-thread unique identifiers to prevent conflicts
125
+ - Optimized busy timeout settings (10 seconds)
126
+
127
+ If issues persist, try reducing concurrency or ensuring no other processes are accessing the benchmark database.
128
+
91
129
  ## 🏗 Architecture
92
130
  * **Engine:** Built on `benchmark-ips`.
93
131
  * **Database:** Uses In-Memory SQLite with `cache=shared` for multi-threaded accuracy.
@@ -17,17 +17,16 @@ module RailsBenchmarkSuite
17
17
  SETUP_MUTEX = Mutex.new
18
18
 
19
19
  def run
20
- # Hardened Isolation: In-memory Shared Cache URI (v0.2.6)
20
+ # Ultimate Hardening: Massive pool and timeout for zero lock contention (v0.2.8)
21
21
  ActiveRecord::Base.establish_connection(
22
22
  adapter: "sqlite3",
23
23
  database: "file:heft_db?mode=memory&cache=shared",
24
- pool: 20,
25
- timeout: 10000
24
+ pool: 50,
25
+ timeout: 30000
26
26
  )
27
27
 
28
- # Explicit Busy Timeout (Critical for multi-threading)
29
- raw_db = ActiveRecord::Base.connection.raw_connection
30
- raw_db.busy_timeout = 10000
28
+ # The 'Busy Timeout' Hammer - force it directly on the raw connection
29
+ ActiveRecord::Base.connection.raw_connection.busy_timeout = 10000
31
30
 
32
31
  # Setup Schema once safely with Mutex
33
32
  SETUP_MUTEX.synchronize do
@@ -37,9 +36,10 @@ module RailsBenchmarkSuite
37
36
  end
38
37
  end
39
38
 
40
- # High-Performance Concurrency Pragmas
41
- raw_db.execute("PRAGMA journal_mode = WAL")
42
- raw_db.execute("PRAGMA synchronous = OFF")
39
+ # High-Performance Pragmas for WAL + NORMAL sync
40
+ ActiveRecord::Base.connection.raw_connection.execute("PRAGMA journal_mode = WAL")
41
+ ActiveRecord::Base.connection.raw_connection.execute("PRAGMA synchronous = NORMAL")
42
+ ActiveRecord::Base.connection.raw_connection.execute("PRAGMA mmap_size = 268435456") # 256MB - reduce disk I/O
43
43
 
44
44
  puts "Running RailsBenchmarkSuite Benchmarks..." unless @json_output
45
45
  puts system_report unless @json_output
@@ -59,7 +59,7 @@ module RailsBenchmarkSuite
59
59
 
60
60
  # Single Threaded
61
61
  x.report("#{suite[:name]} (1 thread)") do
62
- suite[:block].call
62
+ with_retries { suite[:block].call }
63
63
  end
64
64
 
65
65
  # Multi Threaded (4 threads)
@@ -68,7 +68,7 @@ module RailsBenchmarkSuite
68
68
  Thread.new do
69
69
  # Ensure each thread gets a dedicated connection
70
70
  ActiveRecord::Base.connection_pool.with_connection do
71
- suite[:block].call
71
+ with_retries { suite[:block].call }
72
72
  end
73
73
  end
74
74
  end
@@ -97,10 +97,27 @@ module RailsBenchmarkSuite
97
97
 
98
98
  private
99
99
 
100
+ def with_retries
101
+ yield
102
+ rescue ActiveRecord::StatementInvalid => e
103
+ if e.message =~ /locked/i
104
+ # Specifically drop the lock for THIS connection only
105
+ ActiveRecord::Base.connection.reset!
106
+ sleep(rand(0.01..0.05))
107
+ retry
108
+ else
109
+ raise e
110
+ end
111
+ end
112
+
100
113
  def system_report
101
114
  info = RailsBenchmarkSuite::Reporter.system_info
102
- yjit_status = !!(defined?(RubyVM::YJIT) && RubyVM::YJIT.enabled?)
103
- "System: Ruby #{info[:ruby_version]} (#{info[:platform]}), #{info[:processors]} Cores. YJIT: #{yjit_status ? 'Enabled' : 'Disabled'}. Libvips: #{info[:libvips]}"
115
+ yjit_status = if defined?(RubyVM::YJIT) && RubyVM::YJIT.enabled?
116
+ "Enabled"
117
+ else
118
+ "Disabled (Requires Ruby with YJIT support for best results)"
119
+ end
120
+ "System: Ruby #{info[:ruby_version]} (#{info[:platform]}), #{info[:processors]} Cores. YJIT: #{yjit_status}. Libvips: #{info[:libvips]}"
104
121
  end
105
122
 
106
123
  def print_summary(results)
@@ -7,8 +7,11 @@ RailsBenchmarkSuite.register_suite("Active Record Heft", weight: 0.4) do
7
7
  # Workload: Create User with Posts, Join Query, Update
8
8
  # Use transaction rollback to keep the DB clean and avoid costly destroy callbacks
9
9
  ActiveRecord::Base.transaction do
10
- # 1. Create
11
- user = RailsBenchmarkSuite::Models::User.create!(name: "Speedy Gonzales", email: "speedy@example.com")
10
+ # 1. Create - with unique email per thread
11
+ user = RailsBenchmarkSuite::Models::User.create!(
12
+ name: "Benchmark User",
13
+ email: "test-#{Thread.current.object_id}@example.com"
14
+ )
12
15
 
13
16
  # 2. Create associated records (simulate some weight)
14
17
  10.times do |i|
@@ -24,7 +27,7 @@ RailsBenchmarkSuite.register_suite("Active Record Heft", weight: 0.4) do
24
27
  .to_a
25
28
 
26
29
  # 4. Update
27
- user.update!(name: "Slowpoke Rodriguez")
30
+ user.update!(name: "Updated User")
28
31
 
29
32
  # Rollback everything to leave the DB clean for next iteration
30
33
  raise ActiveRecord::Rollback
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # Check if vips is available at registration time
3
4
  begin
4
5
  require "image_processing/vips"
5
6
  require "fileutils"
@@ -9,6 +10,7 @@ begin
9
10
  FileUtils.mkdir_p(ASSET_DIR)
10
11
  SAMPLE_IMAGE = File.join(ASSET_DIR, "sample.jpg")
11
12
 
13
+ # Only register if vips is actually available
12
14
  RailsBenchmarkSuite.register_suite("Image Heft", weight: 0.1) do
13
15
  # Gracefully handle missing dependencies
14
16
  if File.exist?(SAMPLE_IMAGE)
@@ -22,13 +24,8 @@ begin
22
24
  end
23
25
  end
24
26
 
25
- rescue LoadError, StandardError => e
26
- # Register a skipped suite if Libvips is unavailable
27
- RailsBenchmarkSuite.register_suite("Image Heft (Skipped)", weight: 0.0) do
28
- @warned ||= begin
29
- warn "⚠️ [RailsBenchmarkSuite] ImageHeft skipped: #{e.message}. Install libvips to enable."
30
- true
31
- end
32
- end
27
+ rescue LoadError, StandardError
28
+ # Don't register the suite at all if vips is unavailable
29
+ puts "⚠️ Skipping Image Heft: libvips not available. Install with: brew install vips (macOS)"
33
30
  end
34
31
 
@@ -1,3 +1,3 @@
1
1
  module RailsBenchmarkSuite
2
- VERSION = "0.2.6"
2
+ VERSION = "0.2.8"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_benchmark_suite
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.6
4
+ version: 0.2.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - RailsBenchmarkSuite Contributors