Skip to content

Commit

Permalink
wip perf improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
javierhonduco committed Apr 30, 2024
1 parent 7e20e7d commit 3bc602c
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 123 deletions.
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ glob = "0.3.1"
name = "unwind_info"
harness = false

[lib]
bench = false

[profile.dev.package]
insta.opt-level = 3
similar.opt-level = 3
25 changes: 10 additions & 15 deletions benches/unwind_info.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,17 @@
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use lightswitch::unwind_info::{to_vec, remove_redundant, remove_unnecesary_markers};
use lightswitch::unwind_info::{remove_redundant, remove_unnecesary_markers, to_vec};

const NODE_EXE: &'static str = "/home/javierhonduco/.vscode-server/cli/servers/Stable-e170252f762678dec6ca2cc69aba1570769a5d39/server/node";
const NODE_EXE: &'static str = "/opt/redpanda/libexec/redpanda";

pub fn criterion_benchmark(c: &mut Criterion) {
c.bench_function("unwind info + sorting", |b| b.iter(|| {
let mut found_unwind_info = to_vec(NODE_EXE).unwrap();
found_unwind_info.sort_by(|a, b| {
let a_pc = a.pc;
let b_pc = b.pc;
a_pc.cmp(&b_pc)
});

black_box(found_unwind_info);
// let found_unwind_info = remove_unnecesary_markers(&found_unwind_info);
// black_box(remove_redundant(&found_unwind_info));
}));
c.bench_function("unwind info + sorting", |b| {
b.iter(|| {
let mut found_unwind_info = to_vec(NODE_EXE).unwrap();
remove_unnecesary_markers(&mut found_unwind_info);
black_box(remove_redundant(&mut found_unwind_info));
})
});
}

criterion_group!(benches, criterion_benchmark);
criterion_main!(benches);
criterion_main!(benches);
13 changes: 11 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ use tracing_subscriber::FmtSubscriber;
use lightswitch::collector::Collector;
use lightswitch::object::ObjectFile;
use lightswitch::profiler::Profiler;
use lightswitch::unwind_info::{compact_printing_callback, UnwindInfoBuilder};
use lightswitch::unwind_info::remove_redundant;
use lightswitch::unwind_info::remove_unnecesary_markers;
use lightswitch::unwind_info::to_vec;
use lightswitch::unwind_info::UnwindInfoBuilder;

const SAMPLE_FREQ_RANGE: RangeInclusive<usize> = 1..=1009;

