YJIT: `--yjit-dump-disasm=dir`: Hold descriptor for dump file

This mainly aims to make `--yjit-dump-disasm=<relative_path>` 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.
This commit is contained in:
Alan Wu 2024-06-14 16:24:35 -04:00
Родитель a119b5f879
Коммит 657c8db8de
2 изменённых файлов: 15 добавлений и 11 удалений

Просмотреть файл

@ -115,19 +115,22 @@ pub fn disasm_iseq_insn_range(iseq: IseqPtr, start_idx: u16, end_idx: u16) -> St
return out; return out;
} }
/// Dump dissassembly for a range in a [CodeBlock]. VM lock required.
#[cfg(feature = "disasm")] #[cfg(feature = "disasm")]
pub fn dump_disasm_addr_range(cb: &CodeBlock, start_addr: CodePtr, end_addr: CodePtr, dump_disasm: &DumpDisasm) { 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) { for (start_addr, end_addr) in cb.writable_addrs(start_addr, end_addr) {
let disasm = disasm_addr_range(cb, start_addr, end_addr); let disasm = disasm_addr_range(cb, start_addr, end_addr);
if disasm.len() > 0 { if disasm.len() > 0 {
match dump_disasm { match dump_disasm {
DumpDisasm::Stdout => println!("{disasm}"), DumpDisasm::Stdout => println!("{disasm}"),
DumpDisasm::File(path) => { DumpDisasm::File(fd) => {
let mut f = File::options().create(true).append(true).open(path).unwrap(); use std::os::unix::io::{FromRawFd, IntoRawFd};
f.write_all(disasm.as_bytes()).unwrap(); 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
} }
}; };
} }

Просмотреть файл

@ -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; pub static mut rb_yjit_cold_threshold: u64 = 200_000;
// Command-line options // Command-line options
#[derive(Clone, PartialEq, Eq, Debug)] #[derive(Debug)]
#[repr(C)] #[repr(C)]
pub struct Options { pub struct Options {
// Size of the executable memory block to allocate in bytes // Size of the executable memory block to allocate in bytes
@ -120,12 +120,12 @@ pub enum TraceExits {
CountedExit(Counter), CountedExit(Counter),
} }
#[derive(Clone, PartialEq, Eq, Debug)] #[derive(Debug)]
pub enum DumpDisasm { pub enum DumpDisasm {
// Dump to stdout // Dump to stdout
Stdout, Stdout,
// Dump to "yjit_{pid}.log" file under the specified directory // 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 /// 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 => { directory => {
let path = format!("{directory}/yjit_{}.log", std::process::id()); let path = format!("{directory}/yjit_{}.log", std::process::id());
match File::options().create(true).append(true).open(&path) { match File::options().create(true).append(true).open(&path) {
Ok(_) => { Ok(file) => {
use std::os::unix::io::IntoRawFd;
eprintln!("YJIT disasm dump: {path}"); 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}"), Err(err) => eprintln!("Failed to create {path}: {err}"),
} }