Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to specify stack frame depth of CPU sampler #129

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,8 @@ Rbkit.start_profiling(
enable_cpu_profiling: true,
clock_type: :wall,
cpu_profiling_mode: :sampling,
cpu_sampling_interval_usec: 1000
cpu_sampling_interval_usec: 1000,
cpu_sampling_depth: 10
)
```

Expand All @@ -122,6 +123,7 @@ Arguments:
|clock_type | :wall/:cpu | :wall | Specifies clock type to use in CPU profiling |
|cpu_profiling_mode | :sampling | :sampling | CPU profiling mode - currently only sampling |
|cpu_sampling_interval_usec | Fixnums | 1000 | CPU Sampling interval un usec, if sampling mode |
|cpu_sampling_depth | Fixnums | 10 | Depth of stack frame collected by CPU sampler |


## Development
Expand Down
30 changes: 18 additions & 12 deletions ext/rbkit_sampling_profiler.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@

#define BUF_SIZE 2048

static int signal_type;
static int clock_type;
static struct cpu_sampling_args {
int signal_type;
int clock_type;
int sampling_depth;
} args;
queue_sample_func_ptr queue_cpu_sample_for_sending;

#ifdef RBKIT_DEV
Expand All @@ -30,7 +33,9 @@ static void sampling_job_handler(void *data_unused) {

rbkit_cpu_sample *sample = malloc(sizeof(rbkit_cpu_sample));

int collected_size = rb_profile_frames(start, sizeof(buff) / sizeof(VALUE), buff, lines);
int max_depth = sizeof(buff) / sizeof(VALUE);
int depth = (args.sampling_depth > max_depth) ? max_depth : args.sampling_depth;
int collected_size = rb_profile_frames(start, depth, buff, lines);
rbkit_frame_data *frame_data = malloc(sizeof(rbkit_frame_data) * collected_size);
sample->frames = frame_data;
sample->frame_count = collected_size;
Expand Down Expand Up @@ -89,15 +94,15 @@ static void install_signal_handler() {
sa.sa_sigaction = signal_handler;
sa.sa_flags = SA_RESTART | SA_SIGINFO;
sigemptyset(&sa.sa_mask);
sigaction(signal_type, &sa, NULL);
sigaction(args.signal_type, &sa, NULL);
}

static void uninstall_signal_handler() {
struct sigaction sa;
sa.sa_handler = SIG_IGN;
sa.sa_flags = SA_RESTART;
sigemptyset(&sa.sa_mask);
sigaction(signal_type, &sa, NULL);
sigaction(args.signal_type, &sa, NULL);
#ifdef RBKIT_DEV
fprintf(stderr, "Time spent in CPU sampling in usecs = %f(wall) %f(cpu)\n", total_wall_time_spent_in_sampling, total_cpu_time_spent_in_sampling);
#endif
Expand All @@ -109,23 +114,24 @@ static void start_sigprof_timer(int interval) {
timer.it_interval.tv_sec = 0;
timer.it_interval.tv_usec = interval;
timer.it_value = timer.it_interval;
setitimer(clock_type, &timer, 0);
setitimer(args.clock_type, &timer, 0);
}

static void stop_sigprof_timer() {
struct itimerval timer;
memset(&timer, 0, sizeof(timer));
setitimer(clock_type, &timer, 0);
setitimer(args.clock_type, &timer, 0);
}

void rbkit_install_sampling_profiler(int wall_time, int interval, queue_sample_func_ptr func) {
void rbkit_install_sampling_profiler(int wall_time, int interval, int depth, queue_sample_func_ptr func) {
queue_cpu_sample_for_sending = func;
args.sampling_depth = depth;
if(wall_time) {
signal_type = SIGALRM;
clock_type = ITIMER_REAL;
args.signal_type = SIGALRM;
args.clock_type = ITIMER_REAL;
} else {
signal_type = SIGPROF;
clock_type = ITIMER_PROF;
args.signal_type = SIGPROF;
args.clock_type = ITIMER_PROF;
}
install_signal_handler();
start_sigprof_timer(interval);
Expand Down
2 changes: 1 addition & 1 deletion ext/rbkit_sampling_profiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@ typedef struct _rbkit_cpu_sample {

typedef void (*queue_sample_func_ptr) (rbkit_cpu_sample *);

void rbkit_install_sampling_profiler(int wall_time, int interval, queue_sample_func_ptr func);
void rbkit_install_sampling_profiler(int wall_time, int interval, int depth, queue_sample_func_ptr func);
void rbkit_uninstall_sampling_profiler();
#endif
6 changes: 3 additions & 3 deletions ext/rbkit_server.c
Original file line number Diff line number Diff line change
Expand Up @@ -331,12 +331,12 @@ static void queue_cpu_sample_for_sending(rbkit_cpu_sample *sample) {
msgpack_packer_free(packer);
}

static VALUE start_sampling_profiler(VALUE self, VALUE clock_type, VALUE interval) {
static VALUE start_sampling_profiler(VALUE self, VALUE clock_type, VALUE interval, VALUE depth) {
if (logger->sampling_profiler_enabled == Qtrue)
return Qnil;
if(!SYMBOL_P(clock_type))
rb_raise(rb_eArgError, "clock_type should be a symbol, either :wall or :cpu");
rbkit_install_sampling_profiler(clock_type == ID2SYM(rb_intern("wall")), FIX2INT(interval), queue_cpu_sample_for_sending);
rbkit_install_sampling_profiler(clock_type == ID2SYM(rb_intern("wall")), FIX2INT(interval), FIX2INT(depth), queue_cpu_sample_for_sending);
logger->sampling_profiler_enabled = Qtrue;
return Qnil;
}
Expand Down Expand Up @@ -466,7 +466,7 @@ void Init_rbkit_server(void) {
rb_define_method(rbkit_server, "stop_stat_server", stop_stat_server, 0);
rb_define_method(rbkit_server, "start_stat_tracing", start_stat_tracing, 0);
rb_define_method(rbkit_server, "stop_stat_tracing", stop_stat_tracing, 0);
rb_define_method(rbkit_server, "start_sampling_profiler", start_sampling_profiler, 2);
rb_define_method(rbkit_server, "start_sampling_profiler", start_sampling_profiler, 3);
rb_define_method(rbkit_server, "stop_sampling_profiler", stop_sampling_profiler, 0);
rb_define_method(rbkit_server, "poll_for_request", poll_for_request, 0);
rb_define_method(rbkit_server, "send_objectspace_dump", send_objectspace_dump, 0);
Expand Down
4 changes: 2 additions & 2 deletions lib/rbkit.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,13 @@ def self.start_server(pub_port: DEFAULT_PUB_PORT, request_port: DEFAULT_REQ_PORT
def self.start_profiling(pub_port: DEFAULT_PUB_PORT, request_port: DEFAULT_REQ_PORT,
enable_object_trace: true, enable_gc_stats: true,
enable_cpu_profiling: true, clock_type: :wall,
cpu_profiling_mode: :sampling, cpu_sampling_interval_usec: 1000)
cpu_profiling_mode: :sampling, cpu_sampling_interval_usec: 1000, cpu_sampling_depth: 10)
@server ||= Rbkit::Server.new(pub_port, request_port)
@server.start(enable_object_trace: enable_object_trace,
enable_gc_stats: enable_gc_stats,
enable_cpu_profiling: enable_cpu_profiling,
clock_type: clock_type,
cpu_sampling_interval_usec: cpu_sampling_interval_usec)
cpu_sampling_interval_usec: cpu_sampling_interval_usec, cpu_sampling_depth: cpu_sampling_depth)
end

# Stops profiling and brings down the rbkit server if it's running
Expand Down
12 changes: 7 additions & 5 deletions lib/rbkit/server.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ def initialize(pub_port, request_port)
@clock_type = :cpu
@cpu_profiling_mode = :sampling
@cpu_sampling_interval_usec = 1000
@cpu_sampling_depth = 10
@respond_callback = nil
@publish_callback = nil
@gc_stats_timer = Rbkit::Timer.new(5) do
Expand All @@ -23,7 +24,7 @@ def initialize(pub_port, request_port)
end

def start(enable_object_trace: false, enable_gc_stats: false,
enable_cpu_profiling: false, clock_type: nil, cpu_profiling_mode: nil, cpu_sampling_interval_usec: nil)
enable_cpu_profiling: false, clock_type: nil, cpu_profiling_mode: nil, cpu_sampling_interval_usec: nil, cpu_sampling_depth: nil)
if @server_running || !start_stat_server(pub_port, request_port)
$stderr.puts "Rbkit server couldn't bind to socket, check if it is already" \
" running. Profiling data will not be available."
Expand All @@ -33,7 +34,8 @@ def start(enable_object_trace: false, enable_gc_stats: false,
@cpu_profiling_mode = cpu_profiling_mode if cpu_profiling_mode
@clock_type = clock_type if clock_type
@cpu_sampling_interval_usec = cpu_sampling_interval_usec if cpu_sampling_interval_usec
start_cpu_profiling(clock_type: @clock_type, sampling_interval_usec: @cpu_sampling_interval_usec) if enable_cpu_profiling
@cpu_sampling_depth = cpu_sampling_depth if cpu_sampling_depth
start_cpu_profiling(clock_type: @clock_type, sampling_interval_usec: @cpu_sampling_interval_usec, sampling_depth: @cpu_sampling_depth) if enable_cpu_profiling
@enable_gc_stats = enable_gc_stats
@server_running = true

Expand Down Expand Up @@ -77,7 +79,7 @@ def process_incoming_request(incoming_request)
when "use_wall_time"
@clock_type = :wall
when "start_cpu_profiling"
start_cpu_profiling(clock_type: @clock_type, sampling_interval_usec: @cpu_sampling_interval_usec)
start_cpu_profiling(clock_type: @clock_type, sampling_interval_usec: @cpu_sampling_interval_usec, sampling_depth: @cpu_sampling_depth)
when "stop_cpu_profiling"
stop_cpu_profiling
end
Expand All @@ -93,10 +95,10 @@ def stop
true
end

def start_cpu_profiling(mode: :sampling, clock_type: :wall, sampling_interval_usec: 1000)
def start_cpu_profiling(mode: :sampling, clock_type: :wall, sampling_interval_usec: 1000, sampling_depth: 10)
@cpu_profiling_mode = mode
if mode == :sampling
start_sampling_profiler(clock_type, sampling_interval_usec)
start_sampling_profiler(clock_type, sampling_interval_usec, sampling_depth)
else
# TODO
end
Expand Down
Loading