From 130746bc856f5c2eb5672cceb0e1304ee2c95b1e Mon Sep 17 00:00:00 2001 From: johannst Date: Wed, 28 Feb 2024 18:32:44 +0000 Subject: deploy: 7cc72737a0140f5f71e9d83d4f87503eb4c7604f --- src/juicebox_asm/rt.rs.html | 155 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 136 insertions(+), 19 deletions(-) (limited to 'src/juicebox_asm/rt.rs.html') diff --git a/src/juicebox_asm/rt.rs.html b/src/juicebox_asm/rt.rs.html index efc55d3..d58d3e7 100644 --- a/src/juicebox_asm/rt.rs.html +++ b/src/juicebox_asm/rt.rs.html @@ -1,4 +1,5 @@ -rt.rs - source
1
+rt.rs - source
+    
1
 2
 3
 4
@@ -200,21 +201,125 @@
 200
 201
 202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
 
//! Simple `mmap`ed runtime.
 //!
 //! This runtime supports adding code to executable pages and turn the added code into user
 //! specified function pointer.
 
-use nix::sys::mman::{mmap, mprotect, munmap, MapFlags, ProtFlags};
+#[cfg(not(target_os = "linux"))]
+compile_error!("This runtime is only supported on linux");
 
-#[cfg(not(target_os = "linux"))]
-compile_error!("This runtime is only supported on linux");
+use nix::sys::mman::{mmap, mprotect, munmap, MapFlags, ProtFlags};
+
+mod perf {
+    use std::fs;
+    use std::io::Write;
+
+    /// Provide support for the simple [perf jit interface][perf-jit].
+    ///
+    /// This allows a simple (static) jit runtime to generate meta data describing the generated
+    /// functions, which is used during post-processing by `perf report` to symbolize addresses
+    /// captured while executing jitted code.
+    ///
+    /// By the nature of this format, this can not be used for dynamic jit runtimes, which reuses
+    /// memory which previously contained jitted code.
+    ///
+    /// [perf-jit]: https://elixir.bootlin.com/linux/v6.6.6/source/tools/perf/Documentation/jit-interface.txt
+    pub(super) struct PerfMap {
+        file: std::fs::File,
+    }
+
+    impl PerfMap {
+        /// Create an empty perf map file.
+        pub(super) fn new() -> Self {
+            let name = format!("/tmp/perf-{}.map", nix::unistd::getpid());
+            let file = fs::OpenOptions::new()
+                .truncate(true)
+                .create(true)
+                .write(true)
+                .open(&name)
+                .unwrap_or_else(|_| panic!("Failed to open perf map file {}", &name));
+
+            PerfMap { file }
+        }
+
+        /// Add an entry to the perf map file.
+        pub(super) fn add_entry(&mut self, start: usize, len: usize) {
+            // Each line has the following format, fields separated with spaces:
+            //   START SIZE NAME
+            //
+            // START and SIZE are hex numbers without 0x.
+            // NAME is the rest of the line, so it could contain special characters.
+            writeln!(self.file, "{:x} {:x} jitfn_{:x}", start, len, start)
+                .expect("Failed to write PerfMap entry");
+        }
+    }
+}
 
 /// A simple `mmap`ed runtime with executable pages.
 pub struct Runtime {
     buf: *mut u8,
     len: usize,
     idx: usize,
+    perf: Option<perf::PerfMap>,
 }
 
 impl Runtime {
@@ -225,7 +330,7 @@
     /// Panics if the `mmap` call fails.
     pub fn new() -> Runtime {
         // Allocate a single page.
-        let len = core::num::NonZeroUsize::new(4096).expect("Value is non zero");
+        let len = core::num::NonZeroUsize::new(4096).expect("Value is non zero");
         let buf = unsafe {
             mmap(
                 None,
@@ -235,16 +340,23 @@
                 0, /* fd */
                 0, /* off */
             )
-            .expect("Failed to mmap runtime code page") as *mut u8
+            .expect("Failed to mmap runtime code page") as *mut u8
         };
 
         Runtime {
             buf,
             len: len.get(),
             idx: 0,
+            perf: None,
         }
     }
 
+    pub fn with_profile() -> Runtime {
+        let mut rt = Runtime::new();
+        rt.perf = Some(perf::PerfMap::new());
+        rt
+    }
+
     /// Add the block of `code` to the runtime and a get function pointer of type `F`.
     ///
     /// # Panics
@@ -262,21 +374,21 @@
     /// let mut rt = juicebox_asm::Runtime::new();
     ///
     /// let code = [ 0x90 /* nop */, 0xc3 /* ret */ ];
-    /// let nop = unsafe { rt.add_code::<extern "C" fn()>(&code) };
+    /// let nop = unsafe { rt.add_code::<extern "C" fn()>(&code) };
     ///
     /// nop();
     /// ```
     pub unsafe fn add_code<F>(&mut self, code: impl AsRef<[u8]>) -> F {
         // Get pointer to start of next free byte.
-        assert!(self.idx < self.len, "Runtime code page full");
+        assert!(self.idx < self.len, "Runtime code page full");
         let fn_start = self.buf.add(self.idx);
 
         // Copy over code.
         let code = code.as_ref();
-        assert!(!code.is_empty(), "Adding empty code not supported");
+        assert!(!code.is_empty(), "Adding empty code not supported");
         assert!(
             code.len() <= (self.len - self.idx),
-            "Code does not fit on the runtime code page"
+            "Code does not fit on the runtime code page"
         );
         self.unprotect();
         unsafe { std::ptr::copy_nonoverlapping(code.as_ptr(), fn_start, code.len()) };
@@ -285,6 +397,11 @@
         // Increment index to next free byte.
         self.idx += code.len();
 
+        // Add perf map entry.
+        if let Some(map) = &mut self.perf {
+            map.add_entry(fn_start as usize, code.len());
+        }
+
         // Return function to newly added code.
         unsafe { Self::as_fn::<F>(fn_start) }
     }
@@ -304,7 +421,7 @@
     pub fn dump(&self) {
         assert!(self.idx <= self.len);
         let code = unsafe { core::slice::from_raw_parts(self.buf, self.idx) };
-        std::fs::write("jit.asm", code).expect("Failed to write file");
+        std::fs::write("jit.asm", code).expect("Failed to write file");
     }
 
     /// Reinterpret the block of code pointed to by `fn_start` as `F`.
@@ -326,7 +443,7 @@
                 self.len,
                 ProtFlags::PROT_READ | ProtFlags::PROT_EXEC,
             )
