vm: sampling profiler timer for windows

Spawn a thread and have it spin on the performance counter, triggering safepoints on the main thread every sample time
db4
Joe Groff 2011-10-31 14:38:49 -07:00
parent 981862f35e
commit 1351e30e52
5 changed files with 60 additions and 16 deletions

View File

@ -170,18 +170,18 @@ void factor_vm::enqueue_safepoint_fep()
code->guard_safepoint();
}
void factor_vm::enqueue_safepoint_sample(cell pc, bool foreign_thread_p)
void factor_vm::enqueue_safepoint_sample(cell samples, cell pc, bool foreign_thread_p)
{
if (sampling_profiler_p)
if (FACTOR_MEMORY_BARRIER(), sampling_profiler_p)
{
FACTOR_ATOMIC_ADD(&safepoint_sample_count, 1);
FACTOR_ATOMIC_ADD(&safepoint_sample_count, samples);
if (foreign_thread_p)
FACTOR_ATOMIC_ADD(&safepoint_foreign_thread_sample_count, 1);
FACTOR_ATOMIC_ADD(&safepoint_foreign_thread_sample_count, samples);
else {
if (current_gc)
FACTOR_ATOMIC_ADD(&safepoint_gc_sample_count, 1);
if (!code->seg->in_segment_p(pc))
FACTOR_ATOMIC_ADD(&safepoint_foreign_sample_count, 1);
if (FACTOR_MEMORY_BARRIER(), current_gc)
FACTOR_ATOMIC_ADD(&safepoint_gc_sample_count, samples);
if (pc != 0 && !code->seg->in_segment_p(pc))
FACTOR_ATOMIC_ADD(&safepoint_foreign_sample_count, samples);
}
code->guard_safepoint();
}

View File

@ -209,10 +209,10 @@ void sample_signal_handler(int signal, siginfo_t *siginfo, void *uap)
{
factor_vm *vm = current_vm_p();
if (vm)
vm->enqueue_safepoint_sample((cell)UAP_PROGRAM_COUNTER(uap), false);
vm->enqueue_safepoint_sample(1, (cell)UAP_PROGRAM_COUNTER(uap), false);
else if (thread_vms.size() == 1) {
factor_vm *the_only_vm = thread_vms.begin()->second;
the_only_vm->enqueue_safepoint_sample((cell)UAP_PROGRAM_COUNTER(uap), true);
the_only_vm->enqueue_safepoint_sample(1, (cell)UAP_PROGRAM_COUNTER(uap), true);
}
}

View File

@ -301,14 +301,54 @@ void factor_vm::open_console()
SetConsoleCtrlHandler(factor::ctrl_handler, TRUE);
}
void factor_vm::sampler_thread_loop()
{
LARGE_INTEGER counter, new_counter, units_per_second;
assert(QueryPerformanceFrequency(&units_per_second));
long long units_per_sample =
units_per_second.QuadPart / FACTOR_PROFILE_SAMPLES_PER_SECOND;
assert(QueryPerformanceCounter(&counter));
while (FACTOR_MEMORY_BARRIER(), sampling_profiler_p)
{
Sleep(0);
assert(QueryPerformanceCounter(&new_counter));
cell samples = 0;
while (new_counter.QuadPart - counter.QuadPart > units_per_sample) {
// We would have to suspend the thread to sample the PC
++samples;
counter.QuadPart += units_per_sample;
}
enqueue_safepoint_sample(samples, 0, false);
}
}
static DWORD WINAPI sampler_thread_entry(LPVOID parent_vm)
{
static_cast<factor_vm*>(parent_vm)->sampler_thread_loop();
return 0;
}
void factor_vm::start_sampling_profiler_timer()
{
general_error(ERROR_NOT_IMPLEMENTED, false_object, false_object);
sampler_thread = CreateThread(
NULL,
0,
&sampler_thread_entry,
static_cast<LPVOID>(this),
0,
NULL
);
}
void factor_vm::end_sampling_profiler_timer()
{
general_error(ERROR_NOT_IMPLEMENTED, false_object, false_object);
DWORD wait_result = WaitForSingleObject(sampler_thread,
3000/FACTOR_PROFILE_SAMPLES_PER_SECOND);
if (wait_result != WAIT_OBJECT_0)
TerminateThread(sampler_thread);
sampler_thread = NULL;
}
}

View File

@ -101,9 +101,10 @@ void factor_vm::start_sampling_profiler()
void factor_vm::end_sampling_profiler()
{
sampling_profiler_p = false;
FACTOR_MEMORY_BARRIER();
end_sampling_profiler_timer();
record_sample();
sampling_profiler_p = false;
}
void factor_vm::primitive_sampling_profiler()

View File

@ -62,7 +62,7 @@ struct factor_vm
/* Is profiling enabled? */
bool counting_profiler_p;
bool sampling_profiler_p;
volatile bool sampling_profiler_p;
/* Global variables used to pass fault handler state from signal handler
to VM */
@ -93,7 +93,7 @@ struct factor_vm
callback_heap *callbacks;
/* Only set if we're performing a GC */
gc_state *current_gc;
volatile gc_state *current_gc;
/* Mark stack */
std::vector<cell> mark_stack;
@ -216,7 +216,7 @@ struct factor_vm
void synchronous_signal_handler_impl();
void fp_signal_handler_impl();
void enqueue_safepoint_fep();
void enqueue_safepoint_sample(cell pc, bool foreign_thread_p);
void enqueue_safepoint_sample(cell samples, cell pc, bool foreign_thread_p);
void handle_safepoint();
// bignum
@ -727,6 +727,9 @@ struct factor_vm
// os-windows
#if defined(WINDOWS)
HANDLE sampler_thread;
void sampler_thread_loop();
const vm_char *vm_executable_path();
const vm_char *default_image_path();
void windows_image_path(vm_char *full_path, vm_char *temp_path, unsigned int length);