Skip to content

Commit de66be7

Browse files
author
Charlie Savage
committed
Try to fix test reports with test % over 100%. The problem is we assume there is only one top method but in fact there can be more than one. Examples include starting a profile and then returning from a method, profiling at exit blocks and exceptions.
1 parent 336c9ee commit de66be7

20 files changed

+129
-69
lines changed

ext/ruby_prof/rp_method.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ typedef struct
3131
prof_method_key_t *key; /* Method key */
3232
const char *source_file; /* The method's source file */
3333
int line; /* The method's line number. */
34-
struct prof_call_infos_t *call_infos; /* Call info objects for this method */
34+
struct prof_call_infos_t *call_infos; /* Call info objects for this method */
3535
VALUE object; /* Cached ruby object */
3636
VALUE call_infos2; /* Cached array of RubyProf::CallInfo */
3737
} prof_method_t;

ext/ruby_prof/rp_thread.c

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ thread_data_create()
1212
thread_data_t* result = ALLOC(thread_data_t);
1313
result->stack = prof_stack_create();
1414
result->method_table = method_table_create();
15-
result->top = NULL;
1615
result->object = Qnil;
1716
result->methods = Qnil;
1817
return result;
@@ -42,7 +41,6 @@ static void
4241
thread_data_free(thread_data_t* thread_data)
4342
{
4443
thread_data_ruby_gc_free(thread_data);
45-
thread_data->top = NULL;
4644
method_table_free(thread_data->method_table);
4745
prof_stack_free(thread_data->stack);
4846

@@ -68,7 +66,6 @@ prof_thread_mark(thread_data_t *thread)
6866
if (thread->methods != Qnil)
6967
rb_gc_mark(thread->methods);
7068

71-
prof_method_mark(thread->top);
7269
st_foreach(thread->method_table, mark_methods, 0);
7370
}
7471

@@ -179,6 +176,29 @@ switch_thread(void* prof, VALUE thread_id)
179176
return thread_data;
180177
}
181178

179+
180+
int pause_thread(st_data_t key, st_data_t value, st_data_t data)
181+
{
182+
thread_data_t* thread_data = (thread_data_t *) value;
183+
double measurement = (double) data;
184+
185+
prof_frame_t* frame = prof_stack_peek(thread_data->stack);
186+
prof_frame_pause(frame, measurement);
187+
188+
return ST_CONTINUE;
189+
}
190+
191+
int unpause_thread(st_data_t key, st_data_t value, st_data_t data)
192+
{
193+
thread_data_t* thread_data = (thread_data_t *) value;
194+
double measurement = (double) data;
195+
196+
prof_frame_t* frame = prof_stack_peek(thread_data->stack);
197+
prof_frame_unpause(frame, measurement);
198+
199+
return ST_CONTINUE;
200+
}
201+
182202
static int
183203
collect_methods(st_data_t key, st_data_t value, st_data_t result)
184204
{
@@ -220,24 +240,11 @@ prof_thread_methods(VALUE self)
220240
return thread->methods;
221241
}
222242

223-
/* call-seq:
224-
method -> MethodInfo
225-
226-
Returns the top level method for this thread (ie, the starting
227-
method). */
228-
static VALUE
229-
prof_thread_top_method(VALUE self)
230-
{
231-
thread_data_t* thread = prof_get_thread(self);
232-
return prof_method_wrap(thread->top);
233-
}
234-
235243
void rp_init_thread()
236244
{
237245
cRpThread = rb_define_class_under(mProf, "Thread", rb_cObject);
238246
rb_undef_method(CLASS_OF(cRpThread), "new");
239247

240248
rb_define_method(cRpThread, "id", prof_thread_id, 0);
241249
rb_define_method(cRpThread, "methods", prof_thread_methods, 0);
242-
rb_define_method(cRpThread, "top_method", prof_thread_top_method, 0);
243250
}

ext/ruby_prof/rp_thread.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ typedef struct
1212
VALUE thread_id; /* Thread id */
1313
st_table* method_table; /* Methods called in the thread */
1414
prof_stack_t* stack; /* Stack of frames */
15-
prof_method_t* top; /* The top method called in this thread */
1615
} thread_data_t;
1716

1817
void rp_init_thread();
@@ -21,6 +20,7 @@ thread_data_t* switch_thread(void* prof, VALUE thread_id);
2120
void threads_table_free(st_table *table);
2221
VALUE prof_thread_wrap(thread_data_t *thread);
2322
void prof_thread_mark(thread_data_t *thread);
24-
23+
int pause_thread(st_data_t key, st_data_t value, st_data_t data);
24+
int unpause_thread(st_data_t key, st_data_t value, st_data_t data);
2525

