Module: Rbkit

Defined in:
lib/rbkit.rb,
lib/rbkit/timer.rb,
lib/rbkit/version.rb,
lib/rbkit/rbkit_gc.rb,
ext/rbkit_tracer.c,
ext/rbkit_test_helper.c

Overview

Class implements user friendly interface in pure Ruby for profiler.

Defined Under Namespace

Classes: Profiler, RbkitGC, Timer

Constant Summary collapse

DEFAULT_PUB_PORT =
5555
DEFAULT_REQ_PORT =
5556
VERSION =
"0.1.10"
EVENT_TYPES =
rbkit_event_types_as_hash()
MESSAGE_FIELDS =
rbkit_message_fields_as_hash()

Class Method Summary collapse

Class Method Details

.enable_test_modeObject



347
348
349
350
# File 'ext/rbkit_tracer.c', line 347

static VALUE enable_test_mode() {
  Init_rbkit_test_helper();
  return Qnil;
}

.get_queued_messagesObject



9
10
11
12
13
14
15
16
17
18
19
# File 'ext/rbkit_test_helper.c', line 9

static VALUE get_queued_messages() {
  msgpack_sbuffer * sbuf = msgpack_sbuffer_new();
  get_event_collection_message(sbuf);
  if(sbuf && sbuf->size > 0) {
    VALUE str = rb_str_new(sbuf->data, sbuf->size);
    message_list_clear();
    msgpack_sbuffer_destroy(sbuf);
    return str;
  }
  return Qnil;
}

.poll_for_requestObject



213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
# File 'ext/rbkit_tracer.c', line 213

static VALUE poll_for_request() {
  // Wait for 100 millisecond and check if there is a message
  // we can't wait here indefenitely because ruby is not aware this is a
  // blocking operation. Remember ruby releases GVL in a thread
  // whenever it encounters a known blocking operation.
  zmq_poll(items, 1, 100);
  if (items[0].revents && ZMQ_POLLIN) {
    char *message = tracer_string_recv(zmq_response_socket);
    if(strcmp(message, "handshake") == 0) {
      send_handshake_response();
    } else {
      tracer_string_send(zmq_response_socket, "ok");
    }
    VALUE command_ruby_string = rb_str_new_cstr(message);
    free(message);
    return command_ruby_string;
  } else {
    return Qnil;
  }
}

.send_hash_as_event(*args) ⇒ Object



282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
# File 'ext/rbkit_tracer.c', line 282

static VALUE send_hash_as_event(int argc, VALUE *argv, VALUE self) {
  VALUE hash_object;
  VALUE event_type;

  rb_scan_args(argc, argv, "20", &hash_object, &event_type);

  msgpack_sbuffer *buffer = msgpack_sbuffer_new();
  msgpack_packer *packer = msgpack_packer_new(buffer, msgpack_sbuffer_write);

  rbkit_hash_event *event = new_rbkit_hash_event(FIX2INT(event_type), hash_object);
  pack_event((rbkit_event_header *)event, packer);
  free(event);

  add_message(buffer);
  msgpack_sbuffer_free(buffer);
  msgpack_packer_free(packer);
  return Qnil;
}

.send_messagesObject

Creates a msgpack array which contains all the messages packed after the last time send_messages() was called, and sends it over the PUB socket.



334
335
336
337
338
339
340
341
342
343
344
345
# File 'ext/rbkit_tracer.c', line 334

static VALUE send_messages() {
  //Get all aggregated messages as payload of a single event.
  msgpack_sbuffer * sbuf = msgpack_sbuffer_new();
  get_event_collection_message(sbuf);
  //Send the msgpack array over zmq PUB socket
  if(sbuf && sbuf->size > 0)
    zmq_send(zmq_publisher, sbuf->data, sbuf->size, 0);
  // Clear the aggregated messages
  message_list_clear();
  msgpack_sbuffer_free(sbuf);
  return Qnil;
}

.send_objectspace_dumpObject



314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
# File 'ext/rbkit_tracer.c', line 314

static VALUE send_objectspace_dump() {
  msgpack_sbuffer* buffer = msgpack_sbuffer_new();
  msgpack_packer* pk = msgpack_packer_new(buffer, msgpack_sbuffer_write);

  rbkit_object_dump * dump = get_object_dump(logger->object_table);
  rbkit_object_space_dump_event *event = new_rbkit_object_space_dump_event(dump);
  pack_event((rbkit_event_header *)event, pk);
  free(event);
  add_message(buffer);

  free(dump);
  msgpack_sbuffer_free(buffer);
  msgpack_packer_free(pk);
  return Qnil;
}

.start_profiling(pub_port: DEFAULT_PUB_PORT, request_port: DEFAULT_REQ_PORT, enable_object_trace: true, enable_gc_stats: true) ⇒ Object

Starts the server with all tracepoints enabled by default. User can optionally disable tracepoints using the optional arguments. This method can be used to profile the startup process of a ruby application where sending commands from the client to enable profiling is not feasible.



106
107
108
109
110
111
# File 'lib/rbkit.rb', line 106

def self.start_profiling(pub_port: DEFAULT_PUB_PORT, request_port: DEFAULT_REQ_PORT,
                        enable_object_trace: true, enable_gc_stats: true)
  @profiler ||= Rbkit::Profiler.new(pub_port, request_port)
  @profiler.start_server(enable_object_trace: enable_object_trace,
                         enable_gc_stats: enable_gc_stats)
end

.start_server(pub_port: DEFAULT_PUB_PORT, request_port: DEFAULT_REQ_PORT) ⇒ Object

