sampling_prof 0.1.5 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6e74f789ae7dba019462c771325081151d194206
4
- data.tar.gz: 00ee209871452f5fa34f62e973db2d801e6e27b2
3
+ metadata.gz: 3d1357aece706366d12fac2c1670ded8f2bdd24f
4
+ data.tar.gz: 12077ea8a42b5ca17c38df2875aab9c6234e9955
5
5
  SHA512:
6
- metadata.gz: eda0c06539ea65d5a9159cbee26b047f123fd73142cbff761f7b665d90cd97e81ae12fb4718698a86b584a9787f5d02186d3f4eae323468faf4405eb8eb8bb05
7
- data.tar.gz: b3a9f7a9900abd607deb03b669b5721b01a81f3ad2f81cb71ee241e3630ea46c622782786f76af53c34eea34a1ec6fc2b80d641e838a99c4cfd2d99d359e9e46
6
+ metadata.gz: 4fd426493b203256f040399daf7e3c69e3ce44b5428d420b6d70900036cc3cd5d8910d5f2e6d16c7db5ee40894ed4f8f156a5749fd23676cb6b9055bed166586
7
+ data.tar.gz: 65c57574670f4385e0b9f68a994bc33c01766e18b4025ee768292a22a8954662e7cc58f2267dcfc9b276f8f7856f3860c9b4f77be10ef0c51ad1813a7bad01bd
Binary file
data/lib/sampling_prof.rb CHANGED
@@ -9,6 +9,17 @@ class SamplingProf
9
9
 
10
10
  attr_writer :output_file
11
11
 
12
+ def initialize(sampling_interval=0.1,
13
+ multithreading=false,
14
+ output_interval=nil, #sec
15
+ &output_handler)
16
+ self.sampling_interval = sampling_interval
17
+ self.multithreading = multithreading
18
+ self.output_interval = output_interval || (multithreading ? 60 : nil)
19
+ self.output_handler = block_given? ? output_handler : default_output_handler
20
+ internal_initialize if respond_to?(:internal_initialize)
21
+ end
22
+
12
23
  def output_file
13
24
  @output_file ||= DEFAULT_OUTPUT_FILE
14
25
  end
@@ -20,28 +31,10 @@ class SamplingProf
20
31
  stop if block_given?
21
32
  end
22
33
 
23
- def start(handler=default_output_handler)
24
- __start__(&handler)
25
- end
26
-
27
34
  def default_output_handler
28
35
  lambda do |data|
29
- nodes, counts, call_graph = data
30
36
  File.open(output_file, 'w') do |f|
31
- nodes.each do |node|
32
- # node name, node id
33
- f.puts node.join(',')
34
- end
35
- f.puts ""
36
- counts.each do |count|
37
- # node id, count
38
- f.puts count.flatten.join(",")
39
- end
40
- f.puts ""
41
- call_graph.each do |v|
42
- # from node id, to node id, count
43
- f.puts v.flatten.join(",")
44
- end
37
+ f.write(data)
45
38
  end
46
39
  end
47
40
  end
@@ -1,40 +1,47 @@
1
+ require 'set'
2
+ require 'thread'
1
3
 
2
4
  class SamplingProf
3
- class Sample < Struct.new(:self, :total)
4
- end
5
-
6
5
  class Sampling
7
- def initialize
6
+ def initialize(threads)
8
7
  @samples = Hash.new{|h,k| h[k] = [0, 0] }
9
8
  @call_graph = Hash.new{|h,k| h[k] = 0}
10
9
  @nodes = {}
10
+ @threads = threads
11
11
  end
12
12
 
13
13
  def result
14
- [@nodes.to_a, @samples.to_a, @call_graph.to_a]
14
+ ret = []
15
+ ret << @nodes.map {|node| node.join(',')}.join("\n")
16
+ ret << @samples.map {|count| count.flatten.join(',')}.join("\n")
17
+ ret << @call_graph.map {|v| v.flatten.join(',')}.join("\n")
18
+ "#{ret.join("\n\n")}\n"
15
19
  end
16
20
 
