rails_benchmark_suite 0.2.0
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 +7 -0
- data/.gitignore +5 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +25 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +175 -0
- data/LICENSE.txt +21 -0
- data/README.md +77 -0
- data/Rakefile +12 -0
- data/bin/rails_benchmark_suite +49 -0
- data/lib/rails_benchmark_suite/db_setup.rb +20 -0
- data/lib/rails_benchmark_suite/models/post.rb +9 -0
- data/lib/rails_benchmark_suite/models/simulated_job.rb +8 -0
- data/lib/rails_benchmark_suite/models/user.rb +9 -0
- data/lib/rails_benchmark_suite/reporter.rb +26 -0
- data/lib/rails_benchmark_suite/runner.rb +168 -0
- data/lib/rails_benchmark_suite/schema.rb +36 -0
- data/lib/rails_benchmark_suite/suites/active_record_suite.rb +32 -0
- data/lib/rails_benchmark_suite/suites/cache_heft_suite.rb +27 -0
- data/lib/rails_benchmark_suite/suites/image_heft_suite.rb +34 -0
- data/lib/rails_benchmark_suite/suites/job_heft_suite.rb +41 -0
- data/lib/rails_benchmark_suite/suites/view_heft_suite.rb +44 -0
- data/lib/rails_benchmark_suite/version.rb +4 -0
- data/lib/rails_benchmark_suite.rb +30 -0
- data/rails_benchmark_suite.gemspec +41 -0
- metadata +223 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 67247c6ec0477941501c1ab15dcbfabd044faa44e790a55e3cf522013bdced08
|
|
4
|
+
data.tar.gz: bbeab62787dc1a0a2d09dd0069ba3fd963a76de3a15fcdd950c49e0d36a8e388
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: c66eaaedc346d2f66f36412d3032de8ef516cca05a2b36c603e3b449ec3ace814370e5347df5ce59acf0126fb3b10c16e5c91950b6a7e3d3a8f5e326d6b92452
|
|
7
|
+
data.tar.gz: f0cccded74018456e96b160301e59f0beb4bf787146b4f3939d63e999e48a040c256c8bb17bac3e9b7e41c68895b21dd96827cc2cb4ed54408a402b6a6927b53
|
data/.gitignore
ADDED
data/.ruby-version
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.4.1
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [0.2.0] - 2025-12-31
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- **Suite Expansion**: Added 4 new "Omakase" benchmark suites:
|
|
7
|
+
- `ViewHeft`: ActionView ERB rendering performance.
|
|
8
|
+
- `ImageHeft`: ActiveStorage/Libvips image resizing.
|
|
9
|
+
- `CacheHeft`: In-memory key/value throughput (SolidCache simulation).
|
|
10
|
+
- `SearchHeft`: ActiveRecord text search queries.
|
|
11
|
+
- **Reporting**: Added `--json` flag for CI/CD compatible output.
|
|
12
|
+
- **Scoring**: Re-calibrated scoring weights:
|
|
13
|
+
- Active Record: 40%
|
|
14
|
+
- Job Processing: 20%
|
|
15
|
+
- View Rendering: 20%
|
|
16
|
+
- Image Processing: 10%
|
|
17
|
+
- Cache Operations: 10%
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
- **Dependencies**: Added `actionview`, `activestorage`, `image_processing` as runtime dependencies.
|
|
21
|
+
- **Calibration**: Adjusted weights to better reflect "Heft" on modern applications.
|
|
22
|
+
|
|
23
|
+
## [0.1.0] - 2025-12-29
|
|
24
|
+
- Initial Release ("Rails Awareness" update).
|
|
25
|
+
- CLI auto-detects Rails environment.
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
rails_benchmark_suite (0.2.0)
|
|
5
|
+
actionview
|
|
6
|
+
activerecord
|
|
7
|
+
activestorage
|
|
8
|
+
benchmark-ips
|
|
9
|
+
concurrent-ruby
|
|
10
|
+
get_process_mem
|
|
11
|
+
image_processing
|
|
12
|
+
sqlite3
|
|
13
|
+
|
|
14
|
+
GEM
|
|
15
|
+
remote: https://rubygems.org/
|
|
16
|
+
specs:
|
|
17
|
+
actionpack (8.1.1)
|
|
18
|
+
actionview (= 8.1.1)
|
|
19
|
+
activesupport (= 8.1.1)
|
|
20
|
+
nokogiri (>= 1.8.5)
|
|
21
|
+
rack (>= 2.2.4)
|
|
22
|
+
rack-session (>= 1.0.1)
|
|
23
|
+
rack-test (>= 0.6.3)
|
|
24
|
+
rails-dom-testing (~> 2.2)
|
|
25
|
+
rails-html-sanitizer (~> 1.6)
|
|
26
|
+
useragent (~> 0.16)
|
|
27
|
+
actionview (8.1.1)
|
|
28
|
+
activesupport (= 8.1.1)
|
|
29
|
+
builder (~> 3.1)
|
|
30
|
+
erubi (~> 1.11)
|
|
31
|
+
rails-dom-testing (~> 2.2)
|
|
32
|
+
rails-html-sanitizer (~> 1.6)
|
|
33
|
+
activejob (8.1.1)
|
|
34
|
+
activesupport (= 8.1.1)
|
|
35
|
+
globalid (>= 0.3.6)
|
|
36
|
+
activemodel (8.1.1)
|
|
37
|
+
activesupport (= 8.1.1)
|
|
38
|
+
activerecord (8.1.1)
|
|
39
|
+
activemodel (= 8.1.1)
|
|
40
|
+
activesupport (= 8.1.1)
|
|
41
|
+
timeout (>= 0.4.0)
|
|
42
|
+
activestorage (8.1.1)
|
|
43
|
+
actionpack (= 8.1.1)
|
|
44
|
+
activejob (= 8.1.1)
|
|
45
|
+
activerecord (= 8.1.1)
|
|
46
|
+
activesupport (= 8.1.1)
|
|
47
|
+
marcel (~> 1.0)
|
|
48
|
+
activesupport (8.1.1)
|
|
49
|
+
base64
|
|
50
|
+
bigdecimal
|
|
51
|
+
concurrent-ruby (~> 1.0, >= 1.3.1)
|
|
52
|
+
connection_pool (>= 2.2.5)
|
|
53
|
+
drb
|
|
54
|
+
i18n (>= 1.6, < 2)
|
|
55
|
+
json
|
|
56
|
+
logger (>= 1.4.2)
|
|
57
|
+
minitest (>= 5.1)
|
|
58
|
+
securerandom (>= 0.3)
|
|
59
|
+
tzinfo (~> 2.0, >= 2.0.5)
|
|
60
|
+
uri (>= 0.13.1)
|
|
61
|
+
base64 (0.3.0)
|
|
62
|
+
benchmark-ips (2.14.0)
|
|
63
|
+
bigdecimal (4.0.1)
|
|
64
|
+
builder (3.3.0)
|
|
65
|
+
concurrent-ruby (1.3.6)
|
|
66
|
+
connection_pool (3.0.2)
|
|
67
|
+
crass (1.0.6)
|
|
68
|
+
drb (2.2.3)
|
|
69
|
+
erubi (1.13.1)
|
|
70
|
+
ffi (1.17.3-aarch64-linux-gnu)
|
|
71
|
+
ffi (1.17.3-aarch64-linux-musl)
|
|
72
|
+
ffi (1.17.3-arm-linux-gnu)
|
|
73
|
+
ffi (1.17.3-arm-linux-musl)
|
|
74
|
+
ffi (1.17.3-arm64-darwin)
|
|
75
|
+
ffi (1.17.3-x86-linux-gnu)
|
|
76
|
+
ffi (1.17.3-x86-linux-musl)
|
|
77
|
+
ffi (1.17.3-x86_64-darwin)
|
|
78
|
+
ffi (1.17.3-x86_64-linux-gnu)
|
|
79
|
+
ffi (1.17.3-x86_64-linux-musl)
|
|
80
|
+
get_process_mem (1.0.0)
|
|
81
|
+
bigdecimal (>= 2.0)
|
|
82
|
+
ffi (~> 1.0)
|
|
83
|
+
globalid (1.3.0)
|
|
84
|
+
activesupport (>= 6.1)
|
|
85
|
+
i18n (1.14.8)
|
|
86
|
+
concurrent-ruby (~> 1.0)
|
|
87
|
+
image_processing (1.14.0)
|
|
88
|
+
mini_magick (>= 4.9.5, < 6)
|
|
89
|
+
ruby-vips (>= 2.0.17, < 3)
|
|
90
|
+
json (2.18.0)
|
|
91
|
+
logger (1.7.0)
|
|
92
|
+
loofah (2.25.0)
|
|
93
|
+
crass (~> 1.0.2)
|
|
94
|
+
nokogiri (>= 1.12.0)
|
|
95
|
+
marcel (1.1.0)
|
|
96
|
+
mini_magick (5.3.1)
|
|
97
|
+
logger
|
|
98
|
+
mini_portile2 (2.8.9)
|
|
99
|
+
minitest (6.0.1)
|
|
100
|
+
prism (~> 1.5)
|
|
101
|
+
nokogiri (1.19.0)
|
|
102
|
+
mini_portile2 (~> 2.8.2)
|
|
103
|
+
racc (~> 1.4)
|
|
104
|
+
nokogiri (1.19.0-aarch64-linux-gnu)
|
|
105
|
+
racc (~> 1.4)
|
|
106
|
+
nokogiri (1.19.0-aarch64-linux-musl)
|
|
107
|
+
racc (~> 1.4)
|
|
108
|
+
nokogiri (1.19.0-arm-linux-gnu)
|
|
109
|
+
racc (~> 1.4)
|
|
110
|
+
nokogiri (1.19.0-arm-linux-musl)
|
|
111
|
+
racc (~> 1.4)
|
|
112
|
+
nokogiri (1.19.0-arm64-darwin)
|
|
113
|
+
racc (~> 1.4)
|
|
114
|
+
nokogiri (1.19.0-x86_64-darwin)
|
|
115
|
+
racc (~> 1.4)
|
|
116
|
+
nokogiri (1.19.0-x86_64-linux-gnu)
|
|
117
|
+
racc (~> 1.4)
|
|
118
|
+
nokogiri (1.19.0-x86_64-linux-musl)
|
|
119
|
+
racc (~> 1.4)
|
|
120
|
+
prism (1.7.0)
|
|
121
|
+
racc (1.8.1)
|
|
122
|
+
rack (3.2.4)
|
|
123
|
+
rack-session (2.1.1)
|
|
124
|
+
base64 (>= 0.1.0)
|
|
125
|
+
rack (>= 3.0.0)
|
|
126
|
+
rack-test (2.2.0)
|
|
127
|
+
rack (>= 1.3)
|
|
128
|
+
rails-dom-testing (2.3.0)
|
|
129
|
+
activesupport (>= 5.0.0)
|
|
130
|
+
minitest
|
|
131
|
+
nokogiri (>= 1.6)
|
|
132
|
+
rails-html-sanitizer (1.6.2)
|
|
133
|
+
loofah (~> 2.21)
|
|
134
|
+
nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
|
|
135
|
+
rake (13.3.1)
|
|
136
|
+
ruby-vips (2.3.0)
|
|
137
|
+
ffi (~> 1.12)
|
|
138
|
+
logger
|
|
139
|
+
securerandom (0.4.1)
|
|
140
|
+
sqlite3 (2.9.0-aarch64-linux-gnu)
|
|
141
|
+
sqlite3 (2.9.0-aarch64-linux-musl)
|
|
142
|
+
sqlite3 (2.9.0-arm-linux-gnu)
|
|
143
|
+
sqlite3 (2.9.0-arm-linux-musl)
|
|
144
|
+
sqlite3 (2.9.0-arm64-darwin)
|
|
145
|
+
sqlite3 (2.9.0-x86-linux-gnu)
|
|
146
|
+
sqlite3 (2.9.0-x86-linux-musl)
|
|
147
|
+
sqlite3 (2.9.0-x86_64-darwin)
|
|
148
|
+
sqlite3 (2.9.0-x86_64-linux-gnu)
|
|
149
|
+
sqlite3 (2.9.0-x86_64-linux-musl)
|
|
150
|
+
timeout (0.6.0)
|
|
151
|
+
tzinfo (2.0.6)
|
|
152
|
+
concurrent-ruby (~> 1.0)
|
|
153
|
+
uri (1.1.1)
|
|
154
|
+
useragent (0.16.11)
|
|
155
|
+
|
|
156
|
+
PLATFORMS
|
|
157
|
+
aarch64-linux-gnu
|
|
158
|
+
aarch64-linux-musl
|
|
159
|
+
arm-linux-gnu
|
|
160
|
+
arm-linux-musl
|
|
161
|
+
arm64-darwin
|
|
162
|
+
x86-linux-gnu
|
|
163
|
+
x86-linux-musl
|
|
164
|
+
x86_64-darwin
|
|
165
|
+
x86_64-linux-gnu
|
|
166
|
+
x86_64-linux-musl
|
|
167
|
+
|
|
168
|
+
DEPENDENCIES
|
|
169
|
+
bundler
|
|
170
|
+
minitest
|
|
171
|
+
rails_benchmark_suite!
|
|
172
|
+
rake
|
|
173
|
+
|
|
174
|
+
BUNDLED WITH
|
|
175
|
+
2.5.9
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 overnet
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Rails Benchmark Suite
|
|
2
|
+
|
|
3
|
+
A standardized performance suite designed to measure the "Heft" of a machine using realistic, high-throughput Rails 8+ workloads.
|
|
4
|
+
|
|
5
|
+
Unlike synthetic CPU benchmarks, **Rails Benchmark Suite** simulates Active Record object allocation, SQL query complexity, ActionView rendering, and background job throughput.
|
|
6
|
+
|
|
7
|
+
## 📊 The "Heft" Score
|
|
8
|
+
|
|
9
|
+
The Heft Score is a weighted metric representing a machine's ability to handle Rails tasks.
|
|
10
|
+
- **Baseline:** A score of **100** is calibrated to represent an **AWS c6g.large** (ARM) instance.
|
|
11
|
+
- **Objective:** To provide a simple, comparable number for evaluating different computing platforms (Cloud VMs, bare-metal, or local dev rigs).
|
|
12
|
+
|
|
13
|
+
### Baseline Comparisons
|
|
14
|
+
| Score | Classification | Comparable Hardware |
|
|
15
|
+
| :--- | :--- | :--- |
|
|
16
|
+
| < 40 | 🐢 Sluggish | Older Intel Macs, Entry-level VPS |
|
|
17
|
+
| 60 | 🚙 Capable | Standard Cloud VM (c5.large/standard) |
|
|
18
|
+
| **100** | **🏎️ Baseline** | **AWS c6g.large (2 vCPU ARM)** |
|
|
19
|
+
| 150+ | 🚀 High Performance | Apple M-series Pro/Max, Ryzen 5000+ |
|
|
20
|
+
| 300+ | ⚡ Blazing | Server-grade Metal, M3 Ultra |
|
|
21
|
+
|
|
22
|
+
## 🛠 Technical Philosophy
|
|
23
|
+
|
|
24
|
+
Rails Benchmark Suite prioritizes **Benchmarking** (via `benchmark-ips`) over **Profiling**.
|
|
25
|
+
|
|
26
|
+
* **Benchmarking:** Focuses on macro-throughput—"How many iterations can the hardware handle?" This provides the final Heft Score.
|
|
27
|
+
* **Why no Profiling?** Profiling tools (like `StackProf` or `Vernier`) introduce instrumentation overhead that skews hardware metrics. We aim for "Conceptual Compression"—one clear number to inform infrastructure decisions.
|
|
28
|
+
|
|
29
|
+
## 🚀 Installation & Usage
|
|
30
|
+
|
|
31
|
+
### Prerequisites
|
|
32
|
+
* **Ruby:** 3.4.1+ (Recommended for latest YJIT/Prism performance)
|
|
33
|
+
* **Database:** SQLite3
|
|
34
|
+
|
|
35
|
+
### Standalone Usage
|
|
36
|
+
If you want to test hardware performance without an existing application:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
git clone https://github.com/overnet/rails_benchmark_suite.git
|
|
40
|
+
cd rails_benchmark_suite
|
|
41
|
+
bundle install
|
|
42
|
+
bin/rails_benchmark_suite
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Use within a Rails Application
|
|
46
|
+
Rails Benchmark Suite is "Rails-aware." Adding it to your app allows you to benchmark your specific configuration and custom suites.
|
|
47
|
+
|
|
48
|
+
Add to your Gemfile:
|
|
49
|
+
|
|
50
|
+
```ruby
|
|
51
|
+
gem "rails_benchmark_suite", group: :development
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Run via bundle:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
bundle exec rails_benchmark_suite
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
> **Note:** Use `--skip-rails` to ignore the host application and run in isolated mode.
|
|
61
|
+
|
|
62
|
+
## 🏗 Architecture
|
|
63
|
+
* **Engine:** Built on `benchmark-ips`.
|
|
64
|
+
* **Database:** Uses In-Memory SQLite with `cache=shared` for multi-threaded accuracy.
|
|
65
|
+
* **Isolation:** Uses transactional rollbacks (`ActiveRecord::Rollback`) to ensure test isolation without the overhead of row deletion.
|
|
66
|
+
* **Threading:** Supports 1-thread and 4-thread scaling tests to measure vertical efficiency.
|
|
67
|
+
* **Modern Stack:** Optimized for Rails 8+ defaults, including Solid Queue simulation and YJIT detection.
|
|
68
|
+
|
|
69
|
+
## 📜 Credits
|
|
70
|
+
This project is a functional implementation of the performance benchmark vision discussed in the Rails community.
|
|
71
|
+
|
|
72
|
+
* **Vision:** Inspired by @dhh in [rails/rails#50451](https://github.com/rails/rails/issues/50451).
|
|
73
|
+
* **Initial Roadmap:** Based on suggestions by @JoeDupuis.
|
|
74
|
+
* **Implementation:** The Rails Community.
|
|
75
|
+
|
|
76
|
+
## 📄 License
|
|
77
|
+
The gem is available as open source under the terms of the MIT License.
|
data/Rakefile
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "optparse"
|
|
5
|
+
$LOAD_PATH.unshift File.expand_path("../lib", __dir__)
|
|
6
|
+
require "rails_benchmark_suite"
|
|
7
|
+
require "rails_benchmark_suite/version"
|
|
8
|
+
|
|
9
|
+
options = {}
|
|
10
|
+
OptionParser.new do |opts|
|
|
11
|
+
opts.banner = "Usage: rails_benchmark_suite [options]"
|
|
12
|
+
|
|
13
|
+
opts.on("-v", "--version", "Print version") do
|
|
14
|
+
puts "RailsBenchmarkSuite v#{RailsBenchmarkSuite::VERSION}"
|
|
15
|
+
exit 0
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
opts.on("--skip-rails", "Skip Rails environment loading") do
|
|
19
|
+
options[:skip_rails] = true
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
opts.on("-j", "--json", "Output results as JSON") do
|
|
23
|
+
options[:json] = true
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
opts.on("-h", "--help", "Prints this help") do
|
|
27
|
+
puts opts
|
|
28
|
+
exit 0
|
|
29
|
+
end
|
|
30
|
+
end.parse!
|
|
31
|
+
|
|
32
|
+
puts "RailsBenchmarkSuite v#{RailsBenchmarkSuite::VERSION}"
|
|
33
|
+
|
|
34
|
+
# Rails Detection
|
|
35
|
+
rails_env_path = File.join(Dir.pwd, "config", "environment.rb")
|
|
36
|
+
|
|
37
|
+
if !options[:skip_rails] && File.exist?(rails_env_path)
|
|
38
|
+
puts "Rails environment detected at #{rails_env_path}. Loading..."
|
|
39
|
+
require rails_env_path
|
|
40
|
+
puts "Rails loaded successfully."
|
|
41
|
+
else
|
|
42
|
+
if options[:skip_rails]
|
|
43
|
+
puts "Skipping Rails loading (requested via --skip-rails)."
|
|
44
|
+
else
|
|
45
|
+
puts "No Rails environment detected (config/environment.rb not found)."
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
RailsBenchmarkSuite.run(json: options[:json])
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_record"
|
|
4
|
+
require "sqlite3"
|
|
5
|
+
|
|
6
|
+
# Silence ActiveRecord logs during benchmarks to avoid IO bottlenecks
|
|
7
|
+
ActiveRecord::Base.logger = nil
|
|
8
|
+
|
|
9
|
+
# Setup In-Memory SQLite globally for all suites
|
|
10
|
+
# storage_config = ActiveRecord::DatabaseConfigurations::HashConfig.new("test", "sqlite3", { adapter: "sqlite3", database: ":memory:" })
|
|
11
|
+
# Use shared cache to allow threads to see the same in-memory database
|
|
12
|
+
# Skip internal database setup if running within a Rails application
|
|
13
|
+
unless defined?(Rails)
|
|
14
|
+
ActiveRecord::Base.establish_connection(
|
|
15
|
+
adapter: "sqlite3",
|
|
16
|
+
database: "file:rails_benchmark_suite_mem?mode=memory&cache=shared",
|
|
17
|
+
pool: 20,
|
|
18
|
+
timeout: 10000
|
|
19
|
+
)
|
|
20
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RailsBenchmarkSuite
|
|
4
|
+
module Reporter
|
|
5
|
+
module_function
|
|
6
|
+
|
|
7
|
+
def system_info
|
|
8
|
+
{
|
|
9
|
+
ruby_version: RUBY_VERSION,
|
|
10
|
+
platform: RUBY_PLATFORM,
|
|
11
|
+
processors: Concurrent.processor_count,
|
|
12
|
+
libvips: libvips?,
|
|
13
|
+
yjit: yjit_enabled?
|
|
14
|
+
}
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def yjit_enabled?
|
|
18
|
+
defined?(RubyVM::YJIT) && RubyVM::YJIT.enabled?
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def libvips?
|
|
22
|
+
# Naive check for libvips presence
|
|
23
|
+
system("vips --version", out: File::NULL, err: File::NULL)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "benchmark/ips"
|
|
4
|
+
require "get_process_mem"
|
|
5
|
+
|
|
6
|
+
module RailsBenchmarkSuite
|
|
7
|
+
class Runner
|
|
8
|
+
def initialize(suites, json: false)
|
|
9
|
+
@suites = suites
|
|
10
|
+
@json_output = json
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def register(name, &block)
|
|
14
|
+
@suites << { name: name, block: block }
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def run
|
|
18
|
+
puts "Running RailsBenchmarkSuite Benchmarks..." unless @json_output
|
|
19
|
+
puts system_report unless @json_output
|
|
20
|
+
puts "\n" unless @json_output
|
|
21
|
+
|
|
22
|
+
results = {}
|
|
23
|
+
|
|
24
|
+
@suites.each do |suite|
|
|
25
|
+
puts "== Running Suite: #{suite[:name]} ==" unless @json_output
|
|
26
|
+
|
|
27
|
+
# Capture memory before
|
|
28
|
+
mem_before = GetProcessMem.new.mb
|
|
29
|
+
|
|
30
|
+
# Run benchmark
|
|
31
|
+
report = Benchmark.ips do |x|
|
|
32
|
+
x.config(:time => 5, :warmup => 2)
|
|
33
|
+
|
|
34
|
+
# Single Threaded
|
|
35
|
+
x.report("#{suite[:name]} (1 thread)") do
|
|
36
|
+
suite[:block].call
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Multi Threaded (4 threads)
|
|
40
|
+
x.report("#{suite[:name]} (4 threads)") do
|
|
41
|
+
threads = 4.times.map do
|
|
42
|
+
Thread.new do
|
|
43
|
+
# Ensure each thread gets a dedicated connection
|
|
44
|
+
ActiveRecord::Base.connection_pool.with_connection do
|
|
45
|
+
suite[:block].call
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
threads.each(&:join)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
x.compare!
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Capture memory after
|
|
56
|
+
mem_after = GetProcessMem.new.mb
|
|
57
|
+
|
|
58
|
+
results[suite[:name]] = {
|
|
59
|
+
report: report,
|
|
60
|
+
memory_delta_mb: mem_after - mem_before,
|
|
61
|
+
weight: suite[:weight]
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
puts "Memory Footprint: #{mem_after.round(2)} MB (+#{(mem_after - mem_before).round(2)} MB)" unless @json_output
|
|
65
|
+
puts "\n" unless @json_output
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
print_summary(results)
|
|
69
|
+
results
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
private
|
|
73
|
+
|
|
74
|
+
def system_report
|
|
75
|
+
info = RailsBenchmarkSuite::Reporter.system_info
|
|
76
|
+
"System: Ruby #{info[:ruby_version]} (#{info[:platform]}), #{info[:processors]} Cores. YJIT: #{info[:yjit] ? 'Enabled' : 'Disabled'}. Libvips: #{info[:libvips]}"
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def print_summary(results)
|
|
80
|
+
if @json_output
|
|
81
|
+
print_json(results)
|
|
82
|
+
return
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
puts "\n"
|
|
86
|
+
puts "=========================================================================================="
|
|
87
|
+
puts "| %-25s | %-25s | %-12s | %-15s |" % ["Suite", "IPS (1t / 4t)", "Scaling", "Mem Delta"]
|
|
88
|
+
puts "=========================================================================================="
|
|
89
|
+
|
|
90
|
+
total_score = 0
|
|
91
|
+
|
|
92
|
+
results.each do |name, data|
|
|
93
|
+
report = data[:report]
|
|
94
|
+
entries = report.entries
|
|
95
|
+
|
|
96
|
+
entry_1t = entries.find { |e| e.label.include?("(1 thread)") }
|
|
97
|
+
entry_4t = entries.find { |e| e.label.include?("(4 threads)") }
|
|
98
|
+
|
|
99
|
+
ips_1t = entry_1t ? entry_1t.ips : 0
|
|
100
|
+
ips_4t = entry_4t ? entry_4t.ips : 0
|
|
101
|
+
|
|
102
|
+
scaling = ips_1t > 0 ? (ips_4t / ips_1t) : 0
|
|
103
|
+
mem = data[:memory_delta_mb]
|
|
104
|
+
|
|
105
|
+
# Heft Score: Weighted Sum of 4t IPS
|
|
106
|
+
weight = data[:weight] || 1.0
|
|
107
|
+
weighted_score = ips_4t * weight
|
|
108
|
+
total_score += weighted_score
|
|
109
|
+
|
|
110
|
+
puts "| %-25s | %-25s | x%-11.2f | +%-14.2fMB |" % [
|
|
111
|
+
name + " (w: #{weight})",
|
|
112
|
+
"#{humanize(ips_1t)} / #{humanize(ips_4t)}",
|
|
113
|
+
scaling,
|
|
114
|
+
mem
|
|
115
|
+
]
|
|
116
|
+
end
|
|
117
|
+
puts "=========================================================================================="
|
|
118
|
+
puts "\n"
|
|
119
|
+
puts " >>> FINAL HEFT SCORE: #{total_score.round(0)} <<<"
|
|
120
|
+
puts "\n"
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def print_json(results)
|
|
124
|
+
require "json"
|
|
125
|
+
|
|
126
|
+
out = {
|
|
127
|
+
system: RailsBenchmarkSuite::Reporter.system_info,
|
|
128
|
+
total_score: 0,
|
|
129
|
+
suites: []
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
total_score = 0
|
|
133
|
+
|
|
134
|
+
results.each do |name, data|
|
|
135
|
+
weight = data[:weight] || 1.0
|
|
136
|
+
|
|
137
|
+
# Parse reports
|
|
138
|
+
ips_1t = data[:report].entries.find { |e| e.label.include?("(1 thread)") }&.ips || 0
|
|
139
|
+
ips_4t = data[:report].entries.find { |e| e.label.include?("(4 threads)") }&.ips || 0
|
|
140
|
+
|
|
141
|
+
weighted_score = ips_4t * weight
|
|
142
|
+
total_score += weighted_score
|
|
143
|
+
|
|
144
|
+
out[:suites] << {
|
|
145
|
+
name: name,
|
|
146
|
+
weight: weight,
|
|
147
|
+
ips_1t: ips_1t,
|
|
148
|
+
ips_4t: ips_4t,
|
|
149
|
+
scaling: ips_1t > 0 ? (ips_4t / ips_1t) : 0,
|
|
150
|
+
memory_delta_mb: data[:memory_delta_mb],
|
|
151
|
+
score: weighted_score
|
|
152
|
+
}
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
out[:total_score] = total_score.round(0)
|
|
156
|
+
puts out.to_json
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def humanize(ips)
|
|
160
|
+
return "0" if ips.nil?
|
|
161
|
+
if ips > 1000
|
|
162
|
+
"%.1fk" % (ips / 1000.0)
|
|
163
|
+
else
|
|
164
|
+
"%.1f" % ips
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_record"
|
|
4
|
+
|
|
5
|
+
module RailsBenchmarkSuite
|
|
6
|
+
module Schema
|
|
7
|
+
def self.load
|
|
8
|
+
ActiveRecord::Schema.define do
|
|
9
|
+
# Users
|
|
10
|
+
create_table :users, force: true do |t|
|
|
11
|
+
t.string :name
|
|
12
|
+
t.string :email
|
|
13
|
+
t.timestamps
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Posts
|
|
17
|
+
create_table :posts, force: true do |t|
|
|
18
|
+
t.references :user
|
|
19
|
+
t.string :title
|
|
20
|
+
t.text :body
|
|
21
|
+
t.integer :views, default: 0
|
|
22
|
+
t.timestamps
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Simulated Jobs (for Job Heft)
|
|
26
|
+
create_table :simulated_jobs, force: true do |t|
|
|
27
|
+
t.string :queue_name
|
|
28
|
+
t.text :arguments
|
|
29
|
+
t.datetime :scheduled_at
|
|
30
|
+
t.timestamps
|
|
31
|
+
end
|
|
32
|
+
add_index :simulated_jobs, [:queue_name, :scheduled_at]
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_record"
|
|
4
|
+
|
|
5
|
+
# Benchmark Suite
|
|
6
|
+
RailsBenchmarkSuite.register_suite("Active Record Heft", weight: 0.4) do
|
|
7
|
+
# Workload: Create User with Posts, Join Query, Update
|
|
8
|
+
# Use transaction rollback to keep the DB clean and avoid costly destroy callbacks
|
|
9
|
+
ActiveRecord::Base.transaction do
|
|
10
|
+
# 1. Create
|
|
11
|
+
user = RailsBenchmarkSuite::Models::User.create!(name: "Speedy Gonzales", email: "speedy@example.com")
|
|
12
|
+
|
|
13
|
+
# 2. Create associated records (simulate some weight)
|
|
14
|
+
10.times do |i|
|
|
15
|
+
user.posts.create!(title: "Post #{i}", body: "Content " * 50)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# 3. Complex Query (Join + Order)
|
|
19
|
+
# Unloading the relation to force execution
|
|
20
|
+
RailsBenchmarkSuite::Models::User.joins(:posts)
|
|
21
|
+
.where(users: { id: user.id })
|
|
22
|
+
.where("posts.views >= ?", 0)
|
|
23
|
+
.order("posts.created_at DESC")
|
|
24
|
+
.to_a
|
|
25
|
+
|
|
26
|
+
# 4. Update
|
|
27
|
+
user.update!(name: "Slowpoke Rodriguez")
|
|
28
|
+
|
|
29
|
+
# Rollback everything to leave the DB clean for next iteration
|
|
30
|
+
raise ActiveRecord::Rollback
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_support/cache"
|
|
4
|
+
require "securerandom"
|
|
5
|
+
|
|
6
|
+
# Benchmark Suite
|
|
7
|
+
RailsBenchmarkSuite.register_suite("Cache Heft", weight: 0.1) do
|
|
8
|
+
# Simulate SolidCache using MemoryStore
|
|
9
|
+
@cache ||= ActiveSupport::Cache::MemoryStore.new
|
|
10
|
+
|
|
11
|
+
# Workload: Measure serialization and storage throughput
|
|
12
|
+
key_prefix = "cache_test_#{SecureRandom.hex(4)}"
|
|
13
|
+
|
|
14
|
+
# 1. Bulk Write
|
|
15
|
+
1000.times do |i|
|
|
16
|
+
@cache.write("#{key_prefix}/#{i}", { data: "Precious Data " * 20, index: i })
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# 2. Bulk Read
|
|
20
|
+
1000.times do |i|
|
|
21
|
+
val = @cache.read("#{key_prefix}/#{i}")
|
|
22
|
+
next if val.nil?
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# 3. Clean up
|
|
26
|
+
@cache.clear
|
|
27
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
begin
|
|
4
|
+
require "image_processing/vips"
|
|
5
|
+
require "fileutils"
|
|
6
|
+
|
|
7
|
+
# Ensure asset directory exists
|
|
8
|
+
ASSET_DIR = File.expand_path("../../assets", __dir__)
|
|
9
|
+
FileUtils.mkdir_p(ASSET_DIR)
|
|
10
|
+
SAMPLE_IMAGE = File.join(ASSET_DIR, "sample.jpg")
|
|
11
|
+
|
|
12
|
+
RailsBenchmarkSuite.register_suite("Image Heft", weight: 0.1) do
|
|
13
|
+
# Gracefully handle missing dependencies
|
|
14
|
+
if File.exist?(SAMPLE_IMAGE)
|
|
15
|
+
ImageProcessing::Vips
|
|
16
|
+
.source(SAMPLE_IMAGE)
|
|
17
|
+
.resize_to_limit(800, 800)
|
|
18
|
+
.call
|
|
19
|
+
else
|
|
20
|
+
# Maintain benchmark stability if asset is missing
|
|
21
|
+
true
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
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
|
|
33
|
+
end
|
|
34
|
+
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_record"
|
|
4
|
+
require "json"
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
RailsBenchmarkSuite.register_suite("Solid Queue Heft", weight: 0.2) do
|
|
8
|
+
# Simulation: Enqueue 100 jobs, then work them off
|
|
9
|
+
|
|
10
|
+
# 1. Enqueue Loop
|
|
11
|
+
100.times do |i|
|
|
12
|
+
RailsBenchmarkSuite::Models::SimulatedJob.create!(
|
|
13
|
+
queue_name: "default",
|
|
14
|
+
arguments: { job_id: i, payload: "x" * 100 }.to_json,
|
|
15
|
+
scheduled_at: Time.now
|
|
16
|
+
)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# 2. Worker Loop (Drain the queue)
|
|
20
|
+
loop do
|
|
21
|
+
processed = false
|
|
22
|
+
|
|
23
|
+
# Transactional polling
|
|
24
|
+
ActiveRecord::Base.transaction do
|
|
25
|
+
# Fetch batch
|
|
26
|
+
jobs = RailsBenchmarkSuite::Models::SimulatedJob.where("scheduled_at <= ?", Time.now).order(:created_at).limit(10)
|
|
27
|
+
|
|
28
|
+
if jobs.any?
|
|
29
|
+
# Simulate processing time and delete
|
|
30
|
+
ids = jobs.map(&:id)
|
|
31
|
+
RailsBenchmarkSuite::Models::SimulatedJob.where(id: ids).delete_all
|
|
32
|
+
processed = true
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
break unless processed
|
|
37
|
+
|
|
38
|
+
# Simulate worker internal latency
|
|
39
|
+
sleep(0.001)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "action_view"
|
|
4
|
+
require "ostruct"
|
|
5
|
+
|
|
6
|
+
# Benchmark Suite
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# Helper for the suite
|
|
10
|
+
module RailsBenchmarkSuiteNumberHelper
|
|
11
|
+
def self.number_with_delimiter(number)
|
|
12
|
+
number.to_s.gsub(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1,")
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
RailsBenchmarkSuite.register_suite("View Heft", weight: 0.2) do
|
|
17
|
+
# Setup context once
|
|
18
|
+
@view_renderer ||= begin
|
|
19
|
+
lookup_context = ActionView::LookupContext.new([File.expand_path(__dir__)])
|
|
20
|
+
ActionView::Base.with_empty_template_cache.new(lookup_context, {}, nil)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Workload: Render a complex ERB template
|
|
24
|
+
template = <<~ERB
|
|
25
|
+
<h1>Dashboard for <%= user.name %></h1>
|
|
26
|
+
<ul>
|
|
27
|
+
<% posts.each do |post| %>
|
|
28
|
+
<li>
|
|
29
|
+
<strong><%= post.title %></strong>
|
|
30
|
+
<p><%= post.body.truncate(50) %></p>
|
|
31
|
+
<small>Views: <%= RailsBenchmarkSuiteNumberHelper.number_with_delimiter(post.views) %></small>
|
|
32
|
+
</li>
|
|
33
|
+
<% end %>
|
|
34
|
+
</ul>
|
|
35
|
+
<footer>Generated at <%= Time.now.to_s %></footer>
|
|
36
|
+
ERB
|
|
37
|
+
|
|
38
|
+
# Dummy Objects
|
|
39
|
+
user = OpenStruct.new(name: "Speedy")
|
|
40
|
+
posts = 100.times.map { |i| OpenStruct.new(title: "Post #{i}", body: "Content " * 10, views: i * 1000) }
|
|
41
|
+
|
|
42
|
+
# Execution
|
|
43
|
+
@view_renderer.render(inline: template, locals: { user: user, posts: posts })
|
|
44
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "concurrent"
|
|
4
|
+
require "rails_benchmark_suite/version"
|
|
5
|
+
require "rails_benchmark_suite/reporter"
|
|
6
|
+
require "rails_benchmark_suite/runner"
|
|
7
|
+
require "rails_benchmark_suite/db_setup"
|
|
8
|
+
require "rails_benchmark_suite/schema"
|
|
9
|
+
require "rails_benchmark_suite/models/user"
|
|
10
|
+
require "rails_benchmark_suite/models/post"
|
|
11
|
+
require "rails_benchmark_suite/models/simulated_job"
|
|
12
|
+
|
|
13
|
+
module RailsBenchmarkSuite
|
|
14
|
+
@suites = []
|
|
15
|
+
|
|
16
|
+
def self.register_suite(name, weight: 1.0, &block)
|
|
17
|
+
@suites << { name: name, weight: weight, block: block }
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self.run(json: false)
|
|
21
|
+
# Load Schema
|
|
22
|
+
RailsBenchmarkSuite::Schema.load
|
|
23
|
+
|
|
24
|
+
# Load suites
|
|
25
|
+
Dir[File.join(__dir__, "rails_benchmark_suite", "suites", "*.rb")].each { |f| require f }
|
|
26
|
+
|
|
27
|
+
runner = Runner.new(@suites, json: json)
|
|
28
|
+
runner.run
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "lib/rails_benchmark_suite/version"
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |spec|
|
|
6
|
+
spec.name = "rails_benchmark_suite"
|
|
7
|
+
spec.version = RailsBenchmarkSuite::VERSION
|
|
8
|
+
spec.authors = ["RailsBenchmarkSuite Contributors"]
|
|
9
|
+
spec.email = ["team@rails.org"]
|
|
10
|
+
|
|
11
|
+
spec.summary = "Rails-style functionality & performance benchmark tool"
|
|
12
|
+
spec.description = "Measures the 'Heft' (processing power) of a machine using realistic Rails workloads."
|
|
13
|
+
spec.homepage = "https://github.com/overnet/rails_benchmark_suite"
|
|
14
|
+
spec.license = "MIT"
|
|
15
|
+
|
|
16
|
+
spec.metadata["source_code_uri"] = "https://github.com/overnet/rails_benchmark_suite"
|
|
17
|
+
spec.metadata["bug_tracker_uri"] = "https://github.com/overnet/rails_benchmark_suite/issues"
|
|
18
|
+
spec.metadata["changelog_uri"] = "https://github.com/overnet/rails_benchmark_suite/blob/main/CHANGELOG.md"
|
|
19
|
+
|
|
20
|
+
spec.files = Dir.chdir(__dir__) do
|
|
21
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
|
22
|
+
end
|
|
23
|
+
spec.bindir = "bin"
|
|
24
|
+
spec.executables = ["rails_benchmark_suite"]
|
|
25
|
+
spec.require_paths = ["lib"]
|
|
26
|
+
|
|
27
|
+
spec.add_dependency "benchmark-ips", "~> 2.14"
|
|
28
|
+
spec.add_dependency "activerecord", "~> 8.1"
|
|
29
|
+
spec.add_dependency "actionview", "~> 8.1"
|
|
30
|
+
spec.add_dependency "activestorage", "~> 8.1"
|
|
31
|
+
spec.add_dependency "image_processing", "~> 1.14"
|
|
32
|
+
spec.add_dependency "sqlite3", "~> 2.8"
|
|
33
|
+
spec.add_dependency "concurrent-ruby", "~> 1.3"
|
|
34
|
+
spec.add_dependency "get_process_mem", "~> 1.0"
|
|
35
|
+
|
|
36
|
+
spec.add_development_dependency "bundler", "~> 2.5"
|
|
37
|
+
spec.add_development_dependency "rake", "~> 13.0"
|
|
38
|
+
spec.add_development_dependency "minitest", "~> 5.0"
|
|
39
|
+
|
|
40
|
+
spec.required_ruby_version = ">= 3.4.0"
|
|
41
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: rails_benchmark_suite
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.2.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- RailsBenchmarkSuite Contributors
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 2026-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: benchmark-ips
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - "~>"
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '2.14'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - "~>"
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '2.14'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: activerecord
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - "~>"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '8.1'
|
|
33
|
+
type: :runtime
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - "~>"
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '8.1'
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: actionview
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - "~>"
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '8.1'
|
|
47
|
+
type: :runtime
|
|
48
|
+
prerelease: false
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - "~>"
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '8.1'
|
|
54
|
+
- !ruby/object:Gem::Dependency
|
|
55
|
+
name: activestorage
|
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - "~>"
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '8.1'
|
|
61
|
+
type: :runtime
|
|
62
|
+
prerelease: false
|
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - "~>"
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: '8.1'
|
|
68
|
+
- !ruby/object:Gem::Dependency
|
|
69
|
+
name: image_processing
|
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
|
71
|
+
requirements:
|
|
72
|
+
- - "~>"
|
|
73
|
+
- !ruby/object:Gem::Version
|
|
74
|
+
version: '1.14'
|
|
75
|
+
type: :runtime
|
|
76
|
+
prerelease: false
|
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
78
|
+
requirements:
|
|
79
|
+
- - "~>"
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: '1.14'
|
|
82
|
+
- !ruby/object:Gem::Dependency
|
|
83
|
+
name: sqlite3
|
|
84
|
+
requirement: !ruby/object:Gem::Requirement
|
|
85
|
+
requirements:
|
|
86
|
+
- - "~>"
|
|
87
|
+
- !ruby/object:Gem::Version
|
|
88
|
+
version: '2.8'
|
|
89
|
+
type: :runtime
|
|
90
|
+
prerelease: false
|
|
91
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
92
|
+
requirements:
|
|
93
|
+
- - "~>"
|
|
94
|
+
- !ruby/object:Gem::Version
|
|
95
|
+
version: '2.8'
|
|
96
|
+
- !ruby/object:Gem::Dependency
|
|
97
|
+
name: concurrent-ruby
|
|
98
|
+
requirement: !ruby/object:Gem::Requirement
|
|
99
|
+
requirements:
|
|
100
|
+
- - "~>"
|
|
101
|
+
- !ruby/object:Gem::Version
|
|
102
|
+
version: '1.3'
|
|
103
|
+
type: :runtime
|
|
104
|
+
prerelease: false
|
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
106
|
+
requirements:
|
|
107
|
+
- - "~>"
|
|
108
|
+
- !ruby/object:Gem::Version
|
|
109
|
+
version: '1.3'
|
|
110
|
+
- !ruby/object:Gem::Dependency
|
|
111
|
+
name: get_process_mem
|
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
|
113
|
+
requirements:
|
|
114
|
+
- - "~>"
|
|
115
|
+
- !ruby/object:Gem::Version
|
|
116
|
+
version: '1.0'
|
|
117
|
+
type: :runtime
|
|
118
|
+
prerelease: false
|
|
119
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
120
|
+
requirements:
|
|
121
|
+
- - "~>"
|
|
122
|
+
- !ruby/object:Gem::Version
|
|
123
|
+
version: '1.0'
|
|
124
|
+
- !ruby/object:Gem::Dependency
|
|
125
|
+
name: bundler
|
|
126
|
+
requirement: !ruby/object:Gem::Requirement
|
|
127
|
+
requirements:
|
|
128
|
+
- - "~>"
|
|
129
|
+
- !ruby/object:Gem::Version
|
|
130
|
+
version: '2.5'
|
|
131
|
+
type: :development
|
|
132
|
+
prerelease: false
|
|
133
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
134
|
+
requirements:
|
|
135
|
+
- - "~>"
|
|
136
|
+
- !ruby/object:Gem::Version
|
|
137
|
+
version: '2.5'
|
|
138
|
+
- !ruby/object:Gem::Dependency
|
|
139
|
+
name: rake
|
|
140
|
+
requirement: !ruby/object:Gem::Requirement
|
|
141
|
+
requirements:
|
|
142
|
+
- - "~>"
|
|
143
|
+
- !ruby/object:Gem::Version
|
|
144
|
+
version: '13.0'
|
|
145
|
+
type: :development
|
|
146
|
+
prerelease: false
|
|
147
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
148
|
+
requirements:
|
|
149
|
+
- - "~>"
|
|
150
|
+
- !ruby/object:Gem::Version
|
|
151
|
+
version: '13.0'
|
|
152
|
+
- !ruby/object:Gem::Dependency
|
|
153
|
+
name: minitest
|
|
154
|
+
requirement: !ruby/object:Gem::Requirement
|
|
155
|
+
requirements:
|
|
156
|
+
- - "~>"
|
|
157
|
+
- !ruby/object:Gem::Version
|
|
158
|
+
version: '5.0'
|
|
159
|
+
type: :development
|
|
160
|
+
prerelease: false
|
|
161
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
162
|
+
requirements:
|
|
163
|
+
- - "~>"
|
|
164
|
+
- !ruby/object:Gem::Version
|
|
165
|
+
version: '5.0'
|
|
166
|
+
description: Measures the 'Heft' (processing power) of a machine using realistic Rails
|
|
167
|
+
workloads.
|
|
168
|
+
email:
|
|
169
|
+
- team@rails.org
|
|
170
|
+
executables:
|
|
171
|
+
- rails_benchmark_suite
|
|
172
|
+
extensions: []
|
|
173
|
+
extra_rdoc_files: []
|
|
174
|
+
files:
|
|
175
|
+
- ".gitignore"
|
|
176
|
+
- ".ruby-version"
|
|
177
|
+
- CHANGELOG.md
|
|
178
|
+
- Gemfile
|
|
179
|
+
- Gemfile.lock
|
|
180
|
+
- LICENSE.txt
|
|
181
|
+
- README.md
|
|
182
|
+
- Rakefile
|
|
183
|
+
- bin/rails_benchmark_suite
|
|
184
|
+
- lib/rails_benchmark_suite.rb
|
|
185
|
+
- lib/rails_benchmark_suite/db_setup.rb
|
|
186
|
+
- lib/rails_benchmark_suite/models/post.rb
|
|
187
|
+
- lib/rails_benchmark_suite/models/simulated_job.rb
|
|
188
|
+
- lib/rails_benchmark_suite/models/user.rb
|
|
189
|
+
- lib/rails_benchmark_suite/reporter.rb
|
|
190
|
+
- lib/rails_benchmark_suite/runner.rb
|
|
191
|
+
- lib/rails_benchmark_suite/schema.rb
|
|
192
|
+
- lib/rails_benchmark_suite/suites/active_record_suite.rb
|
|
193
|
+
- lib/rails_benchmark_suite/suites/cache_heft_suite.rb
|
|
194
|
+
- lib/rails_benchmark_suite/suites/image_heft_suite.rb
|
|
195
|
+
- lib/rails_benchmark_suite/suites/job_heft_suite.rb
|
|
196
|
+
- lib/rails_benchmark_suite/suites/view_heft_suite.rb
|
|
197
|
+
- lib/rails_benchmark_suite/version.rb
|
|
198
|
+
- rails_benchmark_suite.gemspec
|
|
199
|
+
homepage: https://github.com/overnet/rails_benchmark_suite
|
|
200
|
+
licenses:
|
|
201
|
+
- MIT
|
|
202
|
+
metadata:
|
|
203
|
+
source_code_uri: https://github.com/overnet/rails_benchmark_suite
|
|
204
|
+
bug_tracker_uri: https://github.com/overnet/rails_benchmark_suite/issues
|
|
205
|
+
changelog_uri: https://github.com/overnet/rails_benchmark_suite/blob/main/CHANGELOG.md
|
|
206
|
+
rdoc_options: []
|
|
207
|
+
require_paths:
|
|
208
|
+
- lib
|
|
209
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
210
|
+
requirements:
|
|
211
|
+
- - ">="
|
|
212
|
+
- !ruby/object:Gem::Version
|
|
213
|
+
version: 3.4.0
|
|
214
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
215
|
+
requirements:
|
|
216
|
+
- - ">="
|
|
217
|
+
- !ruby/object:Gem::Version
|
|
218
|
+
version: '0'
|
|
219
|
+
requirements: []
|
|
220
|
+
rubygems_version: 3.6.2
|
|
221
|
+
specification_version: 4
|
|
222
|
+
summary: Rails-style functionality & performance benchmark tool
|
|
223
|
+
test_files: []
|