Module: FastStack

Defined in:
lib/fast_stack.rb,
ext/fast_stack/fast_stack.c

Class Method Summary collapse

Class Method Details

.profile(millisecs = 1, &blk) ⇒ Object



3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/fast_stack.rb', line 3

def self.profile(millisecs=1, &blk)
  done = false
  stacks = []
  thread = Thread.current
  delta = millisecs / 1000.0
  last_time = Time.new

  new_api = thread.respond_to?(:backtrace_locations)

  # NOTE not extracting to another method to avoid adding a frame
  #  to the stack

  # this thread catches stuff fast stack does not
  # the main case is catching sleeping threads
  profile_thread = Thread.new do
    until done
      start = Time.new
      if last_time < start - delta
        last_time = start
        stacks << (new_api ? thread.backtrace_locations : thread.backtrace)
      end

      sleep(delta)
    end
  end

  trap('PROF') do
    start = Time.new
    if last_time < start - delta
      last_time = start
      stack = (new_api ? thread.backtrace_locations : thread.backtrace)
      # I am not sure if this is ensured to run in the thread
      # though in my samples it does
      if thread == Thread.current
        stack = stack[2..-1]
        # since we are in the same thread, might as well remove
        #  our overhead
        start = Time.new
      end
      stacks << stack
    end
  end

  begin
    profile_block(millisecs * 1000, &blk)
  ensure
    done = true
    profile_thread.join
  end

  stacks
end

.profile_block(usec) ⇒ Object



27
28
29
30
31
32
33
34
35
36
37
# File 'ext/fast_stack/fast_stack.c', line 27

static VALUE
rb_profile_block(VALUE module, VALUE usec)
{
    rb_need_block();

    profiler_start(module, usec);
    rb_yield(Qundef);
    profiler_stop(module);

    return Qnil;
}