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/pf2/src/lib.rs DELETED
@@ -1,22 +0,0 @@
1
- extern crate serde;
2
- #[macro_use]
3
- extern crate serde_derive;
4
-
5
- mod ruby_init;
6
-
7
- mod backtrace;
8
- mod profile;
9
- mod profile_serializer;
10
- mod ringbuffer;
11
- mod sample;
12
- mod scheduler;
13
- mod serialization;
14
- mod session;
15
- #[cfg(target_os = "linux")]
16
- mod signal_scheduler;
17
- #[cfg(not(target_os = "linux"))]
18
- mod signal_scheduler_unsupported_platform;
19
- mod timer_thread_scheduler;
20
- mod util;
21
-
22
- mod ruby_internal_apis;
@@ -1,69 +0,0 @@
1
- use std::time::{Instant, SystemTime};
2
- use std::{collections::HashSet, ptr::null_mut};
3
-
4
- use rb_sys::*;
5
-
6
- use backtrace_sys2::backtrace_create_state;
7
-
8
- use super::backtrace::{Backtrace, BacktraceState};
9
- use super::ringbuffer::Ringbuffer;
10
- use super::sample::Sample;
11
-
12
- // Capacity large enough to hold 1 second worth of samples for 16 threads
13
- // 16 threads * 20 samples per second * 1 second = 320
14
- const DEFAULT_RINGBUFFER_CAPACITY: usize = 320;
15
-
16
- #[derive(Debug)]
17
- pub struct Profile {
18
- pub start_timestamp: SystemTime,
19
- pub start_instant: Instant,
20
- pub end_instant: Option<Instant>,
21
- pub samples: Vec<Sample>,
22
- pub temporary_sample_buffer: Ringbuffer,
23
- pub backtrace_state: BacktraceState,
24
- known_values: HashSet<VALUE>,
25
- }
26
-
27
- impl Profile {
28
- pub fn new() -> Self {
29
- let backtrace_state = unsafe {
30
- let ptr = backtrace_create_state(
31
- null_mut(),
32
- 1,
33
- Some(Backtrace::backtrace_error_callback),
34
- null_mut(),
35
- );
36
- BacktraceState::new(ptr)
37
- };
38
-
39
- Self {
40
- start_timestamp: SystemTime::now(),
41
- start_instant: Instant::now(),
42
- end_instant: None,
43
- samples: vec![],
44
- temporary_sample_buffer: Ringbuffer::new(DEFAULT_RINGBUFFER_CAPACITY),
45
- backtrace_state,
46
- known_values: HashSet::new(),
47
- }
48
- }
49
-
50
- pub fn flush_temporary_sample_buffer(&mut self) {
51
- while let Some(sample) = self.temporary_sample_buffer.pop() {
52
- self.known_values.insert(sample.ruby_thread);
53
- for frame in sample.frames.iter() {
54
- if frame == &0 {
55
- break;
56
- }
57
- self.known_values.insert(*frame);
58
- }
59
- self.samples.push(sample);
60
- }
61
- }
62
-
63
- pub unsafe fn dmark(&self) {
64
- for value in self.known_values.iter() {
65
- rb_gc_mark(*value);
66
- }
67
- self.temporary_sample_buffer.dmark();
68
- }
69
- }
@@ -1,241 +0,0 @@
1
- use std::collections::HashMap;
2
- use std::ffi::{c_char, CStr};
3
- use std::hash::Hasher;
4
-
5
- use rb_sys::*;
6
-
7
- use crate::backtrace::Backtrace;
8
- use crate::profile::Profile;
9
- use crate::util::RTEST;
10
-
11
- #[derive(Debug, Deserialize, Serialize)]
12
- pub struct ProfileSerializer {
13
- threads: HashMap<ThreadId, ThreadProfile>,
14
- }
15
-
16
- type ThreadId = VALUE;
17
-
18
- #[derive(Debug, Deserialize, Serialize)]
19
- struct ThreadProfile {
20
- thread_id: ThreadId,
21
- stack_tree: StackTreeNode,
22
- #[serde(rename = "frames")]
23
- frame_table: HashMap<FrameTableId, FrameTableEntry>,
24
- samples: Vec<ProfileSample>,
25
- }
26
-
27
- impl ThreadProfile {
28
- fn new(thread_id: ThreadId) -> ThreadProfile {
29
- ThreadProfile {
30
- thread_id,
31
- // The root node
32
- stack_tree: StackTreeNode { children: HashMap::new(), node_id: 0, frame_id: 0 },
33
- frame_table: HashMap::new(),
34
- samples: vec![],
35
- }
36
- }
37
- }
38
-
39
- type StackTreeNodeId = i32;
40
-
41
- // Arbitary value which is used inside StackTreeNode.
42
- // This VALUE should not be dereferenced as a pointer; we're merely using its pointer as a unique value.
43
- // (Probably should be reconsidered)
44
- type FrameTableId = VALUE;
45
-
46
- #[derive(Debug, Deserialize, Serialize)]
47
- struct StackTreeNode {
48
- // TODO: Maybe a Vec<StackTreeNode> is enough?
49
- // There's no particular meaning in using FrameTableId as key
50
- children: HashMap<FrameTableId, StackTreeNode>,
51
- // An arbitary ID (no particular meaning)
52
- node_id: StackTreeNodeId,
53
- // ?
54
- frame_id: FrameTableId,
55
- }
56
-
57
- #[derive(Debug, Deserialize, Serialize)]
58
- struct FrameTableEntry {
59
- id: FrameTableId,
60
- entry_type: FrameTableEntryType,
61
- full_label: String,
62
- file_name: Option<String>,
63
- function_first_lineno: Option<i32>,
64
- callsite_lineno: Option<i32>,
65
- address: Option<usize>,
66
- }
67
-
68
- #[derive(Debug, Deserialize, Serialize)]
69
- enum FrameTableEntryType {
70
- Ruby,
71
- Native,
72
- }
73
-
74
- // Represents leaf (末端)
75
- #[derive(Debug, Deserialize, Serialize)]
76
- struct ProfileSample {
77
- elapsed_ns: u128,
78
- stack_tree_id: StackTreeNodeId,
79
- }
80
-
81
- struct NativeFunctionFrame {
82
- pub symbol_name: String,
83
- pub address: Option<usize>,
84
- }
85
-
86
- impl ProfileSerializer {
87
- pub fn serialize(profile: &Profile) -> String {
88
- let mut sequence = 1;
89
-
90
- let mut serializer = ProfileSerializer { threads: HashMap::new() };
91
-
92
- unsafe {
93
- // Process each sample
94
- for sample in profile.samples.iter() {
95
- let mut merged_stack: Vec<FrameTableEntry> = vec![];
96
-
97
- // Process C-level stack
98
-
99
- let mut c_stack: Vec<NativeFunctionFrame> = vec![];
100
- // Rebuild the original backtrace (including inlined functions) from the PC.
101
- for i in 0..sample.c_backtrace_pcs[0] {
102
- let pc = sample.c_backtrace_pcs[i + 1];
103
- Backtrace::backtrace_syminfo(
104
- &profile.backtrace_state,
105
- pc,
106
- |_pc: usize, symname: *const c_char, symval: usize, _symsize: usize| {
107
- if symname.is_null() {
108
- c_stack.push(NativeFunctionFrame {
109
- symbol_name: "(no symbol information)".to_owned(),
110
- address: None,
111
- });
112
- } else {
113
- c_stack.push(NativeFunctionFrame {
114
- symbol_name: CStr::from_ptr(symname)
115
- .to_str()
116
- .unwrap()
117
- .to_owned(),
118
- address: Some(symval),
119
- });
120
- }
121
- },
122
- Some(Backtrace::backtrace_error_callback),
123
- );
124
- }
125
- for frame in c_stack.iter() {
126
- if frame.symbol_name.contains("pf2") {
127
- // Skip Pf2-related frames
128
- continue;
129
- }
130
-
131
- merged_stack.push(FrameTableEntry {
132
- id: calculate_id_for_c_frame(&frame.symbol_name),
133
- entry_type: FrameTableEntryType::Native,
134
- full_label: frame.symbol_name.clone(),
135
- file_name: None,
136
- function_first_lineno: None,
137
- callsite_lineno: None,
138
- address: frame.address,
139
- });
140
- }
141
-
142
- // Process Ruby-level stack
143
-
144
- let ruby_stack_depth = sample.line_count;
145
- for i in 0..ruby_stack_depth {
146
- let frame: VALUE = sample.frames[i as usize];
147
- let lineno: i32 = sample.linenos[i as usize];
148
- let address: Option<usize> = {
149
- let cme = frame
150
- as *mut crate::ruby_internal_apis::rb_callable_method_entry_struct;
151
- let cme = &*cme;
152
-
153
- if (*(cme.def)).type_ == 1 {
154
- // The cme is a Cfunc
155
- Some((*(cme.def)).cfunc.func as usize)
156
- } else {
157
- // The cme is an ISeq (Ruby code) or some other type
158
- None
159
- }
160
- };
161
- let mut frame_full_label: VALUE = rb_profile_frame_full_label(frame);
162
- let frame_full_label: String = if RTEST(frame_full_label) {
163
- CStr::from_ptr(rb_string_value_cstr(&mut frame_full_label))
164
- .to_str()
165
- .unwrap()
166
- .to_owned()
167
- } else {
168
- "(unknown)".to_owned()
169
- };
170
- let mut frame_path: VALUE = rb_profile_frame_path(frame);
171
- let frame_path: String = if RTEST(frame_path) {
172
- CStr::from_ptr(rb_string_value_cstr(&mut frame_path))
173
- .to_str()
174
- .unwrap()
175
- .to_owned()
176
- } else {
177
- "(unknown)".to_owned()
178
- };
179
- let frame_first_lineno: VALUE = rb_profile_frame_first_lineno(frame);
180
- let frame_first_lineno: Option<i32> = if RTEST(frame_first_lineno) {
181
- Some(rb_num2int(frame_first_lineno).try_into().unwrap())
182
- } else {
183
- None
184
- };
185
- merged_stack.push(FrameTableEntry {
186
- id: frame,
187
- entry_type: FrameTableEntryType::Ruby,
188
- full_label: frame_full_label,
189
- file_name: Some(frame_path),
190
- function_first_lineno: frame_first_lineno,
191
- callsite_lineno: Some(lineno),
192
- address,
193
- });
194
- }
195
-
196
- // Find the Thread profile for this sample
197
- let thread_serializer = serializer
198
- .threads
199
- .entry(sample.ruby_thread)
200
- .or_insert(ThreadProfile::new(sample.ruby_thread));
201
-
202
- // Stack frames, shallow to deep
203
- let mut stack_tree = &mut thread_serializer.stack_tree;
204
-
205
- while let Some(frame_table_entry) = merged_stack.pop() {
206
- stack_tree = stack_tree.children.entry(frame_table_entry.id).or_insert({
207
- let node = StackTreeNode {
208
- children: HashMap::new(),
209
- node_id: sequence,
210
- frame_id: frame_table_entry.id,
211
- };
212
- sequence += 1;
213
- node
214
- });
215
-
216
- if merged_stack.is_empty() {
217
- // This is the leaf node, record a Sample
218
- let elapsed_ns = (sample.timestamp - profile.start_instant).as_nanos();
219
- thread_serializer
220
- .samples
221
- .push(ProfileSample { elapsed_ns, stack_tree_id: stack_tree.node_id });
222
- }
223
-
224
- // Register frame metadata to frame table, if not registered yet
225
- thread_serializer
226
- .frame_table
227
- .entry(frame_table_entry.id)
228
- .or_insert(frame_table_entry);
229
- }
230
- }
231
- }
232
-
233
- serde_json::to_string(&serializer).unwrap()
234
- }
235
- }
236
-
237
- fn calculate_id_for_c_frame<T: std::hash::Hash>(t: &T) -> FrameTableId {
238
- let mut s = std::collections::hash_map::DefaultHasher::new();
239
- t.hash(&mut s);
240
- s.finish()
241
- }
@@ -1,150 +0,0 @@
1
- use crate::sample::Sample;
2
-
3
- #[derive(Debug)]
4
- pub struct Ringbuffer {
5
- capacity: usize,
6
- buffer: Vec<Option<Sample>>,
7
- read_index: usize,
8
- write_index: usize,
9
- }
10
-
11
- #[derive(Debug, PartialEq)]
12
- pub enum RingbufferError {
13
- Full,
14
- }
15
-
16
- impl Ringbuffer {
17
- pub fn new(capacity: usize) -> Self {
18
- Self {
19
- capacity,
20
- buffer: std::iter::repeat_with(|| None).take(capacity + 1).collect::<Vec<_>>(),
21
- read_index: 0,
22
- write_index: 0,
23
- }
24
- }
25
-
26
- // async-signal-safe
27
- pub fn push(&mut self, sample: Sample) -> Result<(), RingbufferError> {
28
- let next = (self.write_index + 1) % (self.capacity + 1);
29
- if next == self.read_index {
30
- return Err(RingbufferError::Full);
31
- }
32
- self.buffer[self.write_index] = Some(sample);
33
- self.write_index = next;
34
- Ok(())
35
- }
36
-
37
- pub fn pop(&mut self) -> Option<Sample> {
38
- if self.read_index == self.write_index {
39
- return None;
40
- }
41
- let sample = self.buffer[self.read_index].take();
42
- self.read_index = (self.read_index + 1) % (self.capacity + 1);
43
- sample
44
- }
45
-
46
- // This will call rb_gc_mark() for capacity * Sample::MAX_STACK_DEPTH * 2 times, which is a lot!
47
- pub fn dmark(&self) {
48
- for sample in self.buffer.iter().flatten() {
49
- unsafe {
50
- sample.dmark();
51
- }
52
- }
53
- }
54
- }
55
-
56
- #[cfg(test)]
57
- mod tests {
58
- use super::*;
59
- use std::time::Instant;
60
-
61
- #[test]
62
- fn test_ringbuffer() {
63
- let mut ringbuffer = Ringbuffer::new(2);
64
- assert_eq!(ringbuffer.pop(), None);
65
-
66
- let sample1 = Sample {
67
- ruby_thread: 1,
68
- timestamp: Instant::now(),
69
- line_count: 0,
70
- frames: [0; 500],
71
- linenos: [0; 500],
72
- c_backtrace_pcs: [0; 1001],
73
- };
74
- let sample2 = Sample {
75
- ruby_thread: 2,
76
- timestamp: Instant::now(),
77
- line_count: 0,
78
- frames: [0; 500],
79
- linenos: [0; 500],
80
- c_backtrace_pcs: [0; 1001],
81
- };
82
-
83
- ringbuffer.push(sample1).unwrap();
84
- ringbuffer.push(sample2).unwrap();
85
-
86
- assert_eq!(ringbuffer.pop().unwrap().ruby_thread, 1);
87
- assert_eq!(ringbuffer.pop().unwrap().ruby_thread, 2);
88
- assert_eq!(ringbuffer.pop(), None);
89
- }
90
-
91
- #[test]
92
- fn test_ringbuffer_full() {
93
- let mut ringbuffer = Ringbuffer::new(1);
94
- let sample1 = Sample {
95
- ruby_thread: 1,
96
- timestamp: Instant::now(),
97
- line_count: 0,
98
- frames: [0; 500],
99
- linenos: [0; 500],
100
- c_backtrace_pcs: [0; 1001],
101
- };
102
- let sample2 = Sample {
103
- ruby_thread: 2,
104
- timestamp: Instant::now(),
105
- line_count: 0,
106
- frames: [0; 500],
107
- linenos: [0; 500],
108
- c_backtrace_pcs: [0; 1001],
109
- };
110
-
111
- ringbuffer.push(sample1).unwrap();
112
- assert_eq!(ringbuffer.push(sample2), Err(RingbufferError::Full));
113
- }
114
-
115
- #[test]
116
- fn test_ringbuffer_write_a_lot() {
117
- let mut ringbuffer = Ringbuffer::new(2);
118
- let sample1 = Sample {
119
- ruby_thread: 1,
120
- timestamp: Instant::now(),
121
- line_count: 0,
122
- frames: [0; 500],
123
- linenos: [0; 500],
124
- c_backtrace_pcs: [0; 1001],
125
- };
126
- let sample2 = Sample {
127
- ruby_thread: 2,
128
- timestamp: Instant::now(),
129
- line_count: 0,
130
- frames: [0; 500],
131
- linenos: [0; 500],
132
- c_backtrace_pcs: [0; 1001],
133
- };
134
- let sample3 = Sample {
135
- ruby_thread: 3,
136
- timestamp: Instant::now(),
137
- line_count: 0,
138
- frames: [0; 500],
139
- linenos: [0; 500],
140
- c_backtrace_pcs: [0; 1001],
141
- };
142
-
143
- ringbuffer.push(sample1).unwrap();
144
- ringbuffer.pop().unwrap();
145
- ringbuffer.push(sample2).unwrap();
146
- ringbuffer.pop().unwrap();
147
- ringbuffer.push(sample3).unwrap();
148
- assert_eq!(ringbuffer.pop().unwrap().ruby_thread, 3);
149
- }
150
- }
@@ -1,6 +0,0 @@
1
- #include <ruby.h>
2
-
3
- VALUE rb_ull2num(unsigned long long n) {
4
- if (POSFIXABLE(n)) return LONG2FIX((long)n);
5
- return rb_ull2inum(n);
6
- }
@@ -1,40 +0,0 @@
1
- #![deny(unsafe_op_in_unsafe_fn)]
2
-
3
- use rb_sys::*;
4
-
5
- use crate::session::ruby_object::SessionRubyObject;
6
- use crate::util::*;
7
-
8
- #[allow(non_snake_case)]
9
- #[no_mangle]
10
- extern "C" fn Init_pf2() {
11
- #[cfg(feature = "debug")]
12
- {
13
- env_logger::builder().format_timestamp(None).format_module_path(false).init();
14
- }
15
-
16
- unsafe {
17
- let rb_mPf2: VALUE = rb_define_module(cstr!("Pf2"));
18
-
19
- let rb_mPf2_Session = rb_define_class_under(rb_mPf2, cstr!("Session"), rb_cObject);
20
- rb_define_alloc_func(rb_mPf2_Session, Some(SessionRubyObject::rb_alloc));
21
- rb_define_method(
22
- rb_mPf2_Session,
23
- cstr!("initialize"),
24
- Some(to_ruby_cfunc_with_args(SessionRubyObject::rb_initialize)),
25
- -1,
26
- );
27
- rb_define_method(
28
- rb_mPf2_Session,
29
- cstr!("start"),
30
- Some(to_ruby_cfunc_with_no_args(SessionRubyObject::rb_start)),
31
- 0,
32
- );
33
- rb_define_method(
34
- rb_mPf2_Session,
35
- cstr!("stop"),
36
- Some(to_ruby_cfunc_with_no_args(SessionRubyObject::rb_stop)),
37
- 0,
38
- );
39
- }
40
- }
@@ -1,77 +0,0 @@
1
- #![allow(non_snake_case)]
2
- #![allow(non_camel_case_types)]
3
-
4
- use libc::{clockid_t, pthread_t};
5
- use rb_sys::{rb_check_typeddata, rb_data_type_struct, RTypedData, VALUE};
6
- use std::ffi::{c_char, c_int, c_void};
7
- use std::mem::MaybeUninit;
8
-
9
- #[cfg(target_os = "linux")]
10
- use libc::pthread_getcpuclockid;
11
-
12
- #[cfg(not(target_os = "linux"))]
13
- pub unsafe fn pthread_getcpuclockid(thread: pthread_t, clk_id: *mut clockid_t) -> c_int {
14
- unimplemented!()
15
- }
16
-
17
- // Types and structs from Ruby 3.4.0.
18
- #[repr(C)]
19
- pub struct rb_callable_method_entry_struct {
20
- /* same fields with rb_method_entry_t */
21
- pub flags: VALUE,
22
- _padding_defined_class: VALUE,
23
- pub def: *mut rb_method_definition_struct,
24
- // ...
25
- }
26
-
27
- #[repr(C)]
28
- pub struct rb_method_definition_struct {
29
- pub type_: c_int,
30
- _padding: [c_char; 4],
31
- pub cfunc: rb_method_cfunc_struct,
32
- // ...
33
- }
34
-
35
- #[repr(C)]
36
- pub struct rb_method_cfunc_struct {
37
- pub func: *mut c_void,
38
- // ...
39
- }
40
-
41
- type rb_nativethread_id_t = libc::pthread_t;
42
-
43
- #[repr(C)]
44
- struct rb_native_thread {
45
- _padding_serial: [c_char; 4], // rb_atomic_t
46
- _padding_vm: *mut c_int, // struct rb_vm_struct
47
- thread_id: rb_nativethread_id_t,
48
- // ...
49
- }
50
-
51
- #[repr(C)]
52
- struct rb_thread_struct {
53
- _padding_lt_node: [c_char; 16], // struct ccan_list_node
54
- _padding_self: VALUE,
55
- _padding_ractor: *mut c_int, // rb_ractor_t
56
- _padding_vm: *mut c_int, // rb_vm_t
57
- nt: *mut rb_native_thread,
58
- // ...
59
- }
60
- type rb_thread_t = rb_thread_struct;
61
-
62
- /// Reimplementation of the internal RTYPEDDATA_TYPE macro.
63
- unsafe fn RTYPEDDATA_TYPE(obj: VALUE) -> *const rb_data_type_struct {
64
- let typed: *mut RTypedData = obj as *mut RTypedData;
65
- (*typed).type_
66
- }
67
-
68
- unsafe fn rb_thread_ptr(thread: VALUE) -> *mut rb_thread_t {
69
- unsafe { rb_check_typeddata(thread, RTYPEDDATA_TYPE(thread)) as *mut rb_thread_t }
70
- }
71
-
72
- pub unsafe fn rb_thread_getcpuclockid(thread: VALUE) -> clockid_t {
73
- let mut cid: clockid_t = MaybeUninit::zeroed().assume_init();
74
- let pthread_id: pthread_t = (*(*rb_thread_ptr(thread)).nt).thread_id;
75
- pthread_getcpuclockid(pthread_id, &mut cid as *mut clockid_t);
76
- cid
77
- }
@@ -1,67 +0,0 @@
1
- use std::time::Instant;
2
-
3
- use rb_sys::*;
4
-
5
- use crate::backtrace::{Backtrace, BacktraceState};
6
-
7
- const MAX_STACK_DEPTH: usize = 500;
8
- const MAX_C_STACK_DEPTH: usize = 1000;
9
-
10
- #[derive(Debug, PartialEq)]
11
- pub struct Sample {
12
- pub ruby_thread: VALUE,
13
- pub timestamp: Instant,
14
- pub line_count: i32,
15
- pub frames: [VALUE; MAX_STACK_DEPTH],
16
- pub linenos: [i32; MAX_STACK_DEPTH],
17
- /// First element represents the backtrace depth.
18
- pub c_backtrace_pcs: [usize; MAX_C_STACK_DEPTH + 1],
19
- }
20
-
21
- impl Sample {
22
- // Nearly async-signal-safe
23
- // (rb_profile_thread_frames isn't defined as a-s-s)
24
- pub fn capture(ruby_thread: VALUE, backtrace_state: &BacktraceState) -> Self {
25
- let mut c_backtrace_pcs = [0; MAX_C_STACK_DEPTH + 1];
26
-
27
- Backtrace::backtrace_simple(
28
- backtrace_state,
29
- 0,
30
- |pc: usize| -> i32 {
31
- if c_backtrace_pcs[0] >= MAX_C_STACK_DEPTH {
32
- return 1;
33
- }
34
- c_backtrace_pcs[0] += 1;
35
- c_backtrace_pcs[c_backtrace_pcs[0]] = pc;
36
- 0
37
- },
38
- Some(Backtrace::backtrace_error_callback),
39
- );
40
-
41
- let mut sample = Sample {
42
- ruby_thread,
43
- timestamp: Instant::now(),
44
- line_count: 0,
45
- frames: [0; MAX_STACK_DEPTH],
46
- linenos: [0; MAX_STACK_DEPTH],
47
- c_backtrace_pcs,
48
- };
49
- unsafe {
50
- sample.line_count = rb_profile_thread_frames(
51
- ruby_thread,
52
- 0,
53
- 2000,
54
- sample.frames.as_mut_ptr(),
55
- sample.linenos.as_mut_ptr(),
56
- );
57
- };
58
- sample
59
- }
60
-
61
- pub unsafe fn dmark(&self) {
62
- rb_gc_mark(self.ruby_thread);
63
- for frame in self.frames.iter() {
64
- rb_gc_mark(*frame);
65
- }
66
- }
67
- }
@@ -1,10 +0,0 @@
1
- use rb_sys::{size_t, VALUE};
2
-
3
- pub trait Scheduler {
4
- fn start(&self) -> VALUE;
5
- fn stop(&self) -> VALUE;
6
- fn on_new_thread(&self, thread: VALUE);
7
- fn dmark(&self);
8
- fn dfree(&self);
9
- fn dsize(&self) -> size_t;
10
- }