Skip to content

Commit 0c3b9a4

Browse files
committedMay 11, 2016
Added simple, per-thread, random interval sampling.
This is mostly a temporary experiment that will likely be replaced with a calling-context tree or similar structure and a separate profiler thread.
1 parent a81c173 commit 0c3b9a4

File tree

7 files changed

+73
-1
lines changed

7 files changed

+73
-1
lines changed
 

‎core/compiled_code.rb

+6-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,12 @@ def self.of_sender
4444

4545
def jitted?
4646
Rubinius.primitive :compiledcode_jitted_p
47-
raise PrimitiveFailure, "CompiledCode.jitted? primitive failed"
47+
raise PrimitiveFailure, "CompiledCode#jitted? primitive failed"
48+
end
49+
50+
def sample_count
51+
Rubinius.primitive :compiledcode_sample_count
52+
raise PrimitiveFailure, "CompiledCode#sample_count primitive failed"
4853
end
4954

5055
# Returns the CompiledCode object for the currently executing Ruby

‎machine/builtin/compiled_code.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,10 @@ namespace rubinius {
370370
return RBOOL(machine_code() && machine_code()->jitted_p());
371371
}
372372

373+
Fixnum* CompiledCode::sample_count(STATE) {
374+
return Fixnum::from(machine_code()->sample_count);
375+
}
376+
373377
Object* CompiledCode::execute_script(STATE) {
374378
state->thread_state()->clear();
375379

‎machine/builtin/compiled_code.hpp

+3
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,9 @@ namespace rubinius {
127127
// Rubinius.primitive :compiledcode_jitted_p
128128
Object* jitted_p(STATE);
129129

130+
// Rubinius.primitive :compiledcode_sample_count
131+
Fixnum* sample_count(STATE);
132+
130133
String* full_name(STATE);
131134

132135
bool core_method(STATE);

‎machine/machine_code.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ namespace rubinius {
5858
, splat_position(-1)
5959
, stack_size(code->stack_size()->to_native())
6060
, number_of_locals(code->number_of_locals())
61+
, sample_count(0)
6162
, call_count(0)
6263
, uncommon_count(0)
6364
, _call_site_count_(0)

‎machine/machine_code.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ namespace rubinius {
6969
native_int stack_size;
7070
native_int number_of_locals;
7171

72+
native_int sample_count;
7273
native_int call_count;
7374
native_int uncommon_count;
7475

‎machine/vm.cpp

+48
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,10 @@ namespace rubinius {
8787
, current_fiber(this, nil<Fiber>())
8888
, root_fiber(this, nil<Fiber>())
8989
, waiting_object_(this, cNil)
90+
, profile_(this, nil<Tuple>())
91+
, profile_sample_count_(0)
92+
, max_profile_entries_(15)
93+
, min_profile_call_count_(0)
9094
, native_method_environment(NULL)
9195
, custom_wakeup_(NULL)
9296
, custom_wakeup_data_(NULL)
@@ -252,6 +256,50 @@ namespace rubinius {
252256
memory()->collect_maybe(state);
253257
}
254258

259+
static int profile_compare(const void* a, const void* b) {
260+
const CompiledCode* c_a = try_as<CompiledCode>(*(const Object**)(a));
261+
const CompiledCode* c_b = try_as<CompiledCode>(*(const Object**)(b));
262+
263+
if(c_a && c_b) {
264+
return c_a->machine_code()->call_count - c_b->machine_code()->call_count;
265+
} else if(c_a) {
266+
return 1;
267+
} else if(c_b) {
268+
return -1;
269+
} else {
270+
return 0;
271+
}
272+
}
273+
274+
void VM::update_profile(STATE) {
275+
profile_sample_count_++;
276+
277+
CompiledCode* code = state->vm()->call_frame()->compiled_code;
278+
code->machine_code()->sample_count++;
279+
280+
Tuple* profile = profile_.get();
281+
282+
if(profile->nil_p()) {
283+
profile = Tuple::create(state, max_profile_entries_);
284+
profile_.set(profile);
285+
}
286+
287+
::qsort(reinterpret_cast<void*>(profile->field), profile->num_fields(),
288+
sizeof(intptr_t), profile_compare);
289+
290+
for(native_int i = 0; i < profile->num_fields(); i++) {
291+
if(code == profile->at(i)) return;
292+
}
293+
294+
CompiledCode* pcode = try_as<CompiledCode>(profile->at(0));
295+
if(!pcode || (pcode &&
296+
code->machine_code()->call_count > pcode->machine_code()->call_count))
297+
{
298+
profile->put(state, 0, code);
299+
min_profile_call_count_ = code->machine_code()->call_count;
300+
}
301+
}
302+
255303
static void suspend_thread() {
256304
static int i = 0;
257305
static int delay[] = {

‎machine/vm.hpp

+10
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ namespace rubinius {
5858
class Symbol;
5959
class ConfigParser;
6060
class TypeError;
61+
class Tuple;
6162
class Assertion;
6263
struct CallFrame;
6364
class CallSiteInformation;
@@ -143,6 +144,11 @@ namespace rubinius {
143144
/// Object that waits for inflation
144145
memory::TypedRoot<Object*> waiting_object_;
145146

147+
memory::TypedRoot<Tuple*> profile_;
148+
uint64_t profile_sample_count_;
149+
native_int max_profile_entries_;
150+
native_int min_profile_call_count_;
151+
146152
NativeMethodEnvironment* native_method_environment;
147153

148154
void (*custom_wakeup_)(void*);
@@ -407,6 +413,8 @@ namespace rubinius {
407413

408414
void collect_maybe(STATE);
409415

416+
void update_profile(STATE);
417+
410418
#define RBX_PROFILE_MAX_SHIFT 0xf
411419
#define RBX_PROFILE_MAX_INTERVAL 0x1fff
412420

@@ -429,6 +437,8 @@ namespace rubinius {
429437
thread_nexus_->unlock();
430438
}
431439

440+
update_profile(state);
441+
432442
set_profile_interval();
433443
}
434444
}

0 commit comments

Comments
 (0)
Please sign in to comment.