17
- def process(locations)
18
- from = -1
19
- paths = []
20
- calls = []
21
- top_index = locations.size - 1
22
- locations.reverse.each_with_index do |loc, i|
23
- node_id = node_id(loc)
24
- if i == top_index
25
- @samples[node_id][0] += 1
26
- end
21
+ def process
22
+ @threads.each do |thread|
23
+ locations = thread.backtrace_locations
24
+ from = -1
25
+ paths = []
26
+ calls = []
27
+ top_index = locations.size - 1
28
+ locations.reverse.each_with_index do |loc, i|
29
+ node_id = node_id(loc)
30
+ if i == top_index
31
+ @samples[node_id][0] += 1
32
+ end
27
33
 
28
- path = [from, node_id]
29
- if !paths.include?(path)
30
- paths << path
31
- @call_graph[path] += 1
32
- end
33
- if !calls.include?(node_id)
34
- calls << node_id
35
- @samples[node_id][1] += 1
34
+ path = [from, node_id]
35
+ if !paths.include?(path)
36
+ paths << path
37
+ @call_graph[path] += 1
38
+ end
39
+ if !calls.include?(node_id)
40
+ calls << node_id
41
+ @samples[node_id][1] += 1
42
+ end
43
+ from = node_id
36
44
  end
37
- from = node_id
38
45
  end
39
46
  end
40
47
 
@@ -47,24 +54,56 @@ class SamplingProf
47
54
  end
48
55
  end
49
56
 
50
- def initialize(period)
51
- @period = period
57
+ class Threads
58
+ def initialize
59
+ @set = Set.new
60
+ @mutex = Mutex.new
61
+ end
62
+
63
+ def each(&block)
64
+ dup.each(&block)
65
+ end
66
+
67
+ def dup
68
+ @mutex.synchronize { @set.dup }
69
+ end
70
+
71
+ def add(obj)
72
+ @mutex.synchronize { @set.add(obj) }
73
+ end
74
+
75
+ def delete(obj)
76
+ @mutex.synchronize { @set.delete(obj) }
77
+ end
78
+ end
79
+
80
+ attr_accessor :sampling_interval, :multithreading, :output_interval, :output_handler
81
+
82
+ def internal_initialize
52
83
  @running = false
53
84
  @sampling_thread = nil
85
+ @threads = Threads.new
54
86
  end
55
87
 
56
- def __start__(&block)
57
- unless @running
88
+ def start
89
+ if @multithreading || !@running
58
90
  @running = true
59
- target = Thread.current
60
- @sampling_thread = Thread.start do
61
- sampling = Sampling.new
91
+ @threads.add(Thread.current)
92
+ @sampling_thread ||= Thread.start do
62
93
  loop do
94
+ sampling = Sampling.new(@threads)
95
+ start_time = Time.now
96
+ loop do
97
+ break unless @running
98
+ if @multithreading
99
+ break if output_interval < (Time.now - start_time)
100
+ end
101
+ sampling.process
102
+ sleep @sampling_interval
103
+ end
104
+ @output_handler.call(sampling.result)
63
105
  break unless @running
64
- sampling.process(target.backtrace_locations)
65
- sleep @period
66
106
  end
67
- block.call(sampling.result)
68
107
  end
69
108
  true
70
109
  end
@@ -72,13 +111,22 @@ class SamplingProf
72
111
 
73
112
  def stop
74
113
  if @running
75
- @running = false
76
- @sampling_thread.join
77
- @sampling_thread = nil
114
+ if @multithreading
115
+ @threads.delete(Thread.current)
116
+ else
117
+ terminate
118
+ end
78
119
  true
79
120
  end
80
121
  end
81
122
 
123
+ def terminate
124
+ @running = false
125
+ @sampling_thread.join
126
+ @sampling_thread = nil
127
+ true
128
+ end
129
+
82
130
  def profiling?
83
131
  !!@sampling_thread
84
132
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sampling_prof
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Xiao Li
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2014-03-22 00:00:00 Z
12
+ date: 2014-03-23 00:00:00 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake-compiler