Starts the Rbkit server and waits for a client to connect and issue commands to the request_port, until then there’s zero performance overhead. Profiling data is sent asynchronously over pub_port. This method can be called early in a ruby application so that whenever profiling needs to be done, the client can attach itself to the inactive server, do the profiling and leave.



96
97
98
99
# File 'lib/rbkit.rb', line 96

def self.start_server(pub_port: DEFAULT_PUB_PORT, request_port: DEFAULT_REQ_PORT)
  @profiler ||= Rbkit::Profiler.new(pub_port, request_port)
  @profiler.start_server
end

.start_stat_server(*args) ⇒ Object



129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'ext/rbkit_tracer.c', line 129

static VALUE start_stat_server(int argc, VALUE *argv, VALUE self) {
  VALUE pub_port;
  VALUE request_port;
  int bind_result;

  rb_scan_args(argc, argv, "02", &pub_port, &request_port);

  char zmq_endpoint[14];
  sprintf(zmq_endpoint, "tcp://*:%d", FIX2INT(pub_port));
  zmq_context = zmq_ctx_new();
  zmq_publisher = zmq_socket(zmq_context, ZMQ_PUB);
  bind_result = zmq_bind(zmq_publisher, zmq_endpoint);
  if(bind_result != 0)
    return Qfalse;

  char zmq_request_endpoint[14];
  sprintf(zmq_request_endpoint, "tcp://*:%d", FIX2INT(request_port));
  zmq_response_socket = zmq_socket(zmq_context, ZMQ_REP);
  bind_result = zmq_bind(zmq_response_socket, zmq_request_endpoint);
  if(bind_result != 0)
    return Qfalse;

  // Creates a list which aggregates messages
  message_list_new();
  logger = get_trace_logger();
  logger->newobj_trace = rb_tracepoint_new(0, RUBY_INTERNAL_EVENT_NEWOBJ, newobj_i, logger);
  logger->freeobj_trace = rb_tracepoint_new(0, RUBY_INTERNAL_EVENT_FREEOBJ, freeobj_i, logger);
  rb_gc_register_mark_object(logger->newobj_trace);
  rb_gc_register_mark_object(logger->freeobj_trace);
  create_gc_hooks();

  items[0].socket = zmq_response_socket;
  items[0].events = ZMQ_POLLIN;
  return Qtrue;
}

.start_stat_tracingObject



301
302
303
304
305
306
307
308
309
310
311
312
# File 'ext/rbkit_tracer.c', line 301

static VALUE start_stat_tracing() {
  if (logger->enabled == Qtrue)
    return Qnil;
  rb_tracepoint_enable(logger->newobj_trace);
  rb_tracepoint_enable(logger->freeobj_trace);
  int i = 0;
  for (i=0; i<3; i++) {
    rb_tracepoint_enable(logger->hooks[i]);
  }
  logger->enabled = Qtrue;
  return Qnil;
}

.statusObject



186
187
188
189
190
191
192
193
194
195
196
# File 'ext/rbkit_tracer.c', line 186

static VALUE rbkit_status_as_hash() {
  VALUE status = rb_hash_new();
  VALUE pid = rb_funcall(rb_path2class("Process"), rb_intern("pid"), 0, 0);
  VALUE processName = rb_funcall(rb_path2class("Process"), rb_intern("argv0"), 0, 0);
  int object_trace_enabled = (logger && logger->enabled) ? 1 : 0;
  rb_hash_aset(status, ID2SYM(rb_intern("process_name")), processName);
  rb_hash_aset(status, ID2SYM(rb_intern("pwd")), rb_dir_getwd());
  rb_hash_aset(status, ID2SYM(rb_intern("pid")), pid);
  rb_hash_aset(status, ID2SYM(rb_intern("object_trace_enabled")), INT2FIX(object_trace_enabled));
  return status;
}

.stop_serverObject

Stops profiling and brings down the rbkit server if it’s running



114
115
116
117
118
119
120
121
122
# File 'lib/rbkit.rb', line 114

def self.stop_server
  if !@profiler.nil? && @profiler.make_clean_exit
    @profiler = nil
    true
  else
    $stderr.puts "Cannot stop Rbkit server. Is it running?"
    false
  end
end

.stop_stat_serverObject



260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
# File 'ext/rbkit_tracer.c', line 260

static VALUE stop_stat_server() {
  if (logger->enabled == Qtrue)
    stop_stat_tracing();

  // Destroy the list which aggregates messages
  message_list_destroy();
  // Clear object_table which holds object allocation info
  st_foreach(logger->object_table, free_values_i, 0);
  st_clear(logger->object_table);
  st_foreach(logger->str_table, free_keys_i, 0);
  st_clear(logger->str_table);

  msgpack_sbuffer_free(logger->sbuf);
  msgpack_packer_free(logger->msgpacker);
  zmq_close(zmq_publisher);
  zmq_close(zmq_response_socket);
  zmq_ctx_destroy(zmq_context);
  free(logger);
  logger = 0;
  return Qnil;
}

.stop_stat_tracingObject



234
235
236
237
238
239
240
241
242
243
244
245
246
247
# File 'ext/rbkit_tracer.c', line 234

static VALUE stop_stat_tracing() {
  if (logger->hooks[0] != 0) {
    rb_tracepoint_disable(logger->hooks[0]);
    rb_tracepoint_disable(logger->hooks[1]);
    rb_tracepoint_disable(logger->hooks[2]);
  }

  if (logger->newobj_trace) {
    rb_tracepoint_disable(logger->newobj_trace);
    rb_tracepoint_disable(logger->freeobj_trace);
  }
  logger->enabled = Qfalse;
  return Qnil;
}