1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

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

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@47508 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
normal 2014-09-10 06:14:07 +00:00
parent fd31eb3f5c
commit ea4c97904e
6 changed files with 90 additions and 30 deletions

View file

@ -1,3 +1,22 @@
Wed Sep 10 15:07:35 2014 Eric Wong <e@80x24.org>
* 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@80x24.org> Wed Sep 10 15:00:11 2014 Eric Wong <e@80x24.org>
* time.c (time_mark): remove NULL check * time.c (time_mark): remove NULL check

View file

@ -569,21 +569,56 @@ rb_iseq_translate_threaded_code(rb_iseq_t *iseq)
const void * const *table = rb_vm_get_insns_address_table(); const void * const *table = rb_vm_get_insns_address_table();
unsigned int i; 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; /* */ ) { for (i = 0; i < iseq->iseq_size; /* */ ) {
int insn = (int)iseq->iseq_encoded[i]; int insn = (int)iseq->iseq_encoded[i];
int len = insn_len(insn); int len = insn_len(insn);
iseq->iseq_encoded[i] = (VALUE)table[insn]; iseq->iseq_encoded[i] = (VALUE)table[insn];
i += len; i += len;
} }
#else
iseq->iseq_encoded = iseq->iseq;
#endif #endif
return COMPILE_OK; 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 */ /* definition of data structure for compiler */
/*********************************************/ /*********************************************/
@ -1645,7 +1680,7 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *anchor)
} }
#endif #endif
iseq->iseq = (void *)generated_iseq; iseq->iseq_encoded = (void *)generated_iseq;
iseq->iseq_size = pos; iseq->iseq_size = pos;
iseq->stack_max = stack_max; iseq->stack_max = stack_max;

38
iseq.c
View file

@ -75,11 +75,7 @@ iseq_free(void *ptr)
RSTRING_PTR(iseq->location.path)); RSTRING_PTR(iseq->location.path));
} }
if (iseq->iseq != iseq->iseq_encoded) {
RUBY_FREE_UNLESS_NULL(iseq->iseq_encoded); RUBY_FREE_UNLESS_NULL(iseq->iseq_encoded);
}
RUBY_FREE_UNLESS_NULL(iseq->iseq);
RUBY_FREE_UNLESS_NULL(iseq->line_info_table); RUBY_FREE_UNLESS_NULL(iseq->line_info_table);
RUBY_FREE_UNLESS_NULL(iseq->local_table); RUBY_FREE_UNLESS_NULL(iseq->local_table);
RUBY_FREE_UNLESS_NULL(iseq->is_entries); RUBY_FREE_UNLESS_NULL(iseq->is_entries);
@ -88,6 +84,7 @@ iseq_free(void *ptr)
RUBY_FREE_UNLESS_NULL(iseq->arg_opt_table); RUBY_FREE_UNLESS_NULL(iseq->arg_opt_table);
RUBY_FREE_UNLESS_NULL(iseq->arg_keyword_table); RUBY_FREE_UNLESS_NULL(iseq->arg_keyword_table);
compile_data_free(iseq->compile_data); compile_data_free(iseq->compile_data);
RUBY_FREE_UNLESS_NULL(iseq->iseq);
} }
ruby_xfree(ptr); ruby_xfree(ptr);
} }
@ -134,10 +131,6 @@ iseq_memsize(const void *ptr)
if (ptr) { if (ptr) {
iseq = ptr; iseq = ptr;
if (!iseq->orig) { if (!iseq->orig) {
if (iseq->iseq != iseq->iseq_encoded) {
size += iseq->iseq_size * sizeof(VALUE);
}
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->line_info_size * sizeof(struct iseq_line_info_entry);
size += iseq->local_table_size * sizeof(ID); size += iseq->local_table_size * sizeof(ID);
@ -158,6 +151,9 @@ iseq_memsize(const void *ptr)
} }
size += sizeof(struct iseq_compile_data); size += sizeof(struct iseq_compile_data);
} }
if (iseq->iseq) {
size += iseq->iseq_size * sizeof(VALUE);
}
} }
} }
@ -1392,7 +1388,6 @@ rb_iseq_disasm(VALUE self)
rb_secure(1); rb_secure(1);
iseq = iseqdat->iseq;
size = iseqdat->iseq_size; size = iseqdat->iseq_size;
rb_str_cat2(str, "== disasm: "); rb_str_cat2(str, "== disasm: ");
@ -1472,6 +1467,7 @@ rb_iseq_disasm(VALUE self)
} }
/* show each line */ /* show each line */
iseq = rb_iseq_original_iseq(iseqdat);
for (n = 0; n < size;) { for (n = 0; n < size;) {
n += rb_iseq_disasm_insn(str, iseq, n, iseqdat, child); n += rb_iseq_disasm_insn(str, iseq, n, iseqdat, child);
} }
@ -1658,7 +1654,7 @@ iseq_data_to_ary(rb_iseq_t *iseq)
size_t ti; size_t ti;
unsigned int pos; unsigned int pos;
unsigned int line = 0; unsigned int line = 0;
VALUE *seq; VALUE *seq, *iseq_original;
VALUE val = rb_ary_new(); VALUE val = rb_ary_new();
VALUE type; /* Symbol */ VALUE type; /* Symbol */
@ -1759,7 +1755,9 @@ iseq_data_to_ary(rb_iseq_t *iseq)
} }
/* body */ /* 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++; VALUE insn = *seq++;
int j, len = insn_len(insn); int j, len = insn_len(insn);
VALUE *nseq = seq + len - 1; VALUE *nseq = seq + len - 1;
@ -1769,7 +1767,7 @@ iseq_data_to_ary(rb_iseq_t *iseq)
for (j=0; j<len-1; j++, seq++) { for (j=0; j<len-1; j++, seq++) {
switch (insn_op_type(insn, j)) { switch (insn_op_type(insn, j)) {
case TS_OFFSET: { 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)); rb_ary_push(ary, register_label(labels_table, idx));
break; break;
} }
@ -1828,7 +1826,7 @@ iseq_data_to_ary(rb_iseq_t *iseq)
for (i=0; i<RARRAY_LEN(val); i+=2) { for (i=0; i<RARRAY_LEN(val); i+=2) {
VALUE pos = FIX2INT(rb_ary_entry(val, i+1)); 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, rb_ary_store(val, i+1,
register_label(labels_table, idx)); register_label(labels_table, idx));
@ -2100,11 +2098,11 @@ rb_iseq_build_for_ruby2cext(
RB_OBJ_WRITE(iseq->self, &iseq->mark_ary, 0); RB_OBJ_WRITE(iseq->self, &iseq->mark_ary, 0);
iseq->self = iseqval; 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) { for (i=0; i<iseq->iseq_size; i+=2) {
iseq->iseq[i] = BIN(opt_call_c_function); iseq->iseq_encoded[i] = BIN(opt_call_c_function);
iseq->iseq[i+1] = (VALUE)func; iseq->iseq_encoded[i+1] = (VALUE)func;
} }
rb_iseq_translate_threaded_code(iseq); rb_iseq_translate_threaded_code(iseq);
@ -2148,13 +2146,15 @@ rb_iseq_line_trace_each(VALUE iseqval, int (*func)(int line, rb_event_flag_t *ev
size_t insn; size_t insn;
rb_iseq_t *iseq; rb_iseq_t *iseq;
int cont = 1; int cont = 1;
VALUE *iseq_original;
GetISeqPtr(iseqval, iseq); GetISeqPtr(iseqval, iseq);
iseq_original = rb_iseq_original_iseq(iseq);
for (pos = 0; cont && pos < iseq->iseq_size; pos += insn_len(insn)) { for (pos = 0; cont && pos < iseq->iseq_size; pos += insn_len(insn)) {
insn = iseq->iseq[pos]; insn = iseq_original[pos];
if (insn == BIN(trace)) { 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) { if (current_events & RUBY_EVENT_LINE) {
rb_event_flag_t events = current_events & RUBY_EVENT_SPECIFIED_LINE; rb_event_flag_t events = current_events & RUBY_EVENT_SPECIFIED_LINE;
@ -2165,7 +2165,7 @@ rb_iseq_line_trace_each(VALUE iseqval, int (*func)(int line, rb_event_flag_t *ev
/* printf("line: %d\n", line); */ /* printf("line: %d\n", line); */
cont = (*func)(line, &events, data); cont = (*func)(line, &events, data);
if (current_events != events) { 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)); (VALUE)(current_events | (events & RUBY_EVENT_SPECIFIED_LINE));
} }
} }

