This is an automated email from the ASF dual-hosted git repository. manjusaka pushed a commit to branch manjusaka/support-dtrace-layers in repository https://gitbox.apache.org/repos/asf/opendal.git
commit 4a021c8c5847c7c0c58bebce324c9f1443abea78 Author: Manjusaka <[email protected]> AuthorDate: Tue Jan 23 01:44:05 2024 +0800 feat(layers/dtrace): Support User Statically-Defined Tracing(aka USDT) on Linux Signed-off-by: Manjusaka <[email protected]> --- Cargo.lock | 7 ++ core/Cargo.toml | 4 + core/src/layers/dtrace.rs | 227 ++++++++++++++++++++++++++++++++++++++++++++++ core/src/layers/mod.rs | 6 ++ 4 files changed, 244 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 0381b429dd..2a6e9e9b99 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4688,6 +4688,7 @@ dependencies = [ "percent-encoding", "persy", "pretty_assertions", + "probe", "prometheus", "prometheus-client", "prost 0.11.9", @@ -5427,6 +5428,12 @@ dependencies = [ "indexmap 1.9.3", ] +[[package]] +name = "probe" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8e2d2444b730c8f027344c60f9e1f1554d7a3342df9bdd425142ed119a6e5a3" + [[package]] name = "proc-macro-crate" version = "1.3.1" diff --git a/core/Cargo.toml b/core/Cargo.toml index ec73bb4939..f30b4c7022 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -110,6 +110,8 @@ layers-throttle = ["dep:governor"] layers-await-tree = ["dep:await-tree"] # Enable layers async-backtrace support. layers-async-backtrace = ["dep:async-backtrace"] +# Enable dtrace support. +layers-dtrace=["dep:probe"] services-alluxio = [] services-atomicserver = ["dep:atomic_lib"] @@ -360,6 +362,8 @@ prometheus = { version = "0.13", features = ["process"], optional = true } prometheus-client = { version = "0.22.0", optional = true } # for layers-tracing tracing = { version = "0.1", optional = true } +# for layers-dtrace +probe = { version = "0.5.1", optional = true } [target.'cfg(target_arch = "wasm32")'.dependencies] getrandom = { version = "0.2", features = ["js"] } diff --git a/core/src/layers/dtrace.rs b/core/src/layers/dtrace.rs new file mode 100644 index 0000000000..702c2e4978 --- /dev/null +++ b/core/src/layers/dtrace.rs @@ -0,0 +1,227 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use async_trait::async_trait; +use std::fmt::Debug; +use std::fmt::Formatter; + +use crate::raw::*; +use crate::*; +use std::ffi:: CString; + +/// Support User Statically-Defined Tracing(aka USDT) on Linux +/// +/// This layer is a experimental feature, it will be enabled by `features = ["layers-dtrace"]` in Cargo.toml. +/// +/// Example: +/// ``` +/// +/// use anyhow::Result; +/// use opendal::services::Fs; +/// use opendal::Operator; +/// use opendal::layers::DTraceLayer; +/// +/// #[tokio::main] +/// async fn main() -> Result<()> { +/// let mut builder = Fs::default(); +/// +/// builder.root("/tmp"); +/// +/// // `Accessor` provides the low level APIs, we will use `Operator` normally. +/// let op: Operator = Operator::new(builder)?.layer(DTraceLayer{}).finish(); +/// +/// let path="/tmp/test.txt"; +/// for _ in 1..100000{ +/// let bs = vec![0; 64 * 1024 * 1024]; +/// op.write(path, bs).await?; +/// op.read(path).await?; +/// } +/// Ok(()) +/// } +/// ``` +/// +/// Then you can use `readelf -n target/debug/examples/dtrace` to see the probes: +/// +/// ```text +/// Displaying notes found in: .note.stapsdt +/// Owner Data size Description +/// stapsdt 0x00000039 NT_STAPSDT (SystemTap probe descriptors) +/// Provider: opendal +/// Name: create_dir_start +/// Location: 0x00000000000f8f05, Base: 0x0000000000000000, Semaphore: 0x00000000003649f8 +/// Arguments: -8@%rax +/// stapsdt 0x00000037 NT_STAPSDT (SystemTap probe descriptors) +/// Provider: opendal +/// Name: create_dir_end +/// Location: 0x00000000000f9284, Base: 0x0000000000000000, Semaphore: 0x00000000003649fa +/// Arguments: -8@%rax +/// stapsdt 0x0000003c NT_STAPSDT (SystemTap probe descriptors) +/// Provider: opendal +/// Name: blocking_list_start +/// Location: 0x00000000000f9487, Base: 0x0000000000000000, Semaphore: 0x0000000000364a28 +/// Arguments: -8@%rax +/// stapsdt 0x0000003a NT_STAPSDT (SystemTap probe descriptors) +/// Provider: opendal +/// Name: blocking_list_end +/// Location: 0x00000000000f9546, Base: 0x0000000000000000, Semaphore: 0x0000000000364a2a +/// Arguments: -8@%rax +/// stapsdt 0x0000003c NT_STAPSDT (SystemTap probe descriptors) +/// ``` +#[derive(Default, Debug, Clone)] +pub struct DTraceLayer {} + +impl<A: Accessor> Layer<A> for DTraceLayer { + type LayeredAccessor = DTraceAccessor<A>; + fn layer(&self, inner: A) -> Self::LayeredAccessor { + DTraceAccessor { inner } + } +} + +#[derive(Clone)] +pub struct DTraceAccessor<A: Accessor> { + inner: A, +} + +impl<A: Accessor> Debug for DTraceAccessor<A> { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.debug_struct("DTraceAccessor") + .field("inner", &self.inner) + .finish_non_exhaustive() + } +} + +#[async_trait] +impl<A: Accessor> LayeredAccessor for DTraceAccessor<A> { + type Inner = A; + type Reader = A::Reader; + type BlockingReader = A::BlockingReader; + type Writer = A::Writer; + type BlockingWriter = A::BlockingWriter; + type Lister = A::Lister; + type BlockingLister = A::BlockingLister; + fn inner(&self) -> &Self::Inner { + &self.inner + } + + async fn create_dir(&self, path: &str, args: OpCreateDir) -> Result<RpCreateDir> { + let c_path = CString::new(path).unwrap(); + probe::probe_lazy!(opendal, create_dir_start, c_path.as_ptr()); + let create_res = self.inner.create_dir(path, args).await; + probe::probe_lazy!(opendal, create_dir_end, c_path.as_ptr()); + create_res + } + + async fn read(&self, path: &str, args: OpRead) -> Result<(RpRead, Self::Reader)> { + let c_path = CString::new(path).unwrap(); + probe::probe_lazy!(opendal, read_start, c_path.as_ptr()); + let read_res = self.inner.read(path, args).await; + probe::probe_lazy!(opendal, read_end, c_path.as_ptr()); + read_res + } + + async fn write(&self, path: &str, args: OpWrite) -> Result<(RpWrite, Self::Writer)> { + let c_path = CString::new(path).unwrap(); + probe::probe_lazy!(opendal, write_start, c_path.as_ptr()); + let write_res = self.inner.write(path, args).await; + probe::probe_lazy!(opendal, write_end, c_path.as_ptr()); + write_res + } + + async fn stat(&self, path: &str, args: OpStat) -> Result<RpStat> { + let c_path = CString::new(path).unwrap(); + probe::probe_lazy!(opendal, stat_start, c_path.as_ptr()); + let stat_res = self.inner.stat(path, args).await; + probe::probe_lazy!(opendal, stat_end, c_path.as_ptr()); + stat_res + } + + async fn delete(&self, path: &str, args: OpDelete) -> Result<RpDelete> { + let c_path = CString::new(path).unwrap(); + probe::probe_lazy!(opendal, delete_start, c_path.as_ptr()); + let delete_res = self.inner.delete(path, args).await; + probe::probe_lazy!(opendal, delete_end, c_path.as_ptr()); + delete_res + } + + async fn list(&self, path: &str, args: OpList) -> Result<(RpList, Self::Lister)> { + let c_path = CString::new(path).unwrap(); + probe::probe_lazy!(opendal, list_start, c_path.as_ptr()); + let list_res = self.inner.list(path, args).await; + probe::probe_lazy!(opendal, list_end, c_path.as_ptr()); + list_res + } + + async fn batch(&self, args: OpBatch) -> Result<RpBatch> { + self.inner.batch(args).await + } + + async fn presign(&self, path: &str, args: OpPresign) -> Result<RpPresign> { + let c_path = CString::new(path).unwrap(); + probe::probe_lazy!(opendal, presign_start, c_path.as_ptr()); + let result = self.inner.presign(path, args).await; + probe::probe_lazy!(opendal, presign_end, c_path.as_ptr()); + result + } + + fn blocking_create_dir(&self, path: &str, args: OpCreateDir) -> Result<RpCreateDir> { + let c_path = CString::new(path).unwrap(); + probe::probe_lazy!(opendal, blocking_create_dir_start, c_path.as_ptr()); + let result = self.inner.blocking_create_dir(path, args); + probe::probe_lazy!(opendal, blocking_create_dir_end, c_path.as_ptr()); + result + } + + fn blocking_read(&self, path: &str, args: OpRead) -> Result<(RpRead, Self::BlockingReader)> { + let c_path = CString::new(path).unwrap(); + probe::probe_lazy!(opendal, blocking_read_start, c_path.as_ptr()); + let result = self.inner.blocking_read(path, args); + probe::probe_lazy!(opendal, blocking_read_end, c_path.as_ptr()); + result + } + + fn blocking_write(&self, path: &str, args: OpWrite) -> Result<(RpWrite, Self::BlockingWriter)> { + let c_path = CString::new(path).unwrap(); + probe::probe_lazy!(opendal, blocking_write_start, c_path.as_ptr()); + let result = self.inner.blocking_write(path, args); + probe::probe_lazy!(opendal, blocking_write_end, c_path.as_ptr()); + result + } + + fn blocking_stat(&self, path: &str, args: OpStat) -> Result<RpStat> { + let c_path = CString::new(path).unwrap(); + probe::probe_lazy!(opendal, blocking_stat_start, c_path.as_ptr()); + let result = self.inner.blocking_stat(path, args); + probe::probe_lazy!(opendal, blocking_stat_end, c_path.as_ptr()); + result + } + + fn blocking_delete(&self, path: &str, args: OpDelete) -> Result<RpDelete> { + let c_path = CString::new(path).unwrap(); + probe::probe_lazy!(opendal, blocking_delete_start, c_path.as_ptr()); + let result = self.inner.blocking_delete(path, args); + probe::probe_lazy!(opendal, blocking_delete_end, c_path.as_ptr()); + result + } + + fn blocking_list(&self, path: &str, args: OpList) -> Result<(RpList, Self::BlockingLister)> { + let c_path = CString::new(path).unwrap(); + probe::probe_lazy!(opendal, blocking_list_start, c_path.as_ptr()); + let result = self.inner.blocking_list(path, args); + probe::probe_lazy!(opendal, blocking_list_end, c_path.as_ptr()); + result + } +} diff --git a/core/src/layers/mod.rs b/core/src/layers/mod.rs index 7c064cdcf9..5680f81800 100644 --- a/core/src/layers/mod.rs +++ b/core/src/layers/mod.rs @@ -101,3 +101,9 @@ pub use self::await_tree::AwaitTreeLayer; mod async_backtrace; #[cfg(feature = "layers-async-backtrace")] pub use self::async_backtrace::AsyncBacktraceLayer; + +#[cfg(all(target_os = "linux", feature = "layers-dtrace"))] +mod dtrace; + +#[cfg(all(target_os = "linux", feature = "layers-dtrace"))] +pub use self::dtrace::DTraceLayer;
