pf2 0.9.0 → 1.0.0.alpha1

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.
Files changed (131) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +9 -4
  3. data/Rakefile +3 -9
  4. data/doc/development.md +6 -0
  5. data/ext/pf2/debug.h +12 -0
  6. data/ext/pf2/extconf.rb +23 -6
  7. data/ext/{pf2c → pf2}/sample.c +6 -0
  8. data/ext/{pf2c → pf2}/sample.h +4 -0
  9. data/ext/{pf2c → pf2}/serializer.c +1 -1
  10. data/ext/{pf2c → pf2}/session.c +70 -20
  11. data/ext/{pf2c → pf2}/session.h +5 -0
  12. data/lib/pf2/cli.rb +3 -11
  13. data/lib/pf2/reporter/firefox_profiler_ser2.rb +17 -13
  14. data/lib/pf2/reporter/stack_weaver.rb +8 -0
  15. data/lib/pf2/reporter.rb +0 -1
  16. data/lib/pf2/version.rb +1 -1
  17. data/lib/pf2.rb +1 -1
  18. metadata +18 -135
  19. data/Cargo.lock +0 -630
  20. data/Cargo.toml +0 -3
  21. data/crates/backtrace-sys2/.gitignore +0 -1
  22. data/crates/backtrace-sys2/Cargo.toml +0 -9
  23. data/crates/backtrace-sys2/build.rs +0 -45
  24. data/crates/backtrace-sys2/src/lib.rs +0 -5
  25. data/crates/backtrace-sys2/src/libbacktrace/.gitignore +0 -15
  26. data/crates/backtrace-sys2/src/libbacktrace/Isaac.Newton-Opticks.txt +0 -9286
  27. data/crates/backtrace-sys2/src/libbacktrace/LICENSE +0 -29
  28. data/crates/backtrace-sys2/src/libbacktrace/Makefile.am +0 -708
  29. data/crates/backtrace-sys2/src/libbacktrace/Makefile.in +0 -2820
  30. data/crates/backtrace-sys2/src/libbacktrace/README.md +0 -46
  31. data/crates/backtrace-sys2/src/libbacktrace/aclocal.m4 +0 -864
  32. data/crates/backtrace-sys2/src/libbacktrace/alloc.c +0 -167
  33. data/crates/backtrace-sys2/src/libbacktrace/allocfail.c +0 -136
  34. data/crates/backtrace-sys2/src/libbacktrace/allocfail.sh +0 -104
  35. data/crates/backtrace-sys2/src/libbacktrace/atomic.c +0 -113
  36. data/crates/backtrace-sys2/src/libbacktrace/backtrace-supported.h.in +0 -66
  37. data/crates/backtrace-sys2/src/libbacktrace/backtrace.c +0 -129
  38. data/crates/backtrace-sys2/src/libbacktrace/backtrace.h +0 -189
  39. data/crates/backtrace-sys2/src/libbacktrace/btest.c +0 -517
  40. data/crates/backtrace-sys2/src/libbacktrace/compile +0 -348
  41. data/crates/backtrace-sys2/src/libbacktrace/config/enable.m4 +0 -38
  42. data/crates/backtrace-sys2/src/libbacktrace/config/lead-dot.m4 +0 -31
  43. data/crates/backtrace-sys2/src/libbacktrace/config/libtool.m4 +0 -7545
  44. data/crates/backtrace-sys2/src/libbacktrace/config/ltoptions.m4 +0 -369
  45. data/crates/backtrace-sys2/src/libbacktrace/config/ltsugar.m4 +0 -123
  46. data/crates/backtrace-sys2/src/libbacktrace/config/ltversion.m4 +0 -23
  47. data/crates/backtrace-sys2/src/libbacktrace/config/lt~obsolete.m4 +0 -98
  48. data/crates/backtrace-sys2/src/libbacktrace/config/multi.m4 +0 -68
  49. data/crates/backtrace-sys2/src/libbacktrace/config/override.m4 +0 -117
  50. data/crates/backtrace-sys2/src/libbacktrace/config/unwind_ipinfo.m4 +0 -37
  51. data/crates/backtrace-sys2/src/libbacktrace/config/warnings.m4 +0 -227
  52. data/crates/backtrace-sys2/src/libbacktrace/config.guess +0 -1700
  53. data/crates/backtrace-sys2/src/libbacktrace/config.h.in +0 -185
  54. data/crates/backtrace-sys2/src/libbacktrace/config.sub +0 -1885
  55. data/crates/backtrace-sys2/src/libbacktrace/configure +0 -15929
  56. data/crates/backtrace-sys2/src/libbacktrace/configure.ac +0 -632
  57. data/crates/backtrace-sys2/src/libbacktrace/dwarf.c +0 -4409
  58. data/crates/backtrace-sys2/src/libbacktrace/edtest.c +0 -120
  59. data/crates/backtrace-sys2/src/libbacktrace/edtest2.c +0 -43
  60. data/crates/backtrace-sys2/src/libbacktrace/elf.c +0 -7465
  61. data/crates/backtrace-sys2/src/libbacktrace/fileline.c +0 -407
  62. data/crates/backtrace-sys2/src/libbacktrace/filenames.h +0 -52
  63. data/crates/backtrace-sys2/src/libbacktrace/filetype.awk +0 -13
  64. data/crates/backtrace-sys2/src/libbacktrace/install-debuginfo-for-buildid.sh.in +0 -65
  65. data/crates/backtrace-sys2/src/libbacktrace/install-sh +0 -501
  66. data/crates/backtrace-sys2/src/libbacktrace/instrumented_alloc.c +0 -114
  67. data/crates/backtrace-sys2/src/libbacktrace/internal.h +0 -428
  68. data/crates/backtrace-sys2/src/libbacktrace/ltmain.sh +0 -8636
  69. data/crates/backtrace-sys2/src/libbacktrace/macho.c +0 -1361
  70. data/crates/backtrace-sys2/src/libbacktrace/missing +0 -215
  71. data/crates/backtrace-sys2/src/libbacktrace/mmap.c +0 -331
  72. data/crates/backtrace-sys2/src/libbacktrace/mmapio.c +0 -110
  73. data/crates/backtrace-sys2/src/libbacktrace/move-if-change +0 -83
  74. data/crates/backtrace-sys2/src/libbacktrace/mtest.c +0 -410
  75. data/crates/backtrace-sys2/src/libbacktrace/nounwind.c +0 -66
  76. data/crates/backtrace-sys2/src/libbacktrace/pecoff.c +0 -1123
  77. data/crates/backtrace-sys2/src/libbacktrace/posix.c +0 -104
  78. data/crates/backtrace-sys2/src/libbacktrace/print.c +0 -117
  79. data/crates/backtrace-sys2/src/libbacktrace/read.c +0 -110
  80. data/crates/backtrace-sys2/src/libbacktrace/simple.c +0 -108
  81. data/crates/backtrace-sys2/src/libbacktrace/sort.c +0 -108
  82. data/crates/backtrace-sys2/src/libbacktrace/state.c +0 -72
  83. data/crates/backtrace-sys2/src/libbacktrace/stest.c +0 -137
  84. data/crates/backtrace-sys2/src/libbacktrace/test-driver +0 -148
  85. data/crates/backtrace-sys2/src/libbacktrace/test_format.c +0 -55
  86. data/crates/backtrace-sys2/src/libbacktrace/testlib.c +0 -234
  87. data/crates/backtrace-sys2/src/libbacktrace/testlib.h +0 -110
  88. data/crates/backtrace-sys2/src/libbacktrace/ttest.c +0 -161
  89. data/crates/backtrace-sys2/src/libbacktrace/unittest.c +0 -92
  90. data/crates/backtrace-sys2/src/libbacktrace/unknown.c +0 -65
  91. data/crates/backtrace-sys2/src/libbacktrace/xcoff.c +0 -1617
  92. data/crates/backtrace-sys2/src/libbacktrace/xztest.c +0 -508
  93. data/crates/backtrace-sys2/src/libbacktrace/zstdtest.c +0 -523
  94. data/crates/backtrace-sys2/src/libbacktrace/ztest.c +0 -541
  95. data/ext/pf2/Cargo.toml +0 -25
  96. data/ext/pf2/build.rs +0 -10
  97. data/ext/pf2/src/backtrace.rs +0 -127
  98. data/ext/pf2/src/lib.rs +0 -22
  99. data/ext/pf2/src/profile.rs +0 -69
  100. data/ext/pf2/src/profile_serializer.rs +0 -241
  101. data/ext/pf2/src/ringbuffer.rs +0 -150
  102. data/ext/pf2/src/ruby_c_api_helper.c +0 -6
  103. data/ext/pf2/src/ruby_init.rs +0 -40
  104. data/ext/pf2/src/ruby_internal_apis.rs +0 -77
  105. data/ext/pf2/src/sample.rs +0 -67
  106. data/ext/pf2/src/scheduler.rs +0 -10
  107. data/ext/pf2/src/serialization/profile.rs +0 -48
  108. data/ext/pf2/src/serialization/serializer.rs +0 -329
  109. data/ext/pf2/src/serialization.rs +0 -2
  110. data/ext/pf2/src/session/configuration.rs +0 -114
  111. data/ext/pf2/src/session/new_thread_watcher.rs +0 -80
  112. data/ext/pf2/src/session/ruby_object.rs +0 -90
  113. data/ext/pf2/src/session.rs +0 -248
  114. data/ext/pf2/src/siginfo_t.c +0 -5
  115. data/ext/pf2/src/signal_scheduler.rs +0 -201
  116. data/ext/pf2/src/signal_scheduler_unsupported_platform.rs +0 -39
  117. data/ext/pf2/src/timer_thread_scheduler.rs +0 -179
  118. data/ext/pf2/src/util.rs +0 -31
  119. data/ext/pf2c/extconf.rb +0 -21
  120. data/lib/pf2/reporter/firefox_profiler.rb +0 -397
  121. data/rust-toolchain.toml +0 -2
  122. data/rustfmt.toml +0 -1
  123. /data/ext/{pf2c → pf2}/backtrace_state.c +0 -0
  124. /data/ext/{pf2c → pf2}/backtrace_state.h +0 -0
  125. /data/ext/{pf2c → pf2}/configuration.c +0 -0
  126. /data/ext/{pf2c → pf2}/configuration.h +0 -0
  127. /data/ext/{pf2c → pf2}/pf2.c +0 -0
  128. /data/ext/{pf2c → pf2}/pf2.h +0 -0
  129. /data/ext/{pf2c → pf2}/ringbuffer.c +0 -0
  130. /data/ext/{pf2c → pf2}/ringbuffer.h +0 -0
  131. /data/ext/{pf2c → pf2}/serializer.h +0 -0
