Skip to content

Commit

Permalink
Merge branch 'main' into unwind_debug
Browse files Browse the repository at this point in the history
  • Loading branch information
gmarler committed May 2, 2024
2 parents 97edb99 + 07677fb commit d162201
Show file tree
Hide file tree
Showing 12 changed files with 350 additions and 145 deletions.
File renamed without changes.
34 changes: 34 additions & 0 deletions .github/workflows/vmtests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: vmtests
on:
pull_request:
push:

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
vmtests:
runs-on: ubuntu-22.04
permissions:
id-token: write
contents: read

steps:
- uses: actions/checkout@main
- uses: DeterminateSystems/nix-installer-action@main
- uses: DeterminateSystems/magic-nix-cache-action@main

- name: Install system dependencies
run: |
export DEBIAN_FRONTEND=noninteractive
sudo apt-get -y install --no-install-recommends qemu-system-x86 qemu-guest-agent
- name: Set up nix dev env
run: nix develop --command echo 0

- name: Build `lightswitch`
run: nix develop --ignore-environment --command bash -c 'cargo build'

- name: Run kernel tests
run: nix develop --command 'vmtest'
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/target
flame.svg
src/bpf/*_skel.rs
.vmtest.log
7 changes: 7 additions & 0 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,13 @@
# snapshot testing plugin binary
cargo-insta
# ocamlPackages.magic-trace
(import ./vm.nix { inherit pkgs; }).vmtest
(import ./vm.nix { inherit pkgs; }).kernel_5_15
(import ./vm.nix { inherit pkgs; }).kernel_6_0
(import ./vm.nix { inherit pkgs; }).kernel_6_2
(import ./vm.nix { inherit pkgs; }).kernel_6_6
(import ./vm.nix { inherit pkgs; }).kernel_6_8_7
(import ./vm.nix { inherit pkgs; }).kernel_6_9_rc5
];

LIBCLANG_PATH = lib.makeLibraryPath [ llvmPackages_16.libclang ];
Expand Down
32 changes: 11 additions & 21 deletions src/bpf/profiler.bpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,29 +71,19 @@ struct {
} rate_limits SEC(".maps");


// On arm64 running 6.8.4-200.fc39.aarch64 the verifier fails with argument list too long. This
// did not use to happen before and it's probably due to a regression in the way the verifier
// accounts for the explored paths. I have tried many other things, such as two mid variables
// but that did not do it. The theory of why this works is that perhaps it's making the verifier
// reset the state it had about the program exploration so the branches its exploring per iteration
// do not grow as much.
#ifdef __TARGET_ARCH_arm64
static u32 __attribute__((optnone)) verifier_workaround(u32 value) {
return value;
}
#endif
#ifdef __TARGET_ARCH_x86
static __always_inline u32 verifier_workaround(u32 value) {
return value;
}
#endif

// Binary search the unwind table to find the row index containing the unwind
// information for a given program counter (pc) relative to the object file.
static __always_inline u64 find_offset_for_pc(stack_unwind_table_t *table, u64 pc, u64 left,
u64 right) {
u64 found = BINARY_SEARCH_DEFAULT;


// On kernels ~6.8 and greater the verifier fails with argument list too long. This did not use to
// happen before and it's probably due to a regression in the way the verifier accounts for the explored
// paths. I have tried many other things, such as two mid variables but that did not do it.
// Perhaps unrolling the loop works is that the verifier doesn't have as many states to explore
// per iteration.
#pragma unroll
for (int i = 0; i < MAX_BINARY_SEARCH_DEPTH; i++) {
// TODO(javierhonduco): ensure that this condition is right as we use
// unsigned values...
Expand All @@ -102,7 +92,7 @@ static __always_inline u64 find_offset_for_pc(stack_unwind_table_t *table, u64 p
return found;
}

u32 mid = verifier_workaround((left + right) / 2);
u32 mid = (left + right) / 2;
// Appease the verifier.
if (mid < 0 || mid >= MAX_UNWIND_TABLE_SIZE) {
LOG("\t.should never happen, mid: %lu, max: %lu", mid,
Expand Down Expand Up @@ -229,7 +219,7 @@ static __always_inline bool retrieve_task_registers(u64 *ip, u64 *sp, u64 *bp) {
}

void *ptr = stack + THREAD_SIZE - TOP_OF_KERNEL_STACK_PADDING;
struct pt_regs *regs = ((struct pt_regs *)ptr) - 1;
bpf_user_pt_regs_t *regs = ((bpf_user_pt_regs_t *)ptr) - 1;

*ip = PT_REGS_IP_CORE(regs);
*sp = PT_REGS_SP_CORE(regs);
Expand Down Expand Up @@ -350,7 +340,7 @@ int dwarf_unwind(struct bpf_perf_event_data *ctx) {
}

if (mapping->type == 2) {
LOG("JIT section, stopping");
LOG("vDSO section, stopping");
return 1;
}

Expand Down Expand Up @@ -570,7 +560,7 @@ int dwarf_unwind(struct bpf_perf_event_data *ctx) {
}

// Set up the initial unwinding state.
static __always_inline bool set_initial_state(unwind_state_t *unwind_state, struct pt_regs *regs) {
static __always_inline bool set_initial_state(unwind_state_t *unwind_state, bpf_user_pt_regs_t *regs) {
unwind_state->stack.len = 0;
unwind_state->tail_calls = 0;

Expand Down
12 changes: 10 additions & 2 deletions src/bpf/profiler_bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,17 @@ unsafe impl Plain for exec_mappings_key {}
unsafe impl Plain for mapping_t {}

impl exec_mappings_key {
pub fn new(pid: u32, address: u64, prefix: u32) -> Self {
pub fn new(pid: u32, address: u64, prefix_len: u32) -> Self {
let key_size_bits = std::mem::size_of::<Self>() * 8;
assert!(
prefix_len <= key_size_bits.try_into().unwrap(),
"prefix_len {} should be <= than the size of exec_mappings_key {}",
prefix_len,
key_size_bits
);

Self {
prefix_len: 32 + prefix,
prefix_len,
pid: pid.to_be(),
data: address.to_be(),
}
Expand Down
29 changes: 23 additions & 6 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::in_memory_unwind_info;
use lightswitch::unwind_info::remove_redundant;
use lightswitch::unwind_info::remove_unnecesary_markers;
use lightswitch::unwind_info::UnwindInfoBuilder;

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

Expand Down Expand Up @@ -125,6 +128,25 @@ fn main() -> Result<(), Box<dyn Error>> {

let args = Cli::parse();

if let Some(path) = args.show_unwind_info {
let mut unwind_info = in_memory_unwind_info(&path).unwrap();
remove_unnecesary_markers(&mut unwind_info);
remove_redundant(&mut unwind_info);

for compact_row in unwind_info {
let pc = compact_row.pc;
let cfa_type = compact_row.cfa_type;
let rbp_type = compact_row.rbp_type;
let cfa_offset = compact_row.cfa_offset;
let rbp_offset = compact_row.rbp_offset;
println!(
"pc: {:x} cfa_type: {:<2} rbp_type: {:<2} cfa_offset: {:<4} rbp_offset: {:<4}",
pc, cfa_type, rbp_type, cfa_offset, rbp_offset
);
}
return Ok(());
}

let subscriber = FmtSubscriber::builder()
.with_max_level(if args.filter_logs {
Level::TRACE
Expand All @@ -137,11 +159,6 @@ 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()?;
return Ok(());
}

if let Some(path) = args.show_info {
let objet_file = ObjectFile::new(&PathBuf::from(path.clone())).unwrap();
println!("build id {:?}", objet_file.build_id());
Expand Down
14 changes: 3 additions & 11 deletions src/profiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -809,17 +809,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 Expand Up @@ -981,7 +973,7 @@ impl Profiler<'_> {
let key = exec_mappings_key::new(
pid.try_into().unwrap(),
address_range.addr,
address_range.range,
32 + address_range.prefix_len,
);

self.add_bpf_mapping(&key, &mapping).unwrap();
Expand Down
Loading

0 comments on commit d162201

Please sign in to comment.