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 timedb4
parent
981862f35e
commit
1351e30e52
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue