From 051c9cb564b2108a88f24500460602901efb452b Mon Sep 17 00:00:00 2001 From: Colin Davidson Date: Sun, 19 Feb 2023 20:08:11 -0800 Subject: [PATCH 01/16] begin adding tsc frequency getters --- core/intrinsics/intrinsics.odin | 4 +- core/sys/unix/syscalls_linux.odin | 154 ++++++++++++++++++++++++++++++ core/time/perf.odin | 23 ++++- core/time/tsc_linux.odin | 43 +++++++++ 4 files changed, 221 insertions(+), 3 deletions(-) create mode 100644 core/time/tsc_linux.odin diff --git a/core/intrinsics/intrinsics.odin b/core/intrinsics/intrinsics.odin index 38542d2fc..890a6881d 100644 --- a/core/intrinsics/intrinsics.odin +++ b/core/intrinsics/intrinsics.odin @@ -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) --- // 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) --- @@ -305,4 +305,4 @@ valgrind_client_request :: proc(default: uintptr, request: uintptr, a0, a1, a2, // Internal compiler use only -__entry_point :: proc() --- \ No newline at end of file +__entry_point :: proc() --- diff --git a/core/sys/unix/syscalls_linux.odin b/core/sys/unix/syscalls_linux.odin index 8ce3ca3cb..ce810e67d 100644 --- a/core/sys/unix/syscalls_linux.odin +++ b/core/sys/unix/syscalls_linux.odin @@ -1537,6 +1537,7 @@ MAP_SHARED :: 0x1 MAP_PRIVATE :: 0x2 MAP_SHARED_VALIDATE :: 0x3 MAP_ANONYMOUS :: 0x20 +MAP_FAILED :: -1 // mremap flags MREMAP_MAYMOVE :: 1 @@ -1563,6 +1564,155 @@ MADV_WIPEONFORK :: 18 MADV_KEEPONFORK :: 19 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 { 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))) } +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 { if res < 0 && res > -4096 { return i32(-res) diff --git a/core/time/perf.odin b/core/time/perf.odin index 53406646f..d254687fe 100644 --- a/core/time/perf.odin +++ b/core/time/perf.odin @@ -1,6 +1,7 @@ package time import "core:runtime" +import "core:intrinsics" Tick :: struct { _nsec: i64, // relative amount @@ -40,6 +41,26 @@ _tick_duration_end :: proc "contextless" (d: ^Duration, t: Tick) { 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 */ @@ -94,4 +115,4 @@ benchmark :: proc(options: ^Benchmark_Options, allocator := context.allocator) - options->teardown(allocator) or_return } return -} \ No newline at end of file +} diff --git a/core/time/tsc_linux.odin b/core/time/tsc_linux.odin new file mode 100644 index 000000000..91ecb1eae --- /dev/null +++ b/core/time/tsc_linux.odin @@ -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 +} From 6a2ef1f4f3dccaccafd6d28eb9096741e95fb734 Mon Sep 17 00:00:00 2001 From: Colin Davidson Date: Sun, 19 Feb 2023 20:23:35 -0800 Subject: [PATCH 02/16] add osx support --- core/sys/darwin/xnu_system_call_wrappers.odin | 2 +- core/time/tsc_darwin.odin | 23 +++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 core/time/tsc_darwin.odin diff --git a/core/sys/darwin/xnu_system_call_wrappers.odin b/core/sys/darwin/xnu_system_call_wrappers.odin index 685f75ffa..c1d2fd6f7 100644 --- a/core/sys/darwin/xnu_system_call_wrappers.odin +++ b/core/sys/darwin/xnu_system_call_wrappers.odin @@ -416,4 +416,4 @@ syscall_chdir :: #force_inline proc(path: cstring) -> c.int { syscall_fchdir :: #force_inline proc(fd: c.int, path: cstring) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.getentropy), uintptr(fd), transmute(uintptr)path) -} \ No newline at end of file +} diff --git a/core/time/tsc_darwin.odin b/core/time/tsc_darwin.odin new file mode 100644 index 000000000..f2796470e --- /dev/null +++ b/core/time/tsc_darwin.odin @@ -0,0 +1,23 @@ +//+private +//+build darwin +package time + +import "core:sys/darwin" + +_get_tsc_frequency :: proc "contextless" () -> u64 { + @(static) frequency : u64 = 0 + if frequency > 0 { + return frequency + } + + tmp_freq : u64 = 0 + tmp_size : i64 = size_of(tmp_freq) + ret := darwin.syscall_sysctlbyname("machdep.tsc.frequency", &tmp_freq, &tmp_size, nil, 0) + if ret < 0 { + frequency = 1 + return 0 + } + + frequency = tmp_freq + return frequency +} From fb735883be43a62ed707d2f7ef56acaa5ccb76fa Mon Sep 17 00:00:00 2001 From: Colin Davidson Date: Sun, 19 Feb 2023 20:33:48 -0800 Subject: [PATCH 03/16] add a tsc frequency get for windows --- core/time/tsc_windows.odin | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 core/time/tsc_windows.odin diff --git a/core/time/tsc_windows.odin b/core/time/tsc_windows.odin new file mode 100644 index 000000000..635aac2c1 --- /dev/null +++ b/core/time/tsc_windows.odin @@ -0,0 +1,28 @@ +//+private +//+build windows +package time + +import win32 "core:sys/windows" + +_get_tsc_frequency :: proc "contextless" () -> u64 { + @(static) frequency : u64 = 0 + if frequency > 0 { + return frequency + } + + qpc_begin: win32.LARGE_INTEGER + win32.QueryPerformanceCounter(&qpc_begin) + tsc_begin := intrinsics.read_cycle_counter() + + win32.Sleep(2) + + qpc_end: win32.LARGE_INTEGER + win32.QueryPerformanceCounter(&qpc_end) + tsc_end := intrinsics.read_cycle_counter() + + qpc_frequency: win32.LARGE_INTEGER + win32.QueryPerformanceFrequency(&qpc_frequency) + + frequency = ((tsc_end - tsc_begin) * qpc_frequency) / (qpc_end - qpc_begin) + return frequency +} From f2202db517e99dac74f39ba8c257c0595ef27d1a Mon Sep 17 00:00:00 2001 From: Colin Davidson Date: Sun, 19 Feb 2023 20:38:46 -0800 Subject: [PATCH 04/16] make darwin syscalls contextless --- core/sys/darwin/xnu_system_call_numbers.odin | 2 +- core/sys/darwin/xnu_system_call_wrappers.odin | 94 +++++++++---------- 2 files changed, 48 insertions(+), 48 deletions(-) diff --git a/core/sys/darwin/xnu_system_call_numbers.odin b/core/sys/darwin/xnu_system_call_numbers.odin index b90373fdc..429d18964 100644 --- a/core/sys/darwin/xnu_system_call_numbers.odin +++ b/core/sys/darwin/xnu_system_call_numbers.odin @@ -1,6 +1,6 @@ package darwin -unix_offset_syscall :: proc(number: System_Call_Number) -> uintptr { +unix_offset_syscall :: proc "contextless" (number: System_Call_Number) -> uintptr { return uintptr(number) + uintptr(0x2000000) } diff --git a/core/sys/darwin/xnu_system_call_wrappers.odin b/core/sys/darwin/xnu_system_call_wrappers.odin index c1d2fd6f7..c7a6d6bc4 100644 --- a/core/sys/darwin/xnu_system_call_wrappers.odin +++ b/core/sys/darwin/xnu_system_call_wrappers.odin @@ -229,191 +229,191 @@ _Proc_Bsdinfo :: struct { /*--==========================================================================--*/ -syscall_fsync :: #force_inline proc(fildes: c.int) -> bool { +syscall_fsync :: #force_inline proc "contextless" (fildes: c.int) -> bool { return !(cast(bool)intrinsics.syscall(unix_offset_syscall(.fsync), uintptr(fildes))) } -syscall_write :: #force_inline proc (fildes: c.int, buf: ^byte, nbyte: u64) -> bool { +syscall_write :: #force_inline proc "contextless" (fildes: c.int, buf: ^byte, nbyte: u64) -> bool { return !(cast(bool)intrinsics.syscall(unix_offset_syscall(.write), uintptr(fildes), uintptr(buf), uintptr(nbyte))) } -syscall_read :: #force_inline proc(fildes: c.int, buf: ^byte, nbyte: u64) -> i64 { +syscall_read :: #force_inline proc "contextless" (fildes: c.int, buf: ^byte, nbyte: u64) -> i64 { return cast(i64)intrinsics.syscall(unix_offset_syscall(.read), uintptr(fildes), uintptr(buf), uintptr(nbyte)) } -syscall_open :: #force_inline proc(path: cstring, oflag: u32, mode: u32) -> c.int { +syscall_open :: #force_inline proc "contextless" (path: cstring, oflag: u32, mode: u32) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.open), transmute(uintptr)path, uintptr(oflag), uintptr(mode)) } -syscall_close :: #force_inline proc(fd: c.int) -> bool { +syscall_close :: #force_inline proc "contextless" (fd: c.int) -> bool { return !(cast(bool)intrinsics.syscall(unix_offset_syscall(.close), uintptr(fd))) } -syscall_fchmod :: #force_inline proc(fildes: c.int, mode: u32) -> c.int { +syscall_fchmod :: #force_inline proc "contextless" (fildes: c.int, mode: u32) -> c.int { return (cast(c.int)intrinsics.syscall(unix_offset_syscall(.fchmod), uintptr(fildes), uintptr(mode))) } -syscall_chmod :: #force_inline proc(path: cstring, mode: u32) -> c.int { +syscall_chmod :: #force_inline proc "contextless" (path: cstring, mode: u32) -> c.int { return (cast(c.int)intrinsics.syscall(unix_offset_syscall(.chmod), transmute(uintptr)path, uintptr(mode))) } -syscall_mkdir :: #force_inline proc(path: cstring, mode: u32) -> c.int { +syscall_mkdir :: #force_inline proc "contextless" (path: cstring, mode: u32) -> c.int { return (cast(c.int)intrinsics.syscall(unix_offset_syscall(.mkdir), transmute(uintptr)path, uintptr(mode))) } -syscall_mkdir_at :: #force_inline proc(fd: c.int, path: cstring, mode: u32) -> c.int { +syscall_mkdir_at :: #force_inline proc "contextless" (fd: c.int, path: cstring, mode: u32) -> c.int { return (cast(c.int)intrinsics.syscall(unix_offset_syscall(.mkdir), uintptr(fd), transmute(uintptr)path, uintptr(mode))) } -syscall_rmdir :: #force_inline proc(path: cstring, mode: u32) -> c.int { +syscall_rmdir :: #force_inline proc "contextless" (path: cstring, mode: u32) -> c.int { return (cast(c.int)intrinsics.syscall(unix_offset_syscall(.rmdir), transmute(uintptr)path, uintptr(mode))) } -syscall_rename :: #force_inline proc(path_old: cstring, path_new: cstring) -> c.int { +syscall_rename :: #force_inline proc "contextless" (path_old: cstring, path_new: cstring) -> c.int { return (cast(c.int)intrinsics.syscall(unix_offset_syscall(.rename), transmute(uintptr)path_old, transmute(uintptr)path_new)) } -syscall_rename_at :: #force_inline proc(from_fd: c.int, from: cstring, to_fd: c.int, to: cstring) -> c.int { +syscall_rename_at :: #force_inline proc "contextless" (from_fd: c.int, from: cstring, to_fd: c.int, to: cstring) -> c.int { return (cast(c.int)intrinsics.syscall(unix_offset_syscall(.renameat), uintptr(from_fd), transmute(uintptr)from, uintptr(to_fd), transmute(uintptr)to)) } -syscall_lseek :: #force_inline proc(fd: c.int, offset: i64, whence: c.int) -> i64 { +syscall_lseek :: #force_inline proc "contextless" (fd: c.int, offset: i64, whence: c.int) -> i64 { return cast(i64)intrinsics.syscall(unix_offset_syscall(.lseek), uintptr(fd), uintptr(offset), uintptr(whence)) } -syscall_gettid :: #force_inline proc() -> u64 { +syscall_gettid :: #force_inline proc "contextless" () -> u64 { return cast(u64)intrinsics.syscall(unix_offset_syscall(.gettid)) } -syscall_fstat :: #force_inline proc(fd: c.int, status: ^stat) -> c.int { +syscall_fstat :: #force_inline proc "contextless" (fd: c.int, status: ^stat) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.fstat), uintptr(fd), uintptr(status)) } -syscall_lstat :: #force_inline proc(path: cstring, status: ^stat) -> c.int { +syscall_lstat :: #force_inline proc "contextless" (path: cstring, status: ^stat) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.lstat), transmute(uintptr)path, uintptr(status)) } -syscall_stat :: #force_inline proc(path: cstring, status: ^stat) -> c.int { +syscall_stat :: #force_inline proc "contextless" (path: cstring, status: ^stat) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.stat), transmute(uintptr)path, uintptr(status)) } -syscall_fstatat :: #force_inline proc(fd: c.int, path: cstring, status: ^stat) -> c.int { +syscall_fstatat :: #force_inline proc "contextless" (fd: c.int, path: cstring, status: ^stat) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.fstatat), uintptr(fd), transmute(uintptr)path, uintptr(status)) } -syscall_link :: #force_inline proc(path: cstring, to_link: cstring) -> c.int { +syscall_link :: #force_inline proc "contextless" (path: cstring, to_link: cstring) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.link), transmute(uintptr)path, transmute(uintptr)to_link) } -syscall_linkat :: #force_inline proc(fd: c.int, path: cstring, fd2: c.int, to_link: cstring) -> c.int { +syscall_linkat :: #force_inline proc "contextless" (fd: c.int, path: cstring, fd2: c.int, to_link: cstring) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.linkat), uintptr(fd), transmute(uintptr)path, uintptr(fd2), transmute(uintptr)to_link) } -syscall_readlink :: #force_inline proc(path: cstring, buf: ^u8, buf_size: u64) -> i64 { +syscall_readlink :: #force_inline proc "contextless" (path: cstring, buf: ^u8, buf_size: u64) -> i64 { return cast(i64)intrinsics.syscall(unix_offset_syscall(.readlink), transmute(uintptr)path, uintptr(buf), uintptr(buf_size)) } -syscall_readlinkat :: #force_inline proc(fd: c.int, path: cstring, buf: ^u8, buf_size: u64) -> i64 { +syscall_readlinkat :: #force_inline proc "contextless" (fd: c.int, path: cstring, buf: ^u8, buf_size: u64) -> i64 { return cast(i64)intrinsics.syscall(unix_offset_syscall(.readlinkat), uintptr(fd), transmute(uintptr)path, uintptr(buf), uintptr(buf_size)) } -syscall_access :: #force_inline proc(path: cstring, mode: c.int) -> c.int { +syscall_access :: #force_inline proc "contextless" (path: cstring, mode: c.int) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.access), transmute(uintptr)path, uintptr(mode)) } -syscall_faccessat :: #force_inline proc(fd: c.int, path: cstring, mode: c.int, flag: c.int) -> c.int { +syscall_faccessat :: #force_inline proc "contextless" (fd: c.int, path: cstring, mode: c.int, flag: c.int) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.faccessat), uintptr(fd), transmute(uintptr)path, uintptr(mode), uintptr(flag)) } -syscall_getdirentries :: #force_inline proc(fd: c.int, buf: ^u8, nbytes: c.int, base_pointer: ^u32) -> c.int { +syscall_getdirentries :: #force_inline proc "contextless" (fd: c.int, buf: ^u8, nbytes: c.int, base_pointer: ^u32) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.getdirentries), uintptr(fd), uintptr(buf), uintptr(nbytes), uintptr(base_pointer)) } -syscall_truncate :: #force_inline proc (path: cstring, length: off_t) -> c.int { +syscall_truncate :: #force_inline proc "contextless" (path: cstring, length: off_t) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.truncate), transmute(uintptr)path, uintptr(length)) } -syscall_ftruncate :: #force_inline proc (fd: c.int, length: off_t) -> c.int { +syscall_ftruncate :: #force_inline proc "contextless" (fd: c.int, length: off_t) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.ftruncate), uintptr(fd), uintptr(length)) } -syscall_sysctl :: #force_inline proc (name: ^c.int, namelen: c.uint, oldp: rawptr, oldlenp: ^i64, newp: ^i8, newlen: i64) -> c.int { +syscall_sysctl :: #force_inline proc "contextless" (name: ^c.int, namelen: c.uint, oldp: rawptr, oldlenp: ^i64, newp: ^i8, newlen: i64) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.sysctl), uintptr(name), uintptr(namelen), uintptr(oldp), uintptr(oldlenp), uintptr(newp), uintptr(newlen)) } -syscall_copyfile :: #force_inline proc(from: cstring, to: cstring, state: rawptr, flags: u32) -> c.int { +syscall_copyfile :: #force_inline proc "contextless" (from: cstring, to: cstring, state: rawptr, flags: u32) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.copyfile), transmute(uintptr)from, transmute(uintptr)to, uintptr(state), uintptr(flags)) } // think about this? last arg should be more than one -syscall_fcntl :: #force_inline proc(fd: c.int, cmd: c.int, other: rawptr) -> c.int { +syscall_fcntl :: #force_inline proc "contextless" (fd: c.int, cmd: c.int, other: rawptr) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.fsctl), uintptr(fd), uintptr(cmd), uintptr(other)) } -syscall_exit :: #force_inline proc(code: c.int) { +syscall_exit :: #force_inline proc "contextless" (code: c.int) { intrinsics.syscall(unix_offset_syscall(.exit), uintptr(code)) } -syscall_kill :: #force_inline proc(pid: pid_t, sig: c.int) -> c.int { +syscall_kill :: #force_inline proc "contextless" (pid: pid_t, sig: c.int) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.kill), uintptr(pid), uintptr(sig)) } -syscall_dup :: #force_inline proc(fd: c.int) -> c.int { +syscall_dup :: #force_inline proc "contextless" (fd: c.int) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.dup), uintptr(fd)) } -syscall_execve :: #force_inline proc(path: cstring, argv: [^]cstring, env: [^]cstring) -> c.int { +syscall_execve :: #force_inline proc "contextless" (path: cstring, argv: [^]cstring, env: [^]cstring) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.execve), transmute(uintptr)path, transmute(uintptr)argv, transmute(uintptr)env) } -syscall_munmap :: #force_inline proc(addr: rawptr, len: u64) -> c.int { +syscall_munmap :: #force_inline proc "contextless" (addr: rawptr, len: u64) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.mmap), uintptr(addr), uintptr(len)) } -syscall_mmap :: #force_inline proc(addr: ^u8, len: u64, port: c.int, flags: c.int, fd: int, offset: off_t) -> ^u8 { +syscall_mmap :: #force_inline proc "contextless" (addr: ^u8, len: u64, port: c.int, flags: c.int, fd: int, offset: off_t) -> ^u8 { return cast(^u8)intrinsics.syscall(unix_offset_syscall(.mmap), uintptr(addr), uintptr(len), uintptr(port), uintptr(flags), uintptr(fd), uintptr(offset)) } -syscall_flock :: #force_inline proc(fd: c.int, operation: c.int) -> c.int { +syscall_flock :: #force_inline proc "contextless" (fd: c.int, operation: c.int) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.flock), uintptr(fd), uintptr(operation)) } -syscall_utimes :: #force_inline proc(path: cstring, times: ^timeval) -> c.int { +syscall_utimes :: #force_inline proc "contextless" (path: cstring, times: ^timeval) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.utimes), transmute(uintptr)path, uintptr(times)) } -syscall_futimes :: #force_inline proc(fd: c.int, times: ^timeval) -> c.int { +syscall_futimes :: #force_inline proc "contextless" (fd: c.int, times: ^timeval) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.futimes), uintptr(fd), uintptr(times)) } -syscall_adjtime :: #force_inline proc(delta: ^timeval, old_delta: ^timeval) -> c.int { +syscall_adjtime :: #force_inline proc "contextless" (delta: ^timeval, old_delta: ^timeval) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.adjtime), uintptr(delta), uintptr(old_delta)) } -syscall_sysctlbyname :: #force_inline proc(name: cstring, oldp: rawptr, oldlenp: ^i64, newp: rawptr, newlen: i64) -> c.int { +syscall_sysctlbyname :: #force_inline proc "contextless" (name: cstring, oldp: rawptr, oldlenp: ^i64, newp: rawptr, newlen: i64) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.sysctlbyname), transmute(uintptr)name, uintptr(oldp), uintptr(oldlenp), uintptr(newp), uintptr(newlen)) } -syscall_proc_info :: #force_inline proc(num: c.int, pid: u32, flavor: c.int, arg: u64, buffer: rawptr, buffer_size: c.int) -> c.int { +syscall_proc_info :: #force_inline proc "contextless" (num: c.int, pid: u32, flavor: c.int, arg: u64, buffer: rawptr, buffer_size: c.int) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.proc_info), uintptr(num), uintptr(pid), uintptr(flavor), uintptr(arg), uintptr(buffer), uintptr(buffer_size)) } -syscall_openat :: #force_inline proc(fd: int, path: cstring, oflag: u32, mode: u32) -> c.int { +syscall_openat :: #force_inline proc "contextless" (fd: int, path: cstring, oflag: u32, mode: u32) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.openat), uintptr(fd), transmute(uintptr)path, uintptr(oflag), uintptr(mode)) } -syscall_getentropy :: #force_inline proc(buf: [^]u8, buflen: u64) -> c.int { +syscall_getentropy :: #force_inline proc "contextless" (buf: [^]u8, buflen: u64) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.getentropy), uintptr(buf), uintptr(buflen)) } -syscall_pipe :: #force_inline proc(fds: [^]c.int) -> c.int { +syscall_pipe :: #force_inline proc "contextless" (fds: [^]c.int) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.getentropy), uintptr(&fds[0]), uintptr(&fds[1])) } -syscall_chdir :: #force_inline proc(path: cstring) -> c.int { +syscall_chdir :: #force_inline proc "contextless" (path: cstring) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.getentropy), transmute(uintptr)path) } -syscall_fchdir :: #force_inline proc(fd: c.int, path: cstring) -> c.int { +syscall_fchdir :: #force_inline proc "contextless" (fd: c.int, path: cstring) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.getentropy), uintptr(fd), transmute(uintptr)path) } From e559cf32fe1f7151f94d714b04f0f85678ec3351 Mon Sep 17 00:00:00 2001 From: Colin Davidson Date: Sun, 19 Feb 2023 20:39:36 -0800 Subject: [PATCH 05/16] oops, add intrinsics import --- core/time/tsc_windows.odin | 1 + 1 file changed, 1 insertion(+) diff --git a/core/time/tsc_windows.odin b/core/time/tsc_windows.odin index 635aac2c1..6e8ff8d0a 100644 --- a/core/time/tsc_windows.odin +++ b/core/time/tsc_windows.odin @@ -2,6 +2,7 @@ //+build windows package time +import "core:instrinsics" import win32 "core:sys/windows" _get_tsc_frequency :: proc "contextless" () -> u64 { From 9c9300ed58f8f34b0ecd7f5d5cb4d223a0816858 Mon Sep 17 00:00:00 2001 From: Colin Davidson Date: Sun, 19 Feb 2023 20:44:00 -0800 Subject: [PATCH 06/16] derp. raw-syscalls --- core/sys/unix/syscalls_linux.odin | 1 - core/time/tsc_linux.odin | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/core/sys/unix/syscalls_linux.odin b/core/sys/unix/syscalls_linux.odin index ce810e67d..1e89da2d6 100644 --- a/core/sys/unix/syscalls_linux.odin +++ b/core/sys/unix/syscalls_linux.odin @@ -1537,7 +1537,6 @@ MAP_SHARED :: 0x1 MAP_PRIVATE :: 0x2 MAP_SHARED_VALIDATE :: 0x3 MAP_ANONYMOUS :: 0x20 -MAP_FAILED :: -1 // mremap flags MREMAP_MAYMOVE :: 1 diff --git a/core/time/tsc_linux.odin b/core/time/tsc_linux.odin index 91ecb1eae..2c92c905c 100644 --- a/core/time/tsc_linux.odin +++ b/core/time/tsc_linux.odin @@ -25,7 +25,7 @@ _get_tsc_frequency :: proc "contextless" () -> u64 { page_size : uint = 4096 ret := unix.sys_mmap(nil, page_size, unix.PROT_READ, unix.MAP_SHARED, fd, 0) - if ret == unix.MAP_FAILED { + if ret < 0 && > -4096 { frequency = 1 return 0 } From 87d6910bb859ad06e90549df6e407c3bcb04205e Mon Sep 17 00:00:00 2001 From: Colin Davidson Date: Sun, 19 Feb 2023 20:44:49 -0800 Subject: [PATCH 07/16] intrinsics typo --- core/time/tsc_windows.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/time/tsc_windows.odin b/core/time/tsc_windows.odin index 6e8ff8d0a..2a35dd377 100644 --- a/core/time/tsc_windows.odin +++ b/core/time/tsc_windows.odin @@ -2,7 +2,7 @@ //+build windows package time -import "core:instrinsics" +import "core:intrinsics" import win32 "core:sys/windows" _get_tsc_frequency :: proc "contextless" () -> u64 { From d325ee4b916707286b192005aad54fb2cf72a705 Mon Sep 17 00:00:00 2001 From: Colin Davidson Date: Sun, 19 Feb 2023 20:45:56 -0800 Subject: [PATCH 08/16] more typo. yay. --- core/time/tsc_linux.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/time/tsc_linux.odin b/core/time/tsc_linux.odin index 2c92c905c..d4042100c 100644 --- a/core/time/tsc_linux.odin +++ b/core/time/tsc_linux.odin @@ -25,7 +25,7 @@ _get_tsc_frequency :: proc "contextless" () -> u64 { page_size : uint = 4096 ret := unix.sys_mmap(nil, page_size, unix.PROT_READ, unix.MAP_SHARED, fd, 0) - if ret < 0 && > -4096 { + if ret < 0 && ret > -4096 { frequency = 1 return 0 } From 45b742be2324e399947f9c80860d5a77e13fb2b6 Mon Sep 17 00:00:00 2001 From: Colin Davidson Date: Sun, 19 Feb 2023 20:50:30 -0800 Subject: [PATCH 09/16] sort out units to make things happier --- core/time/tsc_windows.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/time/tsc_windows.odin b/core/time/tsc_windows.odin index 2a35dd377..245767b81 100644 --- a/core/time/tsc_windows.odin +++ b/core/time/tsc_windows.odin @@ -24,6 +24,6 @@ _get_tsc_frequency :: proc "contextless" () -> u64 { qpc_frequency: win32.LARGE_INTEGER win32.QueryPerformanceFrequency(&qpc_frequency) - frequency = ((tsc_end - tsc_begin) * qpc_frequency) / (qpc_end - qpc_begin) + frequency = u64((u128(tsc_end - tsc_begin) * u128(qpc_frequency)) / u128(qpc_end - qpc_begin)) return frequency } From f860b090654f78651b293d6c9561d3f4d64b47aa Mon Sep 17 00:00:00 2001 From: Colin Davidson Date: Tue, 21 Feb 2023 05:38:07 -0800 Subject: [PATCH 10/16] use the libc call on darwin so sysctlbyname works --- core/time/perf.odin | 9 ++++----- core/time/tsc_darwin.odin | 20 +++++++++----------- core/time/tsc_linux.odin | 20 ++++++-------------- core/time/tsc_windows.odin | 9 ++------- 4 files changed, 21 insertions(+), 37 deletions(-) diff --git a/core/time/perf.odin b/core/time/perf.odin index d254687fe..43bf2e313 100644 --- a/core/time/perf.odin +++ b/core/time/perf.odin @@ -42,7 +42,7 @@ _tick_duration_end :: proc "contextless" (d: ^Duration, t: Tick) { } when ODIN_ARCH == .amd64 { - _has_invariant_tsc :: proc "contextless" () -> bool { + x86_has_invariant_tsc :: proc "contextless" () -> bool { eax, _, _, _ := intrinsics.x86_cpuid(0x80_000_000, 0) // Is this processor *really* ancient? @@ -53,11 +53,10 @@ when ODIN_ARCH == .amd64 { // 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 + + x86_get_tsc_frequency :: proc "contextless" () -> (u64, bool) { + return _x86_get_tsc_frequency() } } diff --git a/core/time/tsc_darwin.odin b/core/time/tsc_darwin.odin index f2796470e..c82147b1d 100644 --- a/core/time/tsc_darwin.odin +++ b/core/time/tsc_darwin.odin @@ -2,22 +2,20 @@ //+build darwin package time -import "core:sys/darwin" +import "core:c" -_get_tsc_frequency :: proc "contextless" () -> u64 { - @(static) frequency : u64 = 0 - if frequency > 0 { - return frequency - } +foreign import libc "System.framework" +foreign libc { + @(link_name="sysctlbyname") _sysctlbyname :: proc(path: cstring, oldp: rawptr, oldlenp: rawptr, newp: rawptr, newlen: int) -> c.int --- +} +_x86_get_tsc_frequency :: proc "contextless" () -> (u64, bool) { tmp_freq : u64 = 0 tmp_size : i64 = size_of(tmp_freq) - ret := darwin.syscall_sysctlbyname("machdep.tsc.frequency", &tmp_freq, &tmp_size, nil, 0) + ret := _sysctlbyname("machdep.tsc.frequency", &tmp_freq, &tmp_size, nil, 0) if ret < 0 { - frequency = 1 - return 0 + return 0, false } - frequency = tmp_freq - return frequency + return tmp_freq, true } diff --git a/core/time/tsc_linux.odin b/core/time/tsc_linux.odin index d4042100c..c5f2902e9 100644 --- a/core/time/tsc_linux.odin +++ b/core/time/tsc_linux.odin @@ -5,12 +5,7 @@ package time import "core:intrinsics" import "core:sys/unix" -_get_tsc_frequency :: proc "contextless" () -> u64 { - @(static) frequency : u64 = 0 - if frequency > 0 { - return frequency - } - +_get_tsc_frequency :: proc "contextless" () -> (u64, bool) { perf_attr := unix.Perf_Event_Attr{} perf_attr.type = u32(unix.Perf_Type_Id.Hardware) perf_attr.config = u64(unix.Perf_Hardware_Id.Instructions) @@ -18,26 +13,23 @@ _get_tsc_frequency :: proc "contextless" () -> u64 { 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 + return 0, false } 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 < 0 && ret > -4096 { - frequency = 1 - return 0 + return 0, false } 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 + return 0, false } - frequency = u64((u128(1_000_000_000) << u128(event_page.time_shift)) / u128(event_page.time_mult)) - return frequency + frequency := u64((u128(1_000_000_000) << u128(event_page.time_shift)) / u128(event_page.time_mult)) + return frequency, true } diff --git a/core/time/tsc_windows.odin b/core/time/tsc_windows.odin index 245767b81..a1707f982 100644 --- a/core/time/tsc_windows.odin +++ b/core/time/tsc_windows.odin @@ -5,12 +5,7 @@ package time import "core:intrinsics" import win32 "core:sys/windows" -_get_tsc_frequency :: proc "contextless" () -> u64 { - @(static) frequency : u64 = 0 - if frequency > 0 { - return frequency - } - +_get_tsc_frequency :: proc "contextless" () -> (u64, bool) { qpc_begin: win32.LARGE_INTEGER win32.QueryPerformanceCounter(&qpc_begin) tsc_begin := intrinsics.read_cycle_counter() @@ -25,5 +20,5 @@ _get_tsc_frequency :: proc "contextless" () -> u64 { win32.QueryPerformanceFrequency(&qpc_frequency) frequency = u64((u128(tsc_end - tsc_begin) * u128(qpc_frequency)) / u128(qpc_end - qpc_begin)) - return frequency + return frequency, true } From 7322b639918ba3ef34b21bd60f0e27817b36bc4f Mon Sep 17 00:00:00 2001 From: Colin Davidson Date: Tue, 21 Feb 2023 06:22:19 -0800 Subject: [PATCH 11/16] adjust func names --- core/time/tsc_linux.odin | 2 +- core/time/tsc_windows.odin | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/time/tsc_linux.odin b/core/time/tsc_linux.odin index c5f2902e9..4e0209a38 100644 --- a/core/time/tsc_linux.odin +++ b/core/time/tsc_linux.odin @@ -5,7 +5,7 @@ package time import "core:intrinsics" import "core:sys/unix" -_get_tsc_frequency :: proc "contextless" () -> (u64, bool) { +_x86_get_tsc_frequency :: proc "contextless" () -> (u64, bool) { perf_attr := unix.Perf_Event_Attr{} perf_attr.type = u32(unix.Perf_Type_Id.Hardware) perf_attr.config = u64(unix.Perf_Hardware_Id.Instructions) diff --git a/core/time/tsc_windows.odin b/core/time/tsc_windows.odin index a1707f982..2eecf0cd6 100644 --- a/core/time/tsc_windows.odin +++ b/core/time/tsc_windows.odin @@ -5,7 +5,7 @@ package time import "core:intrinsics" import win32 "core:sys/windows" -_get_tsc_frequency :: proc "contextless" () -> (u64, bool) { +_x86_get_tsc_frequency :: proc "contextless" () -> (u64, bool) { qpc_begin: win32.LARGE_INTEGER win32.QueryPerformanceCounter(&qpc_begin) tsc_begin := intrinsics.read_cycle_counter() From 1fc3a25f4727d86bbe1e6adbe47dc18f70b32ff7 Mon Sep 17 00:00:00 2001 From: Colin Davidson Date: Tue, 21 Feb 2023 06:28:55 -0800 Subject: [PATCH 12/16] block all x86 tsc functions in when block --- core/time/tsc_darwin.odin | 18 ++++++++------ core/time/tsc_linux.odin | 50 ++++++++++++++++++++------------------ core/time/tsc_windows.odin | 26 +++++++++++--------- 3 files changed, 50 insertions(+), 44 deletions(-) diff --git a/core/time/tsc_darwin.odin b/core/time/tsc_darwin.odin index c82147b1d..6aaac350e 100644 --- a/core/time/tsc_darwin.odin +++ b/core/time/tsc_darwin.odin @@ -9,13 +9,15 @@ foreign libc { @(link_name="sysctlbyname") _sysctlbyname :: proc(path: cstring, oldp: rawptr, oldlenp: rawptr, newp: rawptr, newlen: int) -> c.int --- } -_x86_get_tsc_frequency :: proc "contextless" () -> (u64, bool) { - tmp_freq : u64 = 0 - tmp_size : i64 = size_of(tmp_freq) - ret := _sysctlbyname("machdep.tsc.frequency", &tmp_freq, &tmp_size, nil, 0) - if ret < 0 { - return 0, false - } +when ODIN_ARCH == .amd64 { + _x86_get_tsc_frequency :: proc "contextless" () -> (u64, bool) { + tmp_freq : u64 = 0 + tmp_size : i64 = size_of(tmp_freq) + ret := _sysctlbyname("machdep.tsc.frequency", &tmp_freq, &tmp_size, nil, 0) + if ret < 0 { + return 0, false + } - return tmp_freq, true + return tmp_freq, true + } } diff --git a/core/time/tsc_linux.odin b/core/time/tsc_linux.odin index 4e0209a38..e355bc5b5 100644 --- a/core/time/tsc_linux.odin +++ b/core/time/tsc_linux.odin @@ -5,31 +5,33 @@ package time import "core:intrinsics" import "core:sys/unix" -_x86_get_tsc_frequency :: proc "contextless" () -> (u64, bool) { - 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 { - return 0, false - } - defer unix.sys_close(fd) +when ODIN_ARCH == .amd64 { + _x86_get_tsc_frequency :: proc "contextless" () -> (u64, bool) { + 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 { + return 0, false + } + 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 < 0 && ret > -4096 { - return 0, false - } - addr := rawptr(uintptr(ret)) - defer unix.sys_munmap(addr, page_size) + page_size : uint = 4096 + ret := unix.sys_mmap(nil, page_size, unix.PROT_READ, unix.MAP_SHARED, fd, 0) + if ret < 0 && ret > -4096 { + return 0, false + } + 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 { - return 0, false - } + event_page := (^unix.Perf_Event_mmap_Page)(addr) + if .User_Time not_in event_page.cap.flags { + return 0, false + } - frequency := u64((u128(1_000_000_000) << u128(event_page.time_shift)) / u128(event_page.time_mult)) - return frequency, true + frequency := u64((u128(1_000_000_000) << u128(event_page.time_shift)) / u128(event_page.time_mult)) + return frequency, true + } } diff --git a/core/time/tsc_windows.odin b/core/time/tsc_windows.odin index 2eecf0cd6..761a3b1cd 100644 --- a/core/time/tsc_windows.odin +++ b/core/time/tsc_windows.odin @@ -5,20 +5,22 @@ package time import "core:intrinsics" import win32 "core:sys/windows" -_x86_get_tsc_frequency :: proc "contextless" () -> (u64, bool) { - qpc_begin: win32.LARGE_INTEGER - win32.QueryPerformanceCounter(&qpc_begin) - tsc_begin := intrinsics.read_cycle_counter() +when ODIN_ARCH == .amd64 { + _x86_get_tsc_frequency :: proc "contextless" () -> (u64, bool) { + qpc_begin: win32.LARGE_INTEGER + win32.QueryPerformanceCounter(&qpc_begin) + tsc_begin := intrinsics.read_cycle_counter() - win32.Sleep(2) + win32.Sleep(2) - qpc_end: win32.LARGE_INTEGER - win32.QueryPerformanceCounter(&qpc_end) - tsc_end := intrinsics.read_cycle_counter() + qpc_end: win32.LARGE_INTEGER + win32.QueryPerformanceCounter(&qpc_end) + tsc_end := intrinsics.read_cycle_counter() - qpc_frequency: win32.LARGE_INTEGER - win32.QueryPerformanceFrequency(&qpc_frequency) + qpc_frequency: win32.LARGE_INTEGER + win32.QueryPerformanceFrequency(&qpc_frequency) - frequency = u64((u128(tsc_end - tsc_begin) * u128(qpc_frequency)) / u128(qpc_end - qpc_begin)) - return frequency, true + frequency = u64((u128(tsc_end - tsc_begin) * u128(qpc_frequency)) / u128(qpc_end - qpc_begin)) + return frequency, true + } } From 91dccf8d6240e140f96b3ea29bd9b3fc1e69734c Mon Sep 17 00:00:00 2001 From: Colin Davidson Date: Tue, 21 Feb 2023 06:46:36 -0800 Subject: [PATCH 13/16] more function name changes --- core/time/perf.odin | 6 ++--- core/time/tsc_darwin.odin | 18 ++++++------- core/time/tsc_linux.odin | 54 ++++++++++++++++++-------------------- core/time/tsc_windows.odin | 26 +++++++++--------- 4 files changed, 49 insertions(+), 55 deletions(-) diff --git a/core/time/perf.odin b/core/time/perf.odin index 43bf2e313..6a9933336 100644 --- a/core/time/perf.odin +++ b/core/time/perf.odin @@ -54,10 +54,10 @@ when ODIN_ARCH == .amd64 { _, _, _, edx := intrinsics.x86_cpuid(0x80_000_007, 0) return (edx & (1 << 8)) != 0 } +} - x86_get_tsc_frequency :: proc "contextless" () -> (u64, bool) { - return _x86_get_tsc_frequency() - } +get_tsc_frequency :: proc "contextless" () -> (u64, bool) { + return _get_tsc_frequency() } /* diff --git a/core/time/tsc_darwin.odin b/core/time/tsc_darwin.odin index 6aaac350e..9e54ee8f7 100644 --- a/core/time/tsc_darwin.odin +++ b/core/time/tsc_darwin.odin @@ -9,15 +9,13 @@ foreign libc { @(link_name="sysctlbyname") _sysctlbyname :: proc(path: cstring, oldp: rawptr, oldlenp: rawptr, newp: rawptr, newlen: int) -> c.int --- } -when ODIN_ARCH == .amd64 { - _x86_get_tsc_frequency :: proc "contextless" () -> (u64, bool) { - tmp_freq : u64 = 0 - tmp_size : i64 = size_of(tmp_freq) - ret := _sysctlbyname("machdep.tsc.frequency", &tmp_freq, &tmp_size, nil, 0) - if ret < 0 { - return 0, false - } - - return tmp_freq, true +_get_tsc_frequency :: proc "contextless" () -> (u64, bool) { + tmp_freq : u64 = 0 + tmp_size : i64 = size_of(tmp_freq) + ret := _sysctlbyname("machdep.tsc.frequency", &tmp_freq, &tmp_size, nil, 0) + if ret < 0 { + return 0, false } + + return tmp_freq, true } diff --git a/core/time/tsc_linux.odin b/core/time/tsc_linux.odin index e355bc5b5..c5f2902e9 100644 --- a/core/time/tsc_linux.odin +++ b/core/time/tsc_linux.odin @@ -5,33 +5,31 @@ package time import "core:intrinsics" import "core:sys/unix" -when ODIN_ARCH == .amd64 { - _x86_get_tsc_frequency :: proc "contextless" () -> (u64, bool) { - 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 { - return 0, false - } - 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 < 0 && ret > -4096 { - return 0, false - } - 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 { - return 0, false - } - - frequency := u64((u128(1_000_000_000) << u128(event_page.time_shift)) / u128(event_page.time_mult)) - return frequency, true +_get_tsc_frequency :: proc "contextless" () -> (u64, bool) { + 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 { + return 0, false } + 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 < 0 && ret > -4096 { + return 0, false + } + 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 { + return 0, false + } + + frequency := u64((u128(1_000_000_000) << u128(event_page.time_shift)) / u128(event_page.time_mult)) + return frequency, true } diff --git a/core/time/tsc_windows.odin b/core/time/tsc_windows.odin index 761a3b1cd..a1707f982 100644 --- a/core/time/tsc_windows.odin +++ b/core/time/tsc_windows.odin @@ -5,22 +5,20 @@ package time import "core:intrinsics" import win32 "core:sys/windows" -when ODIN_ARCH == .amd64 { - _x86_get_tsc_frequency :: proc "contextless" () -> (u64, bool) { - qpc_begin: win32.LARGE_INTEGER - win32.QueryPerformanceCounter(&qpc_begin) - tsc_begin := intrinsics.read_cycle_counter() +_get_tsc_frequency :: proc "contextless" () -> (u64, bool) { + qpc_begin: win32.LARGE_INTEGER + win32.QueryPerformanceCounter(&qpc_begin) + tsc_begin := intrinsics.read_cycle_counter() - win32.Sleep(2) + win32.Sleep(2) - qpc_end: win32.LARGE_INTEGER - win32.QueryPerformanceCounter(&qpc_end) - tsc_end := intrinsics.read_cycle_counter() + qpc_end: win32.LARGE_INTEGER + win32.QueryPerformanceCounter(&qpc_end) + tsc_end := intrinsics.read_cycle_counter() - qpc_frequency: win32.LARGE_INTEGER - win32.QueryPerformanceFrequency(&qpc_frequency) + qpc_frequency: win32.LARGE_INTEGER + win32.QueryPerformanceFrequency(&qpc_frequency) - frequency = u64((u128(tsc_end - tsc_begin) * u128(qpc_frequency)) / u128(qpc_end - qpc_begin)) - return frequency, true - } + frequency = u64((u128(tsc_end - tsc_begin) * u128(qpc_frequency)) / u128(qpc_end - qpc_begin)) + return frequency, true } From 8e5e43f335e0a522c97a67de57bd909a669edca0 Mon Sep 17 00:00:00 2001 From: Colin Davidson Date: Tue, 21 Feb 2023 17:48:49 -0800 Subject: [PATCH 14/16] add sleep-fallback and invariant check --- core/time/perf.odin | 33 +++++++++++++++++++++++++++++++-- core/time/tsc_freebsd.odin | 21 +++++++++++++++++++++ core/time/tsc_openbsd.odin | 7 +++++++ core/time/tsc_windows.odin | 19 +------------------ 4 files changed, 60 insertions(+), 20 deletions(-) create mode 100644 core/time/tsc_freebsd.odin create mode 100644 core/time/tsc_openbsd.odin diff --git a/core/time/perf.odin b/core/time/perf.odin index 6a9933336..9db667b72 100644 --- a/core/time/perf.odin +++ b/core/time/perf.odin @@ -6,7 +6,6 @@ import "core:intrinsics" Tick :: struct { _nsec: i64, // relative amount } - tick_now :: proc "contextless" () -> Tick { return _tick_now() } @@ -56,8 +55,38 @@ when ODIN_ARCH == .amd64 { } } +has_invariant_tsc :: proc "contextless" () -> bool { + when ODIN_ARCH == .amd64 { + return x86_has_invariant_tsc() + } + + return false +} + +_get_tsc_frequency_fallback :: proc "contextless" () -> u64 { + tsc_begin := intrinsics.read_cycle_counter() + tick_begin := tick_now() + + sleep(2 * Second) + + tsc_end := intrinsics.read_cycle_counter() + tick_end := tick_now() + + time_diff := u128(duration_nanoseconds(tick_diff(tick_begin, tick_end))) + return u64((u128(tsc_end - tsc_begin) * 1_000_000_000) / time_diff) +} + get_tsc_frequency :: proc "contextless" () -> (u64, bool) { - return _get_tsc_frequency() + if !has_invariant_tsc() { + return 0, false + } + + hz, ok := _get_tsc_frequency() + if !ok { + hz = _get_tsc_frequency_fallback() + } + + return hz, true } /* diff --git a/core/time/tsc_freebsd.odin b/core/time/tsc_freebsd.odin new file mode 100644 index 000000000..f4d6ccc3a --- /dev/null +++ b/core/time/tsc_freebsd.odin @@ -0,0 +1,21 @@ +//+private +//+build freebsd +package time + +import "core:c" + +foreign import libc "system:c" +foreign libc { + @(link_name="sysctlbyname") _sysctlbyname :: proc(path: cstring, oldp: rawptr, oldlenp: rawptr, newp: rawptr, newlen: int) -> c.int --- +} + +_get_tsc_frequency :: proc "contextless" () -> (u64, bool) { + tmp_freq : u64 = 0 + tmp_size : i64 = size_of(tmp_freq) + ret := _sysctlbyname("machdep.tsc_freq", &tmp_freq, &tmp_size, nil, 0) + if ret < 0 { + return 0, false + } + + return tmp_freq, true +} diff --git a/core/time/tsc_openbsd.odin b/core/time/tsc_openbsd.odin new file mode 100644 index 000000000..ab126d5c1 --- /dev/null +++ b/core/time/tsc_openbsd.odin @@ -0,0 +1,7 @@ +//+private +//+build openbsd +package time + +_get_tsc_frequency :: proc "contextless" () -> (u64, bool) { + return 0, false +} diff --git a/core/time/tsc_windows.odin b/core/time/tsc_windows.odin index a1707f982..7f7be6393 100644 --- a/core/time/tsc_windows.odin +++ b/core/time/tsc_windows.odin @@ -2,23 +2,6 @@ //+build windows package time -import "core:intrinsics" -import win32 "core:sys/windows" - _get_tsc_frequency :: proc "contextless" () -> (u64, bool) { - qpc_begin: win32.LARGE_INTEGER - win32.QueryPerformanceCounter(&qpc_begin) - tsc_begin := intrinsics.read_cycle_counter() - - win32.Sleep(2) - - qpc_end: win32.LARGE_INTEGER - win32.QueryPerformanceCounter(&qpc_end) - tsc_end := intrinsics.read_cycle_counter() - - qpc_frequency: win32.LARGE_INTEGER - win32.QueryPerformanceFrequency(&qpc_frequency) - - frequency = u64((u128(tsc_end - tsc_begin) * u128(qpc_frequency)) / u128(qpc_end - qpc_begin)) - return frequency, true + return 0, false } From c6f463b8c900085342abd812dafe24ef4281dc53 Mon Sep 17 00:00:00 2001 From: Colin Davidson Date: Wed, 22 Feb 2023 12:28:24 -0800 Subject: [PATCH 15/16] shuffle tsc around a little --- core/time/perf.odin | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/core/time/perf.odin b/core/time/perf.odin index 9db667b72..e51b17441 100644 --- a/core/time/perf.odin +++ b/core/time/perf.odin @@ -41,6 +41,7 @@ _tick_duration_end :: proc "contextless" (d: ^Duration, t: Tick) { } when ODIN_ARCH == .amd64 { + @(private) x86_has_invariant_tsc :: proc "contextless" () -> bool { eax, _, _, _ := intrinsics.x86_cpuid(0x80_000_000, 0) @@ -63,27 +64,24 @@ has_invariant_tsc :: proc "contextless" () -> bool { return false } -_get_tsc_frequency_fallback :: proc "contextless" () -> u64 { - tsc_begin := intrinsics.read_cycle_counter() - tick_begin := tick_now() - - sleep(2 * Second) - - tsc_end := intrinsics.read_cycle_counter() - tick_end := tick_now() - - time_diff := u128(duration_nanoseconds(tick_diff(tick_begin, tick_end))) - return u64((u128(tsc_end - tsc_begin) * 1_000_000_000) / time_diff) -} - -get_tsc_frequency :: proc "contextless" () -> (u64, bool) { +tsc_frequency :: proc "contextless" () -> (u64, bool) { if !has_invariant_tsc() { return 0, false } hz, ok := _get_tsc_frequency() if !ok { - hz = _get_tsc_frequency_fallback() + // fallback to approximate TSC + tsc_begin := intrinsics.read_cycle_counter() + tick_begin := tick_now() + + sleep(2 * Second) + + tsc_end := intrinsics.read_cycle_counter() + tick_end := tick_now() + + time_diff := u128(duration_nanoseconds(tick_diff(tick_begin, tick_end))) + hz = u64((u128(tsc_end - tsc_begin) * 1_000_000_000) / time_diff) } return hz, true From ef99d03f211c5b471a25d0bcc6ac21b491369086 Mon Sep 17 00:00:00 2001 From: Tetralux Date: Wed, 22 Feb 2023 21:43:42 +0000 Subject: [PATCH 16/16] Remove debug print --- src/check_stmt.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index f300f45c7..44d7cf59d 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -1293,7 +1293,6 @@ gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_ for (Type *t : variants) { if (!type_ptr_set_exists(&seen, t)) { array_add(&unhandled, t); - gb_printf_err("HERE: %p %s\n", t, type_to_string(t)); } }