diff --git a/core/sys/darwin/xnu_system_call_wrappers.odin b/core/sys/darwin/xnu_system_call_wrappers.odin index b69877cc9..7100da4f1 100644 --- a/core/sys/darwin/xnu_system_call_wrappers.odin +++ b/core/sys/darwin/xnu_system_call_wrappers.odin @@ -337,7 +337,7 @@ syscall_ftruncate :: #force_inline proc "contextless" (fd: c.int, length: off_t) return cast(c.int)intrinsics.syscall(unix_offset_syscall(.ftruncate), uintptr(fd), uintptr(length)) } -syscall_sysctl :: #force_inline proc "contextless" (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.size_t, oldp: rawptr, oldlenp: ^c.size_t, newp: rawptr, newlen: c.size_t) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.sysctl), uintptr(name), uintptr(namelen), uintptr(oldp), uintptr(oldlenp), uintptr(newp), uintptr(newlen)) } @@ -390,8 +390,8 @@ syscall_adjtime :: #force_inline proc "contextless" (delta: ^timeval, old_delta: return cast(c.int)intrinsics.syscall(unix_offset_syscall(.adjtime), uintptr(delta), uintptr(old_delta)) } -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_sysctlbyname :: #force_inline proc "contextless" (name: string, oldp: rawptr, oldlenp: ^c.size_t, newp: rawptr, newlen: c.size_t) -> c.int { + return cast(c.int)intrinsics.syscall(unix_offset_syscall(.sysctlbyname), uintptr(raw_data(name)), uintptr(len(name)), uintptr(oldp), uintptr(oldlenp), uintptr(newp), uintptr(newlen)) } 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 { diff --git a/core/sys/info/cpu_arm.odin b/core/sys/info/cpu_arm.odin index f66f0e780..aa4bb368a 100644 --- a/core/sys/info/cpu_arm.odin +++ b/core/sys/info/cpu_arm.odin @@ -1,26 +1,70 @@ //+build arm32, arm64 package sysinfo -// TODO: Set up an enum with the ARM equivalent of the above. -CPU_Feature :: enum u64 {} +import "core:sys/unix" -cpu_features: Maybe(CPU_Feature) -cpu_name: Maybe(string) +_ :: unix -@(init, private) -init_cpu_features :: proc "c" () { +CPU_Feature :: enum u64 { + // Advanced SIMD & floating-point capabilities: + asimd, // General support for Advanced SIMD instructions/neon. + floatingpoint, // General support for floating-point instructions. + asimdhp, // Advanced SIMD half-precision conversion instructions. + bf16, // Storage and arithmetic instructions of the Brain Floating Point (BFloat16) data type. + fcma, // Floating-point complex number instructions. + fhm, // Floating-point half-precision multiplication instructions. + fp16, // General half-precision floating-point data processing instructions. + frint, // Floating-point to integral valued floating-point number rounding instructions. + i8mm, // Advanced SIMD int8 matrix multiplication instructions. + jscvt, // JavaScript conversion instruction. + rdm, // Advanced SIMD rounding double multiply accumulate instructions. + + flagm, // Condition flag manipulation instructions. + flagm2, // Enhancements to condition flag manipulation instructions. + crc32, // CRC32 instructions. + + lse, // Atomic instructions to support large systems. + lse2, // Changes to single-copy atomicity and alignment requirements for loads and stores for large systems. + lrcpc, // Load-acquire Release Consistency processor consistent (RCpc) instructions. + lrcpc2, // Load-acquire Release Consistency processor consistent (RCpc) instructions version 2. + + aes, + pmull, + sha1, + sha256, + sha512, + sha3, + + sb, // Barrier instruction to control speculation. + ssbs, // Instructions to control speculation of loads and stores. } +CPU_Features :: distinct bit_set[CPU_Feature; u64] + +cpu_features: Maybe(CPU_Features) +cpu_name: Maybe(string) + @(private) -_cpu_name_buf: [72]u8 +cpu_name_buf: [128]byte @(init, private) -init_cpu_name :: proc "c" () { - when ODIN_ARCH == .arm32 { - copy(_cpu_name_buf[:], "ARM") - cpu_name = string(_cpu_name_buf[:3]) - } else { - copy(_cpu_name_buf[:], "ARM64") - cpu_name = string(_cpu_name_buf[:5]) +init_cpu_name :: proc "contextless" () { + generic := true + + when ODIN_OS == .Darwin { + if unix.sysctlbyname("machdep.cpu.brand_string", &cpu_name_buf) { + cpu_name = string(cstring(rawptr(&cpu_name_buf))) + generic = false + } } -} \ No newline at end of file + + if generic { + when ODIN_ARCH == .arm64 { + copy(cpu_name_buf[:], "ARM64") + cpu_name = string(cpu_name_buf[:len("ARM64")]) + } else { + copy(cpu_name_buf[:], "ARM") + cpu_name = string(cpu_name_buf[:len("ARM")]) + } + } +} diff --git a/core/sys/info/cpu_darwin_arm64.odin b/core/sys/info/cpu_darwin_arm64.odin new file mode 100644 index 000000000..336334bc0 --- /dev/null +++ b/core/sys/info/cpu_darwin_arm64.odin @@ -0,0 +1,98 @@ +package sysinfo + +import "core:sys/unix" + +@(init, private) +init_cpu_features :: proc "contextless" () { + @(static) features: CPU_Features + defer cpu_features = features + + try_set :: proc "contextless" (name: string, feature: CPU_Feature) -> (ok: bool) { + support: b32 + if ok = unix.sysctlbyname(name, &support); ok && support { + features += { feature } + } + return + } + + // Docs from Apple: https://developer.apple.com/documentation/kernel/1387446-sysctlbyname/determining_instruction_set_characteristics + // Features from there that do not have (or I didn't find) an equivalent on Linux are commented out below. + + // Advanced SIMD & floating-point capabilities: + { + if !try_set("hw.optional.AdvSIMD", .asimd) { + try_set("hw.optional.neon", .asimd) + } + + try_set("hw.optional.floatingpoint", .floatingpoint) + + if !try_set("hw.optional.AdvSIMD_HPFPCvt", .asimdhp) { + try_set("hw.optional.neon_hpfp", .asimdhp) + } + + try_set("hw.optional.arm.FEAT_BF16", .bf16) + // try_set("hw.optional.arm.FEAT_DotProd", .dotprod) + + if !try_set("hw.optional.arm.FEAT_FCMA", .fcma) { + try_set("hw.optional.armv8_3_compnum", .fcma) + } + + if !try_set("hw.optional.arm.FEAT_FHM", .fhm) { + try_set("hw.optional.armv8_2_fhm", .fhm) + } + + if !try_set("hw.optional.arm.FEAT_FP16", .fp16) { + try_set("hw.optional.neon_fp16", .fp16) + } + + try_set("hw.optional.arm.FEAT_FRINTTS", .frint) + try_set("hw.optional.arm.FEAT_I8MM", .i8mm) + try_set("hw.optional.arm.FEAT_JSCVT", .jscvt) + try_set("hw.optional.arm.FEAT_RDM", .rdm) + } + + // Integer capabilities: + { + try_set("hw.optional.arm.FEAT_FlagM", .flagm) + try_set("hw.optional.arm.FEAT_FlagM2", .flagm2) + try_set("hw.optional.armv8_crc32", .crc32) + } + + // Atomic and memory ordering instruction capabilities: + { + try_set("hw.optional.arm.FEAT_LRCPC", .lrcpc) + try_set("hw.optional.arm.FEAT_LRCPC2", .lrcpc2) + + if !try_set("hw.optional.arm.FEAT_LSE", .lse) { + try_set("hw.optional.armv8_1_atomics", .lse) + } + + // try_set("hw.optional.arm.FEAT_LSE2", .lse2) + } + + // Encryption capabilities: + { + try_set("hw.optional.arm.FEAT_AES", .aes) + try_set("hw.optional.arm.FEAT_PMULL", .pmull) + try_set("hw.optional.arm.FEAT_SHA1", .sha1) + try_set("hw.optional.arm.FEAT_SHA256", .sha256) + + if !try_set("hw.optional.arm.FEAT_SHA512", .sha512) { + try_set("hw.optional.armv8_2_sha512", .sha512) + } + + if !try_set("hw.optional.arm.FEAT_SHA3", .sha3) { + try_set("hw.optional.armv8_2_sha3", .sha3) + } + } + + // General capabilities: + { + // try_set("hw.optional.arm.FEAT_BTI", .bti) + // try_set("hw.optional.arm.FEAT_DPB", .dpb) + // try_set("hw.optional.arm.FEAT_DPB2", .dpb2) + // try_set("hw.optional.arm.FEAT_ECV", .ecv) + try_set("hw.optional.arm.FEAT_SB", .sb) + try_set("hw.optional.arm.FEAT_SSBS", .ssbs) + } +} diff --git a/core/sys/info/cpu_linux_arm.odin b/core/sys/info/cpu_linux_arm.odin new file mode 100644 index 000000000..dcc252971 --- /dev/null +++ b/core/sys/info/cpu_linux_arm.odin @@ -0,0 +1,65 @@ +//+build arm32, arm64 +//+build linux +package sysinfo + +import "core:sys/linux" +import "core:strings" + +@(init, private) +init_cpu_features :: proc() { + fd, err := linux.open("/proc/cpuinfo", {}) + if err != .NONE { return } + defer linux.close(fd) + + // This is probably enough right? + buf: [4096]byte + n, rerr := linux.read(fd, buf[:]) + if rerr != .NONE || n == 0 { return } + + features: CPU_Features + defer cpu_features = features + + str := string(buf[:n]) + for line in strings.split_lines_iterator(&str) { + key, _, value := strings.partition(line, ":") + key = strings.trim_space(key) + value = strings.trim_space(value) + + if key != "Features" { continue } + + for feature in strings.split_by_byte_iterator(&value, ' ') { + switch feature { + case "asimd", "neon": features += { .asimd } + case "fp": features += { .floatingpoint } + case "asimdhp": features += { .asimdhp } + case "asimdbf16": features += { .bf16 } + case "fcma": features += { .fcma } + case "asimdfhm": features += { .fhm } + case "fphp", "half": features += { .fp16 } + case "frint": features += { .frint } + case "i8mm": features += { .i8mm } + case "jscvt": features += { .jscvt } + case "asimdrdm": features += { .rdm } + + case "flagm": features += { .flagm } + case "flagm2": features += { .flagm2 } + case "crc32": features += { .crc32 } + + case "atomics": features += { .lse } + case "lrcpc": features += { .lrcpc } + case "ilrcpc": features += { .lrcpc2 } + + case "aes": features += { .aes } + case "pmull": features += { .pmull } + case "sha1": features += { .sha1 } + case "sha2": features += { .sha256 } + case "sha3": features += { .sha3 } + case "sha512": features += { .sha512 } + + case "sb": features += { .sb } + case "ssbs": features += { .ssbs } + } + } + break + } +} diff --git a/core/sys/info/doc.odin b/core/sys/info/doc.odin index 15af0d4b3..802cd9c60 100644 --- a/core/sys/info/doc.odin +++ b/core/sys/info/doc.odin @@ -19,18 +19,21 @@ Example: import si "core:sys/info" main :: proc() { - fmt.printf("Odin: %v\n", ODIN_VERSION) - fmt.printf("OS: %v\n", si.os_version.as_string) - fmt.printf("OS: %#v\n", si.os_version) - fmt.printf("CPU: %v\n", si.cpu_name) - fmt.printf("RAM: %v MiB\n", si.ram.total_ram / 1024 / 1024) + fmt.printfln("Odin: %v", ODIN_VERSION) + fmt.printfln("OS: %v", si.os_version.as_string) + fmt.printfln("OS: %#v", si.os_version) + fmt.printfln("CPU: %v", si.cpu_name) + fmt.printfln("RAM: %#.1M", si.ram.total_ram) + + // fmt.printfln("Features: %v", si.cpu_features) + // fmt.printfln("MacOS version: %v", si.macos_version) fmt.println() for gpu, i in si.gpus { - fmt.printf("GPU #%v:\n", i) - fmt.printf("\tVendor: %v\n", gpu.vendor_name) - fmt.printf("\tModel: %v\n", gpu.model_name) - fmt.printf("\tVRAM: %v MiB\n", gpu.total_ram / 1024 / 1024) + fmt.printfln("GPU #%v:", i) + fmt.printfln("\tVendor: %v", gpu.vendor_name) + fmt.printfln("\tModel: %v", gpu.model_name) + fmt.printfln("\tVRAM: %#.1M", gpu.total_ram) } } @@ -51,11 +54,11 @@ Example: as_string = "Windows 10 Professional (version: 20H2), build: 19042.1466", } CPU: AMD Ryzen 7 1800X Eight-Core Processor - RAM: 65469 MiB + RAM: 64.0 GiB GPU #0: Vendor: Advanced Micro Devices, Inc. Model: Radeon RX Vega - VRAM: 8176 MiB + VRAM: 8.0 GiB - Example macOS output: @@ -73,6 +76,6 @@ Example: as_string = "macOS Monterey 12.4 (build 21F79, kernel 21.5.0)", } CPU: Intel(R) Core(TM) i5-7360U CPU @ 2.30GHz - RAM: 8192 MiB + RAM: 8.0 GiB */ package sysinfo diff --git a/core/sys/info/platform_darwin.odin b/core/sys/info/platform_darwin.odin index b95a48bd0..122dd42ee 100644 --- a/core/sys/info/platform_darwin.odin +++ b/core/sys/info/platform_darwin.odin @@ -1,4 +1,3 @@ -// +build darwin package sysinfo import sys "core:sys/unix" @@ -76,6 +75,8 @@ init_os_version :: proc () { os_version.minor = rel.darwin.y os_version.patch = rel.darwin.z + macos_version = transmute(Version)rel.release.version + strings.write_string(&b, rel.os_name) if match == .Exact || match == .Nearest { strings.write_rune(&b, ' ') @@ -113,7 +114,7 @@ init_os_version :: proc () { os_version.as_string = strings.to_string(b) } -@(init) +@(init, private) init_ram :: proc() { // Retrieve RAM info using `sysctl` diff --git a/core/sys/info/platform_freebsd.odin b/core/sys/info/platform_freebsd.odin index 26b4be7e9..c1429c4b2 100644 --- a/core/sys/info/platform_freebsd.odin +++ b/core/sys/info/platform_freebsd.odin @@ -1,4 +1,3 @@ -// +build freebsd package sysinfo import sys "core:sys/unix" @@ -68,7 +67,7 @@ init_os_version :: proc () { } } -@(init) +@(init, private) init_ram :: proc() { // Retrieve RAM info using `sysctl` mib := []i32{sys.CTL_HW, sys.HW_PHYSMEM} diff --git a/core/sys/info/platform_linux.odin b/core/sys/info/platform_linux.odin index 89b1204a7..45efc3329 100644 --- a/core/sys/info/platform_linux.odin +++ b/core/sys/info/platform_linux.odin @@ -1,11 +1,9 @@ -// +build linux package sysinfo import "base:intrinsics" -import "base:runtime" -import "core:strings" -import "core:strconv" +import "core:strconv" +import "core:strings" import "core:sys/linux" @(private) @@ -14,32 +12,37 @@ version_string_buf: [1024]u8 @(init, private) init_os_version :: proc () { os_version.platform = .Linux - // Try to parse `/etc/os-release` for `PRETTY_NAME="Ubuntu 20.04.3 LTS` - fd, errno := linux.open("/etc/os-release", {.RDONLY}, {}) - assert(errno == .NONE, "Failed to read /etc/os-release") - defer { - cerrno := linux.close(fd) - assert(cerrno == .NONE, "Failed to close the file descriptor") - } - os_release_buf: [2048]u8 - n, read_errno := linux.read(fd, os_release_buf[:]) - assert(read_errno == .NONE, "Failed to read data from /etc/os-release") - release := string(os_release_buf[:n]) - // Search the line in the file until we find "PRETTY_NAME=" - NEEDLE :: "PRETTY_NAME=\"" - pretty_start := strings.index(release, NEEDLE) + b := strings.builder_from_bytes(version_string_buf[:]) - if pretty_start > 0 { - for r, i in release[pretty_start + len(NEEDLE):] { - if r == '"' { - strings.write_string(&b, release[pretty_start + len(NEEDLE):][:i]) - break - } else if r == '\r' || r == '\n' { - strings.write_string(&b, "Unknown Linux Distro") - break + + // Try to parse `/etc/os-release` for `PRETTY_NAME="Ubuntu 20.04.3 LTS` + { + fd, errno := linux.open("/etc/os-release", {}) + assert(errno == .NONE, "Failed to read /etc/os-release") + defer { + cerrno := linux.close(fd) + assert(cerrno == .NONE, "Failed to close the file descriptor") + } + + os_release_buf: [2048]u8 + n, read_errno := linux.read(fd, os_release_buf[:]) + assert(read_errno == .NONE, "Failed to read data from /etc/os-release") + release := string(os_release_buf[:n]) + + // Search the line in the file until we find "PRETTY_NAME=" + NEEDLE :: "PRETTY_NAME=\"" + _, _, post := strings.partition(release, NEEDLE) + if len(post) > 0 { + end := strings.index_any(post, "\"\n") + if end > -1 && post[end] == '"' { + strings.write_string(&b, post[:end]) } } + if strings.builder_len(b) == 0 { + strings.write_string(&b, "Unknown Linux Distro") + } } + // Grab kernel info using `uname()` syscall, https://linux.die.net/man/2/uname uts: linux.UTS_Name uname_errno := linux.uname(&uts) @@ -48,31 +51,39 @@ init_os_version :: proc () { strings.write_string(&b, ", ") strings.write_string(&b, string(cstring(&uts.sysname[0]))) strings.write_rune(&b, ' ') - l := strings.builder_len(b) + + release_i := strings.builder_len(b) strings.write_string(&b, string(cstring(&uts.release[0]))) - // Parse kernel version, as substrings of the version info in `version_string_buf` - runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() - version_bits := strings.split_n(strings.to_string(b)[l:], "-", 2, context.temp_allocator) - if len(version_bits) > 1 { - os_version.version = version_bits[1] - } - // Parse major, minor, patch from release info - triplet := strings.split(version_bits[0], ".", context.temp_allocator) - if len(triplet) == 3 { - major, major_ok := strconv.parse_int(triplet[0]) - minor, minor_ok := strconv.parse_int(triplet[1]) - patch, patch_ok := strconv.parse_int(triplet[2]) - if major_ok && minor_ok && patch_ok { - os_version.major = major - os_version.minor = minor - os_version.patch = patch + release_str := string(b.buf[release_i:]) + + os_version.as_string = strings.to_string(b) + + // Parse the Linux version out of the release string + { + version_num, _, version_suffix := strings.partition(release_str, "-") + os_version.version = version_suffix + + i: int + for part in strings.split_iterator(&version_num, ".") { + defer i += 1 + + dst: ^int + switch i { + case 0: dst = &os_version.major + case 1: dst = &os_version.minor + case 2: dst = &os_version.patch + case: break + } + + num, ok := strconv.parse_int(part) + if !ok { break } + + dst^ = num } } - // Finish the string - os_version.as_string = strings.to_string(b) } -@(init) +@(init, private) init_ram :: proc() { // Retrieve RAM info using `sysinfo` sys_info: linux.Sys_Info @@ -84,4 +95,4 @@ init_ram :: proc() { total_swap = int(sys_info.totalswap) * int(sys_info.mem_unit), free_swap = int(sys_info.freeswap) * int(sys_info.mem_unit), } -} \ No newline at end of file +} diff --git a/core/sys/info/platform_openbsd.odin b/core/sys/info/platform_openbsd.odin index 772531ceb..3a7c07570 100644 --- a/core/sys/info/platform_openbsd.odin +++ b/core/sys/info/platform_openbsd.odin @@ -1,4 +1,3 @@ -// +build openbsd package sysinfo import sys "core:sys/unix" @@ -61,7 +60,7 @@ init_os_version :: proc () { os_version.as_string = strings.to_string(b) } -@(init) +@(init, private) init_ram :: proc() { // Retrieve RAM info using `sysctl` mib := []i32{sys.CTL_HW, sys.HW_PHYSMEM64} diff --git a/core/sys/info/platform_windows.odin b/core/sys/info/platform_windows.odin index 250f938b1..4c00ddadf 100644 --- a/core/sys/info/platform_windows.odin +++ b/core/sys/info/platform_windows.odin @@ -1,4 +1,3 @@ -// +build windows package sysinfo import sys "core:sys/windows" @@ -259,7 +258,7 @@ init_os_version :: proc () { } } -@(init) +@(init, private) init_ram :: proc() { state: sys.MEMORYSTATUSEX diff --git a/core/sys/info/sysinfo.odin b/core/sys/info/sysinfo.odin index 69f9f1584..f0262f317 100644 --- a/core/sys/info/sysinfo.odin +++ b/core/sys/info/sysinfo.odin @@ -8,6 +8,9 @@ os_version: OS_Version ram: RAM gpus: []GPU +// Only on MacOS, contains the actual MacOS version, while the `os_version` contains the kernel version. +macos_version: Version + OS_Version_Platform :: enum { Unknown, Windows, @@ -19,12 +22,14 @@ OS_Version_Platform :: enum { NetBSD, } +Version :: struct { + major, minor, patch: int, +} + OS_Version :: struct { platform: OS_Version_Platform, - major: int, - minor: int, - patch: int, + using _: Version, build: [2]int, version: string, @@ -42,4 +47,4 @@ GPU :: struct { vendor_name: string, model_name: string, total_ram: int, -} \ No newline at end of file +} diff --git a/core/sys/unix/sysctl_darwin.odin b/core/sys/unix/sysctl_darwin.odin index 76c72f478..6417961e5 100644 --- a/core/sys/unix/sysctl_darwin.odin +++ b/core/sys/unix/sysctl_darwin.odin @@ -1,20 +1,29 @@ //+build darwin package unix -import "core:sys/darwin" import "base:intrinsics" +import "core:c" +import "core:sys/darwin" + _ :: darwin -sysctl :: proc(mib: []i32, val: ^$T) -> (ok: bool) { - mib := mib - result_size := i64(size_of(T)) +sysctl :: proc "contextless" (mib: []i32, val: ^$T) -> (ok: bool) { + result_size := c.size_t(size_of(T)) + res := darwin.syscall_sysctl( + raw_data(mib), len(mib), + val, &result_size, + nil, 0, + ) + return res == 0 +} - res := intrinsics.syscall( - darwin.unix_offset_syscall(.sysctl), - uintptr(raw_data(mib)), uintptr(len(mib)), - uintptr(val), uintptr(&result_size), - uintptr(0), uintptr(0), +sysctlbyname :: proc "contextless" (name: string, val: ^$T) -> (ok: bool) { + result_size := c.size_t(size_of(T)) + res := darwin.syscall_sysctlbyname( + name, + val, &result_size, + nil, 0, ) return res == 0 } diff --git a/core/time/tsc_darwin.odin b/core/time/tsc_darwin.odin index 6688ae7d8..841c0b692 100644 --- a/core/time/tsc_darwin.odin +++ b/core/time/tsc_darwin.odin @@ -1,21 +1,10 @@ //+private -//+build darwin package time -import "core:c" +import "core:sys/unix" -foreign import libc "system:System.framework" -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.frequency", &tmp_freq, &tmp_size, nil, 0) - if ret < 0 { - return 0, false - } - - return tmp_freq, true +_get_tsc_frequency :: proc "contextless" () -> (freq: u64, ok: bool) { + unix.sysctlbyname("machdep.tsc.frequency", &freq) or_return + ok = true + return } diff --git a/src/bug_report.cpp b/src/bug_report.cpp index e919ba67b..88ab9492c 100644 --- a/src/bug_report.cpp +++ b/src/bug_report.cpp @@ -204,14 +204,27 @@ gb_internal void report_cpu_info() { } #elif defined(GB_CPU_ARM) - /* - TODO(Jeroen): On *nix, perhaps query `/proc/cpuinfo`. - */ - #if defined(GB_ARCH_64_BIT) - gb_printf("ARM64\n"); - #else - gb_printf("ARM\n"); + bool generic = true; + + #if defined(GB_SYSTEM_OSX) + char cpu_name[128] = {}; + size_t cpu_name_size = 128; + if (sysctlbyname("machdep.cpu.brand_string", &cpu_name, &cpu_name_size, nullptr, 0) == 0) { + generic = false; + gb_printf("%s\n", (char *)&cpu_name[0]); + } #endif + + if (generic) { + /* + TODO(Jeroen): On *nix, perhaps query `/proc/cpuinfo`. + */ + #if defined(GB_ARCH_64_BIT) + gb_printf("ARM64\n"); + #else + gb_printf("ARM\n"); + #endif + } #else gb_printf("Unknown\n"); #endif