Files
Odin/core/sys/info/sysinfo.odin
2026-02-23 23:09:37 +01:00

189 lines
4.9 KiB
Odin

package sysinfo
import "base:runtime"
import "core:strings"
import "core:strconv"
#assert(
ODIN_ARCH == .amd64 || ODIN_ARCH == .i386 || \
ODIN_ARCH == .arm32 || ODIN_ARCH == .arm64 || \
ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 || \
ODIN_ARCH == .riscv64,
"This package is unsupported on this architecture.")
/*
Retrieves the number of physical and logical CPU cores
Returns:
- physical: The number of physical cores
- logical: The number of logical cores
- ok: `true` when we could retrieve the CPU information, `false` otherwise
*/
cpu_core_count :: proc "contextless" () -> (physical: int, logical: int, ok: bool) {
return _cpu_core_count()
}
/*
Retrieves CPU features where available
The results are cached
Returns:
- features: An architecture-specific `bit_set`
- ok: `true` when we could retrieve the CPU features, `false` otherwise
*/
cpu_features :: proc "contextless" () -> (features: CPU_Features, ok: bool) {
return _cpu_features()
}
/*
Retrieves the CPU's name
The results are cached
Returns:
- name: A `string` containing the CPU model name, empty if the lookup failed
*/
cpu_name :: proc() -> (name: string) {
return _cpu_name()
}
/*
Retrieves RAM statistics
Unavailable stats will be returned as `0` bytes
Returns:
- total_ram: Total RAM reported by the operating system, in bytes
- free_ram: Free RAM reported by the operating system, in bytes
- total_swap: Total SWAP reported by the operating system, in bytes
- free_swap: Free SWAP reported by the operating system, in bytes
- ok: `true` when we could retrieve RAM statistics, `false` otherwise
*/
ram_stats :: proc "contextless" () -> (total_ram, free_ram, total_swap, free_swap: i64, ok: bool) {
return _ram_stats()
}
/*
Retrieves OS version information
*Allocates Using Provided Allocator*
You can use `destroy_os_version` to free the results
Inputs:
- allocator: A `runtime.Allocator` on which the version strings will be allocated
- loc: The caller location
Returns:
- res: An `OS_Version` struct
- ok: `true` when we could retrieve OS version information, `false` otherwise
*/
os_version :: proc(allocator: runtime.Allocator, loc := #caller_location) -> (res: OS_Version, ok: bool) {
return _os_version(allocator = allocator, loc = loc)
}
/*
Releases an `OS_Version`'s strings
*Frees Using Provided Allocator*
Inputs:
- version: An `OS_Version` struct
- allocator: A `runtime.Allocator` on which the version strings will be freed
*/
destroy_os_version :: proc(version: OS_Version, allocator: runtime.Allocator) {
delete(version.full, allocator)
// `version.release` is part of `version.full` and does not need to be freed separately.
}
OS_Version :: struct {
platform: OS_Version_Platform, // Windows, Linux, MacOS, iOS, etc.
full: string, // e.g. Windows 10 Professional (version: 22H2), build: 19045.6575
release: string, // e.g. 22H2
os: Version, // e.g. {major = 10, minor = 10, patch = 0}
kernel: Version, // e.g. {major = 10, minor = 19045, patch = 6575}
}
OS_Version_Platform :: enum {
Unknown,
Windows,
Linux,
MacOS,
iOS,
FreeBSD,
OpenBSD,
NetBSD,
}
Version :: struct {
major, minor, patch: int,
}
/*
Iterates over GPU adapters
On Windows: Enumerates `Computer\HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Class\{4d36e968-e325-11ce-bfc1-08002be10318}`
Elsewhere: Unsupported at the moment, returns `{}, 0, false`
Important: The `vendor` name, `model` name and `driver` version strings are backed by the `GPU_Iterator`.
Clone them if you want to these to persist.
Inputs:
- it: A pointer to a `GPU_Iterator`
- minimum_vram: The number of bytes of VRAM an adapter has to have to be considered, default 256 MiB
(This excludes most screen mirroring / remote desktop drivers)
Returns:
gpu: A `GPU` struct which contains `vendor` name, `model` name, `driver` version and `vram` in bytes
index: Loop index, optional
ok: `true` if this was a success and we should continue, `false` otherwise
*/
iterate_gpus :: proc(it: ^GPU_Iterator, minimum_vram := i64(256 * 1024 * 1024)) -> (gpu: GPU, index: int, ok: bool) {
when ODIN_OS == .Windows {
return _iterate_gpus(it, minimum_vram)
} else {
// Not implemented on another OS, yet
return {}, 0, false
}
}
GPU :: struct {
vendor: string,
model: string,
driver: string,
vram: i64,
}
GPU_Iterator :: struct {
// Public iterator index
index: int,
// Internal buffer + index
_buffer: [512]u8,
_index: int,
}
@(private)
_parse_version :: proc (str: string) -> (res: Version) {
str := str
i: int
for part in strings.split_iterator(&str, ".") {
defer i += 1
dst: ^int
switch i {
case 0: dst = &res.major
case 1: dst = &res.minor
case 2: dst = &res.patch
case: return
}
if num, num_ok := strconv.parse_int(part); !num_ok {
return
} else {
dst^ = num
}
}
return
}