1 // Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved.
2 //
3 // StratoVirt is licensed under Mulan PSL v2.
4 // You can use this software according to the terms and conditions of the Mulan
5 // PSL v2.
6 // You may obtain a copy of Mulan PSL v2 at:
7 //         http://license.coscl.org.cn/MulanPSL2
8 // THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
9 // KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
10 // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
11 // See the Mulan PSL v2 for more details.
12 
13 use std::ffi::OsStr;
14 
15 use anyhow::{Context, Result};
16 use lazy_static::lazy_static;
17 use libloading::os::unix::Symbol;
18 use libloading::Library;
19 use log::error;
20 
21 const HITRACE_TAG_VIRSE: u64 = 1u64 << 11;
22 
23 lazy_static! {
24     static ref HITRACE_FUNC_TABLE: HitraceFuncTable =
25         // SAFETY: The dynamic library should be always existing.
26         unsafe {
27             HitraceFuncTable::new(OsStr::new("libhitrace_meter.so"))
28                 .map_err(|e| {
29                     error!("failed to init HitraceFuncTable with error: {:?}", e);
30                     e
31                 })
32                 .unwrap()
33         };
34 }
35 
36 macro_rules! get_libfn {
37     ( $lib: ident, $tname: ident, $fname: ident ) => {
38         $lib.get::<$tname>(stringify!($fname).as_bytes())
39             .with_context(|| format!("failed to get function {}", stringify!($fname)))?
40             .into_raw()
41     };
42 }
43 
44 type StartTraceWrapperFn = unsafe extern "C" fn(u64, *const u8);
45 type FinishTraceFn = unsafe extern "C" fn(u64);
46 type StartAsyncTraceWrapperFn = unsafe extern "C" fn(u64, *const u8, i32);
47 type FinishAsyncTraceWrapperFn = unsafe extern "C" fn(u64, *const u8, i32);
48 
49 struct HitraceFuncTable {
50     pub start_trace: Symbol<StartTraceWrapperFn>,
51     pub finish_trace: Symbol<FinishTraceFn>,
52     pub start_trace_async: Symbol<StartAsyncTraceWrapperFn>,
53     pub finish_trace_async: Symbol<FinishAsyncTraceWrapperFn>,
54 }
55 
56 impl HitraceFuncTable {
new(library_name: &OsStr) -> Result<HitraceFuncTable>57     unsafe fn new(library_name: &OsStr) -> Result<HitraceFuncTable> {
58         let library =
59             Library::new(library_name).with_context(|| "failed to load hitrace_meter library")?;
60 
61         Ok(Self {
62             start_trace: get_libfn!(library, StartTraceWrapperFn, StartTraceWrapper),
63             finish_trace: get_libfn!(library, FinishTraceFn, FinishTrace),
64             start_trace_async: get_libfn!(
65                 library,
66                 StartAsyncTraceWrapperFn,
67                 StartAsyncTraceWrapper
68             ),
69             finish_trace_async: get_libfn!(
70                 library,
71                 FinishAsyncTraceWrapperFn,
72                 FinishAsyncTraceWrapper
73             ),
74         })
75     }
76 }
77 
start_trace(value: &str)78 pub fn start_trace(value: &str) {
79     if let Ok(value_ptr) = std::ffi::CString::new(value) {
80         // SAFETY: All parameters have been checked.
81         unsafe {
82             (HITRACE_FUNC_TABLE.start_trace)(HITRACE_TAG_VIRSE, value_ptr.as_ptr() as *const u8)
83         }
84     }
85 }
86 
finish_trace()87 pub fn finish_trace() {
88     // SAFETY: All parameters have been checked.
89     unsafe {
90         (HITRACE_FUNC_TABLE.finish_trace)(HITRACE_TAG_VIRSE);
91     }
92 }
93 
start_trace_async(value: &str, task_id: i32)94 pub fn start_trace_async(value: &str, task_id: i32) {
95     if let Ok(value_ptr) = std::ffi::CString::new(value) {
96         // SAFETY: All parameters have been checked.
97         unsafe {
98             (HITRACE_FUNC_TABLE.start_trace_async)(
99                 HITRACE_TAG_VIRSE,
100                 value_ptr.as_ptr() as *const u8,
101                 task_id,
102             )
103         }
104     }
105 }
106 
finish_trace_async(value: &str, task_id: i32)107 pub fn finish_trace_async(value: &str, task_id: i32) {
108     if let Ok(value_ptr) = std::ffi::CString::new(value) {
109         // SAFETY: All parameters have been checked.
110         unsafe {
111             (HITRACE_FUNC_TABLE.finish_trace_async)(
112                 HITRACE_TAG_VIRSE,
113                 value_ptr.as_ptr() as *const u8,
114                 task_id,
115             )
116         }
117     }
118 }
119