mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 23:58:50 +00:00
begin adding tsc frequency getters
This commit is contained in:
@@ -283,7 +283,7 @@ wasm_memory_atomic_wait32 :: proc(ptr: ^u32, expected: u32, timeout_ns: i64) -
|
|||||||
wasm_memory_atomic_notify32 :: proc(ptr: ^u32, waiters: u32) -> (waiters_woken_up: u32) ---
|
wasm_memory_atomic_notify32 :: proc(ptr: ^u32, waiters: u32) -> (waiters_woken_up: u32) ---
|
||||||
|
|
||||||
// x86 Targets (i386, amd64)
|
// x86 Targets (i386, amd64)
|
||||||
x86_cpuid :: proc(ax, cx: u32) -> (eax, ebc, ecx, edx: u32) ---
|
x86_cpuid :: proc(ax, cx: u32) -> (eax, ebx, ecx, edx: u32) ---
|
||||||
x86_xgetbv :: proc(cx: u32) -> (eax, edx: u32) ---
|
x86_xgetbv :: proc(cx: u32) -> (eax, edx: u32) ---
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1537,6 +1537,7 @@ MAP_SHARED :: 0x1
|
|||||||
MAP_PRIVATE :: 0x2
|
MAP_PRIVATE :: 0x2
|
||||||
MAP_SHARED_VALIDATE :: 0x3
|
MAP_SHARED_VALIDATE :: 0x3
|
||||||
MAP_ANONYMOUS :: 0x20
|
MAP_ANONYMOUS :: 0x20
|
||||||
|
MAP_FAILED :: -1
|
||||||
|
|
||||||
// mremap flags
|
// mremap flags
|
||||||
MREMAP_MAYMOVE :: 1
|
MREMAP_MAYMOVE :: 1
|
||||||
@@ -1563,6 +1564,155 @@ MADV_WIPEONFORK :: 18
|
|||||||
MADV_KEEPONFORK :: 19
|
MADV_KEEPONFORK :: 19
|
||||||
MADV_HWPOISON :: 100
|
MADV_HWPOISON :: 100
|
||||||
|
|
||||||
|
// perf event data
|
||||||
|
Perf_Sample :: struct #raw_union {
|
||||||
|
period: u64,
|
||||||
|
frequency: u64,
|
||||||
|
}
|
||||||
|
Perf_Wakeup :: struct #raw_union {
|
||||||
|
events: u32,
|
||||||
|
watermark: u32,
|
||||||
|
}
|
||||||
|
Perf_Field1 :: struct #raw_union {
|
||||||
|
breakpoint_addr: u64,
|
||||||
|
kprobe_func: u64,
|
||||||
|
uprobe_path: u64,
|
||||||
|
config1: u64,
|
||||||
|
}
|
||||||
|
Perf_Field2 :: struct #raw_union {
|
||||||
|
breakpoint_len: u64,
|
||||||
|
kprobe_addr: u64,
|
||||||
|
uprobe_offset: u64,
|
||||||
|
config2: u64,
|
||||||
|
}
|
||||||
|
Perf_Event_Attr :: struct #packed {
|
||||||
|
type: u32,
|
||||||
|
size: u32,
|
||||||
|
config: u64,
|
||||||
|
sample: Perf_Sample,
|
||||||
|
sample_type: u64,
|
||||||
|
read_format: u64,
|
||||||
|
flags: Perf_Flags,
|
||||||
|
wakeup: Perf_Wakeup,
|
||||||
|
breakpoint_type: u32,
|
||||||
|
field1: Perf_Field1,
|
||||||
|
field2: Perf_Field2,
|
||||||
|
branch_sample_type: u64,
|
||||||
|
sample_regs_user: u64,
|
||||||
|
sample_stack_user: u32,
|
||||||
|
clock_id: i32,
|
||||||
|
sample_regs_intr: u64,
|
||||||
|
aux_watermark: u32,
|
||||||
|
sample_max_stack: u16,
|
||||||
|
_padding: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
Perf_Event_Flags :: distinct bit_set[Perf_Event_Flag; u64]
|
||||||
|
Perf_Event_Flag :: enum u64 {
|
||||||
|
Bit0 = 0,
|
||||||
|
Bit0_Is_Deprecated = 1,
|
||||||
|
User_Rdpmc = 2,
|
||||||
|
User_Time = 3,
|
||||||
|
User_Time_Zero = 4,
|
||||||
|
User_Time_Short = 5,
|
||||||
|
}
|
||||||
|
Perf_Capabilities :: struct #raw_union {
|
||||||
|
capabilities: u64,
|
||||||
|
flags: Perf_Event_Flags,
|
||||||
|
}
|
||||||
|
Perf_Event_mmap_Page :: struct #packed {
|
||||||
|
version: u32,
|
||||||
|
compat_version: u32,
|
||||||
|
lock: u32,
|
||||||
|
index: u32,
|
||||||
|
offset: i64,
|
||||||
|
time_enabled: u64,
|
||||||
|
time_running: u64,
|
||||||
|
cap: Perf_Capabilities,
|
||||||
|
pmc_width: u16,
|
||||||
|
time_shift: u16,
|
||||||
|
time_mult: u32,
|
||||||
|
time_offset: u64,
|
||||||
|
time_zero: u64,
|
||||||
|
size: u32,
|
||||||
|
reserved1: u32,
|
||||||
|
time_cycles: u64,
|
||||||
|
time_mask: u64,
|
||||||
|
reserved2: [116*8]u8,
|
||||||
|
data_head: u64,
|
||||||
|
data_tail: u64,
|
||||||
|
data_offset: u64,
|
||||||
|
data_size: u64,
|
||||||
|
aux_head: u64,
|
||||||
|
aux_tail: u64,
|
||||||
|
aux_offset: u64,
|
||||||
|
aux_size: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
Perf_Type_Id :: enum u32 {
|
||||||
|
Hardware = 0,
|
||||||
|
Software = 1,
|
||||||
|
Tracepoint = 2,
|
||||||
|
HW_Cache = 3,
|
||||||
|
Raw = 4,
|
||||||
|
Breakpoint = 5,
|
||||||
|
}
|
||||||
|
|
||||||
|
Perf_Hardware_Id :: enum u64 {
|
||||||
|
CPU_Cycles = 0,
|
||||||
|
Instructions = 1,
|
||||||
|
Cache_References = 2,
|
||||||
|
Cache_Misses = 3,
|
||||||
|
Branch_Instructions = 4,
|
||||||
|
Branch_Misses = 5,
|
||||||
|
Bus_Cycles = 6,
|
||||||
|
Stalled_Cycles_Frontend = 7,
|
||||||
|
Stalled_Cycles_Backend = 8,
|
||||||
|
Ref_CPU_Cycles = 9,
|
||||||
|
}
|
||||||
|
|
||||||
|
Perf_Flags :: distinct bit_set[Perf_Flag; u64]
|
||||||
|
Perf_Flag :: enum u64 {
|
||||||
|
Disabled = 0,
|
||||||
|
Inherit = 1,
|
||||||
|
Pinned = 2,
|
||||||
|
Exclusive = 3,
|
||||||
|
Exclude_User = 4,
|
||||||
|
Exclude_Kernel = 5,
|
||||||
|
Exclude_HV = 6,
|
||||||
|
Exclude_Idle = 7,
|
||||||
|
mmap = 8,
|
||||||
|
Comm = 9,
|
||||||
|
Freq = 10,
|
||||||
|
Inherit_Stat = 11,
|
||||||
|
Enable_On_Exec = 12,
|
||||||
|
Task = 13,
|
||||||
|
Watermark = 14,
|
||||||
|
Precise_IP_0 = 15,
|
||||||
|
Precise_IP_1 = 16,
|
||||||
|
mmap_Data = 17,
|
||||||
|
Sample_Id_All = 18,
|
||||||
|
Exclude_Host = 19,
|
||||||
|
Exclude_Guest = 20,
|
||||||
|
Exclude_Callchain_Kernel = 21,
|
||||||
|
Exclude_Callchain_User = 22,
|
||||||
|
mmap2 = 23,
|
||||||
|
Comm_Exec = 24,
|
||||||
|
Use_Clockid = 25,
|
||||||
|
Context_Switch = 26,
|
||||||
|
Write_Backward = 27,
|
||||||
|
Namespaces = 28,
|
||||||
|
KSymbol = 29,
|
||||||
|
BPF_Event = 30,
|
||||||
|
Aux_Output = 31,
|
||||||
|
CGroup = 32,
|
||||||
|
Text_Poke = 33,
|
||||||
|
Build_Id = 34,
|
||||||
|
Inherit_Thread = 35,
|
||||||
|
Remove_On_Exec = 36,
|
||||||
|
Sigtrap = 37,
|
||||||
|
}
|
||||||
|
|
||||||
sys_gettid :: proc "contextless" () -> int {
|
sys_gettid :: proc "contextless" () -> int {
|
||||||
return cast(int)intrinsics.syscall(SYS_gettid)
|
return cast(int)intrinsics.syscall(SYS_gettid)
|
||||||
}
|
}
|
||||||
@@ -1846,6 +1996,10 @@ sys_utimensat :: proc "contextless" (dfd: int, path: cstring, times: rawptr, fla
|
|||||||
return int(intrinsics.syscall(SYS_utimensat, uintptr(dfd), uintptr(rawptr(path)), uintptr(times), uintptr(flags)))
|
return int(intrinsics.syscall(SYS_utimensat, uintptr(dfd), uintptr(rawptr(path)), uintptr(times), uintptr(flags)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sys_perf_event_open :: proc "contextless" (event_attr: rawptr, pid: i32, cpu: i32, group_fd: i32, flags: u32) -> int {
|
||||||
|
return int(intrinsics.syscall(SYS_perf_event_open, uintptr(event_attr), uintptr(pid), uintptr(cpu), uintptr(group_fd), uintptr(flags)))
|
||||||
|
}
|
||||||
|
|
||||||
get_errno :: proc "contextless" (res: int) -> i32 {
|
get_errno :: proc "contextless" (res: int) -> i32 {
|
||||||
if res < 0 && res > -4096 {
|
if res < 0 && res > -4096 {
|
||||||
return i32(-res)
|
return i32(-res)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package time
|
package time
|
||||||
|
|
||||||
import "core:runtime"
|
import "core:runtime"
|
||||||
|
import "core:intrinsics"
|
||||||
|
|
||||||
Tick :: struct {
|
Tick :: struct {
|
||||||
_nsec: i64, // relative amount
|
_nsec: i64, // relative amount
|
||||||
@@ -40,6 +41,26 @@ _tick_duration_end :: proc "contextless" (d: ^Duration, t: Tick) {
|
|||||||
d^ = tick_since(t)
|
d^ = tick_since(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
when ODIN_ARCH == .amd64 {
|
||||||
|
_has_invariant_tsc :: proc "contextless" () -> bool {
|
||||||
|
eax, _, _, _ := intrinsics.x86_cpuid(0x80_000_000, 0)
|
||||||
|
|
||||||
|
// Is this processor *really* ancient?
|
||||||
|
if eax < 0x80_000_007 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if the invariant TSC bit is set
|
||||||
|
_, _, _, edx := intrinsics.x86_cpuid(0x80_000_007, 0)
|
||||||
|
return (edx & (1 << 8)) != 0
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_has_invariant_tsc :: proc "contextless" () -> bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Benchmark helpers
|
Benchmark helpers
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
//+private
|
||||||
|
//+build linux
|
||||||
|
package time
|
||||||
|
|
||||||
|
import "core:intrinsics"
|
||||||
|
import "core:sys/unix"
|
||||||
|
|
||||||
|
_get_tsc_frequency :: proc "contextless" () -> u64 {
|
||||||
|
@(static) frequency : u64 = 0
|
||||||
|
if frequency > 0 {
|
||||||
|
return frequency
|
||||||
|
}
|
||||||
|
|
||||||
|
perf_attr := unix.Perf_Event_Attr{}
|
||||||
|
perf_attr.type = u32(unix.Perf_Type_Id.Hardware)
|
||||||
|
perf_attr.config = u64(unix.Perf_Hardware_Id.Instructions)
|
||||||
|
perf_attr.size = size_of(perf_attr)
|
||||||
|
perf_attr.flags = {.Disabled, .Exclude_Kernel, .Exclude_HV}
|
||||||
|
fd := unix.sys_perf_event_open(&perf_attr, 0, -1, -1, 0)
|
||||||
|
if fd == -1 {
|
||||||
|
frequency = 1
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
defer unix.sys_close(fd)
|
||||||
|
|
||||||
|
page_size : uint = 4096
|
||||||
|
ret := unix.sys_mmap(nil, page_size, unix.PROT_READ, unix.MAP_SHARED, fd, 0)
|
||||||
|
if ret == unix.MAP_FAILED {
|
||||||
|
frequency = 1
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
addr := rawptr(uintptr(ret))
|
||||||
|
defer unix.sys_munmap(addr, page_size)
|
||||||
|
|
||||||
|
event_page := (^unix.Perf_Event_mmap_Page)(addr)
|
||||||
|
if .User_Time not_in event_page.cap.flags {
|
||||||
|
frequency = 1
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
frequency = u64((u128(1_000_000_000) << u128(event_page.time_shift)) / u128(event_page.time_mult))
|
||||||
|
return frequency
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user