]> gitweb.factorcode.org Git - factor.git/commitdiff
vm: groundwork for sampling profiler
authorJoe Groff <arcata@gmail.com>
Fri, 28 Oct 2011 22:42:33 +0000 (15:42 -0700)
committerJoe Groff <arcata@gmail.com>
Wed, 2 Nov 2011 20:23:06 +0000 (13:23 -0700)
Set up the state necessary to collect samples. We still need to add GC support for walking the sample set, and the compiler needs to register GC roots before safepoints as well. We also need primitives to expose the data to Factor for reporting.

GNUmakefile
Nmakefile
vm/errors.cpp
vm/master.hpp
vm/os-unix.cpp
vm/primitives.hpp
vm/sampling_profiler.cpp [new file with mode: 0644]
vm/sampling_profiler.hpp [new file with mode: 0644]
vm/utilities.hpp
vm/vm.cpp
vm/vm.hpp

index c48e3a363e5a7fce5feb07ad3a15654f0c7b0f5b..ea0ee832dee71a7e51f0d77ae6adb4d85b091e5c 100755 (executable)
@@ -34,6 +34,7 @@ ifdef CONFIG
                vm/code_heap.o \
                vm/compaction.o \
                vm/contexts.o \
+               vm/counting_profiler.o \
                vm/data_heap.o \
                vm/data_heap_checker.o \
                vm/debug.o \
@@ -56,9 +57,9 @@ ifdef CONFIG
                vm/object_start_map.o \
                vm/objects.o \
                vm/primitives.o \
-               vm/counting_profiler.o \
                vm/quotations.o \
                vm/run.o \
+               vm/sampling_profiler.o \
                vm/strings.o \
                vm/to_tenured_collector.o \
                vm/tuples.o \
index 1aa568b746d8f9c233101ae876fa975e94b1678a..a4d2da45037dae26332f33d91d605c95b3456d29 100755 (executable)
--- a/Nmakefile
+++ b/Nmakefile
@@ -21,7 +21,7 @@ PLAF_DLL_OBJS = vm\os-windows-x86.64.obj vm\cpu-x86.obj
 
 ML_FLAGS = /nologo /safeseh
 
-EXE_OBJS = vm/main-windows.obj vm\factor.res
+EXE_OBJS = vm\main-windows.obj vm\factor.res
 
 DLL_OBJS = $(PLAF_DLL_OBJS) \
        vm\os-windows.obj \
@@ -37,6 +37,7 @@ DLL_OBJS = $(PLAF_DLL_OBJS) \
        vm\code_heap.obj \
        vm\compaction.obj \
        vm\contexts.obj \
+       vm\counting_profiler.obj \
        vm\data_heap.obj \
        vm\data_heap_checker.obj \
        vm\debug.obj \
@@ -60,9 +61,9 @@ DLL_OBJS = $(PLAF_DLL_OBJS) \
        vm\object_start_map.obj \
        vm\objects.obj \
        vm\primitives.obj \
-       vm\counting_profiler.obj \
        vm\quotations.obj \
        vm\run.obj \
+       vm\sampling_profiler.obj \
        vm\strings.obj \
        vm\to_tenured_collector.obj \
        vm\tuples.obj \
index 340ccbaa1a974d5472559269ee7322bc56bd3c7c..7ed28babba68195b1f182395efcfe39caeb8bbc9 100755 (executable)
@@ -173,7 +173,11 @@ void factor_vm::enqueue_safepoint_fep()
 void factor_vm::enqueue_safepoint_sample()
 {
        if (sampling_profiler_p)
-               ++safepoint_sample_count;
+       {
+               FACTOR_ATOMIC_ADD(&safepoint_sample_count, 1);
+               if (current_gc)
+                       FACTOR_ATOMIC_ADD(&safepoint_gc_sample_count, 1);
+       }
 }
 
 void factor_vm::handle_safepoint()
