type_balancer 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 9d017bcd987973e61c2cca2f30f3a968ebccc0604b7043e44fd7ca4aa22a57a2
4
+ data.tar.gz: 214815b85a1095b6c4b9b853c6154b3c919d4671db2c69a6730ca21dcad5c559
5
+ SHA512:
6
+ metadata.gz: c8e8dd1cd9854f80d68a54475e13634bb2ca2e78350f9fe4994252a502bd7acd75d764f7a7c0bd779808ebf39ba496289efa50f8bc7a281391d9e11d3a8ab500
7
+ data.tar.gz: fbcec72c85c4480f6b035f07bc8f49311798b90dd14c6eaf8cf4a7054c8ec2e7ded4ef9d1dd08e9029a5ce2f698696054f9f96191fae5f88461ad5d303aa10c8
data/.rubocop.yml ADDED
@@ -0,0 +1,96 @@
1
+ require:
2
+ - rubocop-rspec
3
+
4
+ AllCops:
5
+ TargetRubyVersion: 3.2
6
+ NewCops: enable
7
+ SuggestExtensions: false
8
+ Exclude:
9
+ - 'bin/*'
10
+ - 'ext/**/*'
11
+ - 'benchmark/**/*'
12
+ - 'vendor/**/*'
13
+ - 'examples/quality.rb'
14
+
15
+ Style/StringLiterals:
16
+ EnforcedStyle: single_quotes
17
+
18
+ Style/Documentation:
19
+ Enabled: false
20
+
21
+ Style/DocumentDynamicEvalDefinition:
22
+ Enabled: false
23
+
24
+ Metrics/BlockLength:
25
+ Enabled: true
26
+ Exclude:
27
+ - 'spec/**/*'
28
+ - 'Rakefile'
29
+
30
+ Metrics/MethodLength:
31
+ Max: 20
32
+ Exclude:
33
+ - 'lib/type_balancer/distributor.rb'
34
+ - 'lib/type_balancer/balancer.rb'
35
+
36
+ Metrics/AbcSize:
37
+ Max: 20
38
+ Exclude:
39
+ - 'lib/type_balancer/distributor.rb'
40
+ - 'lib/type_balancer/balancer.rb'
41
+
42
+ Metrics/CyclomaticComplexity:
43
+ Max: 10
44
+ Exclude:
45
+ - 'lib/type_balancer/distributor.rb'
46
+ - 'lib/type_balancer/balancer.rb'
47
+
48
+ Metrics/PerceivedComplexity:
49
+ Max: 10
50
+ Exclude:
51
+ - 'lib/type_balancer/distributor.rb'
52
+ - 'lib/type_balancer/balancer.rb'
53
+
54
+ RSpec/ExampleLength:
55
+ Max: 15
56
+
57
+ RSpec/MultipleExpectations:
58
+ Max: 5
59
+
60
+ RSpec/NestedGroups:
61
+ Max: 4
62
+
63
+ RSpec/VerifiedDoubles:
64
+ Enabled: false
65
+
66
+ RSpec/MultipleMemoizedHelpers:
67
+ Max: 10
68
+
69
+ RSpec/RepeatedExample:
70
+ Enabled: false # We have intentionally repeated examples
71
+
72
+ RSpec/MultipleDescribes:
73
+ Enabled: false # We have intentionally structured our specs this way
74
+
75
+ RSpec/RepeatedExampleGroupDescription:
76
+ Enabled: false # We have intentionally structured our specs this way
77
+
78
+ # Disable all Capybara/RSpec cops
79
+ Capybara/RSpec:
80
+ Enabled: false
81
+
82
+ # Disable all RSpec/Capybara cops
83
+ RSpec/Capybara:
84
+ Enabled: false
85
+
86
+ # Disable all RSpec/FactoryBot cops
87
+ RSpec/FactoryBot:
88
+ Enabled: false
89
+
90
+ # Disable all RSpec/Rails cops
91
+ RSpec/Rails:
92
+ Enabled: false
93
+
94
+ # Disable PredicateMatcher cop that's causing errors
95
+ RSpec/PredicateMatcher:
96
+ Enabled: false
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.4.1
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.1.0] - 2025-03-29
4
+
5
+ - Initial release
data/Dockerfile ADDED
@@ -0,0 +1,38 @@
1
+ # Allow platform to be specified at build time
2
+ ARG PLATFORM=linux/arm64
3
+ ARG RUBY_VERSION
4
+ FROM --platform=${PLATFORM} ruby:${RUBY_VERSION}-slim
5
+
6
+ # Install build dependencies
7
+ RUN apt-get update && apt-get install -y \
8
+ git \
9
+ build-essential \
10
+ pkg-config \
11
+ libffi-dev \
12
+ && rm -rf /var/lib/apt/lists/*
13
+
14
+ # Install Rust if YJIT is enabled
15
+ ARG ENABLE_YJIT=false
16
+ RUN if [ "${ENABLE_YJIT}" = "true" ]; then \
17
+ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y; \
18
+ fi
19
+
20
+ WORKDIR /app
21
+
22
+ # Copy all necessary files for building the gem
23
+ COPY Gemfile Gemfile.lock type_balancer.gemspec Rakefile ./
24
+ COPY lib/ lib/
25
+ COPY sig/ sig/
26
+ COPY benchmark/ benchmark/
27
+
28
+ # Initialize Git repository and stage files (needed for gemspec)
29
+ RUN git init && \
30
+ git add .
31
+
32
+ # Install dependencies
33
+ RUN bundle install
34
+
35
+ # Set environment variable for Ruby to find native extensions
36
+ ENV RUBYLIB=/app/lib
37
+
38
+ CMD ["bundle", "exec", "rake", "benchmark:complete"]
data/Gemfile ADDED
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ # Specify your gem's dependencies in type_balancer.gemspec
6
+ gemspec
7
+
8
+ group :development do
9
+ gem 'benchmark'
10
+ gem 'benchmark-ips', '~> 2.12'
11
+ gem 'ffi'
12
+ gem 'rake', '~> 13.0'
13
+ gem 'rake-compiler', '~> 1.2'
14
+ gem 'rspec', '~> 3.0'
15
+ gem 'rubocop', '~> 1.21'
16
+ gem 'rubocop-rake', '~> 0.6.0'
17
+ gem 'rubocop-rspec', '~> 2.26'
18
+ gem 'simplecov', '~> 0.22.0'
19
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,101 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ type_balancer (0.1.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ ast (2.4.3)
10
+ benchmark (0.4.0)
11
+ benchmark-ips (2.14.0)
12
+ diff-lcs (1.6.1)
13
+ docile (1.4.1)
14
+ ffi (1.17.1)
15
+ ffi (1.17.1-arm64-darwin)
16
+ json (2.10.2)
17
+ language_server-protocol (3.17.0.4)
18
+ lint_roller (1.1.0)
19
+ parallel (1.26.3)
20
+ parser (3.3.7.3)
21
+ ast (~> 2.4.1)
22
+ racc
23
+ prism (1.4.0)
24
+ racc (1.8.1)
25
+ rainbow (3.1.1)
26
+ rake (13.2.1)
27
+ rake-compiler (1.2.9)
28
+ rake
29
+ regexp_parser (2.10.0)
30
+ rspec (3.13.0)
31
+ rspec-core (~> 3.13.0)
32
+ rspec-expectations (~> 3.13.0)
33
+ rspec-mocks (~> 3.13.0)
34
+ rspec-core (3.13.3)
35
+ rspec-support (~> 3.13.0)
36
+ rspec-expectations (3.13.3)
37
+ diff-lcs (>= 1.2.0, < 2.0)
38
+ rspec-support (~> 3.13.0)
39
+ rspec-mocks (3.13.2)
40
+ diff-lcs (>= 1.2.0, < 2.0)
41
+ rspec-support (~> 3.13.0)
42
+ rspec-support (3.13.2)
43
+ rubocop (1.75.1)
44
+ json (~> 2.3)
45
+ language_server-protocol (~> 3.17.0.2)
46
+ lint_roller (~> 1.1.0)
47
+ parallel (~> 1.10)
48
+ parser (>= 3.3.0.2)
49
+ rainbow (>= 2.2.2, < 4.0)
50
+ regexp_parser (>= 2.9.3, < 3.0)
51
+ rubocop-ast (>= 1.43.0, < 2.0)
52
+ ruby-progressbar (~> 1.7)
53
+ unicode-display_width (>= 2.4.0, < 4.0)
54
+ rubocop-ast (1.43.0)
55
+ parser (>= 3.3.7.2)
56
+ prism (~> 1.4)
57
+ rubocop-capybara (2.22.1)
58
+ lint_roller (~> 1.1)
59
+ rubocop (~> 1.72, >= 1.72.1)
60
+ rubocop-factory_bot (2.27.1)
61
+ lint_roller (~> 1.1)
62
+ rubocop (~> 1.72, >= 1.72.1)
63
+ rubocop-rake (0.6.0)
64
+ rubocop (~> 1.0)
65
+ rubocop-rspec (2.31.0)
66
+ rubocop (~> 1.40)
67
+ rubocop-capybara (~> 2.17)
68
+ rubocop-factory_bot (~> 2.22)
69
+ rubocop-rspec_rails (~> 2.28)
70
+ rubocop-rspec_rails (2.29.1)
71
+ rubocop (~> 1.61)
72
+ ruby-progressbar (1.13.0)
73
+ simplecov (0.22.0)
74
+ docile (~> 1.1)
75
+ simplecov-html (~> 0.11)
76
+ simplecov_json_formatter (~> 0.1)
77
+ simplecov-html (0.13.1)
78
+ simplecov_json_formatter (0.1.4)
79
+ unicode-display_width (3.1.4)
80
+ unicode-emoji (~> 4.0, >= 4.0.4)
81
+ unicode-emoji (4.0.4)
82
+
83
+ PLATFORMS
84
+ arm64-darwin-23
85
+ ruby
86
+
87
+ DEPENDENCIES
88
+ benchmark
89
+ benchmark-ips (~> 2.12)
90
+ ffi
91
+ rake (~> 13.0)
92
+ rake-compiler (~> 1.2)
93
+ rspec (~> 3.0)
94
+ rubocop (~> 1.21)
95
+ rubocop-rake (~> 0.6.0)
96
+ rubocop-rspec (~> 2.26)
97
+ simplecov (~> 0.22.0)
98
+ type_balancer!
99
+
100
+ BUNDLED WITH
101
+ 2.6.2
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2025 Carl Smith
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
13
+ all 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
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,86 @@
1
+ <img src="https://www.ruby-lang.org/images/header-ruby-logo.png" width="50" align="right" alt="Ruby Logo"/>
2
+
3
+ # TypeBalancer
4
+
5
+ [![Gem Version](https://badge.fury.io/rb/type_balancer.svg)](https://badge.fury.io/rb/type_balancer)
6
+ [![CI](https://github.com/llwebconsulting/type_balancer/actions/workflows/ci.yml/badge.svg)](https://github.com/llwebconsulting/type_balancer/actions/workflows/ci.yml)
7
+ [![Ruby Coverage](https://img.shields.io/badge/ruby--coverage-78.57%25-yellow.svg)](https://github.com/llwebconsulting/type_balancer/blob/main/coverage/index.html)
8
+ [![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE.txt)
9
+
10
+ A Ruby gem for balancing and distributing items of different types across a sequence while maintaining optimal spacing.
11
+
12
+ ## Installation
13
+
14
+ Add this line to your application's Gemfile:
15
+
16
+ ```ruby
17
+ gem 'type_balancer'
18
+ ```
19
+
20
+ And then execute:
21
+
22
+ ```bash
23
+ $ bundle install
24
+ ```
25
+
26
+ Or install it yourself as:
27
+
28
+ ```bash
29
+ $ gem install type_balancer
30
+ ```
31
+
32
+ ## Usage
33
+
34
+ ```ruby
35
+ items = [
36
+ { type: 'video', title: 'Video 1' },
37
+ { type: 'image', title: 'Image 1' },
38
+ { type: 'article', title: 'Article 1' },
39
+ # ... more items
40
+ ]
41
+
42
+ # Balance items by type
43
+ balanced_items = TypeBalancer.balance(items, type_field: :type)
44
+ ```
45
+
46
+ ## Performance Characteristics
47
+
48
+ TypeBalancer is designed to handle collections of varying sizes efficiently. Here are the current performance metrics:
49
+
50
+ - Tiny collections (10 items): Microsecond-level processing (9-14μs)
51
+ - Small collections (100 items): Sub-millisecond processing (~450-500μs)
52
+ - Medium collections (1,000 items): Fast processing (~20-21ms)
53
+ - Large collections (10,000 items): Efficient processing (~193-209ms)
54
+
55
+ Performance has been thoroughly tested across Ruby versions (3.2.8, 3.3.7, and 3.4.2). YJIT provides significant improvements for small datasets (up to 51% faster for tiny collections) with varying impact on larger datasets. For detailed benchmarks across Ruby versions and YJIT configurations, see our [benchmark documentation](docs/benchmarks/README.md).
56
+
57
+ ### Recommendations
58
+
59
+ - Suitable for real-time processing of collections up to 10,000 items
60
+ - Excellent performance for content management systems and feed generation
61
+ - Thread-safe and memory-efficient
62
+ - If you need to process very large collections (>10,000 items), consider batch processing or open an issue for guidance
63
+
64
+ ## Features
65
+
66
+ - Maintains optimal spacing between items of the same type
67
+ - Supports custom type fields
68
+ - Preserves original item data
69
+ - Thread-safe
70
+ - Zero dependencies
71
+
72
+ ## Development
73
+
74
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
75
+
76
+ ## Contributing
77
+
78
+ Bug reports and pull requests are welcome on GitHub at https://github.com/llwebconsulting/type_balancer. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/llwebconsulting/type_balancer/blob/main/CODE_OF_CONDUCT.md).
79
+
80
+ ## License
81
+
82
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
83
+
84
+ ## Code of Conduct
85
+
86
+ Everyone interacting in the TypeBalancer project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/llwebconsulting/type_balancer/blob/main/CODE_OF_CONDUCT.md).
data/Rakefile ADDED
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rake/extensiontask'
5
+ require 'rspec/core/rake_task'
6
+
7
+ RSpec::Core::RakeTask.new(:spec)
8
+
9
+ require 'rubocop/rake_task'
10
+
11
+ RuboCop::RakeTask.new
12
+
13
+ Rake::ExtensionTask.new('type_balancer') do |ext|
14
+ ext.lib_dir = 'lib/type_balancer'
15
+ ext.ext_dir = 'ext/type_balancer'
16
+ ext.source_pattern = '*.{c,h}'
17
+ ext.config_options = ['--with-cflags=-Wall -Wextra -O3']
18
+ end
19
+
20
+ # Add GoogleTest task using CMake
21
+ namespace :gtest do
22
+ desc 'Build and run all GoogleTest tests'
23
+ task :all do
24
+ Dir.chdir('c_tests') do
25
+ sh './build.sh'
26
+ end
27
+ end
28
+
29
+ desc 'Build and run a specific GoogleTest test (e.g., rake gtest:run[TestSuite.TestName])'
30
+ task :run, [:test_name] do |_, args|
31
+ test_filter = args[:test_name] ? "--gtest_filter=#{args[:test_name]}" : ''
32
+ Dir.chdir('c_tests') do
33
+ sh "rm -rf build && mkdir build && cd build && cmake .. && make && ./type_balancer_tests #{test_filter} | cat"
34
+ end
35
+ end
36
+
37
+ desc 'List all available GoogleTest tests'
38
+ task :list do
39
+ Dir.chdir('c_tests') do
40
+ sh 'rm -rf build && mkdir build && cd build && cmake .. && make && ./type_balancer_tests --gtest_list_tests | cat'
41
+ end
42
+ end
43
+ end
44
+
45
+ namespace :lint do
46
+ desc 'Run C linting with clang-tidy'
47
+ task :c do
48
+ mkdir_p 'c_tests/build'
49
+ Dir.chdir('c_tests/build') do
50
+ sh 'cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON ..'
51
+ end
52
+ sh 'clang-tidy -p c_tests/build ext/type_balancer/*.{c,h}'
53
+ end
54
+
55
+ desc 'Run all linting checks'
56
+ task all: %i[rubocop c]
57
+ end
58
+
59
+ desc 'Run all tests with proper mocking'
60
+ task test_with_mocks: [:spec] do
61
+ puts 'Running tests with proper mocking...'
62
+ Rake::Task['gtest:all'].invoke
63
+ end
64
+
65
+ task default: [:test_with_mocks, 'lint:all']
66
+
67
+ # Benchmark tasks
68
+ namespace :benchmark do
69
+ desc 'Run distributor benchmark comparing C extension vs Pure Ruby (without YJIT)'
70
+ task :distributor do
71
+ ruby 'benchmark/distributor_benchmark.rb'
72
+ end
73
+
74
+ desc 'Run combined benchmark comparing full C vs Ruby implementations (without YJIT)'
75
+ task :combined do
76
+ ruby 'benchmark/combined_benchmark.rb'
77
+ end
78
+
79
+ desc 'Run all benchmarks (without YJIT)'
80
+ task all: %i[distributor combined]
81
+
82
+ namespace :yjit do
83
+ desc 'Run distributor benchmark comparing C extension vs Pure Ruby with YJIT enabled'
84
+ task :distributor do
85
+ ENV['RUBY_YJIT_ENABLE'] = '1'
86
+ ruby 'benchmark/distributor_benchmark.rb'
87
+ end
88
+
89
+ desc 'Run combined benchmark comparing full C vs Ruby implementations with YJIT enabled'
90
+ task :combined do
91
+ ENV['RUBY_YJIT_ENABLE'] = '1'
92
+ ruby 'benchmark/combined_benchmark.rb'
93
+ end
94
+
95
+ desc 'Run all benchmarks with YJIT enabled'
96
+ task all: %i[distributor combined]
97
+ end
98
+
99
+ desc 'Run all benchmarks with and without YJIT'
100
+ task complete: %i[all yjit:all]
101
+ end
@@ -0,0 +1,90 @@
1
+ # TypeBalancer Benchmarks
2
+
3
+ This directory contains benchmarks for measuring TypeBalancer's performance across different Ruby versions and configurations.
4
+
5
+ ## Latest Benchmark Results
6
+
7
+ Tests run on ARM64 platform (M-series Mac via Docker) with Ruby versions 3.2.8, 3.3.7, and 3.4.2, both with and without YJIT.
8
+
9
+ ### Processing Time by Dataset Size
10
+
11
+ #### Tiny Dataset (10 items)
12
+ - Processing time: ~15 microseconds
13
+ - Throughput: ~65-70k operations/second
14
+ - Even distribution achieved: 40/30/30 split
15
+
16
+ #### Small Dataset (100 items)
17
+ - Processing time: ~550 microseconds
18
+ - Throughput: ~1.8k operations/second
19
+ - Even distribution achieved: 34/33/33 split
20
+
21
+ #### Medium Dataset (1,000 items)
22
+ - Processing time: ~50 milliseconds
23
+ - Throughput: ~20 operations/second
24
+ - Even distribution achieved: 33.4/33.3/33.3 split
25
+
26
+ #### Large Dataset (10,000 items)
27
+ - Processing time: ~4.3-4.7 seconds
28
+ - Throughput: ~0.21-0.23 operations/second
29
+ - Even distribution achieved: 33.34/33.33/33.33 split
30
+
31
+ ### Performance Analysis
32
+
33
+ #### Ruby Version Comparison (10,000 items)
34
+ | Ruby Version | YJIT | Time (seconds) |
35
+ |-------------|------|----------------|
36
+ | 3.2.8 | No | 4.37 |
37
+ | 3.2.8 | Yes | 4.29 |
38
+ | 3.3.7 | No | 4.45 |
39
+ | 3.3.7 | Yes | 4.31 |
40
+ | 3.4.2 | No | 4.71 |
41
+ | 3.4.2 | Yes | 4.71 |
42
+
43
+ #### Key Findings
44
+ 1. YJIT Impact:
45
+ - Provides modest improvements (2-3%) on larger datasets
46
+ - Most effective with Ruby 3.2.8
47
+ - Diminishing returns in newer Ruby versions
48
+
49
+ 2. Scaling Characteristics:
50
+ - Performance scales non-linearly with dataset size
51
+ - Sweet spot appears to be around 1,000 items
52
+ - Processing time increases significantly beyond 1,000 items
53
+
54
+ 3. Distribution Quality:
55
+ - Maintains excellent distribution ratios across all dataset sizes
56
+ - Larger datasets achieve near-perfect distribution (33.33%)
57
+
58
+ ## Current Limitations and Future Work
59
+
60
+ 1. Performance Concerns:
61
+ - Large datasets (>10,000 items) process slower than desired
62
+ - Non-linear scaling suggests algorithmic optimization opportunities
63
+ - Current implementation prioritizes distribution quality over speed
64
+
65
+ 2. Optimization Priorities:
66
+ - Improve processing time for large datasets
67
+ - Investigate algorithmic improvements in distribution logic
68
+ - Explore parallel processing options for large collections
69
+
70
+ 3. Recommendations:
71
+ - For production use, process collections of ≤1,000 items at a time
72
+ - Break larger datasets into smaller batches
73
+ - Monitor memory usage with very large collections
74
+
75
+ ## Running Benchmarks
76
+
77
+ To run the benchmarks:
78
+
79
+ ```bash
80
+ # Run all Ruby versions with and without YJIT
81
+ ./bin/run_benchmarks.sh --platform linux/arm64
82
+
83
+ # Run specific version with YJIT
84
+ ./bin/run_benchmarks.sh -v 3.3.8 --yjit --platform linux/arm64
85
+
86
+ # Run specific version without YJIT
87
+ ./bin/run_benchmarks.sh -v 3.3.8 --no-yjit --platform linux/arm64
88
+ ```
89
+
90
+ Results will be saved in the `benchmark_results` directory.
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "bundler/setup"
5
+ require "benchmark/ips"
6
+ require_relative "../lib/type_balancer"
7
+
8
+ # Print Ruby and platform info
9
+ puts "Ruby version: #{RUBY_VERSION}"
10
+ puts "RUBY_PLATFORM: #{RUBY_PLATFORM}"
11
+ puts "YJIT enabled: #{RubyVM.const_defined?(:YJIT) && RubyVM::YJIT.enabled?}"
12
+
13
+ # Test data generator
14
+ def generate_test_data(size)
15
+ types = %w[video image article]
16
+ Array.new(size) do |i|
17
+ {
18
+ id: i,
19
+ type: types[i % types.size],
20
+ title: "Item #{i}"
21
+ }
22
+ end
23
+ end
24
+
25
+ # More granular test cases
26
+ TEST_CASES = [
27
+ { name: "Tiny Dataset", size: 10 },
28
+ { name: "Small Dataset", size: 100 },
29
+ { name: "Medium Dataset", size: 1_000 },
30
+ { name: "Large Dataset", size: 10_000 }
31
+ ]
32
+
33
+ def run_benchmark
34
+ puts "\nRunning benchmarks..."
35
+
36
+ TEST_CASES.each do |test_case|
37
+ puts "\nBenchmarking #{test_case[:name]} (#{test_case[:size]} items)"
38
+ collection = generate_test_data(test_case[:size])
39
+
40
+ # Single warmup run to ensure everything is loaded
41
+ TypeBalancer.balance(collection, type_field: :type)
42
+
43
+ # Run benchmark
44
+ Benchmark.ips do |bm|
45
+ # Adjust warmup/time based on dataset size
46
+ warmup_time = test_case[:size] <= 100 ? 1 : 2
47
+ bench_time = test_case[:size] <= 100 ? 2 : 3
48
+
49
+ bm.config(time: bench_time, warmup: warmup_time)
50
+ bm.report("Ruby Implementation") do
51
+ TypeBalancer.balance(collection, type_field: :type)
52
+ end
53
+ end
54
+
55
+ # Print distribution stats for verification
56
+ result = TypeBalancer.balance(collection, type_field: :type)
57
+ puts "\nDistribution Stats:"
58
+ %w[video image article].each do |type|
59
+ count = result.count { |i| i[:type] == type }
60
+ puts "#{type.capitalize}: #{count} (#{(count.to_f / test_case[:size] * 100).round(2)}%)"
61
+ end
62
+ end
63
+ end
64
+
65
+ run_benchmark