FastOsc
A Ruby wrapper around rtosc to encode and decode OSC messages.
This also includes a fallback implementation in pure Ruby in the case that the compiled version doesn't load properly. This can be forced by setting an environment variable of FAST_OSC_USE_FALLBACK=1
where needed.
Installation
Add this line to your application's Gemfile:
gem 'fast_osc'
And then execute:
$ bundle
Or install it yourself as:
$ gem install fast_osc
Is it fast?
Let's see...
Key:
fast_osc
- this gemosc
-osc-ruby
samsosc
-OSC
classes from Sonic Pi (which are optimised pure Ruby based onpack
andunpack
)
Encoding Benchmark
Warming up --------------------------------------
fast_osc 64.995k i/100ms
samsosc 23.371k i/100ms
osc-ruby 7.691k i/100ms
Calculating -------------------------------------
fast_osc 797.673k (±15.0%) i/s - 3.900M in 5.043770s
samsosc 258.331k (±12.8%) i/s - 1.285M in 5.063755s
osc-ruby 83.203k (±12.6%) i/s - 415.314k in 5.073578s
Decoding Bencmark
Warming up --------------------------------------
fast_osc 102.344k i/100ms
samsosc 20.770k i/100ms
osc-ruby 3.145k i/100ms
Calculating -------------------------------------
fast_osc 1.650M (±14.5%) i/s - 8.085M in 5.017162s
samsosc 234.951k (±14.0%) i/s - 1.163M in 5.049167s
osc-ruby 34.266k (±13.3%) i/s - 169.830k in 5.048509s
Benchmarks are now part of this repo - run rake test
to see the results for yourself.
What about Truffle Ruby?
A high performance implementation of the Ruby programming language. Built on GraalVM by Oracle Labs.
Just for fun, I re-ran the benchmarks using TruffleRuby. First some install steps:
git clone this repo
bundle install
export PATH="/usr/local/opt/llvm@4/bin:$PATH"
rake clean && rake compile
then the test:
$ rake test
ENCODING TEST
Warming up --------------------------------------
fast_osc 3.000 i/100ms
samsosc 28.219k i/100ms
osc-ruby 234.000 i/100ms
Calculating -------------------------------------
fast_osc 33.294 (±45.1%) i/s - 129.000 in 5.295649s
samsosc 1.369M (±33.5%) i/s - 3.556M in 5.010343s
osc-ruby 274.170k (±20.2%) i/s - 1.064M in 4.971832s
DECODING TEST
Warming up --------------------------------------
fast_osc 9.000 i/100ms
samsosc 6.087k i/100ms
osc-ruby 418.000 i/100ms
Calculating -------------------------------------
fast_osc 71.034 (±45.0%) i/s - 261.000 in 5.015393s
samsosc 114.443k (±70.2%) i/s - 261.741k in 5.283892s
osc-ruby 84.236k (±34.7%) i/s - 237.424k in 5.317738s
# update - retested using rc5
ENCODING TEST
Warming up --------------------------------------
fast_osc 106.000 i/100ms
samsosc 999.000 i/100ms
osc-ruby 159.000 i/100ms
Calculating -------------------------------------
fast_osc 24.507k (±28.6%) i/s - 83.316k in 4.984544s
samsosc 1.494M (±22.4%) i/s - 2.785M in 4.988822s
osc-ruby 265.322k (±26.5%) i/s - 597.522k in 5.014127s
DECODING TEST
Warming up --------------------------------------
fast_osc 173.000 i/100ms
samsosc 454.000 i/100ms
osc-ruby 208.000 i/100ms
Calculating -------------------------------------
fast_osc 73.712k (±66.4%) i/s - 163.831k in 5.049410s
samsosc 325.920k (±33.7%) i/s - 875.766k in 4.989279s
osc-ruby 63.624k (±52.3%) i/s - 129.792k in 5.005088s
Run options: --seed 56032
The Good
The encoding benchmark - the optimised pure Ruby version is nearly as fast as the C extension!
# C ext in MRI
fast_osc 797.673k (±15.0%) i/s - 3.900M in 5.043770s
# Pure Ruby in Truffle rc3
samsosc 1.369M (±33.5%) i/s - 3.556M in 5.010343s
# Pure Ruby in Truffle rc5
samsosc 1.494M (±22.4%) i/s - 2.785M in 4.988822s
The Bad
Decoding was generally slower, although the (non optimised) osc gem seemed to prefer TruffleRuby, running around 40% faster.
~Also the performance of the C extension in TruffleRuby was very, very poor but this may be due to not warming up enough.~ update - this appears to be better in rc5.
Usage
>> FastOsc.encode_single_message("/foo", ["baz", 1, 2.0])
=> "/foo\x00\x00\x00\x00,sif\x00\x00\x00\x00baz\x00\x00\x00\x00\x01@\x00\x00\x00"
>> res = _
>> FastOsc.decode_single_message(res)
=> ["/foo", ["baz", 1, 2.0]]
>> FastOsc.encode_single_bundle(Time.now.to_i, "/foo", ["baz", 1, 2.0])
=> "#bundle\x00\x00\x00\x00\x00W*1\x7F\x00\x00\x00\x1C/foo\x00\x00\x00\x00,sif\x00\x00\x00\x00baz\x00\x00\x00\x00\x01@\x00\x00\x00"
See the test suite for additional methods regarding bundles with timestamps. Bundles are only supported with a single message at present. A timestamp of nil
is a special case meaning "immediately".
Running the test suite
$ gem install minitest # or bundle install
$ rake clean && rake clobber && rake compile && rake test
Still todo
- [x] Implement more types
- [x] Bring benchmarks into the repo
- [ ] Work out cross compilation story for easier packaging
- [x] Implement multi message/nested bundles
- [ ] More documentation
- [x] Travis
Development notes
bundle install
rake compile
https://gist.github.com/xavriley/507eff0a75d4552fa56e
Contributing
- Fork it ( http://github.com/
/fast_osc/fork ) - Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create new Pull Request