Skip to content

Commit cfe3002

Browse files
committed
Get optcarrot working with ractors
I just copied the code over to the ractor directory because it would too hard otherwise. You can run it with: $ WARMUP_ITRS=5 ruby run_benchmarks.rb --category=ractor-only --skip-yjit optcarrot
1 parent bc27c1c commit cfe3002

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

74 files changed

+9244
-0
lines changed
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
.bundle/
2+
Gemfile.lock
3+
coverage/
4+
doc/
5+
pkg/
6+
vendor/
7+
optcarrot-*.gem
8+
9+
.git
10+
.dockerignore
11+
.*.sw*
12+
**/.*.sw*
13+
tools/nes-test-roms
14+
SDL2.dll
15+
video.png
16+
video.gif
17+
audio.wav
18+
stackprof-*.dump
19+
perf.data
20+
perf.data.old
21+
benchmark/bm-*.csv
22+
benchmark/Dockerfile.*
23+
tmp
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/.bundle/
2+
/Gemfile.lock
3+
/benchmark
4+
/coverage/
5+
/pkg/
6+
/vendor/
7+
optcarrot-*.gem
8+
9+
.*.sw*
10+
/tools/nes-test-roms
11+
video.png
12+
video.gif
13+
audio.wav
14+
stackprof-*.dump
15+
perf.data
16+
perf.data.old
17+
benchmark/bm-*.csv
18+
ppu-core.rb
19+
cpu-core.rb
20+
benchmark/Dockerfile.*
21+
benchmark/*-core-opt-*.rb
Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
AllCops:
2+
NewCops: enable
3+
Exclude:
4+
- "*-core.rb"
5+
- "tools/plot.rb"
6+
- "tmp/**"
7+
- "test/**"
8+
- "benchmark/*-core-opt-*.rb"
9+
- "benchmark/Dockerfile.*"
10+
11+
# "eval" is the swiss army knife
12+
Security/Eval:
13+
Enabled: false
14+
15+
# Marshal.load is needed when needed
16+
Security/MarshalLoad:
17+
Enabled: false
18+
19+
# "while true" loop is easy and fast
20+
Lint/Loop:
21+
Enabled: false
22+
Style/InfiniteLoop:
23+
Enabled: false
24+
25+
# `String#%` is a great invention of Ruby
26+
Style/FormatString:
27+
EnforcedStyle: percent
28+
29+
# I hate frozen string literal
30+
Style/FrozenStringLiteralComment:
31+
Enabled: false
32+
33+
# 10_000 looks dirty to me
34+
Style/NumericLiterals:
35+
MinDigits: 6
36+
37+
# explicit return is sometimes good for consistency
38+
Style/RedundantReturn:
39+
Enabled: false
40+
41+
# `x == :error ? error-case : normal-case` does not look beautiful to me
42+
Style/NegatedIfElseCondition:
43+
Enabled: false
44+
45+
# I like `foo {|x| bar(x) }` and `foo { bar }`
46+
Layout/SpaceInsideBlockBraces:
47+
EnforcedStyleForEmptyBraces: space
48+
SpaceBeforeBlockParameters: false
49+
50+
# `"foo#{bar}baz"` looks too dense to me
51+
Layout/SpaceInsideStringInterpolation:
52+
EnforcedStyle: space
53+
54+
# I consistently use double quotes
55+
Style/StringLiterals:
56+
EnforcedStyle: double_quotes
57+
Style/StringLiteralsInInterpolation:
58+
EnforcedStyle: double_quotes
59+
60+
# A trailing comma in array/hash literal is super cool
61+
Style/TrailingCommaInArrayLiteral:
62+
Enabled: false
63+
Style/TrailingCommaInHashLiteral:
64+
Enabled: false
65+
66+
# I don't like this so much but virtually needed for ffi struct layout
67+
Style/TrailingCommaInArguments:
68+
Enabled: false
69+
70+
# I don't want to fill my code with `.freeze`
71+
Style/MutableConstant:
72+
Enabled: false
73+
74+
# I have no idea why this is prohibited...
75+
Style/ParallelAssignment:
76+
Enabled: false
77+
78+
# Backrefs are indeed dirty, but `Regexp.last_match` is too verbose
79+
Style/PerlBackrefs:
80+
Enabled: false
81+
82+
# I think `{|ary| ary.size }` is not so bad since its type is explicit
83+
Style/SymbolProc:
84+
Enabled: false
85+
86+
# Wrapping a code is so bad? Case-by-case.
87+
Style/GuardClause:
88+
Enabled: false
89+
90+
# I use hyphen-separated case for script program.
91+
Naming/FileName:
92+
Exclude:
93+
- 'tools/*.rb'
94+
95+
# I don't care class/module size
96+
Metrics/ClassLength:
97+
Max: 1000
98+
Metrics/ModuleLength:
99+
Max: 1000
100+
101+
# I accept two-screen size (about 100 lines?)
102+
Metrics/MethodLength:
103+
Max: 100
104+
Metrics/BlockLength:
105+
Max: 100
106+
107+
# Don't worry, my terminal is big enough
108+
Layout/LineLength:
109+
Max: 120
110+
111+
# Code metrics is good, but I think the default is too strict...
112+
Metrics/CyclomaticComplexity:
113+
Max: 40
114+
Metrics/PerceivedComplexity:
115+
Max: 40
116+
Metrics/AbcSize:
117+
Max: 100
118+
Metrics/BlockNesting:
119+
Max: 5
120+
121+
# I like `x == 0`
122+
Style/NumericPredicate:
123+
EnforcedStyle: comparison
124+
125+
# I like `foo1` and `foo_bar_1`
126+
Naming/VariableNumber:
127+
Enabled: false
128+
129+
# empty is empty
130+
Style/EmptyMethod:
131+
Enabled: false
132+
Lint/EmptyWhen:
133+
Enabled: false
134+
135+
# if-elsif-elsif... looks awkward to me
136+
Style/EmptyCaseCondition:
137+
Enabled: false
138+
139+
# `rescue StandardError` looks redundant to me
140+
Style/RescueStandardError:
141+
Enabled: false
142+
143+
# `END` is always my heredoc delimiter
144+
Naming/HeredocDelimiterNaming:
145+
Enabled: false
146+
147+
# I like `%w()`
148+
Style/PercentLiteralDelimiters:
149+
PreferredDelimiters:
150+
'%w': '()'
151+
152+
# I cannot use `%i()` since I want to make this code run in 1.8
153+
Style/SymbolArray:
154+
EnforcedStyle: brackets
155+
156+
# `0 <= n && n <= 0x7f` is completely innocent
157+
Style/YodaCondition:
158+
Enabled: false
159+
160+
# I understand but `while true` is faster than `loop do`
161+
Lint/LiteralAsCondition:
162+
Enabled: false
163+
164+
# What I want to do is to puts a message to stderr, not to warn users
165+
Style/StderrPuts:
166+
Exclude:
167+
- 'tools/shim.rb'
168+
169+
# Leave me alone
170+
Style/CommentedKeyword:
171+
Enabled: false
172+
173+
# I want to casually use %s for simple format
174+
Style/FormatStringToken:
175+
Enabled: false
176+
177+
# Indeed, if having a single-line body is not so smart, but just not smart
178+
Style/IfUnlessModifier:
179+
Enabled: false
180+
181+
# Let me choose "" + ""
182+
Style/StringConcatenation:
183+
Enabled: false
184+
185+
# Keyword arguments cannot be used in Ruby 1.8
186+
Style/OptionalBooleanParameter:
187+
Enabled: false
188+
189+
# I don't use `Kernel#Array`
190+
Style/ArrayCoercion:
191+
Enabled: false
192+
193+
# `(1 + 1)**-1` looks awkward
194+
Layout/SpaceAroundOperators:
195+
Enabled: false
196+
197+
# One-letter variable is cute
198+
Naming/MethodParameterName:
199+
Enabled: false
200+
201+
# It highly depends on the context
202+
Layout/EmptyLineAfterGuardClause:
203+
Enabled: false
204+
205+
# Hash table literal is a kind of an art, difficult for machine
206+
Layout/HashAlignment:
207+
Enabled: false
208+
209+
# The program needs to work on old rubies
210+
Style/SafeNavigation:
211+
Enabled: false
212+
213+
# I want to use %w() only when the length is long
214+
Style/WordArray:
215+
Enabled: false
216+
217+
# I want to align lines
218+
Layout/SpaceAroundMethodCallOperator:
219+
Enabled: false
220+
221+
# shim is shim
222+
Layout/EmptyLinesAroundAttributeAccessor:
223+
Exclude:
224+
- 'tools/shim.rb'
225+
226+
# This is sometimes a good habit
227+
Style/RedundantAssignment:
228+
Enabled: false
229+
230+
# We support Ruby 1.8
231+
Gemspec/RequiredRubyVersion:
232+
Enabled: false
233+
234+
# Ruby 1.8 does not allow rescue clause in a block
235+
Style/RedundantBegin:
236+
Enabled: false
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
language: ruby
2+
rvm:
3+
- 2.7.1
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
source "https://rubygems.org"
2+
3+
gem "benchmark_driver", ">= 0.11.0", group: :development
4+
gem "ffi"
5+
gem "rake", group: [:development, :test]
6+
gem "rubocop", group: :development
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2016 Yusuke Endoh
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.
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# Optcarrot: A NES Emulator for Ruby Benchmark
2+
3+
## Project Goals
4+
5+
This project aims to provide an "enjoyable" benchmark for Ruby implementation to drive ["Ruby3x3: Ruby 3 will be 3 times faster"][ruby3x3].
6+
7+
The specific target is a NES (Nintendo Entertainment System) emulator that works at *20 fps* in Ruby 2.0. An original NES works at 60 fps. If Ruby3x3 is succeeded, we can enjoy a NES game with Ruby!
8+
9+
NOTE: We do *not* aim to create a practical NES emulator. There have been already many great emulators available. We recommend you use another emulator if you just want to play a game.
10+
11+
## Basic usage
12+
13+
SDL2 is required.
14+
15+
$ git clone http://github.com/mame/optcarrot.git
16+
$ cd optcarrot
17+
$ bin/optcarrot examples/Lan_Master.nes
18+
19+
|key |button |
20+
|------|-------------|
21+
|arrow |D-pad |
22+
|`Z` |A button |
23+
|`X` |B button |
24+
|space |Start button |
25+
|return|Select button|
26+
27+
See [`doc/bonus.md`](doc/bonus.md) for advanced usage.
28+
29+
## Benchmark example
30+
31+
Here is FPS after 3 seconds in the game's clock.
32+
33+
![benchmark chart](doc/benchmark-summary.png)
34+
35+
Here is FPS after 50 seconds in the game's clock. (Only fast implementations are listed.)
36+
37+
![benchmark chart for 3000 frames](doc/benchmark-summary-3000.png)
38+
39+
See [`doc/benchmark.md`](doc/benchmark.md) for the measurement condition and some other charts.
40+
41+
See also [Ruby Releases Benchmarks](https://rubybench.org/ruby/ruby/releases?result_type=Optcarrot%20Lan_Master.nes) and [Ruby Commits Benchmarks](https://rubybench.org/ruby/ruby/commits?result_type=Optcarrot%20Lan_Master.nes&display_count=2000) for the continuous benchmark results.
42+
43+
You may also want to read [@eregon's great post](https://eregon.me/blog/2016/11/28/optcarrot.html) for TruffleRuby potential performance after warm-up.
44+
45+
## Optimized mode
46+
47+
It may run faster with the option `--opt`.
48+
49+
$ bin/optcarrot --opt examples/Lan_Master.nes
50+
51+
This option will generate an optimized (and super-dirty) Ruby code internally, and replace some bottleneck methods with them. See [`doc/internal.md`](doc/internal.md) in detail.
52+
53+
## See also
54+
55+
* [Slide deck](http://www.slideshare.net/mametter/optcarrot-a-pureruby-nes-emulator) ([Tokyo RubyKaigi 11](http://regional.rubykaigi.org/tokyo11/en/))
56+
57+
## Acknowledgement
58+
59+
We appreciate all the people who devoted efforts to NES analysis. If it had not been not for the [NESdev Wiki][nesdev-wiki], we could not create this program. We also read the source code of Nestopia, NESICIDE, and others. We used the test ROMs due to NESICIDE.
60+
61+
[ruby3x3]: https://www.youtube.com/watch?v=LE0g2TUsJ4U&t=3248
62+
[nesdev-wiki]: http://wiki.nesdev.com/w/index.php/NES_reference_guide
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
task :test do
2+
ruby "tools/run-tests.rb"
3+
end
4+
5+
task :benchmark do
6+
ruby "tools/run-benchmark.rb", "all", "-m", "all", "-c", "10"
7+
end
8+
9+
task :wc do
10+
puts "lines of minimal source code:"
11+
sh "wc -l bin/optcarrot lib/optcarrot.rb lib/optcarrot/*.rb"
12+
end
13+
14+
task :"wc-all" do
15+
sh "wc -l bin/optcarrot lib/optcarrot.rb lib/optcarrot/*.rb lib/optcarrot/*/*.rb"
16+
end
17+
18+
task default: :test

0 commit comments

Comments
 (0)