fast_stack 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/MIT-LICENSE +21 -21
- data/README.md +32 -37
- data/ext/fast_stack/extconf.rb +13 -8
- data/ext/fast_stack/fast_stack.c +12 -46
- data/ext/fast_stack/fast_stack.h +13 -0
- data/ext/fast_stack/fast_stack_linux.c +87 -0
- data/ext/fast_stack/fast_stack_windows.c +58 -0
- data/lib/fast_stack.rb +142 -26
- data/spec/fast_stack_spec.rb +40 -28
- metadata +20 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5379c5d5a7c8876efd6c43433644a7d88454afce
|
4
|
+
data.tar.gz: 5446ba4ccea259eae6264339aab38f0e72b54f74
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a92d6aefd51e5effae3d804934218e6c3f74a71d3f8268792f44a2a2722d3b6f1639a873111ff31c532b8ae03b4e7aac94650decea798fe060e5070e4b6c2d41
|
7
|
+
data.tar.gz: d350f9fd8154e9d78f6934b687fbefd975706788b723266bff4bffa4469c01ab3e32fb615bc101bd4ec41bd4a03ebda9a10b68737760a6e2079e51d36b059bf4
|
data/MIT-LICENSE
CHANGED
@@ -1,21 +1,21 @@
|
|
1
|
-
Copyright (c) 2006-2009 Steve Sloan
|
2
|
-
|
3
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
-
a copy of this software and associated documentation files (the
|
5
|
-
"Software"), to deal in the Software without restriction, including
|
6
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
-
permit persons to whom the Software is furnished to do so, subject to
|
9
|
-
the following conditions:
|
10
|
-
|
11
|
-
The above copyright notice and this permission notice shall be
|
12
|
-
included in all copies or substantial portions of the Software.
|
13
|
-
|
14
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
-
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
-
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
-
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
21
|
-
|
1
|
+
Copyright (c) 2006-2009 Steve Sloan
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
21
|
+
|
data/README.md
CHANGED
@@ -1,37 +1,32 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
Very efficient collection of ruby backtraces, even under heavy CPU load
|
4
|
-
|
5
|
-
### How do you use it?
|
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
|
-
This technique was conceived by https://github.com/tmm1 , big thank you.
|
34
|
-
|
35
|
-
Ruby 2.0 uses #backtrace_locations, 1.9.3 uses #backtrace
|
36
|
-
|
37
|
-
(gem template based on https://github.com/CodeMonkeySteve/fast_xor )
|
1
|
+
# Fast stack [![Build Status](https://travis-ci.org/SamSaffron/fast_stack.svg?branch=master)](https://travis-ci.org/SamSaffron/fast_stack)
|
2
|
+
|
3
|
+
Very efficient collection of ruby backtraces, even under heavy CPU load
|
4
|
+
|
5
|
+
### How do you use it?
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
require 'fast_stack'
|
9
|
+
```
|
10
|
+
|
11
|
+
### Usage
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
def fib( n )
|
15
|
+
return n if ( 0..1 ).include? n
|
16
|
+
( fib( n - 1 ) + fib( n - 2 ) )
|
17
|
+
end
|
18
|
+
|
19
|
+
stacks = FastStack.profile do
|
20
|
+
fib(30)
|
21
|
+
end
|
22
|
+
|
23
|
+
puts stacks.count # => 30
|
24
|
+
```
|
25
|
+
|
26
|
+
### Notes
|
27
|
+
|
28
|
+
This technique was conceived by https://github.com/tmm1 , big thank you.
|
29
|
+
|
30
|
+
Ruby 2.0 uses #backtrace_locations, 1.9.3 uses #backtrace
|
31
|
+
|
32
|
+
(gem template based on https://github.com/CodeMonkeySteve/fast_xor )
|
data/ext/fast_stack/extconf.rb
CHANGED
@@ -1,8 +1,13 @@
|
|
1
|
-
require 'mkmf'
|
2
|
-
require 'rbconfig'
|
3
|
-
require 'fileutils'
|
4
|
-
|
5
|
-
# work around ruby 2.0 p0 bug
|
6
|
-
FileUtils.mkdir_p(File.expand_path('../../../lib/fast_stack',__FILE__))
|
7
|
-
|
8
|
-
|
1
|
+
require 'mkmf'
|
2
|
+
require 'rbconfig'
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
# work around ruby 2.0 p0 bug
|
6
|
+
FileUtils.mkdir_p(File.expand_path('../../../lib/fast_stack',__FILE__))
|
7
|
+
|
8
|
+
have_func('backtrace_symbols_fd')
|
9
|
+
have_func('CreateTimerQueueTimer')
|
10
|
+
have_library('winmm', 'timeBeginPeriod')
|
11
|
+
|
12
|
+
|
13
|
+
create_makefile('fast_stack/fast_stack')
|
data/ext/fast_stack/fast_stack.c
CHANGED
@@ -1,46 +1,12 @@
|
|
1
|
-
#include
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
setitimer(ITIMER_REAL, &timer, 0);
|
14
|
-
|
15
|
-
return Qnil;
|
16
|
-
}
|
17
|
-
|
18
|
-
static VALUE
|
19
|
-
rb_profile_stop(VALUE module)
|
20
|
-
{
|
21
|
-
struct itimerval timer;
|
22
|
-
memset(&timer, 0, sizeof(timer));
|
23
|
-
setitimer(ITIMER_REAL, &timer, 0);
|
24
|
-
|
25
|
-
return Qnil;
|
26
|
-
}
|
27
|
-
|
28
|
-
static VALUE
|
29
|
-
rb_profile_block(VALUE module, VALUE usec)
|
30
|
-
{
|
31
|
-
rb_need_block();
|
32
|
-
|
33
|
-
rb_profile_start(module, usec);
|
34
|
-
rb_yield(Qundef);
|
35
|
-
rb_profile_stop(module);
|
36
|
-
|
37
|
-
return Qnil;
|
38
|
-
}
|
39
|
-
|
40
|
-
void Init_fast_stack( void )
|
41
|
-
{
|
42
|
-
VALUE rb_mFastStack = rb_define_module("FastStack");
|
43
|
-
rb_define_module_function(rb_mFastStack, "profile_block", rb_profile_block, 1);
|
44
|
-
rb_define_module_function(rb_mFastStack, "stop", rb_profile_stop, 0);
|
45
|
-
rb_define_module_function(rb_mFastStack, "start", rb_profile_start, 1);
|
46
|
-
}
|
1
|
+
#include "fast_stack.h"
|
2
|
+
|
3
|
+
void Init_fast_stack( void )
|
4
|
+
{
|
5
|
+
VALUE rb_mFastStack = rb_define_module("FastStack");
|
6
|
+
rb_define_module_function(rb_mFastStack, "start", rb_profile_start, 1);
|
7
|
+
rb_define_module_function(rb_mFastStack, "stop", rb_profile_stop, 0);
|
8
|
+
rb_define_module_function(rb_mFastStack, "signal", rb_profile_signal, 0);
|
9
|
+
|
10
|
+
rb_define_module_function(rb_mFastStack, "start_native", rb_profile_start_native, 2);
|
11
|
+
rb_define_module_function(rb_mFastStack, "stop_native", rb_profile_stop_native, 0);
|
12
|
+
}
|
@@ -0,0 +1,13 @@
|
|
1
|
+
#ifndef FAST_STACK_H__
|
2
|
+
#define FAST_STACK_H__
|
3
|
+
|
4
|
+
#include <ruby.h>
|
5
|
+
#include <ruby/encoding.h>
|
6
|
+
|
7
|
+
VALUE rb_profile_start_native(VALUE module, VALUE usec, VALUE fd);
|
8
|
+
VALUE rb_profile_stop_native(VALUE module);
|
9
|
+
VALUE rb_profile_start(VALUE module, VALUE usec);
|
10
|
+
VALUE rb_profile_stop(VALUE module);
|
11
|
+
VALUE rb_profile_signal(VALUE module);
|
12
|
+
|
13
|
+
#endif
|
@@ -0,0 +1,87 @@
|
|
1
|
+
#ifdef HAVE_BACKTRACE_SYMBOLS_FD
|
2
|
+
|
3
|
+
#include <stdio.h>
|
4
|
+
#include <unistd.h>
|
5
|
+
#include <stdlib.h>
|
6
|
+
#include <sys/time.h>
|
7
|
+
#include <sys/types.h>
|
8
|
+
#include <signal.h>
|
9
|
+
#include <execinfo.h>
|
10
|
+
|
11
|
+
#include "fast_stack.h"
|
12
|
+
|
13
|
+
struct sigaction old_alrm;
|
14
|
+
int backtrace_fd;
|
15
|
+
|
16
|
+
static void alrm_handler(int signum)
|
17
|
+
{
|
18
|
+
static void *trace[2048];
|
19
|
+
int n = backtrace(trace, 2048);
|
20
|
+
|
21
|
+
if(n>2){
|
22
|
+
backtrace_symbols_fd(trace + sizeof(void*)*2 , n-2, backtrace_fd);
|
23
|
+
write(backtrace_fd, "__SEP__\n", 8);
|
24
|
+
}
|
25
|
+
}
|
26
|
+
|
27
|
+
VALUE rb_profile_start_native(VALUE module, VALUE usec, VALUE fd)
|
28
|
+
{
|
29
|
+
struct itimerval timer;
|
30
|
+
struct sigaction sa;
|
31
|
+
|
32
|
+
backtrace_fd = NUM2INT(fd);
|
33
|
+
sigaction(SIGALRM, NULL, &old_alrm);
|
34
|
+
|
35
|
+
memset(&sa, 0, sizeof(sa));
|
36
|
+
sa.sa_handler = alrm_handler;
|
37
|
+
sigemptyset(&sa.sa_mask);
|
38
|
+
sigaction(SIGALRM, &sa, NULL);
|
39
|
+
|
40
|
+
timer.it_interval.tv_sec = 0;
|
41
|
+
timer.it_interval.tv_usec = (suseconds_t)NUM2LONG(usec);
|
42
|
+
timer.it_value = timer.it_interval;
|
43
|
+
setitimer(ITIMER_REAL, &timer, 0);
|
44
|
+
|
45
|
+
return Qnil;
|
46
|
+
}
|
47
|
+
|
48
|
+
|
49
|
+
VALUE rb_profile_stop_native(VALUE module)
|
50
|
+
{
|
51
|
+
struct itimerval timer;
|
52
|
+
|
53
|
+
sigaction(SIGALRM, &old_alrm, NULL);
|
54
|
+
|
55
|
+
memset(&timer, 0, sizeof(timer));
|
56
|
+
setitimer(ITIMER_REAL, &timer, 0);
|
57
|
+
|
58
|
+
return Qnil;
|
59
|
+
}
|
60
|
+
|
61
|
+
VALUE rb_profile_start(VALUE module, VALUE usec)
|
62
|
+
{
|
63
|
+
struct itimerval timer;
|
64
|
+
|
65
|
+
timer.it_interval.tv_sec = 0;
|
66
|
+
timer.it_interval.tv_usec = (suseconds_t)NUM2LONG(usec);
|
67
|
+
timer.it_value = timer.it_interval;
|
68
|
+
setitimer(ITIMER_REAL, &timer, 0);
|
69
|
+
|
70
|
+
return Qnil;
|
71
|
+
}
|
72
|
+
|
73
|
+
VALUE rb_profile_stop(VALUE module)
|
74
|
+
{
|
75
|
+
struct itimerval timer;
|
76
|
+
memset(&timer, 0, sizeof(timer));
|
77
|
+
setitimer(ITIMER_REAL, &timer, 0);
|
78
|
+
|
79
|
+
return Qnil;
|
80
|
+
}
|
81
|
+
|
82
|
+
VALUE rb_profile_signal(VALUE module)
|
83
|
+
{
|
84
|
+
return rb_str_new_cstr("ALRM");
|
85
|
+
}
|
86
|
+
|
87
|
+
#endif // HAVE_BACKTRACE_SYMBOLS_FD
|
@@ -0,0 +1,58 @@
|
|
1
|
+
#ifdef HAVE_CREATETIMERQUEUETIMER
|
2
|
+
|
3
|
+
#include "fast_stack.h"
|
4
|
+
|
5
|
+
static VALUE handler_proc;
|
6
|
+
static HANDLE timer = NULL;
|
7
|
+
|
8
|
+
VALUE rb_profile_start_native(VALUE module, VALUE usec, VALUE fd)
|
9
|
+
{
|
10
|
+
rb_raise(rb_eNotImpError, "Not implemented on Windows");
|
11
|
+
return Qnil;
|
12
|
+
}
|
13
|
+
|
14
|
+
VALUE rb_profile_stop_native(VALUE module)
|
15
|
+
{
|
16
|
+
rb_raise(rb_eNotImpError, "Not implemented on Windows");
|
17
|
+
return Qnil;
|
18
|
+
}
|
19
|
+
|
20
|
+
static void CALLBACK timer_handler(void* handler, BOOLEAN from_timer)
|
21
|
+
{
|
22
|
+
raise(SIGINT);
|
23
|
+
}
|
24
|
+
|
25
|
+
VALUE rb_profile_start(VALUE module, VALUE usec)
|
26
|
+
{
|
27
|
+
DWORD interval;
|
28
|
+
|
29
|
+
interval = NUM2LONG(usec) / 1000; /* Windows resolution is in milliseconds */
|
30
|
+
|
31
|
+
timeBeginPeriod(1);
|
32
|
+
if (!CreateTimerQueueTimer(&timer, NULL, &timer_handler, (void*)handler_proc,
|
33
|
+
interval, interval, WT_EXECUTEDEFAULT))
|
34
|
+
{
|
35
|
+
rb_raise(rb_eRuntimeError, "Cannot start timer: %d", GetLastError());
|
36
|
+
}
|
37
|
+
|
38
|
+
return Qnil;
|
39
|
+
}
|
40
|
+
|
41
|
+
VALUE rb_profile_stop(VALUE module)
|
42
|
+
{
|
43
|
+
if (timer)
|
44
|
+
{
|
45
|
+
DeleteTimerQueueTimer(NULL, timer, NULL);
|
46
|
+
timer = NULL;
|
47
|
+
}
|
48
|
+
timeEndPeriod(1);
|
49
|
+
|
50
|
+
return Qnil;
|
51
|
+
}
|
52
|
+
|
53
|
+
VALUE rb_profile_signal(VALUE module)
|
54
|
+
{
|
55
|
+
return rb_str_new_cstr("INT");
|
56
|
+
}
|
57
|
+
|
58
|
+
#endif // HAVE_CREATETIMERQUEUETIMER
|
data/lib/fast_stack.rb
CHANGED
@@ -1,26 +1,142 @@
|
|
1
|
-
require 'fast_stack/fast_stack'
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
1
|
+
require 'fast_stack/fast_stack'
|
2
|
+
require 'tempfile'
|
3
|
+
module FastStack
|
4
|
+
|
5
|
+
def self.profile(millisecs=1, mode=:ruby, &blk)
|
6
|
+
|
7
|
+
return profile_native(millisecs, &blk) if mode == :c
|
8
|
+
|
9
|
+
stacks = []
|
10
|
+
thread = Thread.current
|
11
|
+
|
12
|
+
new_api = thread.respond_to?(:backtrace_locations)
|
13
|
+
|
14
|
+
handler do
|
15
|
+
FastStack.stop
|
16
|
+
stack = (new_api ? thread.backtrace_locations : thread.backtrace)
|
17
|
+
# I am not sure if this is ensured to run in the thread
|
18
|
+
# though in my samples it always does
|
19
|
+
if thread == Thread.current
|
20
|
+
stack = stack[2..-1]
|
21
|
+
end
|
22
|
+
stacks << stack
|
23
|
+
FastStack.start(millisecs*1000)
|
24
|
+
end
|
25
|
+
|
26
|
+
begin
|
27
|
+
FastStack.start(millisecs*1000)
|
28
|
+
blk.call
|
29
|
+
ensure
|
30
|
+
FastStack.stop
|
31
|
+
end
|
32
|
+
|
33
|
+
stacks
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def self.handler(&block)
|
40
|
+
trap(signal, &block)
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.profile_native(millisecs)
|
44
|
+
temp = Tempfile.new('stacks')
|
45
|
+
stacks = nil
|
46
|
+
|
47
|
+
begin
|
48
|
+
FastStack.start_native(millisecs*1000, temp.fileno)
|
49
|
+
yield
|
50
|
+
ensure
|
51
|
+
FastStack.stop_native
|
52
|
+
end
|
53
|
+
|
54
|
+
temp.flush
|
55
|
+
temp.close
|
56
|
+
temp.open
|
57
|
+
stacks = []
|
58
|
+
stack = []
|
59
|
+
temp.each_line do |line|
|
60
|
+
if line.strip == "__SEP__"
|
61
|
+
stacks << stack
|
62
|
+
stack = []
|
63
|
+
else
|
64
|
+
stack << line.strip
|
65
|
+
end
|
66
|
+
end
|
67
|
+
temp.close
|
68
|
+
temp.unlink
|
69
|
+
|
70
|
+
resolve_frames!(stacks)
|
71
|
+
stacks
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.resolve_frames!(stacks)
|
75
|
+
frames = {}
|
76
|
+
resolved = {}
|
77
|
+
stacks.each do |stack|
|
78
|
+
stack.map! do |frame|
|
79
|
+
frames[frame] ||= resolve_frame(frame,resolved)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.process_name
|
85
|
+
@name ||= File.readlink("/proc/#{Process.pid}/exe")
|
86
|
+
end
|
87
|
+
|
88
|
+
def self.pmap
|
89
|
+
@pmap ||= begin
|
90
|
+
|
91
|
+
result = []
|
92
|
+
|
93
|
+
unparsed = `pmap #{Process.pid} | awk '{ printf $1; for(i=4;i<=10;i++) printf " %s ",$i; print "" }'`.split("\n")
|
94
|
+
unparsed[1..-1].each do |line|
|
95
|
+
split = line.split(" ")
|
96
|
+
if split[0] != "total"
|
97
|
+
result << [split[0].hex, split[1..-1].join(" ").strip]
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
result
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def self.parse_frame(frame)
|
106
|
+
matches = frame.match(/(.*)\((.*)\)\[(.*)\]/)
|
107
|
+
{exe: matches[1], local: matches[2], global: matches[3]}
|
108
|
+
rescue
|
109
|
+
{exe: "unknown", local: "0", global: "0"}
|
110
|
+
end
|
111
|
+
|
112
|
+
def self.global_to_local(global)
|
113
|
+
prev = 0
|
114
|
+
pmap.each do |location, e|
|
115
|
+
if location > global
|
116
|
+
return global - prev
|
117
|
+
end
|
118
|
+
prev = location
|
119
|
+
end
|
120
|
+
|
121
|
+
0
|
122
|
+
end
|
123
|
+
|
124
|
+
def self.resolve_frame(frame,resolved)
|
125
|
+
resolved[frame] ||= begin
|
126
|
+
|
127
|
+
parsed = parse_frame(frame)
|
128
|
+
|
129
|
+
resolved_location = global_to_local(parsed[:global].hex)
|
130
|
+
|
131
|
+
info = `addr2line -f -C -e #{process_name} 0x#{resolved_location.to_s(16)}`.split("\n")
|
132
|
+
parsed[:fn] = info[0].strip
|
133
|
+
parsed[:file], parsed[:line] = info[1].strip.split(":")
|
134
|
+
|
135
|
+
file = parsed[:file] == "??" ? parsed[:exe] : parsed[:file]
|
136
|
+
fn = parsed[:fn] == "??" ? parsed[:local] : parsed[:fn]
|
137
|
+
|
138
|
+
"#{file}:#{parsed[:line]}:in `#{fn}'"
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
data/spec/fast_stack_spec.rb
CHANGED
@@ -1,28 +1,40 @@
|
|
1
|
-
require 'fast_stack'
|
2
|
-
|
3
|
-
|
4
|
-
describe String do
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
1
|
+
require 'fast_stack'
|
2
|
+
|
3
|
+
|
4
|
+
RSpec.describe String do
|
5
|
+
|
6
|
+
it "works for c mode" do
|
7
|
+
s = FastStack.profile(1, :c) do
|
8
|
+
t = Time.new
|
9
|
+
while (Time.new - t) < 0.01 do
|
10
|
+
"nothing"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
expect(s.count).to be > 2
|
15
|
+
end
|
16
|
+
|
17
|
+
it "works" do
|
18
|
+
s = FastStack.profile do
|
19
|
+
t = Time.new
|
20
|
+
while (Time.new - t) < 0.1 do
|
21
|
+
"nothing"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
expect(s.count).to be > 2
|
26
|
+
end
|
27
|
+
|
28
|
+
def fib( n )
|
29
|
+
return n if ( 0..1 ).include? n
|
30
|
+
( fib( n - 1 ) + fib( n - 2 ) )
|
31
|
+
end
|
32
|
+
|
33
|
+
it "fibos" do
|
34
|
+
s = FastStack.profile do
|
35
|
+
fib(30)
|
36
|
+
end
|
37
|
+
|
38
|
+
expect(s.count).to be > 10
|
39
|
+
end
|
40
|
+
end
|
metadata
CHANGED
@@ -1,58 +1,58 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fast_stack
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sam Saffron
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-04-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '0'
|
20
|
-
type: :
|
20
|
+
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rake-compiler
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '0'
|
34
|
-
type: :
|
34
|
+
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rspec
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- -
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '0'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- -
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
|
-
description: Fast method for collecting stack traces in Ruby 2.1
|
55
|
+
description: Fast method for collecting stack traces in Ruby 2.1+
|
56
56
|
email: sam.saffron@gmail.com
|
57
57
|
executables: []
|
58
58
|
extensions:
|
@@ -61,9 +61,12 @@ extra_rdoc_files: []
|
|
61
61
|
files:
|
62
62
|
- MIT-LICENSE
|
63
63
|
- README.md
|
64
|
-
- lib/fast_stack.rb
|
65
|
-
- ext/fast_stack/fast_stack.c
|
66
64
|
- ext/fast_stack/extconf.rb
|
65
|
+
- ext/fast_stack/fast_stack.c
|
66
|
+
- ext/fast_stack/fast_stack.h
|
67
|
+
- ext/fast_stack/fast_stack_linux.c
|
68
|
+
- ext/fast_stack/fast_stack_windows.c
|
69
|
+
- lib/fast_stack.rb
|
67
70
|
- spec/fast_stack_spec.rb
|
68
71
|
homepage: https://github.com/SamSaffron/fast_stack
|
69
72
|
licenses:
|
@@ -75,19 +78,19 @@ require_paths:
|
|
75
78
|
- lib
|
76
79
|
required_ruby_version: !ruby/object:Gem::Requirement
|
77
80
|
requirements:
|
78
|
-
- -
|
81
|
+
- - ">="
|
79
82
|
- !ruby/object:Gem::Version
|
80
83
|
version: '0'
|
81
84
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
82
85
|
requirements:
|
83
|
-
- -
|
86
|
+
- - ">="
|
84
87
|
- !ruby/object:Gem::Version
|
85
88
|
version: '0'
|
86
89
|
requirements: []
|
87
90
|
rubyforge_project:
|
88
|
-
rubygems_version: 2.
|
91
|
+
rubygems_version: 2.4.8
|
89
92
|
signing_key:
|
90
93
|
specification_version: 4
|
91
|
-
summary: Fast method for collecting stack traces in Ruby 2.1
|
94
|
+
summary: Fast method for collecting stack traces in Ruby 2.1+
|
92
95
|
test_files:
|
93
96
|
- spec/fast_stack_spec.rb
|