likwid_marker/
lib.rs

1//! Bindins for the [LIKWID](https://hpc.fau.de/research/tools/likwid/) marker API.
2//!
3//! See to the [LIKWID documentation](https://github.com/RRZE-HPC/likwid/wiki/TutorialMarkerC) for
4//! a guide on how to use it with `likwid-perfctr`
5
6use std::ffi::{c_char, CStr};
7
8#[cfg(feature = "enable")]
9extern "C" {
10    fn likwid_markerInit();
11    fn likwid_markerThreadInit();
12    fn likwid_markerClose();
13
14    fn likwid_markerRegisterRegion(tag: *const c_char) -> i32;
15    fn likwid_markerStartRegion(tag: *const c_char) -> i32;
16    fn likwid_markerStopRegion(tag: *const c_char) -> i32;
17    fn likwid_markerResetRegion(tag: *const c_char) -> i32;
18
19    fn likwid_markerNextGroup();
20
21    fn likwid_markerWriteFile(marker_file: *const c_char) -> i32;
22
23    fn likwid_pinProcess(processor_id: i32) -> i32;
24    fn likwid_pinThread(processor_id: i32) -> i32;
25}
26
27/// Initialize LIKWID's marker API
28///
29/// Must be called in serial region of the application to set up basic data
30/// structures of LIKWID. Reads environment variables:
31/// - LIKWID_MODE (access mode)
32/// - LIKWID_MASK (event bitmask)
33/// - LIKWID_EVENTS (event string)
34/// - LIKWID_THREADS (cpu list separated by ,)
35/// - LIKWID_GROUPS (amount of groups)
36pub fn init() {
37    #[cfg(feature = "enable")]
38    unsafe {
39        likwid_markerInit();
40    }
41}
42
43/// Must be called in serial region of the application.
44/// It gathers all data of regions and writes them out to a file
45/// (filepath in env variable LIKWID_FILEPATH).
46pub fn close() {
47    #[cfg(feature = "enable")]
48    unsafe {
49        likwid_markerClose();
50    }
51}
52
53/// Must be called in serial region of the application.
54/// It gathers all data of regions and writes them out to file.
55pub fn write_file(marker_file: &CStr) -> Result<(), i32> {
56    #[cfg(feature = "enable")]
57    unsafe {
58        match likwid_markerWriteFile(marker_file.as_ptr()) {
59            0 => Ok(()),
60            err => Err(err),
61        }
62    }
63    #[cfg(not(feature = "enable"))]
64    Ok(())
65}
66
67/// Initialize LIKWID's marker API for the current thread
68///
69/// Must be called in parallel region of the application to set up basic data structures of LIKWID.
70/// Before you can call likwid_markerThreadInit() you have to call likwid_markerInit().
71pub fn thread_init() {
72    #[cfg(feature = "enable")]
73    unsafe {
74        likwid_markerThreadInit();
75    }
76}
77
78/// Register a measurement region
79///
80/// Initializes the hashTable entry in order to reduce execution time of
81/// likwid_markerStartRegion().
82pub fn register_region(tag: &CStr) -> Result<(), i32> {
83    #[cfg(feature = "enable")]
84    unsafe {
85        match likwid_markerRegisterRegion(tag.as_ptr()) {
86            0 => Ok(()),
87            err => Err(err),
88        }
89    }
90    #[cfg(not(feature = "enable"))]
91    Ok(())
92}
93
94/// Start a measurement region
95///
96/// Reads the values of all configured counters and saves the results under the
97/// name given in regionTag. Must be called on every thread that is to be measured,
98/// e.g. if the code to be measured is run in a parallel region, this function must
99/// also be called in a parallel region (typically the same parallel region as the
100/// measured code). If this function is to be called multiple times in one parallel
101/// region, place a barrier ("#pragma omp barrier" or similar) before each call to
102/// likwid_markerStartRegion
103pub fn start_region(tag: &CStr) -> Result<(), i32> {
104    #[cfg(feature = "enable")]
105    unsafe {
106        match likwid_markerStartRegion(tag.as_ptr()) {
107            0 => Ok(()),
108            err => Err(err),
109        }
110    }
111    #[cfg(not(feature = "enable"))]
112    Ok(())
113}
114
115/// Stop a measurement region
116///
117/// Reads the values of all configured counters and saves the results under the
118/// name given in regionTag. The measurement data of the stopped region gets summed
119/// up in global region counters. Must be called on every thread that is to be
120/// measured, e.g. if the code to be measured is run in a parallel region, this
121/// function must also be called in a parallel region (typically the same parallel
122/// region as the measured code). If this function is called multiple times in one
123/// parallel region, place a barrier ("#pragma omp barrier" or similar) after each
124/// call to likwid_markerStopRegion
125pub fn stop_region(tag: &CStr) -> Result<(), i32> {
126    #[cfg(feature = "enable")]
127    unsafe {
128        match likwid_markerStopRegion(tag.as_ptr()) {
129            0 => Ok(()),
130            err => Err(err),
131        }
132    }
133    #[cfg(not(feature = "enable"))]
134    Ok(())
135}
136
137/// Reset a measurement region
138///
139/// Reset the values of all configured counters and timers.
140pub fn reset_region(tag: &CStr) -> Result<(), i32> {
141    #[cfg(feature = "enable")]
142    unsafe {
143        match likwid_markerResetRegion(tag.as_ptr()) {
144            0 => Ok(()),
145            err => Err(err),
146        }
147    }
148    #[cfg(not(feature = "enable"))]
149    Ok(())
150}
151
152/// Switch to next group to measure
153///
154/// Should be called in a serial region of code. If it is to be called from inside
155/// a parallel region, ensure only one thread runs it by using "#pragma omp single"
156/// or similar. Additionally, if this function is called in a parallel region,
157/// ensure that the serial regions is preceeded by a barrier ("#pragma omp barrier"
158/// or similar) to prevent race conditions.
159pub fn next_group() {
160    #[cfg(feature = "enable")]
161    unsafe {
162        likwid_markerNextGroup();
163    }
164}
165
166/// Pin the current process to the given CPU ID. The process cannot be scheduled to
167/// another CPU after pinning but the pinning can be changed anytime with this
168/// function.
169pub fn pin_process(processor_id: i32) -> Result<(), i32> {
170    #[cfg(feature = "enable")]
171    unsafe {
172        match likwid_pinProcess(processor_id) {
173            1 => Ok(()),
174            err => Err(err),
175        }
176    }
177    #[cfg(not(feature = "enable"))]
178    Ok(())
179}
180
181/// Pin the current thread to the given CPU ID. The thread cannot be scheduled to
182/// another CPU after pinning but the pinning can be changed anytime with this
183/// function
184pub fn pin_thread(processor_id: i32) -> Result<(), i32> {
185    #[cfg(feature = "enable")]
186    unsafe {
187        match likwid_pinThread(processor_id) {
188            1 => Ok(()),
189            err => Err(err),
190        }
191    }
192    #[cfg(not(feature = "enable"))]
193    Ok(())
194}
195
196#[test]
197fn call_likwid_fn() {
198    init();
199}