Spawn a thread and have it spin on the performance counter, triggering safepoints on the main thread every sample time
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();
}
{
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);
}
}
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;
}
}
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()
/* 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 */
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;
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
// 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);