1
iseq.h
View file

@ -17,6 +17,7 @@ RUBY_SYMBOL_EXPORT_BEGIN
/* compile.c */ /* compile.c */
VALUE rb_iseq_compile_node(VALUE self, NODE *node); VALUE rb_iseq_compile_node(VALUE self, NODE *node);
int rb_iseq_translate_threaded_code(rb_iseq_t *iseq); 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 rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE locals, VALUE args,
VALUE exception, VALUE body); VALUE exception, VALUE body);

View file

@ -212,8 +212,7 @@ struct rb_iseq_struct {
rb_iseq_location_t location; rb_iseq_location_t location;
VALUE *iseq; /* iseq (insn number and operands) */ VALUE *iseq_encoded; /* encoded iseq (insn addr and operands) */
VALUE *iseq_encoded; /* encoded iseq */
unsigned int iseq_size; unsigned int iseq_size;
unsigned int line_info_size; unsigned int line_info_size;
@ -309,6 +308,10 @@ struct rb_iseq_struct {
/* used at compile time */ /* used at compile time */
struct iseq_compile_data *compile_data; 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 { enum ruby_special_exceptions {

View file

@ -13,6 +13,7 @@
#include "addr2line.h" #include "addr2line.h"
#include "vm_core.h" #include "vm_core.h"
#include "internal.h" #include "internal.h"
#include "iseq.h"
/* see vm_insnhelper.h for the values */ /* see vm_insnhelper.h for the values */
#ifndef VMDEBUG #ifndef VMDEBUG
@ -359,7 +360,6 @@ rb_vmdebug_debug_print_pre(rb_thread_t *th, rb_control_frame_t *cfp,VALUE *_pc)
rb_iseq_t *iseq = cfp->iseq; rb_iseq_t *iseq = cfp->iseq;
if (iseq != 0) { if (iseq != 0) {
VALUE *seq = iseq->iseq;
ptrdiff_t pc = _pc - iseq->iseq_encoded; ptrdiff_t pc = _pc - iseq->iseq_encoded;
int i; int i;
@ -371,7 +371,9 @@ rb_vmdebug_debug_print_pre(rb_thread_t *th, rb_control_frame_t *cfp,VALUE *_pc)
/* printf("%3"PRIdPTRDIFF" ", VM_CFP_CNT(th, cfp)); */ /* printf("%3"PRIdPTRDIFF" ", VM_CFP_CNT(th, cfp)); */
if (pc >= 0) { 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);
} }
} }