@@ -181,10 +185,15 @@ void factor_vm::handle_safepoint()
        code->unguard_safepoint();
        if (safepoint_fep)
        {
+               if (sampling_profiler_p)
+                       end_sampling_profiler();
                std::cout << "Interrupted\n";
                factorbug();
                safepoint_fep = false;
-               return;
+       }
+       else if (sampling_profiler_p)
+       {
+               record_sample();
        }
 }
 
index c7f8836c2b5daca4f274559ef0ba526bbb9da248..2b51b0575f97bff5669af2e23454a3bdb5d01756 100755 (executable)
@@ -95,6 +95,7 @@ namespace factor
 #include "run.hpp"
 #include "objects.hpp"
 #include "counting_profiler.hpp"
+#include "sampling_profiler.hpp"
 #include "errors.hpp"
 #include "bignumint.hpp"
 #include "bignum.hpp"
index 90324de03e68cf8001186c6e576e827e33d64d31..28c697f575758976ef05ddf8ea668af99f0598b5 100755 (executable)
@@ -153,6 +153,22 @@ void factor_vm::enqueue_safepoint_signal(cell signal)
        */
 }
 
+void factor_vm::start_sampling_profiler_timer()
+{
+       struct itimerval timer;
+       memset((void*)&timer, 0, sizeof(struct itimerval));
+       timer.it_value.tv_usec = 1000000/FACTOR_PROFILE_SAMPLES_PER_SECOND;
+       timer.it_interval.tv_usec = 1000000/FACTOR_PROFILE_SAMPLES_PER_SECOND;
+       setitimer(ITIMER_REAL, &timer, NULL);
+}
+
+void factor_vm::end_sampling_profiler_timer()
+{
+       struct itimerval timer;
+       memset((void*)&timer, 0, sizeof(struct itimerval));
+       setitimer(ITIMER_REAL, &timer, NULL);
+}
+
 void memory_signal_handler(int signal, siginfo_t *siginfo, void *uap)
 {
        factor_vm *vm = current_vm();
@@ -239,21 +255,6 @@ static void init_sigaction_with_handler(struct sigaction *act,
 
 void factor_vm::unix_init_signals()
 {
-       /* OpenBSD doesn't support sigaltstack() if we link against
-       libpthread. See http://redmine.ruby-lang.org/issues/show/1239 */
-
-#ifndef __OpenBSD__
-       signal_callstack_seg = new segment(callstack_size,false);
-
-       stack_t signal_callstack;
-       signal_callstack.ss_sp = (char *)signal_callstack_seg->start;
-       signal_callstack.ss_size = signal_callstack_seg->size;
-       signal_callstack.ss_flags = 0;
-
-       if(sigaltstack(&signal_callstack,(stack_t *)NULL) < 0)
-               fatal_error("sigaltstack() failed",0);
-#endif
-
        struct sigaction memory_sigaction;
        struct sigaction synchronous_sigaction;
        struct sigaction enqueue_sigaction;
index b3a36b273a7b9d1cc6aac35387fb29d392f7d1af..31845a2122e0bcafd78f9d125e4d79a9d70ae0f6 100644 (file)
@@ -45,6 +45,7 @@ namespace factor
        _(context_object) \
        _(context_object_for) \
        _(current_callback) \
+       _(counting_profiler) \
        _(data_room) \
        _(datastack) \
        _(datastack_for) \
@@ -100,7 +101,6 @@ namespace factor
        _(modify_code_heap) \
        _(nano_count) \
        _(optimized_p) \
-       _(counting_profiler) \
        _(quot_compiled_p) \
        _(quotation_code) \
        _(reset_dispatch_stats) \
@@ -109,6 +109,7 @@ namespace factor
        _(resize_string) \
        _(retainstack) \
        _(retainstack_for) \
+       _(sampling_profiler) \
        _(save_image) \
        _(save_image_and_exit) \
        _(set_context_object) \
diff --git a/vm/sampling_profiler.cpp b/vm/sampling_profiler.cpp
new file mode 100644 (file)
index 0000000..08e6427
--- /dev/null
@@ -0,0 +1,62 @@
+#include "master.hpp"
+
+namespace factor
+{
+
+void factor_vm::record_sample()
+{
+       cell recorded_sample_count;
+       cell recorded_gc_sample_count;
+
+       recorded_sample_count = safepoint_sample_count;
+       recorded_gc_sample_count = safepoint_gc_sample_count;
+       if (recorded_sample_count == 0 && recorded_gc_sample_count == 0)
+               return;
+
+       /* Another sample signal could be raised while we record these counts */
+       FACTOR_ATOMIC_SUB(&safepoint_sample_count, recorded_sample_count);
+       FACTOR_ATOMIC_SUB(&safepoint_gc_sample_count, recorded_gc_sample_count);
+
+       samples.push_back(profiling_sample(
+               recorded_sample_count,
+               recorded_gc_sample_count,
+               ctx,
+               capture_callstack(ctx)
+       ));
+}
+
+void factor_vm::set_sampling_profiler(bool sampling_p)
+{
+       if (sampling_p == sampling_profiler_p)
+               return;
+       
+       if (sampling_p)
+               start_sampling_profiler();
+       else
+               end_sampling_profiler();
+}
+
+void factor_vm::start_sampling_profiler()
+{
+       safepoint_sample_count = 0;
+       safepoint_gc_sample_count = 0;
+       samples.clear();
+       samples.reserve(10*FACTOR_PROFILE_SAMPLES_PER_SECOND);
+       sampling_profiler_p = true;
+       start_sampling_profiler_timer();
+}
+
+void factor_vm::end_sampling_profiler()
+{
+       end_sampling_profiler_timer();
+       record_sample();
+       sampling_profiler_p = false;
+}
+
+void factor_vm::primitive_sampling_profiler()
+{
+       set_sampling_profiler(to_boolean(ctx->pop()));
+}
+
+
+}
diff --git a/vm/sampling_profiler.hpp b/vm/sampling_profiler.hpp
new file mode 100644 (file)
index 0000000..540d6b6
--- /dev/null
@@ -0,0 +1,30 @@
+namespace factor
+{
+
+#define FACTOR_PROFILE_SAMPLES_PER_SECOND 1000
+
+struct profiling_sample
+{
+       // Number of samples taken before the safepoint that recorded the sample
+       cell sample_count;
+       // Number of samples taken during GC
+       cell gc_sample_count;
+       // Active context during sample
+       context *ctx;
+       // The callstack at safepoint time
+       cell callstack;
+
+       profiling_sample(cell sample_count,
+               cell gc_sample_count,
+               context *ctx,
+               cell callstack)
+               :
+               sample_count(sample_count),
+               gc_sample_count(gc_sample_count),
+               ctx(ctx),
+               callstack(callstack)
+       {
+       }
+};
+
+}
index 5f37644213e42b5465c185888e7257c04902954f..2b93a62fbcf8baa3f64e0c4f2ee0b4bec47ef4f5 100755 (executable)
@@ -53,4 +53,45 @@ vm_char *safe_strdup(const vm_char *str);
 cell read_cell_hex();
 VM_C_API void *factor_memcpy(void *dst, void *src, size_t len);
 
+#if defined(WINDOWS)
+
+       #if defined(FACTOR_64)
+
+               #define FACTOR_ATOMIC_CAS(ptr, old_val, new_val) \
+                       (InterlockedCompareExchange64(ptr, new_val, old_val) == old_val)
+
+               #define FACTOR_ATOMIC_ADD(ptr, val) \
+                       InterlockedAdd64(ptr, val)
+
+               #define FACTOR_ATOMIC_SUB(ptr, val) \
+                       InterlockedSub64(ptr, val)
+
+       #else
+
+               #define FACTOR_ATOMIC_CAS(ptr, old_val, new_val) \
+                       (InterlockedCompareExchange(ptr, new_val, old_val) == old_val)
+
+               #define FACTOR_ATOMIC_ADD(ptr, val) \
+                       InterlockedAdd(ptr, val)
+
+               #define FACTOR_ATOMIC_SUB(ptr, val) \
+                       InterlockedSub(ptr, val)
+
+       #endif
+
+#elif defined(__GNUC__) || defined(__clang__)
+
+       #define FACTOR_ATOMIC_CAS(ptr, old_val, new_val) \
+               __sync_bool_compare_and_swap(ptr, old_val, new_val)
+
+       #define FACTOR_ATOMIC_ADD(ptr, val) \
+               __sync_add_and_fetch(ptr, val)
+
+       #define FACTOR_ATOMIC_SUB(ptr, val) \
+               __sync_sub_and_fetch(ptr, val)
+
+#else
+       #error "Unsupported compiler"
+#endif
+
 }
index a1da97cd6d4b156cf9e1958321999703abf20a80..47669f615afcaf6f17f973bef7ecb979bac83fe9 100755 (executable)
--- a/vm/vm.cpp
+++ b/vm/vm.cpp
@@ -11,6 +11,7 @@ factor_vm::factor_vm() :
        sampling_profiler_p(false),
        safepoint_fep(false),
        safepoint_sample_count(0),
+       safepoint_gc_sample_count(0),
        gc_off(false),
        current_gc(NULL),
        gc_events(NULL),
index 4c92caa26f6fde412ce9ba3e1aa3053419d43daa..2c2772e9909b26a3cf044b08c275a2514b9885d7 100755 (executable)
--- a/vm/vm.hpp
+++ b/vm/vm.hpp
@@ -60,9 +60,8 @@ struct factor_vm
        /* External entry points */
        c_to_factor_func_type c_to_factor_func;
 
-       /* Is call counting enabled? */
+       /* Is profiling enabled? */
        bool counting_profiler_p;
-       /* Is sampling profiler enabled? */
        bool sampling_profiler_p;
 
        /* Global variables used to pass fault handler state from signal handler
@@ -71,8 +70,12 @@ struct factor_vm
        cell signal_number;
        cell signal_fault_addr;
        unsigned int signal_fpu_status;
-       bool safepoint_fep;
-       cell safepoint_sample_count;
+       volatile bool safepoint_fep;
+
+       /* State kept by the sampling profiler */
+       std::vector<profiling_sample> samples;
+       volatile cell safepoint_sample_count;
+       volatile cell safepoint_gc_sample_count;
 
        /* GC is off during heap walking */
        bool gc_off;
@@ -186,6 +189,13 @@ struct factor_vm
        void set_counting_profiler(bool counting_profiler);
        void primitive_counting_profiler();
 
+       /* Sampling profiler */
+       void record_sample();
+       void start_sampling_profiler();
+       void end_sampling_profiler();
+       void set_sampling_profiler(bool sampling);
+       void primitive_sampling_profiler();
+
        // errors
        void general_error(vm_error_type error, cell arg1, cell arg2);
        void type_error(cell type, cell tagged);
@@ -383,7 +393,7 @@ struct factor_vm
        void find_data_references_step(cell *scan);
        void find_data_references(cell look_for_);
        void dump_code_heap();
-       void factorbug_usage();
+       void factorbug_usage(bool advanced_p);
        void factorbug();
        void primitive_die();
 
@@ -705,6 +715,8 @@ struct factor_vm
        void ffi_dlclose(dll *dll);
        void c_to_factor_toplevel(cell quot);
        void init_signals();
+       void start_sampling_profiler_timer();
+       void end_sampling_profiler_timer();
 
        // os-windows
   #if defined(WINDOWS)