24 July 2014

C Extension Notes

Dan Mayer
Dan Mayer @danmayer

These are unorganized notes from building a c extension, I found it in the drafts folder and figured it might as well be set free.

Building a Ruby Gem with a C extension

Notes

Examples

Gotchas

  • If you are compiling locally over and over, it appears that the .o files from install gems will stick around. You need to gem uninstall the native gem and reinstall it to pick up your changes.

Perf Progress

ab -n 100 -c5 http://admin.lsdev.co:80/

No Coverband

Time taken for tests: 3.980 seconds / 3.999 seconds

Ruby Coverband

Time taken for tests: 31.489 seconds / 29.064 seconds

Ruby Coverband C Ext V1

Time taken for tests: 14.679 seconds / 12.033 seconds

Ruby Coverband C Ext V2 with Regex

Time taken for tests: 6.131 seconds / 6.321 seconds

PL app

ab -n 50 -c5 http://pipeline.lsdev.co:80/pipeline/cities

No Coverband

Time taken for tests: 31.347 seconds / 31.298 seconds

Ruby Coverband

(moved to, so slow ab -n 10 -c5 http://pipeline.lsdev.co:80/pipeline/cities, then multiplied by 5 to keep the numbers in line) Time taken for tests: 336.53 seconds / 331.89 seconds

Ruby Coverband C Ext V2 with Regex (back to the default 50 requests)

Time taken for tests: 42.785 seconds / 43.343 seconds

C code to debug

    rb_eval_string("puts 'self is:'");
    rb_funcall(rb_mKernel, rb_intern("puts"), 1, self);
    rb_eval_string("puts 'klass is:'");
    rb_funcall(rb_mKernel, rb_intern("puts"), 1, klass);

Warnings I need to fix

    make
    compiling coverband_ext.c
	coverband_ext.c:44:23: warning: incompatible pointer types passing 'void (VALUE, VALUE, VALUE, ID, VALUE)' to parameter of type 'rb_event_hook_func_t' (aka 'void (*)(rb_event_flag_t, VALUE, VALUE, ID, VALUE)') [-Wincompatible-pointer-types]
    rb_add_event_hook(trace_line_handler_ext, RUBY_EVENT_LINE, 0);
	                      ^~~~~~~~~~~~~~~~~~~~~~
	/opt/boxen/rbenv/versions/1.9.3-p448/include/ruby-1.9.1/ruby/ruby.h:1427:45: note: passing argument to parameter 'func' here
	void rb_add_event_hook(rb_event_hook_func_t func, rb_event_flag_t events,
	                                            ^
	coverband_ext.c:45:15: error: use of undeclared identifier 'bindval'
    rb_iv_set(bindval, "@tracer_set", Qtrue);
	              ^
	coverband_ext.c:53:24: warning: incompatible pointer types passing 'void (VALUE, VALUE, VALUE, ID, VALUE)' to parameter of type 'rb_event_hook_func_t' (aka 'void (*)(rb_event_flag_t, VALUE, VALUE, ID, VALUE)') [-Wincompatible-pointer-types]
	  rb_remove_event_hook(trace_line_handler_ext);
	                       ^~~~~~~~~~~~~~~~~~~~~~
	/opt/boxen/rbenv/versions/1.9.3-p448/include/ruby-1.9.1/ruby/ruby.h:1429:47: note: passing argument to parameter 'func' here
	int rb_remove_event_hook(rb_event_hook_func_t func);
	                                              ^
	2 warnings and 1 error generated.
	make: *** [coverband_ext.o] Error 1  

C Extension Code examples

Working with ifdef to detect and deal with ruby version differences

    #if defined(RUBY_VM)
      #include <ruby/re.h>
      #include <ruby/intern.h>
    
      #if defined(HAVE_RB_PROFILE_FRAMES)
        #include <ruby/debug.h>
      #else
        #include <vm_core.h>
        #include <iseq.h>
        // There's a compile error on 1.9.3. So:
        #ifdef RTYPEDDATA_DATA
          #define ruby_current_thread ((rb_thread_t *)RTYPEDDATA_DATA(rb_thread_current()))
        #endif
      #endif
    #else
      #include <st.h>
      #include <re.h>
      #include <intern.h>
      #include <node.h>
      #include <env.h>
      typedef rb_event_t rb_event_flag_t;
    #endif

flame graphs in miniprofiler

try with adding ALL the headers to the folder

https://github.com/banister/binding_of_caller/tree/master/ext/binding_of_caller/ruby_headers/193

https://github.com/banister/binding_of_caller/blob/master/ext/binding_of_caller/extconf.rb

https://github.com/banister/binding_of_caller/blob/master/ext/binding_of_caller/binding_of_caller.c

plane does this as well to work on 1.9.2 and 1.9.3

https://github.com/soba1104/PLine/blob/master/ext/pline/ruby_source/1.9.3/vm_core.h

good ifdef examples as I move beyond and try to get it working on 193 and 2.1

https://github.com/tmm1/rblineprof/blob/master/ext/rblineprof.c

good book on working on ruby core code

http://ruby-hacking-guide.github.io/evaluator.html

more about trace

https://bugs.ruby-lang.org/issues/2565

WHERE LINE NUMBS COME FROM IN 1.9.3

http://rxr.whitequark.org/mri/source/vm.c?v=1.9.3-p547#888

1.9.3 set trace fun

http://apidock.com/ruby/Kernel/set_trace_func

calling a method

http://blog.x-aeon.com/2012/12/13/the-ruby-c-api-basics/#TRCAB_Calling

sharing data between C and ruby http://www.eqqon.com/index.php/Ruby_C_Extension_API_Documentation_(Ruby_1.8)

ruby c cheet sheet http://blog.jacius.info/ruby-c-extension-cheat-sheet/

more on set_TRace_Func

http://aphyr.com/posts/173-monkeypatching-is-for-wimps-use-set-trace-func

http://ruby-doc.org/core-1.9.3/Kernel.html#method-i-set_trace_func

http://t-a-w.blogspot.com/2007/04/settracefunc-smoke-and-mirrors.html

on creating a proc object

http://www.ruby-doc.org/core-1.9.3/Proc.html

example c code

https://github.com/tmm1/rbtrace/blob/master/ext/rbtrace.c

extending ruby

http://phrogz.net/programmingruby/ext_ruby.html

Dtrace

https://bugs.ruby-lang.org/issues/2565

Categories

Ruby