2626
#endif //__RP_THREAD__

ext/ruby_prof/ruby_prof.c

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -116,10 +116,6 @@ static prof_method_t*
116116

117117
method = create_method(event, klass, mid, source_file, line);
118118
method_table_insert(thread_data->method_table, method->key, method);
119-
120-
/* Is this the first method added to the thread? */
121-
if (!thread_data->top)
122-
thread_data->top = method;
123119
}
124120
return method;
125121
}

lib/ruby-prof.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
require 'ruby-prof/method_info'
1616
require 'ruby-prof/profile'
1717
require 'ruby-prof/rack'
18+
require 'ruby-prof/thread'
1819

1920
require 'ruby-prof/printers/abstract_printer'
2021
require 'ruby-prof/printers/call_info_printer'

lib/ruby-prof/call_info_visitor.rb

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,10 @@ def initialize(thread)
2626
def visit(&block)
2727
@block = block
2828

29-
self.thread.top_method.call_infos.each do |call_info|
30-
self.visit_call_info(call_info)
29+
self.thread.top_methods.each do |method_info|
30+
method_info.call_infos.each do |call_info|
31+
self.visit_call_info(call_info)
32+
end
3133
end
3234
end
3335

lib/ruby-prof/printers/call_info_printer.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class CallInfoPrinter < AbstractPrinter
1212

1313
def print_header(thread)
1414
@output << "Thread ID: #{thread.id}\n"
15-
@output << "Total Time: #{thread.top_method.total_time}\n"
15+
@output << "Total Time: #{thread.total_time}\n"
1616
@output << "Sort by: #{sort_method}\n"
1717
@output << "\n"
1818
end

lib/ruby-prof/printers/call_stack_printer.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,20 +45,20 @@ def print(output = STDOUT, options = {})
4545
print_header
4646

4747
@overall_threads_time = @result.threads.inject(0) do |val, thread|
48-
val += thread.top_method.total_time
48+
val += thread.total_time
4949
end
5050

5151
@result.threads.each do |thread|
5252
@current_thread_id = thread.id
53-
@overall_time = thread.top_method.total_time
53+
@overall_time = thread.total_time
5454
@output.print "<div class=\"thread\">Thread: #{thread.id} (#{"%4.2f%%" % ((@overall_time/@overall_threads_time)*100)} ~ #{@overall_time})</div>"
5555
@output.print "<ul name=\"thread\">"
5656
thread.methods.each do |m|
5757
# $stderr.print m.dump
5858
next unless m.root?
5959
m.call_infos.each do |ci|
6060
next unless ci.root?
61-
print_stack ci, thread.top_method.total_time
61+
print_stack ci, thread.total_time
6262
end
6363
end
6464
@output.print "</ul>"

lib/ruby-prof/printers/dot_printer.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ def dot_id(subject)
7979
end
8080

8181
def print_thread(thread)
82-
total_time = thread.top_method.total_time
82+
total_time = thread.total_time
8383
thread.methods.sort_by(&sort_method).reverse_each do |method|
8484
total_percentage = (method.total_time/total_time) * 100
8585

lib/ruby-prof/printers/flat_printer.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,14 @@ def sort_method
2828

2929
def print_header(thread)
3030
@output << "Thread ID: %d\n" % thread.id
31-
@output << "Total: %0.6f\n" % thread.top_method.total_time
31+
@output << "Total: %0.6f\n" % thread.total_time
3232
@output << "Sort by: #{sort_method}\n"
3333
@output << "\n"
34-
@output << " %self total self wait child calls name\n"
34+
@output << " %self total self wait child calls name\n"
3535
end
3636

3737
def print_methods(thread)
38-
total_time = thread.top_method.total_time
38+
total_time = thread.total_time
3939
methods = thread.methods.sort_by(&sort_method).reverse
4040

4141
sum = 0
@@ -47,7 +47,7 @@ def print_methods(thread)
4747
#self_time_called = method.called > 0 ? method.self_time/method.called : 0
4848
#total_time_called = method.called > 0? method.total_time/method.called : 0
4949

50-
@output << "%6.2f %8.2f %8.2f %8.2f %8.2f %8d %s%s \n" % [
50+
@output << "%6.2f %9.3f %9.3f %9.3f %9.3f %8d %s%s \n" % [
5151
method.self_time / total_time * 100, # %self
5252
method.total_time, # total
5353
method.self_time, # self

0 commit comments

Comments
 (0)