Skip to content

Eventpipe #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 38 commits into
base: unity
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
0df18c7
Implement cross-platform Eventpipe CoreCLR event parsing
vvuk Jun 6, 2024
b8be0bc
rundown ModuleDCEnd
vvuk Jun 24, 2024
fdaaef7
Capture dotnet trace events on mac with --coreclr
vvuk Jul 18, 2024
6fa1f9e
Add events to dump-nettrace
vvuk Jul 18, 2024
3b268fe
Merge remote-tracking branch 'unity/unity' into eventpipe
vvuk Jul 29, 2024
90d07c4
Update eventpipe and coreclr code for new samply changes
vvuk Jul 29, 2024
57dcd17
Fix server URL
vvuk Jul 30, 2024
b2c4804
Handle ImageID without checksum safely
vvuk Jul 31, 2024
8bc8751
Increase xperf buffer size
vvuk Jul 31, 2024
7f6c799
Coreclr fixes for unmerged ETL files
vvuk Jul 31, 2024
2c7a722
Bump version number
vvuk Jul 31, 2024
8d4ae26
Remove nettrace file after processing
vvuk Aug 14, 2024
8f8b78e
version
vvuk Aug 14, 2024
c6d1555
ifdef'd code to use dotnet trace for launching
vvuk Aug 14, 2024
9491402
misc clippy fixes
vvuk Aug 14, 2024
51ff2e3
misc clippy fixes
vvuk Aug 14, 2024
792995a
--amend
vvuk Aug 14, 2024
8d04722
Start moving around eventpipe-rs
vvuk Aug 19, 2024
5540bfa
Move etw parsing into eventpipe-rs
vvuk Aug 19, 2024
4eb6429
Rename eventpipe-rs to coreclr-tracing
vvuk Aug 19, 2024
c26809c
More coreclr-tracing refactoring
vvuk Aug 20, 2024
04f4a68
CoreCLR refactor mostly complete
vvuk Aug 20, 2024
e4b1e30
Add --auto-upload-profile flag
vvuk Sep 2, 2024
793cc50
Split build/release
vvuk Sep 2, 2024
2cfb840
Test build
vvuk Sep 2, 2024
ae84e18
Sigh
vvuk Sep 2, 2024
9a5a65e
prerelease 2
vvuk Sep 2, 2024
50af6d7
Have samply exit after auto-upload; version bump
vvuk Sep 3, 2024
a65fa7f
Search for xperf.exe in the default install location
vvuk Sep 3, 2024
9f2f8bd
Bump version
vvuk Sep 3, 2024
1dd71d6
Fix CoreCLR method name
vvuk Sep 3, 2024
52c8565
Bump to pre.5
vvuk Sep 4, 2024
8f5a00d
Fixes for coreclr method name rendering
vvuk Sep 5, 2024
5ea9c6a
Support coreclr args on non-windows as well
vvuk Sep 9, 2024
893fa5d
Remove old unused function
vvuk Sep 9, 2024
9cbb755
More unused removals
vvuk Sep 9, 2024
2828761
Merge remote-tracking branch 'unity/unity' into eventpipe
vvuk Sep 9, 2024
db6839a
Fix ETW CoreCLR GC markers and stacks
vvuk Sep 12, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
446 changes: 221 additions & 225 deletions Cargo.lock

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ members = [
"wholesym-addr2line",
"tools/benchmarks",
"tools/dump_table",
"tools/query_api"
"tools/query_api",
"coreclr-tracing"
]
exclude = ["etw-reader"] # Should not be compiled on non-Windows

Expand Down
18 changes: 18 additions & 0 deletions coreclr-tracing/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[package]
name = "coreclr-tracing"
version = "0.1.0"
edition = "2021"

[dependencies]
binrw = "0.13.3"
bitflags = "2.4.2"
num-traits = "0.2"
num-derive = "0.4"
log = "0.4.21"

[target.'cfg(windows)'.dependencies]
etw-reader = { path = "../etw-reader" }

# linux-perf-data = "0.10.1"
[[example]]
name = "dump-nettrace"
110 changes: 110 additions & 0 deletions coreclr-tracing/examples/dump-nettrace.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#![allow(unused)]
use std::fs::File;

