ext/ruby_prof/rp_method.c in ruby-prof-1.1.0 vs ext/ruby_prof/rp_method.c in ruby-prof-1.2.0
- old
+ new
@@ -1,17 +1,16 @@
/* Copyright (C) 2005-2019 Shugo Maeda <shugo@ruby-lang.org> and Charlie Savage <cfis@savagexi.com>
Please see the LICENSE file for copyright and distribution information */
#include "rp_allocation.h"
-#include "rp_call_info.h"
+#include "rp_call_trees.h"
#include "rp_method.h"
VALUE cRpMethodInfo;
/* ================ Helper Functions =================*/
-VALUE
-resolve_klass(VALUE klass, unsigned int *klass_flags)
+VALUE resolve_klass(VALUE klass, unsigned int* klass_flags)
{
VALUE result = klass;
if (klass == 0 || klass == Qnil)
{
@@ -60,12 +59,11 @@
result = resolve_klass(RBASIC(klass)->klass, &dummy);
}
return result;
}
-VALUE
-resolve_klass_name(VALUE klass, unsigned int* klass_flags)
+VALUE resolve_klass_name(VALUE klass, unsigned int* klass_flags)
{
VALUE result = Qnil;
if (klass == Qnil)
{
@@ -81,12 +79,11 @@
}
return result;
}
-st_data_t
-method_key(VALUE klass, VALUE msym)
+st_data_t method_key(VALUE klass, VALUE msym)
{
VALUE resolved_klass = klass;
/* Is this an include for a module? If so get the actual
module class since we want to combine all profiling
@@ -102,50 +99,44 @@
return (resolved_klass << 4) + (msym);
}
/* ====== Allocation Table ====== */
-st_table*
-allocations_table_create()
+st_table* allocations_table_create()
{
- return st_init_numtable();
+ return rb_st_init_numtable();
}
-static int
-allocations_table_free_iterator(st_data_t key, st_data_t value, st_data_t dummy)
-{
+static int allocations_table_free_iterator(st_data_t key, st_data_t value, st_data_t dummy)
+{
prof_allocation_free((prof_allocation_t*)value);
return ST_CONTINUE;
}
-static int
-prof_method_collect_allocations(st_data_t key, st_data_t value, st_data_t result)
+static int prof_method_collect_allocations(st_data_t key, st_data_t value, st_data_t result)
{
prof_allocation_t* allocation = (prof_allocation_t*)value;
VALUE arr = (VALUE)result;
rb_ary_push(arr, prof_allocation_wrap(allocation));
return ST_CONTINUE;
}
-static int
-prof_method_mark_allocations(st_data_t key, st_data_t value, st_data_t data)
+static int prof_method_mark_allocations(st_data_t key, st_data_t value, st_data_t data)
{
prof_allocation_t* allocation = (prof_allocation_t*)value;
prof_allocation_mark(allocation);
return ST_CONTINUE;
}
-void
-allocations_table_free(st_table* table)
+void allocations_table_free(st_table* table)
{
- st_foreach(table, allocations_table_free_iterator, 0);
- st_free_table(table);
+ rb_st_foreach(table, allocations_table_free_iterator, 0);
+ rb_st_free_table(table);
}
/* ================ prof_method_t =================*/
-static prof_method_t*
-prof_get_method(VALUE self)
+prof_method_t* prof_get_method(VALUE self)
{
/* Can't use Data_Get_Struct because that triggers the event hook
ending up in endless recursion. */
prof_method_t* result = DATA_PTR(self);
@@ -153,31 +144,26 @@
rb_raise(rb_eRuntimeError, "This RubyProf::MethodInfo instance has already been freed, likely because its profile has been freed.");
return result;
}
-prof_method_t*
-prof_method_create(VALUE klass, VALUE msym, VALUE source_file, int source_line)
+prof_method_t* prof_method_create(VALUE klass, VALUE msym, VALUE source_file, int source_line)
{
- prof_method_t *result = ALLOC(prof_method_t);
+ prof_method_t* result = ALLOC(prof_method_t);
result->key = method_key(klass, msym);
result->klass_flags = 0;
- /* Note we do not call resolve_klass_name now because that causes an object allocation that shows up
+ /* Note we do not call resolve_klass_name now because that causes an object allocation that shows up
in the allocation results so we want to avoid it until after the profile run is complete. */
result->klass = resolve_klass(klass, &result->klass_flags);
result->klass_name = Qnil;
result->method_name = msym;
result->measurement = prof_measurement_create();
- result->root = false;
- result->excluded = false;
-
- result->parent_call_infos = method_table_create();
- result->child_call_infos = method_table_create();
+ result->call_trees = prof_call_trees_create();
result->allocations_table = allocations_table_create();
-
+
result->visits = 0;
result->recursive = false;
result->object = Qnil;
@@ -185,184 +171,112 @@
result->source_line = source_line;
return result;
}
-prof_method_t*
-prof_method_create_excluded(VALUE klass, VALUE msym)
-{
- prof_method_t* result = prof_method_create(klass, msym, Qnil, 0);
- result->excluded = 1;
- return result;
-}
-
-static int
-prof_method_collect_call_infos(st_data_t key, st_data_t value, st_data_t result)
-{
- prof_call_info_t* call_info = (prof_call_info_t*)value;
- VALUE arr = (VALUE)result;
- rb_ary_push(arr, prof_call_info_wrap(call_info));
- return ST_CONTINUE;
-}
-
-static int
-prof_method_mark_call_infos(st_data_t key, st_data_t value, st_data_t data)
-{
- prof_call_info_t* call_info = (prof_call_info_t*)value;
- prof_call_info_mark(call_info);
- return ST_CONTINUE;
-}
-
-static int
-call_infos_free_iterator(st_data_t key, st_data_t value, st_data_t dummy)
-{
- prof_call_info_free((prof_call_info_t*)value);
- return ST_CONTINUE;
-}
-
-void
-call_info_table_free(st_table* table)
-{
- st_foreach(table, call_infos_free_iterator, 0);
- st_free_table(table);
-}
-
/* The underlying c structures are freed when the parent profile is freed.
However, on shutdown the Ruby GC frees objects in any will-nilly order.
That means the ruby thread object wrapping the c thread struct may
be freed before the parent profile. Thus we add in a free function
for the garbage collector so that if it does get called will nil
out our Ruby object reference.*/
-static void
-prof_method_ruby_gc_free(void *data)
+static void prof_method_ruby_gc_free(void* data)
{
prof_method_t* method = (prof_method_t*)data;
+ method->object = Qnil;
+}
+static void prof_method_free(prof_method_t* method)
+{
/* Has this method object been accessed by Ruby? If
- yes clean it up so to avoid a segmentation fault. */
- if (method->object != Qnil)
- {
+ yes clean it up so to avoid a segmentation fault. */
+ if (method->object != Qnil)
+ {
RDATA(method->object)->dmark = NULL;
RDATA(method->object)->dfree = NULL;
RDATA(method->object)->data = NULL;
method->object = Qnil;
}
- method->klass_name = Qnil;
- method->method_name = Qnil;
-}
-static void
-prof_method_free(prof_method_t* method)
-{
- prof_method_ruby_gc_free(method);
allocations_table_free(method->allocations_table);
-
- /* Remember call infos are referenced by their parent method and child method, so we only want
- to iterate over one of them to avoid a double freeing */
- call_info_table_free(method->parent_call_infos);
- xfree(method->child_call_infos);
-
+ prof_call_trees_free(method->call_trees);
prof_measurement_free(method->measurement);
xfree(method);
}
-size_t
-prof_method_size(const void *data)
+size_t prof_method_size(const void* data)
{
return sizeof(prof_method_t);
}
-void
-prof_method_mark(void *data)
+void prof_method_mark(void* data)
{
prof_method_t* method = (prof_method_t*)data;
+
+ if (method->object != Qnil)
+ rb_gc_mark(method->object);
+
rb_gc_mark(method->klass_name);
rb_gc_mark(method->method_name);
-
+ rb_gc_mark(method->source_file);
+
if (method->klass != Qnil)
rb_gc_mark(method->klass);
- if (method->object != Qnil)
- rb_gc_mark(method->object);
-
prof_measurement_mark(method->measurement);
-
- st_foreach(method->parent_call_infos, prof_method_mark_call_infos, 0);
- st_foreach(method->child_call_infos, prof_method_mark_call_infos, 0);
- st_foreach(method->allocations_table, prof_method_mark_allocations, 0);
+
+ rb_st_foreach(method->allocations_table, prof_method_mark_allocations, 0);
}
-static VALUE
-prof_method_allocate(VALUE klass)
+static VALUE prof_method_allocate(VALUE klass)
{
prof_method_t* method_data = prof_method_create(Qnil, Qnil, Qnil, 0);
method_data->object = prof_method_wrap(method_data);
return method_data->object;
}
-VALUE
-prof_method_wrap(prof_method_t *method)
+VALUE prof_method_wrap(prof_method_t* method)
{
- if (method->object == Qnil)
- {
- method->object = Data_Wrap_Struct(cRpMethodInfo, prof_method_mark, prof_method_ruby_gc_free, method);
- }
- return method->object;
-}
-
-prof_method_t *
-prof_method_get(VALUE self)
-{
- /* Can't use Data_Get_Struct because that triggers the event hook
- ending up in endless recursion. */
- prof_method_t* result = DATA_PTR(self);
-
- if (!result)
+ if (method->object == Qnil)
{
- rb_raise(rb_eRuntimeError, "This RubyProf::MethodInfo instance has already been freed, likely because its profile has been freed.");
- }
-
- return result;
+ method->object = Data_Wrap_Struct(cRpMethodInfo, prof_method_mark, prof_method_ruby_gc_free, method);
+ }
+ return method->object;
}
-st_table *
-method_table_create()
+st_table* method_table_create()
{
- return st_init_numtable();
+ return rb_st_init_numtable();
}
-static int
-method_table_free_iterator(st_data_t key, st_data_t value, st_data_t dummy)
+static int method_table_free_iterator(st_data_t key, st_data_t value, st_data_t dummy)
{
- prof_method_free((prof_method_t *)value);
+ prof_method_free((prof_method_t*)value);
return ST_CONTINUE;
}
-void
-method_table_free(st_table *table)
+void method_table_free(st_table* table)
{
- st_foreach(table, method_table_free_iterator, 0);
- st_free_table(table);
+ rb_st_foreach(table, method_table_free_iterator, 0);
+ rb_st_free_table(table);
}
-size_t
-method_table_insert(st_table *table, st_data_t key, prof_method_t *val)
+size_t method_table_insert(st_table* table, st_data_t key, prof_method_t* val)
{
- return st_insert(table, (st_data_t) key, (st_data_t) val);
+ return rb_st_insert(table, (st_data_t)key, (st_data_t)val);
}
-prof_method_t *
-method_table_lookup(st_table *table, st_data_t key)
+prof_method_t* method_table_lookup(st_table* table, st_data_t key)
{
st_data_t val;
- if (st_lookup(table, (st_data_t)key, &val))
+ if (rb_st_lookup(table, (st_data_t)key, &val))
{
- return (prof_method_t *) val;
+ return (prof_method_t*)val;
}
else
{
- return NULL;
+ return NULL;
}
}
/* ================ Method Info =================*/
/* Document-class: RubyProf::MethodInfo
@@ -373,54 +287,26 @@
created. RubyProf::MethodInfo objects can be accessed via
the RubyProf::Profile object.
*/
/* call-seq:
- callers -> array
-
-Returns an array of call info objects that called this method (ie, parents).*/
-static VALUE
-prof_method_callers(VALUE self)
-{
- prof_method_t* method = prof_get_method(self);
- VALUE result = rb_ary_new();
- st_foreach(method->parent_call_infos, prof_method_collect_call_infos, result);
- return result;
-}
-
-/* call-seq:
- callees -> array
-
-Returns an array of call info objects that this method called (ie, children).*/
-static VALUE
-prof_method_callees(VALUE self)
-{
- prof_method_t* method = prof_get_method(self);
- VALUE result = rb_ary_new();
- st_foreach(method->child_call_infos, prof_method_collect_call_infos, result);
- return result;
-}
-
-/* call-seq:
allocations -> array
Returns an array of allocation information.*/
-static VALUE
-prof_method_allocations(VALUE self)
+static VALUE prof_method_allocations(VALUE self)
{
prof_method_t* method = prof_get_method(self);
VALUE result = rb_ary_new();
- st_foreach(method->allocations_table, prof_method_collect_allocations, result);
+ rb_st_foreach(method->allocations_table, prof_method_collect_allocations, result);
return result;
}
/* call-seq:
called -> Measurement
Returns the measurement associated with this method. */
-static VALUE
-prof_method_measurement(VALUE self)
+static VALUE prof_method_measurement(VALUE self)
{
prof_method_t* method = prof_get_method(self);
return prof_measurement_wrap(method->measurement);
}
@@ -429,35 +315,33 @@
return the source file of the method
*/
static VALUE prof_method_source_file(VALUE self)
{
- prof_method_t* method = prof_method_get(self);
+ prof_method_t* method = prof_get_method(self);
return method->source_file;
}
/* call-seq:
line_no -> int
returns the line number of the method */
-static VALUE
-prof_method_line(VALUE self)
+static VALUE prof_method_line(VALUE self)
{
- prof_method_t* method = prof_method_get(self);
+ prof_method_t* method = prof_get_method(self);
return INT2FIX(method->source_line);
}
/* call-seq:
klass_name -> string
Returns the name of this method's class. Singleton classes
will have the form <Object::Object>. */
-static VALUE
-prof_method_klass_name(VALUE self)
+static VALUE prof_method_klass_name(VALUE self)
{
- prof_method_t *method = prof_method_get(self);
+ prof_method_t* method = prof_get_method(self);
if (method->klass_name == Qnil)
method->klass_name = resolve_klass_name(method->klass, &method->klass_flags);
return method->klass_name;
}
@@ -465,139 +349,99 @@
/* call-seq:
klass_flags -> integer
Returns the klass flags */
-static VALUE
-prof_method_klass_flags(VALUE self)
+static VALUE prof_method_klass_flags(VALUE self)
{
- prof_method_t* method = prof_method_get(self);
+ prof_method_t* method = prof_get_method(self);
return INT2FIX(method->klass_flags);
}
/* call-seq:
method_name -> string
Returns the name of this method in the format Object#method. Singletons
methods will be returned in the format <Object::Object>#method.*/
-static VALUE
-prof_method_name(VALUE self)
+static VALUE prof_method_name(VALUE self)
{
- prof_method_t *method = prof_method_get(self);
+ prof_method_t* method = prof_get_method(self);
return method->method_name;
}
/* call-seq:
- root? -> boolean
-
- Returns the true if this method is at the top of the call stack */
-static VALUE
-prof_method_root(VALUE self)
-{
- prof_method_t *method = prof_method_get(self);
- return method->root ? Qtrue : Qfalse;
-}
-
-/* call-seq:
recursive? -> boolean
Returns the true if this method is recursively invoked */
-static VALUE
-prof_method_recursive(VALUE self)
+static VALUE prof_method_recursive(VALUE self)
{
- prof_method_t* method = prof_method_get(self);
+ prof_method_t* method = prof_get_method(self);
return method->recursive ? Qtrue : Qfalse;
}
/* call-seq:
- excluded? -> boolean
+ call_trees -> CallTrees
- Returns the true if this method was excluded */
-static VALUE
-prof_method_excluded(VALUE self)
+Returns the CallTrees associated with this method. */
+static VALUE prof_method_call_trees(VALUE self)
{
- prof_method_t* method = prof_method_get(self);
- return method->excluded ? Qtrue : Qfalse;
+ prof_method_t* method = prof_get_method(self);
+ return prof_call_trees_wrap(method->call_trees);
}
/* :nodoc: */
-static VALUE
-prof_method_dump(VALUE self)
+static VALUE prof_method_dump(VALUE self)
{
prof_method_t* method_data = DATA_PTR(self);
VALUE result = rb_hash_new();
rb_hash_aset(result, ID2SYM(rb_intern("klass_name")), prof_method_klass_name(self));
rb_hash_aset(result, ID2SYM(rb_intern("klass_flags")), INT2FIX(method_data->klass_flags));
rb_hash_aset(result, ID2SYM(rb_intern("method_name")), method_data->method_name);
rb_hash_aset(result, ID2SYM(rb_intern("key")), INT2FIX(method_data->key));
- rb_hash_aset(result, ID2SYM(rb_intern("root")), prof_method_root(self));
rb_hash_aset(result, ID2SYM(rb_intern("recursive")), prof_method_recursive(self));
- rb_hash_aset(result, ID2SYM(rb_intern("excluded")), prof_method_excluded(self));
rb_hash_aset(result, ID2SYM(rb_intern("source_file")), method_data->source_file);
rb_hash_aset(result, ID2SYM(rb_intern("source_line")), INT2FIX(method_data->source_line));
+ rb_hash_aset(result, ID2SYM(rb_intern("call_trees")), prof_call_trees_wrap(method_data->call_trees));
rb_hash_aset(result, ID2SYM(rb_intern("measurement")), prof_measurement_wrap(method_data->measurement));
-
- rb_hash_aset(result, ID2SYM(rb_intern("callers")), prof_method_callers(self));
- rb_hash_aset(result, ID2SYM(rb_intern("callees")), prof_method_callees(self));
-
rb_hash_aset(result, ID2SYM(rb_intern("allocations")), prof_method_allocations(self));
return result;
}
/* :nodoc: */
-static VALUE
-prof_method_load(VALUE self, VALUE data)
+static VALUE prof_method_load(VALUE self, VALUE data)
{
prof_method_t* method_data = RDATA(self)->data;
method_data->object = self;
method_data->klass_name = rb_hash_aref(data, ID2SYM(rb_intern("klass_name")));
method_data->klass_flags = FIX2INT(rb_hash_aref(data, ID2SYM(rb_intern("klass_flags"))));
method_data->method_name = rb_hash_aref(data, ID2SYM(rb_intern("method_name")));
method_data->key = FIX2LONG(rb_hash_aref(data, ID2SYM(rb_intern("key"))));
- method_data->root = rb_hash_aref(data, ID2SYM(rb_intern("root"))) == Qtrue ? true : false;
method_data->recursive = rb_hash_aref(data, ID2SYM(rb_intern("recursive"))) == Qtrue ? true : false;
- method_data->excluded = rb_hash_aref(data, ID2SYM(rb_intern("excluded"))) == Qtrue ? true : false;
method_data->source_file = rb_hash_aref(data, ID2SYM(rb_intern("source_file")));
method_data->source_line = FIX2INT(rb_hash_aref(data, ID2SYM(rb_intern("source_line"))));
+ VALUE call_trees = rb_hash_aref(data, ID2SYM(rb_intern("call_trees")));
+ method_data->call_trees = prof_get_call_trees(call_trees);
+
VALUE measurement = rb_hash_aref(data, ID2SYM(rb_intern("measurement")));
method_data->measurement = prof_get_measurement(measurement);
- VALUE callers = rb_hash_aref(data, ID2SYM(rb_intern("callers")));
- for (int i = 0; i < rb_array_len(callers); i++)
- {
- VALUE call_info = rb_ary_entry(callers, i);
- prof_call_info_t *call_info_data = prof_get_call_info(call_info);
- st_data_t key = call_info_data->parent ? call_info_data->parent->key : method_key(Qnil, 0);
- call_info_table_insert(method_data->parent_call_infos, key, call_info_data);
- }
-
- VALUE callees = rb_hash_aref(data, ID2SYM(rb_intern("callees")));
- for (int i = 0; i < rb_array_len(callees); i++)
- {
- VALUE call_info = rb_ary_entry(callees, i);
- prof_call_info_t *call_info_data = prof_get_call_info(call_info);
-
- st_data_t key = call_info_data->method ? call_info_data->method->key : method_key(Qnil, 0);
- call_info_table_insert(method_data->child_call_infos, key, call_info_data);
- }
-
VALUE allocations = rb_hash_aref(data, ID2SYM(rb_intern("allocations")));
for (int i = 0; i < rb_array_len(allocations); i++)
{
VALUE allocation = rb_ary_entry(allocations, i);
prof_allocation_t* allocation_data = prof_allocation_get(allocation);
- st_insert(method_data->allocations_table, allocation_data->key, (st_data_t)allocation_data);
+ rb_st_insert(method_data->allocations_table, allocation_data->key, (st_data_t)allocation_data);
}
return data;
}
void rp_init_method_info()
@@ -607,24 +451,20 @@
rb_undef_method(CLASS_OF(cRpMethodInfo), "new");
rb_define_alloc_func(cRpMethodInfo, prof_method_allocate);
rb_define_method(cRpMethodInfo, "klass_name", prof_method_klass_name, 0);
rb_define_method(cRpMethodInfo, "klass_flags", prof_method_klass_flags, 0);
-
rb_define_method(cRpMethodInfo, "method_name", prof_method_name, 0);
-
- rb_define_method(cRpMethodInfo, "callers", prof_method_callers, 0);
- rb_define_method(cRpMethodInfo, "callees", prof_method_callees, 0);
- rb_define_method(cRpMethodInfo, "allocations", prof_method_allocations, 0);
+ rb_define_method(cRpMethodInfo, "call_trees", prof_method_call_trees, 0);
+
+ rb_define_method(cRpMethodInfo, "allocations", prof_method_allocations, 0);
rb_define_method(cRpMethodInfo, "measurement", prof_method_measurement, 0);
-
+
rb_define_method(cRpMethodInfo, "source_file", prof_method_source_file, 0);
rb_define_method(cRpMethodInfo, "line", prof_method_line, 0);
- rb_define_method(cRpMethodInfo, "root?", prof_method_root, 0);
rb_define_method(cRpMethodInfo, "recursive?", prof_method_recursive, 0);
- rb_define_method(cRpMethodInfo, "excluded?", prof_method_excluded, 0);
rb_define_method(cRpMethodInfo, "_dump_data", prof_method_dump, 0);
rb_define_method(cRpMethodInfo, "_load_data", prof_method_load, 1);
-}
+}
\ No newline at end of file