ruby-changes:35426
From: normal <ko1@a...>
Date: Wed, 10 Sep 2014 15:14:22 +0900 (JST)
Subject: [ruby-changes:35426] normal:r47508 (trunk): compile: translate iseq in-place
normal 2014-09-10 15:14:07 +0900 (Wed, 10 Sep 2014) New Revision: 47508 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=47508 Log: compile: translate iseq in-place running "ruby -rpp -e 'pp GC.stat'", a reduction in malloc usage is shown: before: :malloc_increase=>118784, :oldmalloc_increase=>1178736, after: :malloc_increase=>99832, :oldmalloc_increase=>1031976, For "ruby -e exit", valgrind reports over 300K reduction in overall allocations (and unnecessary memory copies). before: total heap usage: 49,622 allocs, 20,492 frees, 8,697,493 bytes allocated after: total heap usage: 48,935 allocs, 19,805 frees, 8,373,773 bytes allocated (numbers from x86-64) v2 changes based on ko1 recommendations [ruby-core:64883]: - squashed in-place direct thread translation to avoid alloc+copy - renamed rb_iseq_untranslate_threaded_code to rb_iseq_original_iseq, cache new iseq->iseq_original field. * compile.c (rb_iseq_translate_threaded_code): modify in-place w/o copy (rb_vm_addr2insn): new function for debug (rb_iseq_original_iseq): ditto (iseq_set_sequence): assign iseq_encoded directly [Feature #10185] * vm_core (rb_iseq_t): move original ->iseq to bottom * iseq.c (iseq_free, iseq_free): adjust for new layout (rb_iseq_disasm): use original iseq for dump (iseq_data_to_ary): ditto (rb_iseq_line_trace_each): ditto (rb_iseq_build_for_ruby2cext): use iseq_encoded directly * vm_dump.c (rb_vmdebug_debug_print_pre): use original iseq Modified files: trunk/ChangeLog trunk/compile.c trunk/iseq.c trunk/iseq.h trunk/vm_core.h trunk/vm_dump.c Index: ChangeLog =================================================================== --- ChangeLog (revision 47507) +++ ChangeLog (revision 47508) @@ -1,3 +1,22 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 +Wed Sep 10 15:07:35 2014 Eric Wong <e@8...> + + * compile.c (rb_iseq_translate_threaded_code): + modify in-place w/o copy + (rb_vm_addr2insn): new function for debug + (rb_iseq_original_iseq): ditto + (iseq_set_sequence): assign iseq_encoded directly + [Feature #10185] + + * vm_core (rb_iseq_t): move original ->iseq to bottom + + * iseq.c (iseq_free, iseq_free): adjust for new layout + (rb_iseq_disasm): use original iseq for dump + (iseq_data_to_ary): ditto + (rb_iseq_line_trace_each): ditto + (rb_iseq_build_for_ruby2cext): use iseq_encoded directly + + * vm_dump.c (rb_vmdebug_debug_print_pre): use original iseq + Wed Sep 10 15:00:11 2014 Eric Wong <e@8...> * time.c (time_mark): remove NULL check Index: vm_core.h =================================================================== --- vm_core.h (revision 47507) +++ vm_core.h (revision 47508) @@ -212,8 +212,7 @@ struct rb_iseq_struct { https://github.com/ruby/ruby/blob/trunk/vm_core.h#L212 rb_iseq_location_t location; - VALUE *iseq; /* iseq (insn number and operands) */ - VALUE *iseq_encoded; /* encoded iseq */ + VALUE *iseq_encoded; /* encoded iseq (insn addr and operands) */ unsigned int iseq_size; unsigned int line_info_size; @@ -309,6 +308,10 @@ struct rb_iseq_struct { https://github.com/ruby/ruby/blob/trunk/vm_core.h#L308 /* used at compile time */ struct iseq_compile_data *compile_data; + + /* original iseq, before encoding + * used for debug/dump (TODO: union with compile_data) */ + VALUE *iseq; }; enum ruby_special_exceptions { Index: iseq.c =================================================================== --- iseq.c (revision 47507) +++ iseq.c (revision 47508) @@ -75,11 +75,7 @@ iseq_free(void *ptr) https://github.com/ruby/ruby/blob/trunk/iseq.c#L75 RSTRING_PTR(iseq->location.path)); } - if (iseq->iseq != iseq->iseq_encoded) { - RUBY_FREE_UNLESS_NULL(iseq->iseq_encoded); - } - - RUBY_FREE_UNLESS_NULL(iseq->iseq); + RUBY_FREE_UNLESS_NULL(iseq->iseq_encoded); RUBY_FREE_UNLESS_NULL(iseq->line_info_table); RUBY_FREE_UNLESS_NULL(iseq->local_table); RUBY_FREE_UNLESS_NULL(iseq->is_entries); @@ -88,6 +84,7 @@ iseq_free(void *ptr) https://github.com/ruby/ruby/blob/trunk/iseq.c#L84 RUBY_FREE_UNLESS_NULL(iseq->arg_opt_table); RUBY_FREE_UNLESS_NULL(iseq->arg_keyword_table); compile_data_free(iseq->compile_data); + RUBY_FREE_UNLESS_NULL(iseq->iseq); } ruby_xfree(ptr); } @@ -134,10 +131,6 @@ iseq_memsize(const void *ptr) https://github.com/ruby/ruby/blob/trunk/iseq.c#L131 if (ptr) { iseq = ptr; if (!iseq->orig) { - if (iseq->iseq != iseq->iseq_encoded) { - size += iseq->iseq_size * sizeof(VALUE); - } - size += iseq->iseq_size * sizeof(VALUE); size += iseq->line_info_size * sizeof(struct iseq_line_info_entry); size += iseq->local_table_size * sizeof(ID); @@ -158,6 +151,9 @@ iseq_memsize(const void *ptr) https://github.com/ruby/ruby/blob/trunk/iseq.c#L151 } size += sizeof(struct iseq_compile_data); } + if (iseq->iseq) { + size += iseq->iseq_size * sizeof(VALUE); + } } } @@ -1392,7 +1388,6 @@ rb_iseq_disasm(VALUE self) https://github.com/ruby/ruby/blob/trunk/iseq.c#L1388 rb_secure(1); - iseq = iseqdat->iseq; size = iseqdat->iseq_size; rb_str_cat2(str, "== disasm: "); @@ -1472,6 +1467,7 @@ rb_iseq_disasm(VALUE self) https://github.com/ruby/ruby/blob/trunk/iseq.c#L1467 } /* show each line */ + iseq = rb_iseq_original_iseq(iseqdat); for (n = 0; n < size;) { n += rb_iseq_disasm_insn(str, iseq, n, iseqdat, child); } @@ -1658,7 +1654,7 @@ iseq_data_to_ary(rb_iseq_t *iseq) https://github.com/ruby/ruby/blob/trunk/iseq.c#L1654 size_t ti; unsigned int pos; unsigned int line = 0; - VALUE *seq; + VALUE *seq, *iseq_original; VALUE val = rb_ary_new(); VALUE type; /* Symbol */ @@ -1759,7 +1755,9 @@ iseq_data_to_ary(rb_iseq_t *iseq) https://github.com/ruby/ruby/blob/trunk/iseq.c#L1755 } /* body */ - for (seq = iseq->iseq; seq < iseq->iseq + iseq->iseq_size; ) { + iseq_original = rb_iseq_original_iseq(iseq); + + for (seq = iseq_original; seq < iseq_original + iseq->iseq_size; ) { VALUE insn = *seq++; int j, len = insn_len(insn); VALUE *nseq = seq + len - 1; @@ -1769,7 +1767,7 @@ iseq_data_to_ary(rb_iseq_t *iseq) https://github.com/ruby/ruby/blob/trunk/iseq.c#L1767 for (j=0; j<len-1; j++, seq++) { switch (insn_op_type(insn, j)) { case TS_OFFSET: { - unsigned long idx = nseq - iseq->iseq + *seq; + unsigned long idx = nseq - iseq_original + *seq; rb_ary_push(ary, register_label(labels_table, idx)); break; } @@ -1828,7 +1826,7 @@ iseq_data_to_ary(rb_iseq_t *iseq) https://github.com/ruby/ruby/blob/trunk/iseq.c#L1826 for (i=0; i<RARRAY_LEN(val); i+=2) { VALUE pos = FIX2INT(rb_ary_entry(val, i+1)); - unsigned long idx = nseq - iseq->iseq + pos; + unsigned long idx = nseq - iseq_original + pos; rb_ary_store(val, i+1, register_label(labels_table, idx)); @@ -2100,11 +2098,11 @@ rb_iseq_build_for_ruby2cext( https://github.com/ruby/ruby/blob/trunk/iseq.c#L2098 RB_OBJ_WRITE(iseq->self, &iseq->mark_ary, 0); iseq->self = iseqval; - iseq->iseq = ALLOC_N(VALUE, iseq->iseq_size); + iseq->iseq_encoded = ALLOC_N(VALUE, iseq->iseq_size); for (i=0; i<iseq->iseq_size; i+=2) { - iseq->iseq[i] = BIN(opt_call_c_function); - iseq->iseq[i+1] = (VALUE)func; + iseq->iseq_encoded[i] = BIN(opt_call_c_function); + iseq->iseq_encoded[i+1] = (VALUE)func; } rb_iseq_translate_threaded_code(iseq); @@ -2148,13 +2146,15 @@ rb_iseq_line_trace_each(VALUE iseqval, i https://github.com/ruby/ruby/blob/trunk/iseq.c#L2146 size_t insn; rb_iseq_t *iseq; int cont = 1; + VALUE *iseq_original; GetISeqPtr(iseqval, iseq); + iseq_original = rb_iseq_original_iseq(iseq); for (pos = 0; cont && pos < iseq->iseq_size; pos += insn_len(insn)) { - insn = iseq->iseq[pos]; + insn = iseq_original[pos]; if (insn == BIN(trace)) { - rb_event_flag_t current_events = (VALUE)iseq->iseq[pos+1]; + rb_event_flag_t current_events = (VALUE)iseq_original[pos+1]; if (current_events & RUBY_EVENT_LINE) { rb_event_flag_t events = current_events & RUBY_EVENT_SPECIFIED_LINE; @@ -2165,7 +2165,7 @@ rb_iseq_line_trace_each(VALUE iseqval, i https://github.com/ruby/ruby/blob/trunk/iseq.c#L2165 /* printf("line: %d\n", line); */ cont = (*func)(line, &events, data); if (current_events != events) { - iseq->iseq[pos+1] = iseq->iseq_encoded[pos+1] = + iseq_original[pos+1] = iseq->iseq_encoded[pos+1] = (VALUE)(current_events | (events & RUBY_EVENT_SPECIFIED_LINE)); } } Index: iseq.h =================================================================== --- iseq.h (revision 47507) +++ iseq.h (revision 47508) @@ -17,6 +17,7 @@ RUBY_SYMBOL_EXPORT_BEGIN https://github.com/ruby/ruby/blob/trunk/iseq.h#L17 /* compile.c */ VALUE rb_iseq_compile_node(VALUE self, NODE *node); int rb_iseq_translate_threaded_code(rb_iseq_t *iseq); +VALUE *rb_iseq_original_iseq(rb_iseq_t *iseq); VALUE rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE locals, VALUE args, VALUE exception, VALUE body); Index: compile.c =================================================================== --- compile.c (revision 47507) +++ compile.c (revision 47508) @@ -569,21 +569,56 @@ rb_iseq_translate_threaded_code(rb_iseq_ https://github.com/ruby/ruby/blob/trunk/compile.c#L569 const void * const *table = rb_vm_get_insns_address_table(); unsigned int i; - iseq->iseq_encoded = ALLOC_N(VALUE, iseq->iseq_size); - MEMCPY(iseq->iseq_encoded, iseq->iseq, VALUE, iseq->iseq_size); - for (i = 0; i < iseq->iseq_size; /* */ ) { int insn = (int)iseq->iseq_encoded[i]; int len = insn_len(insn); iseq->iseq_encoded[i] = (VALUE)table[insn]; i += len; } -#else - iseq->iseq_encoded = iseq->iseq; #endif return COMPILE_OK; } +#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE +static int +rb_vm_addr2insn(const void *addr) /* cold path */ +{ + int insn; + const void * const *table = rb_vm_get_insns_address_table(); + + for (insn = 0; insn < VM_INSTRUCTION_SIZE; insn++) { + if (table[insn] == addr) + return insn; + } + rb_bug("rb_vm_addr2insn: invalid insn address: %p", addr); +} +#endif + +VALUE * +rb_iseq_original_iseq(rb_iseq_t *iseq) /* cold path */ +{ + if (iseq->iseq) return iseq->iseq; + + iseq->iseq = ALLOC_N(VALUE, iseq->iseq_size); + + MEMCPY(iseq->iseq, iseq->iseq_encoded, VALUE, iseq->iseq_size); + +#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE + { + unsigned int i; + + for (i = 0; i < iseq->iseq_size; /* */ ) { + const void *addr = (const void *)iseq->iseq[i]; + int insn = (VALUE)rb_vm_addr2insn(addr); + + iseq->iseq[i] = insn; + i += insn_len(insn); + } + } +#endif + return iseq->iseq; +} + /*********************************************/ /* definition of data structure for compiler */ /*********************************************/ @@ -1645,7 +1680,7 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ https://github.com/ruby/ruby/blob/trunk/compile.c#L1680 } #endif - iseq->iseq = (void *)generated_iseq; + iseq->iseq_encoded = (void *)generated_iseq; iseq->iseq_size = pos; iseq->stack_max = stack_max; Index: vm_dump.c =================================================================== --- vm_dump.c (revision 47507) +++ vm_dump.c (revision 47508) @@ -13,6 +13,7 @@ https://github.com/ruby/ruby/blob/trunk/vm_dump.c#L13 #include "addr2line.h" #include "vm_core.h" #include "internal.h" +#include "iseq.h" /* see vm_insnhelper.h for the values */ #ifndef VMDEBUG @@ -359,7 +360,6 @@ rb_vmdebug_debug_print_pre(rb_thread_t * https://github.com/ruby/ruby/blob/trunk/vm_dump.c#L360 rb_iseq_t *iseq = cfp->iseq; if (iseq != 0) { - VALUE *seq = iseq->iseq; ptrdiff_t pc = _pc - iseq->iseq_encoded; int i; @@ -371,7 +371,9 @@ rb_vmdebug_debug_print_pre(rb_thread_t * https://github.com/ruby/ruby/blob/trunk/vm_dump.c#L371 /* printf("%3"PRIdPTRDIFF" ", VM_CFP_CNT(th, cfp)); */ if (pc >= 0) { - rb_iseq_disasm_insn(0, seq, (size_t)pc, iseq, 0); + const VALUE *iseq_original = rb_iseq_original_iseq(iseq); + + rb_iseq_disasm_insn(0, iseq_original, (size_t)pc, iseq, 0); } } -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/