Expand Down Expand Up @@ -138,7 +141,13 @@ fn main() -> Result<(), Box<dyn Error>> {
tracing::subscriber::set_global_default(subscriber).expect("setting default subscriber failed");

if let Some(path) = args.show_unwind_info {
UnwindInfoBuilder::with_callback(&path, compact_printing_callback)?.process()?;
let mut unwind_info = to_vec(&path).unwrap();
remove_unnecesary_markers(&mut unwind_info);
remove_redundant(&mut unwind_info);

for compact_row in unwind_info {
println!("{:?}", compact_row);
}
return Ok(());
}

Expand Down
14 changes: 3 additions & 11 deletions src/profiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use crate::bpf::tracers_skel::{TracersSkel, TracersSkelBuilder};
use crate::collector::*;
use crate::object::{BuildId, ObjectFile};
use crate::perf_events::setup_perf_event;
use crate::unwind_info::{to_vec, remove_redundant, remove_unnecesary_markers};
use crate::unwind_info::{remove_redundant, remove_unnecesary_markers, to_vec};
use crate::util::summarize_address_range;

pub enum TracerEvent {
Expand Down Expand Up @@ -752,17 +752,9 @@ impl Profiler<'_> {
}
span.exit();

let span: span::EnteredSpan = span!(Level::DEBUG, "sort unwind info").entered();
found_unwind_info.sort_by(|a, b| {
let a_pc = a.pc;
let b_pc = b.pc;
a_pc.cmp(&b_pc)
});
span.exit();

let span: span::EnteredSpan = span!(Level::DEBUG, "optimize unwind info").entered();
let found_unwind_info = remove_unnecesary_markers(&found_unwind_info);
let found_unwind_info = remove_redundant(&found_unwind_info);
remove_unnecesary_markers(&mut found_unwind_info);
remove_redundant(&mut found_unwind_info);
span.exit();

debug!(
Expand Down
208 changes: 113 additions & 95 deletions src/unwind_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use thiserror::Error;

use crate::bpf::profiler_bindings::stack_unwind_row_t;
use anyhow::anyhow;
use tracing::error;
use tracing::{error, span, Level};

#[repr(u8)]
pub enum CfaType {
Expand Down Expand Up @@ -252,16 +252,16 @@ impl<'a> UnwindInfoBuilder<'a> {
let eh_frame = EhFrame::new(eh_frame_data, endian);
let mut entries_iter = eh_frame.entries(&bases);

let mut ctx = Box::new(UnwindContext::new());
let mut cur_cie = None;
let mut pc_and_fde_offset = Vec::new();

while let Ok(Some(entry)) = entries_iter.next() {
match entry {
CieOrFde::Cie(cie) => {
cur_cie = Some(cie);
}
CieOrFde::Fde(partial_fde) => {
if let Ok(fde) = partial_fde.parse(|eh_frame, bases, cie_offset| {
let fde = partial_fde.parse(|eh_frame, bases, cie_offset| {
if let Some(cie) = &cur_cie {
if cie.offset() == cie_offset.0 {
return Ok(cie.clone());
Expand All @@ -272,111 +272,125 @@ impl<'a> UnwindInfoBuilder<'a> {
cur_cie = Some(cie.clone());
}
cie
}) {
(self.callback)(&UnwindData::Function(
fde.initial_address(),
fde.initial_address() + fde.len(),
));

let mut table = fde.rows(&eh_frame, &bases, &mut ctx)?;

loop {
let mut compact_row = CompactUnwindRow::default();

match table.next_row() {
Ok(None) => break,
Ok(Some(row)) => {
compact_row.pc = row.start_address();
match row.cfa() {
CfaRule::RegisterAndOffset { register, offset } => {
if register == &RBP_X86 {
compact_row.cfa_type =
CfaType::FramePointerOffset as u8;
} else if register == &RSP_X86 {
compact_row.cfa_type =
CfaType::StackPointerOffset as u8;
} else {
compact_row.cfa_type =
CfaType::UnsupportedRegisterOffset as u8;
}

match u16::try_from(*offset) {
Ok(off) => {
compact_row.cfa_offset = off;
}
Err(_) => {
compact_row.cfa_type =
CfaType::OffsetDidNotFit as u8;
}
}
}
CfaRule::Expression(exp) => {
let found_expression = exp.0.slice();

if found_expression == *PLT1 {
compact_row.cfa_offset = PltType::Plt1 as u16;
} else if found_expression == *PLT2 {
compact_row.cfa_offset = PltType::Plt2 as u16;
}

compact_row.cfa_type = CfaType::Expression as u8;
}
};

match row.register(RBP_X86) {
gimli::RegisterRule::Undefined => {}
gimli::RegisterRule::Offset(offset) => {
compact_row.rbp_type = RbpType::CfaOffset as u8;
compact_row.rbp_offset =
i16::try_from(offset).expect("convert rbp offset");
}
gimli::RegisterRule::Register(_reg) => {
compact_row.rbp_type = RbpType::Register as u8;
}
gimli::RegisterRule::Expression(_) => {
compact_row.rbp_type = RbpType::Expression as u8;
}
_ => {
// print!(", rbp unsupported {:?}", rbp);
}
}
});

if let Ok(fde) = fde {
pc_and_fde_offset.push((fde.initial_address(), fde.offset()));
}
}
}
}

if row.register(fde.cie().return_address_register())
== gimli::RegisterRule::Undefined
{
compact_row.rbp_type =
RbpType::UndefinedReturnAddress as u8;
let span = span!(Level::DEBUG, "sort pc and fdes").entered();
pc_and_fde_offset.sort_by_key(|(pc, _)| *pc);
span.exit();

let mut ctx = Box::new(UnwindContext::new());
for (_, fde_offset) in pc_and_fde_offset {
let fde = eh_frame.fde_from_offset(
&bases,
gimli::EhFrameOffset(fde_offset),
EhFrame::cie_from_offset,
)?;

(self.callback)(&UnwindData::Function(
fde.initial_address(),
fde.initial_address() + fde.len(),
));

let mut table = fde.rows(&eh_frame, &bases, &mut ctx)?;

loop {
let mut compact_row = CompactUnwindRow::default();

match table.next_row() {
Ok(None) => break,
Ok(Some(row)) => {
compact_row.pc = row.start_address();
match row.cfa() {
CfaRule::RegisterAndOffset { register, offset } => {
if register == &RBP_X86 {
compact_row.cfa_type = CfaType::FramePointerOffset as u8;
} else if register == &RSP_X86 {
compact_row.cfa_type = CfaType::StackPointerOffset as u8;
} else {
compact_row.cfa_type = CfaType::UnsupportedRegisterOffset as u8;
}

match u16::try_from(*offset) {
Ok(off) => {
compact_row.cfa_offset = off;
}
Err(_) => {
compact_row.cfa_type = CfaType::OffsetDidNotFit as u8;
}
}
}
CfaRule::Expression(exp) => {
let found_expression = exp.0.slice();

// print!(", ra {:?}", row.register(fde.cie().return_address_register()));
if found_expression == *PLT1 {
compact_row.cfa_offset = PltType::Plt1 as u16;
} else if found_expression == *PLT2 {
compact_row.cfa_offset = PltType::Plt2 as u16;
}
_ => continue,

compact_row.cfa_type = CfaType::Expression as u8;
}
};

(self.callback)(&UnwindData::Instruction(compact_row));
match row.register(RBP_X86) {
gimli::RegisterRule::Undefined => {}
gimli::RegisterRule::Offset(offset) => {
compact_row.rbp_type = RbpType::CfaOffset as u8;
compact_row.rbp_offset =
i16::try_from(offset).expect("convert rbp offset");
}
gimli::RegisterRule::Register(_reg) => {
compact_row.rbp_type = RbpType::Register as u8;
}
gimli::RegisterRule::Expression(_) => {
compact_row.rbp_type = RbpType::Expression as u8;
}
_ => {
// print!(", rbp unsupported {:?}", rbp);
}
}
// start_addresses.push(fde.initial_address() as u32);
// end_addresses.push((fde.initial_address() + fde.len()) as u32);

if row.register(fde.cie().return_address_register())
== gimli::RegisterRule::Undefined
{
compact_row.rbp_type = RbpType::UndefinedReturnAddress as u8;
}

// print!(", ra {:?}", row.register(fde.cie().return_address_register()));
}
_ => continue,
}

(self.callback)(&UnwindData::Instruction(compact_row));
}
// start_addresses.push(fde.initial_address() as u32);
// end_addresses.push((fde.initial_address() + fde.len()) as u32);
}
Ok(())
}
}

// Must be sorted. Also, not very optimized as of now.
pub fn remove_unnecesary_markers(info: &Vec<stack_unwind_row_t>) -> Vec<stack_unwind_row_t> {
let mut unwind_info = Vec::with_capacity(info.len());
pub fn remove_unnecesary_markers(unwind_info: &mut Vec<stack_unwind_row_t>) {
let mut last_row: Option<stack_unwind_row_t> = None;
let mut new_i: usize = 0;

for i in 0..unwind_info.len() {
let row = unwind_info[i];

for row in info {
if let Some(last_row_unwrapped) = last_row {
let previous_is_redundant_marker = (last_row_unwrapped.cfa_type
== CfaType::EndFdeMarker as u8)
&& last_row_unwrapped.pc == row.pc;
if previous_is_redundant_marker {
unwind_info.pop();
new_i -= 1;
}
}

Expand All @@ -387,22 +401,25 @@ pub fn remove_unnecesary_markers(info: &Vec<stack_unwind_row_t>) -> Vec<stack_un
}

if !current_is_redundant_marker {
unwind_info.push(*row);
unwind_info[new_i] = row;
new_i += 1;
}

last_row = Some(*row);
last_row = Some(row);
}

unwind_info
unwind_info.truncate(new_i);
}

// Must be sorted. Also, not very optimized as of now.
pub fn remove_redundant(info: &Vec<stack_unwind_row_t>) -> Vec<stack_unwind_row_t> {
let mut unwind_info = Vec::with_capacity(info.len());
// Must be sorted.
pub fn remove_redundant(unwind_info: &mut Vec<stack_unwind_row_t>) {
let mut last_row: Option<stack_unwind_row_t> = None;
let mut new_i: usize = 0;

for row in info {
for i in 0..unwind_info.len() {
let mut redundant = false;
let row = unwind_info[i];

if let Some(last_row_unwrapped) = last_row {
redundant = row.cfa_type == last_row_unwrapped.cfa_type
&& row.cfa_offset == last_row_unwrapped.cfa_offset
Expand All @@ -411,13 +428,14 @@ pub fn remove_redundant(info: &Vec<stack_unwind_row_t>) -> Vec<stack_unwind_row_
}

if !redundant {
unwind_info.push(*row);
unwind_info[new_i] = row;
new_i += 1;
}

last_row = Some(*row);
last_row = Some(row);
}

unwind_info
unwind_info.truncate(new_i);
}

pub fn to_vec(path: &str) -> anyhow::Result<Vec<stack_unwind_row_t>> {
Expand Down

0 comments on commit 3bc602c

Please sign in to comment.