Skip to content

Commit

Permalink
2024-06-12 08:30:56
Browse files Browse the repository at this point in the history
  • Loading branch information
mohanson committed Jun 12, 2024
1 parent 9d86ddf commit 1528774
Showing 1 changed file with 54 additions and 42 deletions.
96 changes: 54 additions & 42 deletions src/machine/pprof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ use crate::memory::Memory;
use crate::registers::{A0, SP};
use crate::{Bytes, CoreMachine, Error, Machine, Register, SupportMachine, ISA_MOP};
use std::borrow::Cow;
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
use std::sync::{Arc, Mutex};

type Addr2LineEndianReader =
addr2line::gimli::EndianReader<addr2line::gimli::RunTimeEndian, Rc<[u8]>>;
type Addr2LineContext = addr2line::Context<Addr2LineEndianReader>;
// type Addr2LineContext = addr2line::Context<Addr2LineEndianReader>;
type Addr2LineFrameIter<'a> = addr2line::FrameIter<'a, Addr2LineEndianReader>;

fn sprint_fun(frame_iter: &mut Addr2LineFrameIter) -> String {
Expand Down Expand Up @@ -60,8 +60,8 @@ struct TrieNode {
addr: u64,
link: u64,
pc: u64,
parent: Option<Rc<RefCell<TrieNode>>>,
childs: Vec<Rc<RefCell<TrieNode>>>,
parent: Option<Arc<Mutex<TrieNode>>>,
childs: Vec<Arc<Mutex<TrieNode>>>,
cycles: u64,
regs: [[u64; 32]; 2],
}
Expand Down Expand Up @@ -120,9 +120,9 @@ impl Tags {
}

pub struct Profile {
addrctx: Addr2LineContext,
trie_root: Rc<RefCell<TrieNode>>,
trie_node: Rc<RefCell<TrieNode>>,
program: Bytes,
trie_root: Arc<Mutex<TrieNode>>,
trie_node: Arc<Mutex<TrieNode>>,
cache_tag: HashMap<u64, Tags>,
cache_fun: HashMap<u64, String>,
sbrk_addr: u64,
Expand All @@ -131,22 +131,27 @@ pub struct Profile {
}

impl Profile {
pub fn new(program: &Bytes) -> Result<Self, Box<dyn std::error::Error>> {
let object = addr2line::object::File::parse(program.as_ref())?;
let ctx = addr2line::Context::new(&object)?;
let trie_root = Rc::new(RefCell::new(TrieNode::root()));
let elf = goblin_v040::elf::Elf::parse(&program)?;
trie_root.borrow_mut().addr = elf.entry;
Ok(Self {
addrctx: ctx,
pub fn new() -> Self {
let trie_root = Arc::new(Mutex::new(TrieNode::root()));
Self {
program: Bytes::new(),
trie_root: trie_root.clone(),
trie_node: trie_root,
cache_tag: HashMap::new(),
cache_fun: goblin_fun(&elf),
sbrk_addr: goblin_get_sym(&elf, "_sbrk"),
sbrk_heap: goblin_get_sym(&elf, "_end"),
cache_fun: HashMap::new(),
sbrk_addr: 0,
sbrk_heap: 0,
disable_overlapping_detection: false,
})
}
}

pub fn load_program(&mut self, program: &Bytes) -> Result<(), Box<dyn std::error::Error>> {
let elf = goblin_v040::elf::Elf::parse(&program)?;
self.trie_root.lock().unwrap().addr = elf.entry;
self.cache_fun = goblin_fun(&elf);
self.sbrk_addr = goblin_get_sym(&elf, "_sbrk");
self.sbrk_heap = goblin_get_sym(&elf, "_end");
Ok(())
}

pub fn set_disable_overlapping_detection(mut self, disable_detection: bool) -> Self {
Expand All @@ -159,14 +164,16 @@ impl Profile {
return data.clone();
}
let mut tag = Tags::new(addr);
let loc = self.addrctx.find_location(addr).unwrap();
let object = addr2line::object::File::parse(self.program.as_ref()).unwrap();
let ctx = addr2line::Context::new(&object).unwrap();
let loc = ctx.find_location(addr).unwrap();
if let Some(loc) = loc {
tag.file = loc.file.as_ref().unwrap().to_string();
if let Some(line) = loc.line {
tag.line = line;
}
}
let mut frame_iter = self.addrctx.find_frames(addr).unwrap();
let mut frame_iter = ctx.find_frames(addr).unwrap();
tag.func = sprint_fun(&mut frame_iter);
self.cache_tag.insert(addr, tag.clone());
tag
Expand All @@ -175,14 +182,18 @@ impl Profile {
fn display_flamegraph_rec(
&mut self,
prefix: &str,
node: Rc<RefCell<TrieNode>>,
node: Arc<Mutex<TrieNode>>,
writer: &mut impl std::io::Write,
) {
let prefix_name = format!("{}{}", prefix, self.get_tag(node.borrow().addr).simple());
let prefix_name = format!(
"{}{}",
prefix,
self.get_tag(node.lock().unwrap().addr).simple()
);
writer
.write_all(format!("{} {}\n", prefix_name, node.borrow().cycles).as_bytes())
.write_all(format!("{} {}\n", prefix_name, node.lock().unwrap().cycles).as_bytes())
.unwrap();
for e in &node.borrow().childs {
for e in &node.lock().unwrap().childs {
self.display_flamegraph_rec(format!("{}; ", prefix_name).as_str(), e.clone(), writer);
}
writer.flush().unwrap();
Expand All @@ -194,10 +205,10 @@ impl Profile {

pub fn display_stacktrace(&mut self, prefix: &str, writer: &mut impl std::io::Write) {
let mut frame = self.trie_node.clone();
let mut stack = vec![self.get_tag(frame.borrow().pc).detail()];
let mut stack = vec![self.get_tag(frame.lock().unwrap().pc).detail()];
loop {
stack.push(self.get_tag(frame.borrow().link).detail());
let parent = frame.borrow().parent.clone();
stack.push(self.get_tag(frame.lock().unwrap().link).detail());
let parent = frame.lock().unwrap().parent.clone();
if let Some(p) = parent {
frame = p.clone();
} else {
Expand Down Expand Up @@ -231,15 +242,15 @@ impl Profile {
let inst = decoder.decode(machine.memory_mut(), pc)?;
let opcode = instructions::extract_opcode(inst);
let cycles = machine.instruction_cycle_func()(inst);
self.trie_node.borrow_mut().cycles += cycles;
self.trie_node.borrow_mut().pc = pc;
self.trie_node.lock().unwrap().cycles += cycles;
self.trie_node.lock().unwrap().pc = pc;

let call = |s: &mut Self, addr: u64, link: u64| {
let mut regs = [[0; 32]; 2];
for i in 0..32 {
regs[0][i] = machine.registers()[i].to_u64();
}
let chd = Rc::new(RefCell::new(TrieNode {
let chd = Arc::new(Mutex::new(TrieNode {
addr: addr,
link: link,
pc: pc,
Expand All @@ -248,35 +259,35 @@ impl Profile {
cycles: 0,
regs: regs,
}));
s.trie_node.borrow_mut().childs.push(chd.clone());
s.trie_node.lock().unwrap().childs.push(chd.clone());
s.trie_node = chd;
};

let sbrk_or_skip = |s: &mut Self| {
if s.trie_node.borrow().addr == s.sbrk_addr {
if s.trie_node.lock().unwrap().addr == s.sbrk_addr {
// https://github.com/nervosnetwork/riscv-newlib/blob/newlib-4.1.0-fork/libgloss/riscv/sys_sbrk.c#L49
// Note incr could be negative.
s.sbrk_heap =
s.trie_node.borrow().regs[0][A0].wrapping_add(s.trie_node.borrow().regs[1][A0]);
s.sbrk_heap = s.trie_node.lock().unwrap().regs[0][A0]
.wrapping_add(s.trie_node.lock().unwrap().regs[1][A0]);
}
};

let quit_or_skip = |s: &mut Self, addr: u64| {
let mut f = s.trie_node.clone();
loop {
if f.borrow().link == addr {
if f.lock().unwrap().link == addr {
for i in 0..32 {
s.trie_node.borrow_mut().regs[1][i] = machine.registers()[i].to_u64();
s.trie_node.lock().unwrap().regs[1][i] = machine.registers()[i].to_u64();
}
sbrk_or_skip(s);
if let Some(p) = f.borrow().parent.clone() {
if let Some(p) = f.lock().unwrap().parent.clone() {
s.trie_node = p.clone();
} else {
unimplemented!();
}
break;
}
let p = f.borrow().parent.clone();
let p = f.lock().unwrap().parent.clone();
if let Some(p) = p {
f = p.clone();
} else {
Expand Down Expand Up @@ -402,14 +413,14 @@ impl<R: Register, M: Memory<REG = R>, Inner: SupportMachine<REG = R, MEM = M>> M

impl<R: Register, M: Memory<REG = R>, Inner: SupportMachine<REG = R, MEM = M>> PProfMachine<Inner> {
pub fn new(machine: DefaultMachine<Inner>) -> Self {
let code = machine.code().clone();
Self {
machine,
profile: Profile::new(&code).unwrap(),
profile: Profile::new(),
}
}

pub fn load_program(&mut self, program: &Bytes, args: &[Bytes]) -> Result<u64, Error> {
self.profile.load_program(program);
self.machine.load_program(program, args)
}

Expand All @@ -436,7 +447,8 @@ impl<R: Register, M: Memory<REG = R>, Inner: SupportMachine<REG = R, MEM = M>> P
while self.machine.running() {
if self.machine.reset_signal() {
decoder.reset_instructions_cache();
self.profile = Profile::new(&self.machine.code()).unwrap();
self.profile = Profile::new();
self.profile.load_program(&self.machine.code()).unwrap();
}
self.profile.step(&mut self.machine, &mut decoder)?;
self.machine.step(&mut decoder)?;
Expand Down

0 comments on commit 1528774

Please sign in to comment.