pf2 0.5.0 → 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c4b713a9333a657f9b2259cdbae91e9aabde4312c2791a4dce517ce7d30cc46a
4
- data.tar.gz: f01a941327ac6f2ce8b116a466a85a3021ffe0f612063b0f1466e7a31b373984
3
+ metadata.gz: 66bf1eb8d6457621a04819a8d100bdb109bf1fd7b4820eb1423a85dcfb91799c
4
+ data.tar.gz: b1046c04ae8a2a0630d3bd2ed86c4dc645a9ca42c8038bfaaee0be4c71dbec78
5
5
  SHA512:
6
- metadata.gz: cf8c6b94d2a2ccee5912388a4f2f43f09612f9f3ba5a4ff10d615c7798bde30eb6061f03a9c79fa1ffe946da5f4a065eeae2bbe75ce1bb99821ce5253cc3ba9f
7
- data.tar.gz: 50bd5c325fded53cf1585245469232c3fb184d1b3b893df0deb35a8f5d410046c3c821b1a27d468df6a3bb9ac8e2d7a12011aaa94a8d6889ca013dd4ec1f8eb1
6
+ metadata.gz: 5e8854a44c477c42dc9baa0a5b2cd95e19cd09a3c41fad0e950e7de6bd88ff90bf6a3d8e7b61c43c966976211047d5ecb6da11fbe5cba6460ab456186856e2b8
7
+ data.tar.gz: 8d577d2502f38dab61d3ab130f2555b314667c414ec13b2829f2e7fdf0ddf1f114310d560806685145e5ce65f7f24cc50f834f9fc6eb2b1e0d7763b8ebe69d5f
data/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.5.2] - 2024-07-13
4
+
5
+ ### Fixed
6
+
7
+ - Properly default to TimerThread scheduler on non-Linux environments.
8
+
9
+
10
+ ## [0.5.1] - 2024-03-25
11
+
12
+ ### Fixed
13
+
14
+ - Fixed compilation on non-Linux environments.
15
+
3
16
 
4
17
  ## [0.5.0] - 2024-03-25
5
18
 