data/ext/pf2c/extconf.rb DELETED
@@ -1,21 +0,0 @@
1
- require 'mkmf'
2
- require 'mini_portile2'
3
-
4
- libbacktrace = MiniPortile.new('libbacktrace', '1.0.0')
5
- libbacktrace.source_directory = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'vendor', 'libbacktrace'))
6
- libbacktrace.configure_options << 'CFLAGS=-fPIC'
7
- libbacktrace.cook
8
- libbacktrace.mkmf_config
9
-
10
- if !have_func('backtrace_full', 'backtrace.h')
11
- raise 'libbacktrace has not been properly configured'
12
- end
13
-
14
- append_ldflags('-lrt') # for timer_create
15
- append_cflags('-fvisibility=hidden')
16
- append_cflags('-DPF2_DEBUG') # TODO: make this conditional
17
-
18
- if have_func('timer_create')
19
- $srcs = Dir.glob("#{File.join(File.dirname(__FILE__), '*.c')}")
20
- create_makefile 'pf2/pf2'
21
- end
@@ -1,397 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'json'
4
-
5
- module Pf2
6
- module Reporter
7
- # Generates Firefox Profiler's "processed profile format"
8
- # https://github.com/firefox-devtools/profiler/blob/main/docs-developer/processed-profile-format.md
9
- class FirefoxProfiler
10
- def initialize(profile)
11
- @profile = FirefoxProfiler.deep_intize_keys(profile)
12
- end
13
-
14
- def inspect
15
- "#<#{self.class.name}>" # TODO: add sample count etc.
16
- end
17
-
18
- def emit
19
- report = {
20
- meta: {
21
- interval: 10, # ms; TODO: replace with actual interval
22
- start_time: 0,
23
- process_type: 0,
24
- product: 'ruby',
25
- stackwalk: 0,
26
- version: 28,
27
- preprocessed_profile_version: 47,
28
- symbolicated: true,
29
- categories: [
30
- {
31
- name: "Logs",
32
- color: "grey",
33
- subcategories: ["Unused"],
34
- },
35
- {
36
- name: "Ruby",
37
- color: "red",
38
- subcategories: ["Code"],
39
- },
40
- {
41
- name: "Native",
42
- color: "blue",
43
- subcategories: ["Code"],
44
- },
45
- {
46
- name: "Native",
47
- color: "lightblue",
48
- subcategories: ["Code"],
49
- },
50
- ],
51
- marker_schema: [],
52
- },
53
- libs: [],
54
- counters: [],
55
- threads: @profile[:threads].values.map {|th| ThreadReport.new(th).emit }
56
- }
57
- FirefoxProfiler.deep_camelize_keys(report)
58
- end
59
-
60
- class ThreadReport
61
- def initialize(thread)
62
- @thread = thread
63
-
64
- # Populated in other methods
65
- @func_id_map = {}
66
- @frame_id_map = {}
67
- @stack_tree_id_map = {}
68
-
69
- @string_table = {}
70
- end
71
-
72
- def inspect
73
- "" # TODO: provide something better
74
- end
75
-
76
- def emit
77
- x = weave_native_stack(@thread[:stack_tree])
78
- @thread[:stack_tree] = x
79
- func_table = build_func_table
80
- frame_table = build_frame_table
81
- stack_table = build_stack_table(func_table, frame_table)
82
- samples = build_samples
83
-
84
- string_table = build_string_table
85
-
86
- {
87
- process_type: 'default',
88
- process_name: 'ruby',
89
- process_startup_time: 0,
90
- process_shutdown_time: nil,
91
- register_time: 0,
92
- unregister_time: nil,
93
- paused_ranges: [],
94
- name: "Thread (tid: #{@thread[:thread_id]})",
95
- is_main_thread: true,
96
- is_js_tracer: true,
97
- # FIXME: We can fill the correct PID only after we correctly fill is_main_thread
98
- # (only one thread could be marked as is_main_thread in a single process)
99
- pid: @thread[:thread_id],
100
- tid: @thread[:thread_id],
101
- samples: samples,
102
- markers: markers,
103
- stack_table: stack_table,
104
- frame_table: frame_table,
105
- string_array: build_string_table,
106
- func_table: func_table,
107
- resource_table: {
108
- lib: [],
109
- name: [],
110
- host: [],
111
- type: [],
112
- length: 0,
113
- },
114
- native_symbols: [],
115
- }
116
- end
117
-
118
- def build_samples
119
- ret = {
120
- event_delay: [],
121
- stack: [],
122
- time: [],
123
- duration: [],
124
- # weight: nil,
125
- # weight_type: 'samples',
126
- }
127
-
128
- @thread[:samples].each do |sample|
129
- ret[:stack] << @stack_tree_id_map[sample[:stack_tree_id]]
130
- ret[:time] << sample[:elapsed_ns] / 1000000 # ns -> ms
131
- ret[:duration] << 1
132
- ret[:event_delay] << 0
133
- end
134
-
135
- ret[:length] = ret[:stack].length
136
- ret
137
- end
138
-
139
- def build_frame_table
140
- ret = {
141
- address: [],
142
- category: [],
143
- subcategory: [],
144
- func: [],
145
- inner_window_id: [],
146
- implementation: [],
147
- line: [],
148
- column: [],
149
- optimizations: [],
150
- inline_depth: [],
151
- native_symbol: [],
152
- }
153
-
154
- @thread[:frames].each.with_index do |(id, frame), i|
155
- ret[:address] << frame[:address].to_s
156
- ret[:category] << 1
157
- ret[:subcategory] << 1
158
- ret[:func] << i # TODO
159
- ret[:inner_window_id] << nil
160
- ret[:implementation] << nil
161
- ret[:line] << frame[:callsite_lineno]
162
- ret[:column] << nil
163
- ret[:optimizations] << nil
164
- ret[:inline_depth] << 0
165
- ret[:native_symbol] << nil
166
-
167
- @frame_id_map[id] = i
168
- end
169
-
170
- ret[:length] = ret[:address].length
171
- ret
172
- end
173
-
174
- def build_func_table
175
- ret = {
176
- name: [],
177
- is_js: [],
178
- relevant_for_js: [],
179
- resource: [],
180
- file_name: [],
181
- line_number: [],
182
- column_number: [],
183
- }
184
-
185
- @thread[:frames].each.with_index do |(id, frame), i|
186
- native = (frame[:entry_type] == 'Native')
187
- label = "#{native ? "Native: " : ""}#{frame[:full_label]}"
188
- ret[:name] << string_id(label)
189
- ret[:is_js] << !native
190
- ret[:relevant_for_js] << false
191
- ret[:resource] << -1
192
- ret[:file_name] << string_id(frame[:file_name])
193
- ret[:line_number] << frame[:function_first_lineno]
194
- ret[:column_number] << nil
195
-
196
- @func_id_map[id] = i
197
- end
198
-
199
- ret[:length] = ret[:name].length
200
- ret
201
- end
202
-
203
- # "Weave" the native stack into the Ruby stack.
204
- #
205
- # Strategy:
206
- # - Split the stack into Ruby and Native parts
207
- # - Start from the root of the Native stack
208
- # - Dig in to the native stack until we hit a rb_vm_exec(), which marks a call into Ruby code
209
- # - Switch to Ruby stack. Keep digging until we hit a Cfunc call, then switch back to Native stack
210
- # - Repeat until we consume the entire stack
211
- def weave_native_stack(stack_tree)
212
- collected_paths = []
213
- tree_to_array_of_paths(stack_tree, @thread[:frames], [], collected_paths)
214
- collected_paths = collected_paths.map do |path|
215
- next if path.size == 0
216
-
217
- new_path = []
218
- new_path << path.shift # root
219
-
220
- # Split the stack into Ruby and Native parts
221
- native_path, ruby_path = path.partition do |frame|
222
- frame_id = frame[:frame_id]
223
- @thread[:frames][frame_id][:entry_type] == 'Native'
224
- end
225
-
226
- mode = :native
227
-
228
- loop do
229
- break if ruby_path.size == 0 && native_path.size == 0
230
-
231
- case mode
232
- when :ruby
233
- if ruby_path.size == 0
234
- mode = :native
235
- next
236
- end
237
-
238
- next_node = ruby_path[0]
239
- new_path << ruby_path.shift
240
- next_node_frame = @thread[:frames][next_node[:frame_id]]
241
- if native_path.size > 0
242
- # Search the remainder of the native stack for the same address
243
- # Note: This isn't a very efficient way for the job... but it still works
244
- ruby_addr = next_node_frame[:address]
245
- native_path[0..].each do |native_node|
246
- native_addr = @thread[:frames][native_node[:frame_id]][:address]
247
- if ruby_addr && native_addr && ruby_addr == native_addr
248
- # A match has been found. Switch to native mode
249
- mode = :native
250
- break
251
- end
252
- end
253
- end
254
- when :native
255
- if native_path.size == 0
256
- mode = :ruby
257
- next
258
- end
259
-
260
- # Dig until we meet a rb_vm_exec
261
- next_node = native_path[0]
262
- new_path << native_path.shift
263
- if @thread[:frames][next_node[:frame_id]][:full_label] =~ /vm_exec_core/ # VM_EXEC in vm_exec.h
264
- mode = :ruby
265
- end
266
- end
267
- end
268
-
269
- new_path
270
- end
271
-
272
- # reconstruct stack_tree
273
- new_stack_tree = array_of_paths_to_tree(collected_paths)
274
- new_stack_tree
275
- end
276
-
277
- def tree_to_array_of_paths(stack_tree, frames, path, collected_paths)
278
- new_path = path + [{ frame_id: stack_tree[:frame_id], node_id: stack_tree[:node_id] }]
279
- if stack_tree[:children].empty?
280
- collected_paths << new_path
281
- else
282
- stack_tree[:children].each do |frame_id, child|
283
- tree_to_array_of_paths(child, frames, new_path, collected_paths)
284
- end
285
- end
286
- end
287
-
288
- def array_of_paths_to_tree(paths)
289
- new_stack_tree = { children: {}, node_id: 0, frame_id: 0 }
290
- paths.each do |path|
291
- current = new_stack_tree
292
- path[1..].each do |frame|
293
- frame_id = frame[:frame_id]
294
- node_id = frame[:node_id]
295
- current[:children][frame_id] ||= { children: {}, node_id: node_id, frame_id: frame_id }
296
- current = current[:children][frame_id]
297
- end
298
- end
299
- new_stack_tree
300
- end
301
-
302
- def build_stack_table(func_table, frame_table)
303
- ret = {
304
- frame: [],
305
- category: [],
306
- subcategory: [],
307
- prefix: [],
308
- }
309
-
310
- queue = []
311
-
312
- @thread[:stack_tree][:children].each {|_, c| queue << [nil, c] }
313
-
314
- loop do
315
- break if queue.size == 0
316
-
317
- prefix, node = queue.shift
318
- ret[:frame] << @frame_id_map[node[:frame_id]]
319
- ret[:category] << (build_string_table[func_table[:name][frame_table[:func][@frame_id_map[node[:frame_id]]]]].start_with?('Native:') ? 2 : 1)
320
- ret[:subcategory] << nil
321
- ret[:prefix] << prefix
322
-
323
- # The index of this frame - children can refer to this frame using this index as prefix
324
- frame_index = ret[:frame].length - 1
325
- @stack_tree_id_map[node[:node_id]] = frame_index
326
-
327
- # Enqueue children nodes
328
- node[:children].each {|_, c| queue << [frame_index, c] }
329
- end
330
-
331
- ret[:length] = ret[:frame].length
332
- ret
333
- end
334
-
335
- def build_string_table
336
- @string_table.sort_by {|_, v| v}.map {|s| s[0] }
337
- end
338
-
339
- def string_id(str)
340
- return @string_table[str] if @string_table.has_key?(str)
341
- @string_table[str] = @string_table.length
342
- @string_table[str]
343
- end
344
-
345
- def markers
346
- {
347
- data: [],
348
- name: [],
349
- time: [],
350
- start_time: [],
351
- end_time: [],
352
- phase: [],
353
- category: [],
354
- length: 0
355
- }
356
- end
357
- end
358
-
359
- # Util functions
360
- class << self
361
- def snake_to_camel(s)
362
- return "isJS" if s == "is_js"
363
- return "relevantForJS" if s == "relevant_for_js"
364
- return "innerWindowID" if s == "inner_window_id"
365
- s.split('_').inject([]) {|buffer, p| buffer.push(buffer.size == 0 ? p : p.capitalize) }.join
366
- end
367
-
368
- def deep_transform_keys(value, &block)
369
- case value
370
- when Array
371
- value.map {|v| deep_transform_keys(v, &block) }
372
- when Hash
373
- Hash[value.map {|k, v| [yield(k), deep_transform_keys(v, &block)] }]
374
- else
375
- value
376
- end
377
- end
378
-
379
- def deep_camelize_keys(value)
380
- deep_transform_keys(value) do |key|
381
- snake_to_camel(key.to_s).to_sym
382
- end
383
- end
384
-
385
- def deep_intize_keys(value)
386
- deep_transform_keys(value) do |key|
387
- if key.to_s.to_i.to_s == key.to_s
388
- key.to_s.to_i
389
- else
390
- key
391
- end
392
- end
393
- end
394
- end
395
- end
396
- end
397
- end
data/rust-toolchain.toml DELETED
@@ -1,2 +0,0 @@
1
- [toolchain]
2
- channel = "1.75.0"
data/rustfmt.toml DELETED
@@ -1 +0,0 @@
1
- use_small_heuristics = "Max"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes