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