tikv / pprof-rs

A Rust CPU profiler implemented with the help of backtrace-rs
Apache License 2.0
1.29k stars 99 forks source link

Compiling fails on FreeBSD #151

Closed dveeden closed 1 year ago

dveeden commented 2 years ago
% cargo build
   Compiling pprof v0.10.0 (/usr/home/dveeden/dev/pprof-rs)
error[E0425]: cannot find function `create_pipe` in this scope
  --> src/addr_validate.rs:52:35
   |
52 |         let (read_fd, write_fd) = create_pipe()?;
   |                                   ^^^^^^^^^^^ not found in this scope

error[E0425]: cannot find value `addr` in this scope
   --> src/profiler.rs:280:44
    |
280 |                 if profiler.is_blocklisted(addr) {
    |                                            ^^^^ not found in this scope

error[E0308]: mismatched types
   --> src/profiler.rs:205:9
    |
205 | /         unsafe {
206 | |             #[cfg(target_os = "linux")]
207 | |             {
208 | |                 let errno = *libc::__errno_location();
...   |
215 | |             }
216 | |         }
    | |_________^ expected struct `ErrnoProtector`, found `()`

Some errors have detailed explanations: E0308, E0425.
For more information about an error, try `rustc --explain E0308`.
error: could not compile `pprof` due to 3 previous errors
% freebsd-version 
13.0-RELEASE-p11
% cargo --version
cargo 1.63.0-nightly
dveeden commented 2 years ago

This would be a start:

diff --git a/src/addr_validate.rs b/src/addr_validate.rs
index 9e9a34c..6094d6c 100644
--- a/src/addr_validate.rs
+++ b/src/addr_validate.rs
@@ -41,6 +41,29 @@ fn create_pipe() -> nix::Result<(i32, i32)> {
     Ok((read_fd, write_fd))
 }

+#[inline]
+#[cfg(target_os = "freebsd")]
+fn create_pipe() -> nix::Result<(i32, i32)> {
+    use nix::fcntl::{fcntl, FcntlArg, FdFlag, OFlag};
+    use nix::unistd::pipe;
+    use std::os::unix::io::RawFd;
+
+    fn set_flags(fd: RawFd) -> nix::Result<()> {
+        let mut flags = FdFlag::from_bits(fcntl(fd, FcntlArg::F_GETFD)?).unwrap();
+        flags |= FdFlag::FD_CLOEXEC;
+        fcntl(fd, FcntlArg::F_SETFD(flags))?;
+        let mut flags = OFlag::from_bits(fcntl(fd, FcntlArg::F_GETFL)?).unwrap();
+        flags |= OFlag::O_NONBLOCK;
+        fcntl(fd, FcntlArg::F_SETFL(flags))?;
+        Ok(())
+    }
+
+    let (read_fd, write_fd) = pipe()?;
+    set_flags(read_fd)?;
+    set_flags(write_fd)?;
+    Ok((read_fd, write_fd))
+}
+
 fn open_pipe() -> nix::Result<()> {
     MEM_VALIDATE_PIPE.with(|pipes| {
         let mut pipes = pipes.borrow_mut();
diff --git a/src/profiler.rs b/src/profiler.rs
index 4bc72ad..52fcb86 100644
--- a/src/profiler.rs
+++ b/src/profiler.rs
@@ -208,6 +208,11 @@ impl ErrnoProtector {
                 let errno = *libc::__errno_location();
                 Self(errno)
             }
+            #[cfg(target_os = "freebsd")]
+            {
+                let errno = *libc::__error();
+                Self(errno)
+            }
             #[cfg(target_os = "macos")]
             {
                 let errno = *libc::__error();
dveeden commented 2 years ago

Or even better:

diff --git a/src/addr_validate.rs b/src/addr_validate.rs
index 9e9a34c..7ceafd0 100644
--- a/src/addr_validate.rs
+++ b/src/addr_validate.rs
@@ -19,7 +19,7 @@ fn create_pipe() -> nix::Result<(i32, i32)> {
 }

 #[inline]
-#[cfg(target_os = "macos")]
+#[cfg(any(target_os = "macos", target_os = "freebsd"))]
 fn create_pipe() -> nix::Result<(i32, i32)> {
     use nix::fcntl::{fcntl, FcntlArg, FdFlag, OFlag};
     use nix::unistd::pipe;
diff --git a/src/profiler.rs b/src/profiler.rs
index 4bc72ad..d89c164 100644
--- a/src/profiler.rs
+++ b/src/profiler.rs
@@ -208,7 +208,7 @@ impl ErrnoProtector {
                 let errno = *libc::__errno_location();
                 Self(errno)
             }
-            #[cfg(target_os = "macos")]
+            #[cfg(any(target_os = "macos", target_os = "freebsd"))]
             {
                 let errno = *libc::__error();
                 Self(errno)
YangKeao commented 2 years ago

Good! https://github.com/tikv/pprof-rs/pull/150 is working on separating multiple implementations on different platforms. It would be better to take *bsd into consideration https://doc.rust-lang.org/reference/conditional-compilation.html#target_os .

dveeden commented 1 year ago

@YangKeao do you think it still makes sense to do this as part of #150 or should we consider doing something like my suggestion?

YangKeao commented 1 year ago

Or even better:

diff --git a/src/addr_validate.rs b/src/addr_validate.rs
index 9e9a34c..7ceafd0 100644
--- a/src/addr_validate.rs
+++ b/src/addr_validate.rs
@@ -19,7 +19,7 @@ fn create_pipe() -> nix::Result<(i32, i32)> {
 }

 #[inline]
-#[cfg(target_os = "macos")]
+#[cfg(any(target_os = "macos", target_os = "freebsd"))]
 fn create_pipe() -> nix::Result<(i32, i32)> {
     use nix::fcntl::{fcntl, FcntlArg, FdFlag, OFlag};
     use nix::unistd::pipe;
diff --git a/src/profiler.rs b/src/profiler.rs
index 4bc72ad..d89c164 100644
--- a/src/profiler.rs
+++ b/src/profiler.rs
@@ -208,7 +208,7 @@ impl ErrnoProtector {
                 let errno = *libc::__errno_location();
                 Self(errno)
             }
-            #[cfg(target_os = "macos")]
+            #[cfg(any(target_os = "macos", target_os = "freebsd"))]
             {
                 let errno = *libc::__error();
                 Self(errno)

Thank you. I'll test this patch (and add some other modification, if needed) on freebsd tonight. Let's make pprof-rs compile on freebsd :beers:.