/rust/registry/src/index.crates.io-6f17d22bba15001f/ittapi-0.3.3/src/jit.rs
Line | Count | Source (jump to first uncovered line) |
1 | | //! The JIT (Just-In-Time) Profiling API provides functionality to report information about |
2 | | //! just-in-time generated code that can be used by performance tools. The [Jit] Rust structure is a |
3 | | //! high-level view of a subset of the full functionality available. See the [JIT Profiling API] for |
4 | | //! more information. |
5 | | //! |
6 | | //! [JIT Profiling API]: |
7 | | /// https://www.intel.com/content/www/us/en/develop/documentation/vtune-help/top/api-support/jit-profiling-api.html |
8 | | use anyhow::Context; |
9 | | use std::{ffi::CString, os, ptr}; |
10 | | |
11 | | /// Register JIT-compiled methods with a performance tool (e.g., VTune). This structure assumes |
12 | | /// single-threaded access; if your program may be multi-threaded, make sure to guard multi-threaded |
13 | | /// access with a mutex. |
14 | 0 | #[derive(Default)] Unexecuted instantiation: <ittapi::jit::Jit as core::default::Default>::default Unexecuted instantiation: <ittapi::jit::Jit as core::default::Default>::default |
15 | | pub struct Jit { |
16 | | shutdown_complete: bool, |
17 | | } |
18 | | |
19 | | impl Jit { |
20 | | /// Returns a new `MethodId` for use in `MethodLoad` events. |
21 | | #[allow(clippy::unused_self)] |
22 | 0 | pub fn get_method_id(&self) -> MethodId { |
23 | 0 | MethodId(unsafe { ittapi_sys::iJIT_GetNewMethodID() }) |
24 | 0 | } |
25 | | |
26 | | /// Notifies any `EventType` to VTune. |
27 | | /// |
28 | | /// # Errors |
29 | | /// |
30 | | /// May fail if the underlying call to the ITT library fails. |
31 | | #[allow(clippy::unused_self)] |
32 | 0 | pub fn notify_event(&self, mut event: EventType) -> anyhow::Result<()> { |
33 | 0 | let tag = event.tag(); |
34 | 0 | let data = event.data(); |
35 | 0 | log::trace!("notify_event: tag={:?}", tag); |
36 | 0 | let res = unsafe { ittapi_sys::iJIT_NotifyEvent(tag, data) }; |
37 | 0 | if res == 1 { |
38 | 0 | Ok(()) |
39 | | } else { |
40 | 0 | anyhow::bail!("error when notifying event") |
41 | | } |
42 | 0 | } |
43 | | |
44 | | // High-level helpers. |
45 | | |
46 | | /// Notifies VTune that a new function described by the `MethodLoadBuilder` has been jitted. |
47 | | /// |
48 | | /// # Errors |
49 | | /// |
50 | | /// May fail if the builder has invalid data or if the ITT library fails to notify the method |
51 | | /// load event. |
52 | 0 | pub fn load_method(&self, builder: MethodLoadBuilder) -> anyhow::Result<()> { |
53 | 0 | let method_id = self.get_method_id(); |
54 | 0 | let method_load = builder.build(method_id)?; |
55 | 0 | self.notify_event(method_load) |
56 | 0 | } |
57 | | |
58 | | /// Notifies VTune that profiling is being shut down. |
59 | | /// |
60 | | /// # Errors |
61 | | /// |
62 | | /// May fail if the ITT library fails to notify the shutdown event. |
63 | 0 | pub fn shutdown(&mut self) -> anyhow::Result<()> { |
64 | 0 | let res = self.notify_event(EventType::Shutdown); |
65 | 0 | if res.is_ok() { |
66 | 0 | self.shutdown_complete = true; |
67 | 0 | } |
68 | 0 | res |
69 | 0 | } |
70 | | } |
71 | | |
72 | | impl Drop for Jit { |
73 | 0 | fn drop(&mut self) { |
74 | 0 | if !self.shutdown_complete { |
75 | | // There's not much we can do when an error happens here. |
76 | 0 | if let Err(err) = self.shutdown() { |
77 | 0 | log::error!("Error when shutting down VTune: {}", err); |
78 | 0 | } |
79 | 0 | } |
80 | 0 | } |
81 | | } |
82 | | |
83 | | /// Type of event to be dispatched through ittapi's JIT event API. |
84 | | pub enum EventType { |
85 | | /// Send this event after a JITted method has been loaded into memory, and possibly JIT |
86 | | /// compiled, but before the code is executed. |
87 | | MethodLoadFinished(MethodLoad), |
88 | | |
89 | | /// Send this notification to terminate profiling. |
90 | | Shutdown, |
91 | | } |
92 | | |
93 | | impl EventType { |
94 | | /// Returns the C event type to be used when notifying this event to VTune. |
95 | 0 | fn tag(&self) -> ittapi_sys::iJIT_jvm_event { |
96 | 0 | match self { |
97 | | EventType::MethodLoadFinished(_) => { |
98 | 0 | ittapi_sys::iJIT_jvm_event_iJVM_EVENT_TYPE_METHOD_INLINE_LOAD_FINISHED |
99 | | } |
100 | 0 | EventType::Shutdown => ittapi_sys::iJIT_jvm_event_iJVM_EVENT_TYPE_SHUTDOWN, |
101 | | } |
102 | 0 | } |
103 | | |
104 | | /// Returns a raw C pointer to the event-specific data that must be used when notifying this |
105 | | /// event to VTune. |
106 | 0 | fn data(&mut self) -> *mut os::raw::c_void { |
107 | 0 | match self { |
108 | 0 | EventType::MethodLoadFinished(method_load) => ptr::addr_of_mut!(method_load.0).cast(), |
109 | 0 | EventType::Shutdown => ptr::null_mut(), |
110 | | } |
111 | 0 | } |
112 | | } |
113 | | |
114 | | /// Newtype wrapper for a method id returned by ittapi's `iJIT_GetNewMethodID`, as returned by |
115 | | /// `VtuneState::get_method_id` in the high-level API. |
116 | 0 | #[derive(Clone, Copy)] |
117 | | pub struct MethodId(u32); |
118 | | |
119 | | /// Newtype wrapper for a JIT method load. |
120 | | pub struct MethodLoad(ittapi_sys::_iJIT_Method_Load); |
121 | | |
122 | | /// Multi-step constructor using the builder pattern for a `MethodLoad` event. |
123 | | pub struct MethodLoadBuilder { |
124 | | method_name: String, |
125 | | addr: *const u8, |
126 | | len: usize, |
127 | | class_file_name: Option<String>, |
128 | | source_file_name: Option<String>, |
129 | | } |
130 | | |
131 | | impl MethodLoadBuilder { |
132 | | /// Creates a new `MethodLoadBuilder` from scratch. |
133 | | /// |
134 | | /// `addr` is the pointer to the start of the code region, `len` is the size of this code |
135 | | /// region in bytes. |
136 | 0 | pub fn new(method_name: String, addr: *const u8, len: usize) -> Self { |
137 | 0 | Self { |
138 | 0 | method_name, |
139 | 0 | addr, |
140 | 0 | len, |
141 | 0 | class_file_name: None, |
142 | 0 | source_file_name: None, |
143 | 0 | } |
144 | 0 | } |
145 | | |
146 | | /// Attache a class file. |
147 | 0 | pub fn class_file_name(mut self, class_file_name: String) -> Self { |
148 | 0 | self.class_file_name = Some(class_file_name); |
149 | 0 | self |
150 | 0 | } |
151 | | |
152 | | /// Attach a source file. |
153 | 0 | pub fn source_file_name(mut self, source_file_name: String) -> Self { |
154 | 0 | self.source_file_name = Some(source_file_name); |
155 | 0 | self |
156 | 0 | } |
157 | | |
158 | | /// Build a "method load" event for the given `method_id`. |
159 | | /// |
160 | | /// # Errors |
161 | | /// |
162 | | /// May fail if the various names passed to this builder are not valid C strings. |
163 | 0 | pub fn build(self, method_id: MethodId) -> anyhow::Result<EventType> { |
164 | 0 | Ok(EventType::MethodLoadFinished(MethodLoad( |
165 | 0 | ittapi_sys::_iJIT_Method_Load { |
166 | 0 | method_id: method_id.0, |
167 | 0 | method_name: CString::new(self.method_name) |
168 | 0 | .context("CString::new failed")? |
169 | 0 | .into_raw(), |
170 | 0 | method_load_address: self.addr as *mut os::raw::c_void, |
171 | 0 | method_size: self.len.try_into().expect("cannot fit length into 32 bits"), |
172 | 0 | line_number_size: 0, |
173 | 0 | line_number_table: ptr::null_mut(), |
174 | 0 | class_id: 0, // Field officially obsolete in Intel's doc. |
175 | 0 | class_file_name: CString::new( |
176 | 0 | self.class_file_name |
177 | 0 | .as_deref() |
178 | 0 | .unwrap_or("<unknown class file name>"), |
179 | 0 | ) |
180 | 0 | .context("CString::new failed")? |
181 | 0 | .into_raw(), |
182 | 0 | source_file_name: CString::new( |
183 | 0 | self.source_file_name |
184 | 0 | .as_deref() |
185 | 0 | .unwrap_or("<unknown source file name>"), |
186 | 0 | ) |
187 | 0 | .context("CString::new failed")? |
188 | 0 | .into_raw(), |
189 | | }, |
190 | | ))) |
191 | 0 | } |
192 | | } |