pf2 0.5.0 → 0.5.2
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 +4 -4
- data/CHANGELOG.md +13 -0
- data/README.md +3 -3
- data/ext/pf2/src/lib.rs +2 -0
- data/ext/pf2/src/ruby_internal_apis.rs +9 -2
- data/ext/pf2/src/session/configuration.rs +8 -1
- data/ext/pf2/src/session/ruby_object.rs +7 -3
- data/ext/pf2/src/session.rs +27 -7
- data/ext/pf2/src/signal_scheduler.rs +1 -0
- data/ext/pf2/src/signal_scheduler_unsupported_platform.rs +39 -0
- data/lib/pf2/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 66bf1eb8d6457621a04819a8d100bdb109bf1fd7b4820eb1423a85dcfb91799c
|
4
|
+
data.tar.gz: b1046c04ae8a2a0630d3bd2ed86c4dc645a9ca42c8038bfaaee0be4c71dbec78
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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(
|
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(
|
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
@@ -1,13 +1,20 @@
|
|
1
1
|
#![allow(non_snake_case)]
|
2
2
|
#![allow(non_camel_case_types)]
|
3
3
|
|
4
|
-
use libc::{clockid_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
|
-
|
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
|
-
|
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,
|
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(
|
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) {
|
data/ext/pf2/src/session.rs
CHANGED
@@ -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
|
-
|
98
|
-
|
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
|
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
|
-
|
180
|
-
|
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!("
|
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 {
|
@@ -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
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.
|
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-
|
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
|