-            .expect("Failed to RX mprotect runtime code page");
+            .expect("Failed to RX mprotect runtime code page");
         }
     }
 
@@ -339,7 +456,7 @@
         unsafe {
             // Add write permissions to code page.
             mprotect(self.buf.cast(), self.len, ProtFlags::PROT_WRITE)
-                .expect("Failed to W mprotect runtime code page");
+                .expect("Failed to W mprotect runtime code page");
         }
     }
 }
@@ -349,7 +466,7 @@
     /// [`Runtime::add_code`].
     fn drop(&mut self) {
         unsafe {
-            munmap(self.buf.cast(), self.len).expect("Failed to munmap runtime");
+            munmap(self.buf.cast(), self.len).expect("Failed to munmap runtime");
         }
     }
 }
@@ -363,7 +480,7 @@
         let mut rt = Runtime::new();
         let code = [0u8; 4096];
         unsafe {
-            rt.add_code::<extern "C" fn()>(code);
+            rt.add_code::<extern "C" fn()>(code);
         }
     }
 
@@ -373,7 +490,7 @@
         let mut rt = Runtime::new();
         let code = [0u8; 4097];
         unsafe {
-            rt.add_code::<extern "C" fn()>(code);
+            rt.add_code::<extern "C" fn()>(code);
         }
     }
 
@@ -383,12 +500,12 @@
         let mut rt = Runtime::new();
         let code = [0u8; 4096];
         unsafe {
-            rt.add_code::<extern "C" fn()>(code);
+            rt.add_code::<extern "C" fn()>(code);
         }
 
         let code = [0u8; 1];
         unsafe {
-            rt.add_code::<extern "C" fn()>(code);
+            rt.add_code::<extern "C" fn()>(code);
         }
     }
 
@@ -398,7 +515,7 @@
         let mut rt = Runtime::new();
         let code = [0u8; 0];
         unsafe {
-            rt.add_code::<extern "C" fn()>(code);
+            rt.add_code::<extern "C" fn()>(code);
         }
     }
 }
-- 
cgit v1.2.3