Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Rubex: A new way of writing C extensions for CRuby

Rubex: A new way of writing C extensions for CRuby

Presented at Ruby Conf India 2017, Kochi.

Avatar for Sameer Deshmukh

Sameer Deshmukh

January 28, 2017
Tweet

More Decks by Sameer Deshmukh

Other Decks in Programming

Transcript

  1. Daru ­ Data Analysis in RUby A Ruby gem for

    analysis, plotting and cleaning of data.
  2. # In test.rb require ’fast_blank’ a = ”hello” a.blank? /*

    In fast_blank.c: */ VALUE rb_str_blank(VALUE str) CRuby C API Interfaces C code with the CRuby runtime
  3. BIG Problems • Difficult and irritating to write. • Debugging

    is time consuming. • Tough to trace memory leaks. • Change mindset from high level to low level language. • Remember the CRuby C API. • Need to care about small things.™* *Matz.
  4. int calc_addition(int a, int b) { return (a + b);

    } static VALUE caddition(VALUE self, VALUE a, VALUE b) { int i = FIX2INT(a); int j = FIX2INT(b); return INT2FIX(calc_addition(i, j)); }
  5. Rubex code Rubex compiler C code CRuby runtime Knows how

    to interface with the CRuby interpreter. Language which looks like Ruby. Code ready to interface with Ruby. Code actually runs here.
  6. static VALUE rb_str_blank(VALUE str) { // lots of unicode handling

    code omitted s = RSTRING_PTR(str); e = RSTRING_END(str); while (s < e) { // cc = current character if (!rb_isspace(cc) && cc != 0) return Qfalse; } return Qtrue; }
  7. def blank?(string) i32 i = 0 char *s = string

    i32 length = string.size while i < length do return false if s[i] != ' ' i += 1 end return true end
  8. def blank?(string) i32 i = 0 char *s = string

    i32 length = string.size while i < length do return false if s[i] != ' ' i += 1 end return true end
  9. def blank?(string) i32 i = 0 char *s = string

    i32 length = string.size while i < length do return false if s[i] != ' ' i += 1 end return true end
  10. def blank?(string) i32 i = 0 char *s = string

    i32 length = string.size while i < length do return false if s[i] != ' ' i += 1 end return true end
  11. Benchmarks • Comparison : fast_blank’s String#blank? vs. blank? implemented in

    Rubex. • Data : A Ruby String with 2500 spaces in the beginning and three ASCII letters at the end. Data taken so that non­trivial time will be spent on iterations to search for a white space. str = " "*2500 + "dff" • Result: This is new stuff is good.
  12. Benchmark-ips results Warming up -------------------------------------- fast_blank 3.401k i/100ms blank? 57.041k

    i/100ms Calculating ------------------------------------- fast_blank 35.068k (± 0.4%) i/s - 176.852k in 5.043263s blank? 671.289k (± 1.1%) i/s - 3.365M in 5.014016s Comparison: blank?: 671289.0 i/s fast_blank: 35067.6 i/s - 19.14x slower
  13. Conclusion of benchmarks: • fast_blank is not that fast for

    ASCII strings. • Now anybody can write C extensions with Rubex.
  14. Most important use case of Rubex • Not simply for

    abstracting away C code. • SciRuby works with many highly optimized C libraries like ATLAS, BLAS, FFTW & GSL. • These C libraries use complex API calls that need to be interfaced with Ruby with a lot of ‘glue’ code. • Glue code is a pain to write/debug.
  15. Interfacing external C libraries • Example : BLAS::gemm() method for

    multiplying two square matrices. gemm( const enum CBLAS_ORDER, const enum CBLAS_TRANSPOSE, const enum CBLAS_TRANSPOSE, const int, const int, const int, const double*, const double*, const int, const double*, const int, const double*, double*, const int )
  16. # In file maths.rubex lib math do double pow (double,

    double) double cos (double) end def maths(double power) double p = cos(0.5) return pow(p, power) end
  17. # In file maths.rubex lib math do double pow (double,

    double) double cos (double) end def maths(double power) double p = cos(0.5) return pow(p, power) end
  18. # In file maths.rubex lib math do double pow (double,

    double) double cos (double) end def maths(double power) double p = cos(0.5) return pow(p, power) end
  19. # In file maths.rubex lib math do double pow (double,

    double) double cos (double) end def maths(double power) double p = cos(0.5) return pow(p, power) end
  20. # In file maths.rubex lib math do double pow (double,

    double) double cos (double) end def maths(double power) double p = cos(0.5) return pow(p, power) end
  21. Rubex is meant to be a super set of Ruby

    and is as a companion of Ruby. It does not replace Ruby.
  22. Everything in Rubex is NOT an object. There can be

    both primitive C data types and Ruby objects co­existing in a single Rubex program.
  23. You can declare Abstract C Data Types like Structs, Unions

    and Enums using Rubex and pass them to arbitrary C functions.
  24. Future Roadmap • Support both native C and Ruby functions.

    • Ability to encapsulate methods in classes. • Introduce advanced heuristics to convert between C and Ruby data types. • Ability to release the Global Interpreter Lock and perform operations on native threads.