mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 07:38:48 +00:00
update to spall format v3
This commit is contained in:
+88
-36
@@ -8,29 +8,36 @@ import "base:intrinsics"
|
|||||||
|
|
||||||
MANUAL_MAGIC :: u64le(0x0BADF00D)
|
MANUAL_MAGIC :: u64le(0x0BADF00D)
|
||||||
|
|
||||||
Manual_Header :: struct #packed {
|
Manual_Stream_Header :: struct #packed {
|
||||||
magic: u64le,
|
magic: u64le,
|
||||||
version: u64le,
|
version: u64le,
|
||||||
timestamp_scale: f64le,
|
timestamp_scale: f64le,
|
||||||
reserved: u64le,
|
reserved: u64le,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Manual_Buffer_Header :: struct #packed {
|
||||||
|
size: u32le,
|
||||||
|
tid: u32le,
|
||||||
|
pid: u32le,
|
||||||
|
first_ts: u64le,
|
||||||
|
}
|
||||||
|
|
||||||
Manual_Event_Type :: enum u8 {
|
Manual_Event_Type :: enum u8 {
|
||||||
Invalid = 0,
|
Invalid = 0,
|
||||||
|
|
||||||
Begin = 3,
|
Begin = 3,
|
||||||
End = 4,
|
End = 4,
|
||||||
Instant = 5,
|
Instant = 5,
|
||||||
|
|
||||||
Pad_Skip = 7,
|
Pad_Skip = 7,
|
||||||
|
|
||||||
|
Name_Process = 8,
|
||||||
|
Name_Thread = 9,
|
||||||
}
|
}
|
||||||
|
|
||||||
Begin_Event :: struct #packed {
|
Begin_Event :: struct #packed {
|
||||||
type: Manual_Event_Type,
|
type: Manual_Event_Type,
|
||||||
category: u8,
|
ts: u64le,
|
||||||
pid: u32le,
|
|
||||||
tid: u32le,
|
|
||||||
ts: f64le,
|
|
||||||
name_len: u8,
|
name_len: u8,
|
||||||
args_len: u8,
|
args_len: u8,
|
||||||
}
|
}
|
||||||
@@ -38,9 +45,7 @@ BEGIN_EVENT_MAX :: size_of(Begin_Event) + 255 + 255
|
|||||||
|
|
||||||
End_Event :: struct #packed {
|
End_Event :: struct #packed {
|
||||||
type: Manual_Event_Type,
|
type: Manual_Event_Type,
|
||||||
pid: u32le,
|
ts: u64le,
|
||||||
tid: u32le,
|
|
||||||
ts: f64le,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Pad_Skip :: struct #packed {
|
Pad_Skip :: struct #packed {
|
||||||
@@ -48,6 +53,11 @@ Pad_Skip :: struct #packed {
|
|||||||
size: u32le,
|
size: u32le,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Name_Container_Event :: struct #packed {
|
||||||
|
type: Manual_Event_Type,
|
||||||
|
name_len: u8,
|
||||||
|
}
|
||||||
|
|
||||||
// User Interface
|
// User Interface
|
||||||
|
|
||||||
Context :: struct {
|
Context :: struct {
|
||||||
@@ -77,7 +87,7 @@ context_create_with_scale :: proc(filename: string, precise_time: bool, timestam
|
|||||||
ctx.timestamp_scale = timestamp_scale
|
ctx.timestamp_scale = timestamp_scale
|
||||||
|
|
||||||
temp := [size_of(Manual_Header)]u8{}
|
temp := [size_of(Manual_Header)]u8{}
|
||||||
_build_header(temp[:], ctx.timestamp_scale)
|
_build_stream_header(temp[:], ctx.timestamp_scale)
|
||||||
os.write(ctx.fd, temp[:])
|
os.write(ctx.fd, temp[:])
|
||||||
ok = true
|
ok = true
|
||||||
return
|
return
|
||||||
@@ -102,23 +112,32 @@ context_destroy :: proc(ctx: ^Context) {
|
|||||||
|
|
||||||
buffer_create :: proc(data: []byte, tid: u32 = 0, pid: u32 = 0) -> (buffer: Buffer, ok: bool) #optional_ok {
|
buffer_create :: proc(data: []byte, tid: u32 = 0, pid: u32 = 0) -> (buffer: Buffer, ok: bool) #optional_ok {
|
||||||
assert(len(data) >= 1024)
|
assert(len(data) >= 1024)
|
||||||
buffer.data = data
|
buffer.data = data
|
||||||
buffer.tid = tid
|
buffer.tid = tid
|
||||||
buffer.pid = pid
|
buffer.pid = pid
|
||||||
buffer.head = 0
|
buffer.first_ts = 0
|
||||||
|
buffer.head = size_of(Manual_Buffer_Header)
|
||||||
ok = true
|
ok = true
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@(no_instrumentation)
|
@(no_instrumentation)
|
||||||
buffer_flush :: proc "contextless" (ctx: ^Context, buffer: ^Buffer) #no_bounds_check /* bounds check would segfault instrumentation */ {
|
buffer_flush :: proc "contextless" (ctx: ^Context, buffer: ^Buffer) #no_bounds_check /* bounds check would segfault instrumentation */ {
|
||||||
|
buffer_size := buffer.head - size_of(Manual_Buffer_Header)
|
||||||
|
hdr := (^Manual_Buffer_Header)(raw_data(buffer.data))
|
||||||
|
hdr.size = buffer_size
|
||||||
|
hdr.pid = buffer.pid
|
||||||
|
hdr.tid = buffer.tid
|
||||||
|
hdr.first_ts = buffer.first_ts
|
||||||
|
|
||||||
start := _trace_now(ctx)
|
start := _trace_now(ctx)
|
||||||
write(ctx.fd, buffer.data[:buffer.head])
|
write(ctx.fd, buffer.data[:buffer.head])
|
||||||
buffer.head = 0
|
buffer.head = size_of(Manual_Buffer_Header)
|
||||||
end := _trace_now(ctx)
|
end := _trace_now(ctx)
|
||||||
|
|
||||||
buffer.head += _build_begin(buffer.data[buffer.head:], "Spall Trace Buffer Flush", "", start, buffer.tid, buffer.pid)
|
buffer.head += _build_begin(buffer.data[buffer.head:], "Spall Trace Buffer Flush", "", start)
|
||||||
buffer.head += _build_end(buffer.data[buffer.head:], end, buffer.tid, buffer.pid)
|
buffer.head += _build_end(buffer.data[buffer.head:], end)
|
||||||
|
buffer.first_ts = end
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer_destroy :: proc(ctx: ^Context, buffer: ^Buffer) {
|
buffer_destroy :: proc(ctx: ^Context, buffer: ^Buffer) {
|
||||||
@@ -141,16 +160,16 @@ _scoped_buffer_end :: proc(ctx: ^Context, buffer: ^Buffer, _, _: string, _ := #c
|
|||||||
}
|
}
|
||||||
|
|
||||||
@(no_instrumentation)
|
@(no_instrumentation)
|
||||||
_trace_now :: proc "contextless" (ctx: ^Context) -> f64 {
|
_trace_now :: proc "contextless" (ctx: ^Context) -> u64 {
|
||||||
if !ctx.precise_time {
|
if !ctx.precise_time {
|
||||||
return f64(tick_now()) / 1_000
|
return u64(tick_now())
|
||||||
}
|
}
|
||||||
|
|
||||||
return f64(intrinsics.read_cycle_counter())
|
return u64(intrinsics.read_cycle_counter())
|
||||||
}
|
}
|
||||||
|
|
||||||
@(no_instrumentation)
|
@(no_instrumentation)
|
||||||
_build_header :: proc "contextless" (buffer: []u8, timestamp_scale: f64) -> (header_size: int, ok: bool) #optional_ok {
|
_build_stream_header :: proc "contextless" (buffer: []u8, timestamp_scale: f64) -> (header_size: int, ok: bool) #optional_ok {
|
||||||
header_size = size_of(Manual_Header)
|
header_size = size_of(Manual_Header)
|
||||||
if header_size > len(buffer) {
|
if header_size > len(buffer) {
|
||||||
return 0, false
|
return 0, false
|
||||||
@@ -158,7 +177,7 @@ _build_header :: proc "contextless" (buffer: []u8, timestamp_scale: f64) -> (hea
|
|||||||
|
|
||||||
hdr := (^Manual_Header)(raw_data(buffer))
|
hdr := (^Manual_Header)(raw_data(buffer))
|
||||||
hdr.magic = MANUAL_MAGIC
|
hdr.magic = MANUAL_MAGIC
|
||||||
hdr.version = 1
|
hdr.version = 3
|
||||||
hdr.timestamp_scale = f64le(timestamp_scale)
|
hdr.timestamp_scale = f64le(timestamp_scale)
|
||||||
hdr.reserved = 0
|
hdr.reserved = 0
|
||||||
ok = true
|
ok = true
|
||||||
@@ -166,7 +185,7 @@ _build_header :: proc "contextless" (buffer: []u8, timestamp_scale: f64) -> (hea
|
|||||||
}
|
}
|
||||||
|
|
||||||
@(no_instrumentation)
|
@(no_instrumentation)
|
||||||
_build_begin :: #force_inline proc "contextless" (buffer: []u8, name: string, args: string, ts: f64, tid: u32, pid: u32) -> (event_size: int, ok: bool) #optional_ok #no_bounds_check /* bounds check would segfault instrumentation */ {
|
_build_begin :: #force_inline proc "contextless" (buffer: []u8, name: string, args: string, ts: u64) -> (event_size: int, ok: bool) #optional_ok #no_bounds_check /* bounds check would segfault instrumentation */ {
|
||||||
ev := (^Begin_Event)(raw_data(buffer))
|
ev := (^Begin_Event)(raw_data(buffer))
|
||||||
name_len := min(len(name), 255)
|
name_len := min(len(name), 255)
|
||||||
args_len := min(len(args), 255)
|
args_len := min(len(args), 255)
|
||||||
@@ -177,9 +196,7 @@ _build_begin :: #force_inline proc "contextless" (buffer: []u8, name: string, ar
|
|||||||
}
|
}
|
||||||
|
|
||||||
ev.type = .Begin
|
ev.type = .Begin
|
||||||
ev.pid = u32le(pid)
|
ev.ts = u64le(ts)
|
||||||
ev.tid = u32le(tid)
|
|
||||||
ev.ts = f64le(ts)
|
|
||||||
ev.name_len = u8(name_len)
|
ev.name_len = u8(name_len)
|
||||||
ev.args_len = u8(args_len)
|
ev.args_len = u8(args_len)
|
||||||
intrinsics.mem_copy_non_overlapping(raw_data(buffer[size_of(Begin_Event):]), raw_data(name), name_len)
|
intrinsics.mem_copy_non_overlapping(raw_data(buffer[size_of(Begin_Event):]), raw_data(name), name_len)
|
||||||
@@ -190,7 +207,7 @@ _build_begin :: #force_inline proc "contextless" (buffer: []u8, name: string, ar
|
|||||||
}
|
}
|
||||||
|
|
||||||
@(no_instrumentation)
|
@(no_instrumentation)
|
||||||
_build_end :: proc "contextless" (buffer: []u8, ts: f64, tid: u32, pid: u32) -> (event_size: int, ok: bool) #optional_ok {
|
_build_end :: proc "contextless" (buffer: []u8, ts: u64) -> (event_size: int, ok: bool) #optional_ok {
|
||||||
ev := (^End_Event)(raw_data(buffer))
|
ev := (^End_Event)(raw_data(buffer))
|
||||||
event_size = size_of(End_Event)
|
event_size = size_of(End_Event)
|
||||||
if event_size > len(buffer) {
|
if event_size > len(buffer) {
|
||||||
@@ -198,9 +215,28 @@ _build_end :: proc "contextless" (buffer: []u8, ts: f64, tid: u32, pid: u32) ->
|
|||||||
}
|
}
|
||||||
|
|
||||||
ev.type = .End
|
ev.type = .End
|
||||||
ev.pid = u32le(pid)
|
ev.ts = u64le(ts)
|
||||||
ev.tid = u32le(tid)
|
ok = true
|
||||||
ev.ts = f64le(ts)
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
@(no_instrumentation)
|
||||||
|
_build_name_event :: #force_inline proc "contextless" (buffer: []u8, name: string, type: Manual_Event_Type) -> (event_size: int, ok: bool) #optional_ok #no_bounds_check /* bounds check would segfault instrumentation */ {
|
||||||
|
ev := (^Name_Container_Event)(raw_data(buffer))
|
||||||
|
name_len := min(len(name), 255)
|
||||||
|
|
||||||
|
event_size = size_of(Name_Container_Event) + name_len
|
||||||
|
if event_size > len(buffer) {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
if type != .Name_Process && type != .Name_Thread {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
ev.type = type
|
||||||
|
ev.name_len = u8(name_len)
|
||||||
|
intrinsics.mem_copy_non_overlapping(raw_data(buffer[size_of(Name_Container_Event):]), raw_data(name), name_len)
|
||||||
ok = true
|
ok = true
|
||||||
|
|
||||||
return
|
return
|
||||||
@@ -212,7 +248,7 @@ _buffer_begin :: proc "contextless" (ctx: ^Context, buffer: ^Buffer, name: strin
|
|||||||
buffer_flush(ctx, buffer)
|
buffer_flush(ctx, buffer)
|
||||||
}
|
}
|
||||||
name := location.procedure if name == "" else name
|
name := location.procedure if name == "" else name
|
||||||
buffer.head += _build_begin(buffer.data[buffer.head:], name, args, _trace_now(ctx), buffer.tid, buffer.pid)
|
buffer.head += _build_begin(buffer.data[buffer.head:], name, args, _trace_now(ctx))
|
||||||
}
|
}
|
||||||
|
|
||||||
@(no_instrumentation)
|
@(no_instrumentation)
|
||||||
@@ -223,7 +259,23 @@ _buffer_end :: proc "contextless" (ctx: ^Context, buffer: ^Buffer) #no_bounds_ch
|
|||||||
buffer_flush(ctx, buffer)
|
buffer_flush(ctx, buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer.head += _build_end(buffer.data[buffer.head:], ts, buffer.tid, buffer.pid)
|
buffer.head += _build_end(buffer.data[buffer.head:], ts)
|
||||||
|
}
|
||||||
|
|
||||||
|
@(no_instrumentation)
|
||||||
|
_buffer_name_thread :: proc "contextless" (ctx: ^Context, buffer: ^Buffer, name: string, location := #caller_location) #no_bounds_check /* bounds check would segfault instrumentation */ {
|
||||||
|
if buffer.head + NAME_EVENT_MAX > len(buffer.data) {
|
||||||
|
buffer_flush(ctx, buffer)
|
||||||
|
}
|
||||||
|
buffer.head += _build_name_event(buffer.data[buffer.head:], name, .Name_Thread)
|
||||||
|
}
|
||||||
|
|
||||||
|
@(no_instrumentation)
|
||||||
|
_buffer_name_process :: proc "contextless" (ctx: ^Context, buffer: ^Buffer, name: string, location := #caller_location) #no_bounds_check /* bounds check would segfault instrumentation */ {
|
||||||
|
if buffer.head + NAME_EVENT_MAX > len(buffer.data) {
|
||||||
|
buffer_flush(ctx, buffer)
|
||||||
|
}
|
||||||
|
buffer.head += _build_name_event(buffer.data[buffer.head:], name, .Name_Process)
|
||||||
}
|
}
|
||||||
|
|
||||||
@(no_instrumentation)
|
@(no_instrumentation)
|
||||||
|
|||||||
Reference in New Issue
Block a user