use coreclr_tracing::*;
use coreclr_tracing::nettrace::*;

// https://github.com/microsoft/perfview/blob/main/src/TraceEvent/EventPipe/EventPipeFormat.md

fn main() {
// open file as binary, argv[1]
let mut file = File::open(std::env::args().nth(1).unwrap()).unwrap();

let mut reader = EventPipeParser::new(file).expect("Failed to make EventPipeParser");

loop {
match reader.next_event() {
Ok(Some(event)) => {
//if event.provider_name == "Microsoft-DotNETCore-SampleProfiler" {
// continue;
//}

match coreclr_tracing::nettrace::decode_event(&event) {
DecodedEvent::CoreClrEvent((meta, coreclr_event)) => {
match coreclr_event {
CoreClrEvent::MethodLoad(event) => {
println!(
"MethodLoad: 0x{:16x} -- {}.{}",
event.method_start_address,
event.method_namespace,
event.method_name
);
}
CoreClrEvent::GcTriggered(event) => {
println!("GcTriggered: {:?}", event.reason);
}
CoreClrEvent::GcAllocationTick(event) => {
//println!("GcAllocationTick: {:?}", event);
}
CoreClrEvent::ModuleLoad(event) => {
println!("ModuleLoad: {:?}", event);
}
CoreClrEvent::ModuleUnload(event) => {
println!("ModuleUnload: {:?}", event);
}
CoreClrEvent::MethodUnload(event) => {
println!("MethodUnload: {:?}", event);
}
CoreClrEvent::GcSampledObjectAllocation(event) => {
println!("GcSampledObjectAllocation: {:?}", event);
}
CoreClrEvent::ReadyToRunGetEntryPoint(event) => {
println!("ReadyToRunGetEntryPoint: {:?}", event);
}
CoreClrEvent::MethodDCEnd(event) => {
println!("MethodDCEnd: {:?}", event);
}
CoreClrEvent::GcStart(event) => {
println!("GcStart: {:?}", event);
}
CoreClrEvent::GcEnd(event) => {
println!("GcEnd: {:?}", event);
}
}
}
DecodedEvent::UnknownEvent => {
let mut handled = false;

if event.provider_name == "Microsoft-Windows-DotNETRuntime" {
handled = true;
match event.event_id {
145 => println!("MethodJittingStarted [Unhandled]"),
146 => println!("MemoryAllocatedForJitCode [Unhandled]"),
_ => handled = false,
}
} else if event.provider_name == "Microsoft-Windows-DotNETRuntimeRundown" {
handled = true;
match event.event_id {
10 => println!("Rundown: GCSettingsRundown [Unhandled]"),
146 => println!("Rundown: DCEndComplete [Unhandled] @ {}", event.timestamp),
148 => println!("Rundown: DCEndInit [Unhandled] @ {}", event.timestamp),
150 => println!("Rundown: MethodDCEndILToNativeMap_V1 [Unhandled]"),
152 => println!("Rundown: DomainModuleDCEnd [Unhandled]"),
154 => println!("Rundown: ModuleDCEnd [Unhandled] @ {}", event.timestamp),
156 => println!("Rundown: AssemblyDCEnd [Unhandled]"),
158 => println!("Rundown: AppDomainDCEnd [Unhandled]"),
187 => println!("Rundown: RuntimeInformationDCStart [Unhandled]"),
_ => handled = false,
}
}

if !handled {
println!("Unknown: {} / {}", event.provider_name, event.event_id);
}
}
}

//println!("{} -- ({} {}){:?}", name, event);
//println!("{} -- ({} {})", name, event.provider_name, event.event_id);
}
Ok(None) => {
println!("EOF");
break;
}
Err(e) => {
println!("Error: {:?}", e);
break;
}
}
}
}
141 changes: 141 additions & 0 deletions coreclr-tracing/src/coreclr/enums.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
use bitflags::bitflags;

use std::fmt::Display;

use binrw::BinRead;
use num_derive::FromPrimitive;

