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}