data/README.md CHANGED
@@ -58,7 +58,7 @@ File.write("my_program.pf2profile", profile)
58
58
  Profiles can be visualized using the [Firefox Profiler](https://profiler.firefox.com/).
59
59
 
60
60
  ```console
61
- $ pf2 -o report.json my_program.pf2profile
61
+ $ pf2 report -o report.json my_program.pf2profile
62
62
  ```
63
63
 
64
64
  ### Configuration
@@ -108,9 +108,9 @@ Schedulers determine when to execute sample collection, based on configuration (
108
108
 
109
109
  #### SignalScheduler (Linux-only)
110
110
 
111
- The first is the `SignalScheduler`, based on POSIX timers. Pf2 will use this scheduler when possible. SignalScheduler creates a POSIX timer for each Ruby Thread (the underlying pthread to be more accurate) using `timer_create(3)`. This leaves the actual time-keeping to the OS, which is capable of tracking accurate per-thread CPU time usage.
111
+ The first is the `SignalScheduler`, based on POSIX timers. Pf2 will use this scheduler when possible. SignalScheduler creates a POSIX timer for each Ruby Thread (the underlying pthread to be more accurate) using `timer_create(2)`. This leaves the actual time-keeping to the OS, which is capable of tracking accurate per-thread CPU time usage.
112
112
 
113
- When the specified interval has arrived (the timer has _expired_), the OS delivers us a SIGALRM (note: Unlike `setitimer(2)`, `timer_create(3)` allows us to choose which signal to be delivered, and Pf2 uses SIGALRM regardless of time mode). This is why the scheduler is named SignalScheduler.
113
+ When the specified interval has arrived (the timer has _expired_), the OS delivers us a SIGALRM (note: Unlike `setitimer(2)`, `timer_create(2)` allows us to choose which signal to be delivered, and Pf2 uses SIGALRM regardless of time mode). This is why the scheduler is named SignalScheduler.
114
114
 
115
115
  Signals are directed to Ruby Threads' underlying pthread, effectively "pausing" the Thread's activity. This routing is done using `SIGEV_THREAD_ID`, which is a Linux-only feature. Sample collection is done in the signal handler, which is expected to be more _accurate_, capturing the paused Thread's activity.
116
116
 
data/ext/pf2/src/lib.rs CHANGED
@@ -13,6 +13,8 @@ mod scheduler;
13
13
  mod session;
14
14
  #[cfg(target_os = "linux")]
15
15
  mod signal_scheduler;
16
+ #[cfg(not(target_os = "linux"))]
17
+ mod signal_scheduler_unsupported_platform;
16
18
  mod timer_thread_scheduler;
17
19
  mod util;
18
20
 
@@ -1,13 +1,20 @@
1
1
  #![allow(non_snake_case)]
2
2
  #![allow(non_camel_case_types)]
3
3
 
4
- use libc::{clockid_t, pthread_getcpuclockid, pthread_t};
4
+ use libc::{clockid_t, pthread_t};
5
5
  use rb_sys::{rb_check_typeddata, rb_data_type_struct, RTypedData, VALUE};
6
6
  use std::ffi::{c_char, c_int, c_void};
7
7
  use std::mem::MaybeUninit;
8
8
 
9
- // Types and structs from Ruby 3.4.0.
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
+ }
10
16
 
17
+ // Types and structs from Ruby 3.4.0.
11
18
  #[repr(C)]
12
19
  pub struct rb_callable_method_entry_struct {
13
20
  /* same fields with rb_method_entry_t */
@@ -6,9 +6,16 @@ use rb_sys::*;
6
6
 
7
7
  use crate::util::cstr;
8
8
 
9
+ #[cfg(target_os = "linux")]
9
10
  pub const DEFAULT_SCHEDULER: Scheduler = Scheduler::Signal;
10
- pub const DEFAULT_INTERVAL: Duration = Duration::from_millis(49);
11
+ #[cfg(target_os = "linux")]
11
12
  pub const DEFAULT_TIME_MODE: TimeMode = TimeMode::CpuTime;
13
+ #[cfg(not(target_os = "linux"))]
14
+ pub const DEFAULT_SCHEDULER: Scheduler = Scheduler::TimerThread;
15
+ #[cfg(not(target_os = "linux"))]
16
+ pub const DEFAULT_TIME_MODE: TimeMode = TimeMode::WallTime;
17
+
18
+ pub const DEFAULT_INTERVAL: Duration = Duration::from_millis(49);
12
19
 
13
20
  #[derive(Clone, Debug)]
14
21
  pub struct Configuration {
@@ -1,7 +1,7 @@
1
1
  use std::ffi::{c_int, c_void};
2
2
  use std::mem;
3
3
  use std::mem::ManuallyDrop;
4
- use std::ptr::null_mut;
4
+ use std::ptr::{addr_of, null_mut};
5
5
 
6
6
  use rb_sys::*;
7
7
 
@@ -43,7 +43,7 @@ impl SessionRubyObject {
43
43
  // Extract the SessionRubyObject struct from a Ruby object
44
44
  unsafe fn get_struct_from(obj: VALUE) -> ManuallyDrop<Box<Self>> {
45
45
  unsafe {
46
- let ptr = rb_check_typeddata(obj, &RBDATA);
46
+ let ptr = rb_check_typeddata(obj, addr_of!(RBDATA));
47
47
  ManuallyDrop::new(Box::from_raw(ptr as *mut SessionRubyObject))
48
48
  }
49
49
  }
@@ -55,7 +55,11 @@ impl SessionRubyObject {
55
55
  let rb_mPf2: VALUE = rb_define_module(cstr!("Pf2"));
56
56
  let rb_cSession = rb_define_class_under(rb_mPf2, cstr!("Session"), rb_cObject);
57
57
  // Wrap the struct into a Ruby object
58
- rb_data_typed_object_wrap(rb_cSession, Box::into_raw(obj) as *mut c_void, &RBDATA)
58
+ rb_data_typed_object_wrap(
59
+ rb_cSession,
60
+ Box::into_raw(obj) as *mut c_void,
61
+ addr_of!(RBDATA),
62
+ )
59
63
  }
60
64
 
61
65
  unsafe extern "C" fn dmark(ptr: *mut c_void) {
@@ -16,7 +16,10 @@ use self::configuration::Configuration;
16
16
  use self::new_thread_watcher::NewThreadWatcher;
17
17
  use crate::profile::Profile;
18
18
  use crate::scheduler::Scheduler;
19
+ #[cfg(target_os = "linux")]
19
20
  use crate::signal_scheduler::SignalScheduler;
21
+ #[cfg(not(target_os = "linux"))]
22
+ use crate::signal_scheduler_unsupported_platform::SignalScheduler;
20
23
  use crate::timer_thread_scheduler::TimerThreadScheduler;
21
24
  use crate::util::*;
22
25
 
@@ -90,12 +93,17 @@ impl Session {
90
93
  )),
91
94
  };
92
95
 
96
+ let running = Arc::new(AtomicBool::new(false));
97
+
93
98
  let new_thread_watcher = match threads {
94
99
  configuration::Threads::All => {
95
100
  let scheduler = Arc::clone(&scheduler);
101
+ let running = Arc::clone(&running);
96
102
  Some(NewThreadWatcher::watch(move |thread: VALUE| {
97
- log::debug!("New Ruby thread detected: {:?}", thread);
98
- scheduler.on_new_thread(thread);
103
+ if running.load(Ordering::Relaxed) {
104
+ log::debug!("New Ruby thread detected: {:?}", thread);
105
+ scheduler.on_new_thread(thread);
106
+ }
99
107
  }))
100
108
  }
101
109
  configuration::Threads::Targeted(_) => None,
@@ -105,7 +113,7 @@ impl Session {
105
113
  configuration,
106
114
  scheduler,
107
115
  profile,
108
- running: Arc::new(AtomicBool::new(false)),
116
+ running,
109
117
  new_thread_watcher,
110
118
  }
111
119
  }
@@ -176,15 +184,27 @@ impl Session {
176
184
  let ptr = rb_string_value_ptr(&mut str);
177
185
  CStr::from_ptr(ptr).to_str().unwrap()
178
186
  };
179
- configuration::Scheduler::from_str(specified_scheduler).unwrap_or_else(|_| {
180
- // Raise an ArgumentError if the mode is invalid
187
+ let scheduler =
188
+ configuration::Scheduler::from_str(specified_scheduler).unwrap_or_else(|_| {
189
+ // Raise an ArgumentError if the mode is invalid
190
+ unsafe {
191
+ rb_raise(
192
+ rb_eArgError,
193
+ cstr!("Invalid scheduler. Valid values are ':signal' and ':timer_thread'."),
194
+ )
195
+ }
196
+ });
197
+
198
+ // Raise an ArgumentError if the scheduler is not supported on the current platform
199
+ if !cfg!(target_os = "linux") && scheduler == configuration::Scheduler::Signal {
181
200
  unsafe {
182
201
  rb_raise(
183
202
  rb_eArgError,
184
- cstr!("Invalid scheduler. Valid values are ':signal' and ':timer_thread'."),
203
+ cstr!("Signal scheduler is not supported on this platform."),
185
204
  )
186
205
  }
187
- })
206
+ }
207
+ scheduler
188
208
  }
189
209
 
190
210
  pub fn start(&mut self) -> VALUE {
@@ -103,6 +103,7 @@ impl SignalScheduler {
103
103
  if err != 0 {
104
104
  panic!("sigaction failed: {}", err);
105
105
  }
106
+ log::debug!("Signal handler installed");
106
107
  }
107
108
 
108
109
  // Respond to the signal and collect a sample.
@@ -0,0 +1,39 @@
1
+ use std::sync::{Arc, RwLock};
2
+
3
+ use crate::profile::Profile;
4
+ use crate::scheduler::Scheduler;
5
+ use crate::session::configuration::Configuration;
6
+
7
+ pub struct SignalScheduler {}
8
+
9
+ impl Scheduler for SignalScheduler {
10
+ fn start(&self) -> rb_sys::VALUE {
11
+ unimplemented!()
12
+ }
13
+
14
+ fn stop(&self) -> rb_sys::VALUE {
15
+ unimplemented!()
16
+ }
17
+
18
+ fn on_new_thread(&self, thread: rb_sys::VALUE) {
19
+ unimplemented!()
20
+ }
21
+
22
+ fn dmark(&self) {
23
+ unimplemented!()
24
+ }
25
+
26
+ fn dfree(&self) {
27
+ unimplemented!()
28
+ }
29
+
30
+ fn dsize(&self) -> rb_sys::size_t {
31
+ unimplemented!()
32
+ }
33
+ }
34
+
35
+ impl SignalScheduler {
36
+ pub fn new(configuration: &Configuration, profile: Arc<RwLock<Profile>>) -> Self {
37
+ unimplemented!()
38
+ }
39
+ }
data/lib/pf2/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Pf2
2
- VERSION = '0.5.0'
2
+ VERSION = '0.5.2'
3
3
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pf2
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.5.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daisuke Aritomo
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2024-03-24 00:00:00.000000000 Z
10
+ date: 2024-07-12 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: rake-compiler
@@ -177,6 +177,7 @@ files:
177
177
  - ext/pf2/src/session/ruby_object.rs
178
178
  - ext/pf2/src/siginfo_t.c
179
179
  - ext/pf2/src/signal_scheduler.rs
180
+ - ext/pf2/src/signal_scheduler_unsupported_platform.rs
180
181
  - ext/pf2/src/timer_thread_scheduler.rs
181
182
  - ext/pf2/src/util.rs
182
183
  - lib/pf2.rb