#[derive(BinRead, Debug, FromPrimitive, Clone, Copy)]
#[br(repr = u32)]
pub enum GcReason {
AllocSmall = 0,
Induced = 1,
LowMemory = 2,
Empty = 3,
AllocLargeObjectHeap = 4,
OutOfSpaceSmallObjectHeap = 5,
OutOfSpaceLargeObjectHeap = 6,
InducedNotForced = 7,
Stress = 8,
InducedLowMemory = 9,
}

impl Display for GcReason {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
GcReason::AllocSmall => f.write_str("Small object heap allocation"),
GcReason::Induced => f.write_str("Induced"),
GcReason::LowMemory => f.write_str("Low memory"),
GcReason::Empty => f.write_str("Empty"),
GcReason::AllocLargeObjectHeap => f.write_str("Large object heap allocation"),
GcReason::OutOfSpaceSmallObjectHeap => {
f.write_str("Out of space (for small object heap)")
}
GcReason::OutOfSpaceLargeObjectHeap => {
f.write_str("Out of space (for large object heap)")
}
GcReason::InducedNotForced => f.write_str("Induced but not forced as blocking"),
GcReason::Stress => f.write_str("Stress"),
GcReason::InducedLowMemory => f.write_str("Induced low memory"),
}
}
}

#[derive(BinRead, Debug, FromPrimitive, Clone, Copy)]
#[br(repr = u32)]
pub enum GcAllocationKind {
Small = 0,
Large = 1,
Pinned = 2,
}

impl Display for GcAllocationKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
GcAllocationKind::Small => f.write_str("Small"),
GcAllocationKind::Large => f.write_str("Large"),
GcAllocationKind::Pinned => f.write_str("Pinned"),
}
}
}

#[derive(BinRead, Debug, FromPrimitive, Clone, Copy)]
#[br(repr = u32)]
pub enum GcType {
Blocking = 0,
Background = 1,
BlockingDuringBackground = 2,
}

impl Display for GcType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
GcType::Blocking => f.write_str("Blocking GC"),
GcType::Background => f.write_str("Background GC"),
GcType::BlockingDuringBackground => f.write_str("Blocking GC during background GC"),
}
}
}

#[derive(BinRead, Debug, FromPrimitive, Clone, Copy)]
#[br(repr = u32)]
pub enum GcSuspendEeReason {
Other = 0,
GC = 1,
AppDomainShutdown = 2,
CodePitching = 3,
Shutdown = 4,
Debugger = 5,
GcPrep = 6,
DebuggerSweep = 7,
}

impl Display for GcSuspendEeReason {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
GcSuspendEeReason::Other => f.write_str("Other"),
GcSuspendEeReason::GC => f.write_str("GC"),
GcSuspendEeReason::AppDomainShutdown => f.write_str("AppDomain shutdown"),
GcSuspendEeReason::CodePitching => f.write_str("Code pitching"),
GcSuspendEeReason::Shutdown => f.write_str("Shutdown"),
GcSuspendEeReason::Debugger => f.write_str("Debugger"),
GcSuspendEeReason::GcPrep => f.write_str("GC prep"),
GcSuspendEeReason::DebuggerSweep => f.write_str("Debugger sweep"),
}
}
}

bitflags! {
#[derive(PartialEq, Eq)]
pub struct CoreClrMethodFlags: u32 {
const dynamic = 0x1;
const generic = 0x2;
const has_shared_generic_code = 0x4;
const jitted = 0x8;
const jit_helper = 0x10;
const profiler_rejected_precompiled_code = 0x20;
const ready_to_run_rejected_precompiled_code = 0x40;

// next three bits are the tiered compilation level
const opttier_bit0 = 0x80;
const opttier_bit1 = 0x100;
const opttier_bit2 = 0x200;

// extent flags/value (hot/cold)
const extent_bit_0 = 0x10000000; // 0x1 == cold, 0x0 = hot
const extent_bit_1 = 0x20000000; // always 0 for now looks like
const extent_bit_2 = 0x40000000;
const extent_bit_3 = 0x80000000;

const _ = !0;
}

#[derive(PartialEq, Eq)]
pub struct TieredCompilationSettings: u32 {
const none = 0x0;
const quick_jit = 0x1;
const quick_jit_for_loops = 0x2;
const tiered_pgo = 0x4;
const ready_to_run = 0x8;
}
}
Loading