From 657c8db8deb06741ca4b6a8b6635230f68c6d263 Mon Sep 17 00:00:00 2001 From: Alan Wu Date: Fri, 14 Jun 2024 16:24:35 -0400 Subject: [PATCH] YJIT: `--yjit-dump-disasm=dir`: Hold descriptor for dump file This mainly aims to make `--yjit-dump-disasm=` more usable. Previously, it crashed if the program did chdir(2), since it opened the dump file every time when appending. Tested with: ./miniruby --yjit-dump-disasm=. --yjit-call-threshold=1 -e 'Dir.chdir("/") {}' And the `lobsters` benchmark. --- yjit/src/disasm.rs | 15 +++++++++------ yjit/src/options.rs | 11 ++++++----- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/yjit/src/disasm.rs b/yjit/src/disasm.rs index 7875276815..fb5c46e7ce 100644 --- a/yjit/src/disasm.rs +++ b/yjit/src/disasm.rs @@ -115,19 +115,22 @@ pub fn disasm_iseq_insn_range(iseq: IseqPtr, start_idx: u16, end_idx: u16) -> St return out; } +/// Dump dissassembly for a range in a [CodeBlock]. VM lock required. #[cfg(feature = "disasm")] pub fn dump_disasm_addr_range(cb: &CodeBlock, start_addr: CodePtr, end_addr: CodePtr, dump_disasm: &DumpDisasm) { - use std::fs::File; - use std::io::Write; - for (start_addr, end_addr) in cb.writable_addrs(start_addr, end_addr) { let disasm = disasm_addr_range(cb, start_addr, end_addr); if disasm.len() > 0 { match dump_disasm { DumpDisasm::Stdout => println!("{disasm}"), - DumpDisasm::File(path) => { - let mut f = File::options().create(true).append(true).open(path).unwrap(); - f.write_all(disasm.as_bytes()).unwrap(); + DumpDisasm::File(fd) => { + use std::os::unix::io::{FromRawFd, IntoRawFd}; + use std::io::Write; + + // Write with the fd opened during boot + let mut file = unsafe { std::fs::File::from_raw_fd(*fd) }; + file.write_all(disasm.as_bytes()).unwrap(); + file.into_raw_fd(); // keep the fd open } }; } diff --git a/yjit/src/options.rs b/yjit/src/options.rs index 59ec864bf5..ca57da2566 100644 --- a/yjit/src/options.rs +++ b/yjit/src/options.rs @@ -24,7 +24,7 @@ pub static mut rb_yjit_call_threshold: u64 = SMALL_CALL_THRESHOLD; pub static mut rb_yjit_cold_threshold: u64 = 200_000; // Command-line options -#[derive(Clone, PartialEq, Eq, Debug)] +#[derive(Debug)] #[repr(C)] pub struct Options { // Size of the executable memory block to allocate in bytes @@ -120,12 +120,12 @@ pub enum TraceExits { CountedExit(Counter), } -#[derive(Clone, PartialEq, Eq, Debug)] +#[derive(Debug)] pub enum DumpDisasm { // Dump to stdout Stdout, // Dump to "yjit_{pid}.log" file under the specified directory - File(String), + File(std::os::unix::io::RawFd), } /// Type of symbols to dump into /tmp/perf-{pid}.map @@ -257,9 +257,10 @@ pub fn parse_option(str_ptr: *const std::os::raw::c_char) -> Option<()> { directory => { let path = format!("{directory}/yjit_{}.log", std::process::id()); match File::options().create(true).append(true).open(&path) { - Ok(_) => { + Ok(file) => { + use std::os::unix::io::IntoRawFd; eprintln!("YJIT disasm dump: {path}"); - unsafe { OPTIONS.dump_disasm = Some(DumpDisasm::File(path)) } + unsafe { OPTIONS.dump_disasm = Some(DumpDisasm::File(file.into_raw_fd())) } } Err(err) => eprintln!("Failed to create {path}: {err}"), }