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();
|
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)
|
if (foreign_thread_p)
|
||||||
FACTOR_ATOMIC_ADD(&safepoint_foreign_thread_sample_count, 1);
|
FACTOR_ATOMIC_ADD(&safepoint_foreign_thread_sample_count, samples);
|
||||||
else {
|
else {
|
||||||
if (current_gc)
|
if (FACTOR_MEMORY_BARRIER(), current_gc)
|
||||||
FACTOR_ATOMIC_ADD(&safepoint_gc_sample_count, 1);
|
FACTOR_ATOMIC_ADD(&safepoint_gc_sample_count, samples);
|
||||||
if (!code->seg->in_segment_p(pc))
|
if (pc != 0 && !code->seg->in_segment_p(pc))
|
||||||
FACTOR_ATOMIC_ADD(&safepoint_foreign_sample_count, 1);
|
FACTOR_ATOMIC_ADD(&safepoint_foreign_sample_count, samples);
|
||||||
}
|
}
|
||||||
code->guard_safepoint();
|
code->guard_safepoint();
|
||||||
}
|
}
|
||||||
|
|
|
@ -209,10 +209,10 @@ void sample_signal_handler(int signal, siginfo_t *siginfo, void *uap)
|
||||||
{
|
{
|
||||||
factor_vm *vm = current_vm_p();
|
factor_vm *vm = current_vm_p();
|
||||||
if (vm)
|
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) {
|
else if (thread_vms.size() == 1) {
|
||||||
factor_vm *the_only_vm = thread_vms.begin()->second;
|
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);
|
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()
|
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()
|
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()
|
void factor_vm::end_sampling_profiler()
|
||||||
{
|
{
|
||||||
|
sampling_profiler_p = false;
|
||||||
|
FACTOR_MEMORY_BARRIER();
|
||||||
end_sampling_profiler_timer();
|
end_sampling_profiler_timer();
|
||||||
record_sample();
|
record_sample();
|
||||||
sampling_profiler_p = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void factor_vm::primitive_sampling_profiler()
|
void factor_vm::primitive_sampling_profiler()
|
||||||
|
|
|
@ -62,7 +62,7 @@ struct factor_vm
|
||||||
|
|
||||||
/* Is profiling enabled? */
|
/* Is profiling enabled? */
|
||||||
bool counting_profiler_p;
|
bool counting_profiler_p;
|
||||||
bool sampling_profiler_p;
|
volatile bool sampling_profiler_p;
|
||||||
|
|
||||||
/* Global variables used to pass fault handler state from signal handler
|
/* Global variables used to pass fault handler state from signal handler
|
||||||
to VM */
|
to VM */
|
||||||
|
@ -93,7 +93,7 @@ struct factor_vm
|
||||||
callback_heap *callbacks;
|
callback_heap *callbacks;
|
||||||
|
|
||||||
/* Only set if we're performing a GC */
|
/* Only set if we're performing a GC */
|
||||||
gc_state *current_gc;
|
volatile gc_state *current_gc;
|
||||||
|
|
||||||
/* Mark stack */
|
/* Mark stack */
|
||||||
std::vector<cell> mark_stack;
|
std::vector<cell> mark_stack;
|
||||||
|
@ -216,7 +216,7 @@ struct factor_vm
|
||||||
void synchronous_signal_handler_impl();
|
void synchronous_signal_handler_impl();
|
||||||
void fp_signal_handler_impl();
|
void fp_signal_handler_impl();
|
||||||
void enqueue_safepoint_fep();
|
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();
|
void handle_safepoint();
|
||||||
|
|
||||||
// bignum
|
// bignum
|
||||||
|
@ -727,6 +727,9 @@ struct factor_vm
|
||||||
|
|
||||||
// os-windows
|
// os-windows
|
||||||
#if defined(WINDOWS)
|
#if defined(WINDOWS)
|
||||||
|
HANDLE sampler_thread;
|
||||||
|
void sampler_thread_loop();
|
||||||
|
|
||||||
const vm_char *vm_executable_path();
|
const vm_char *vm_executable_path();
|
||||||
const vm_char *default_image_path();
|
const vm_char *default_image_path();
|
||||||
void windows_image_path(vm_char *full_path, vm_char *temp_path, unsigned int length);
|
void windows_image_path(vm_char *full_path, vm_char *temp_path, unsigned int length);
|
||||||
|
|
Loading…
Reference in New Issue