The Modern Gamer
The Modern Gamer

Reputation: 45

Getting hardware info in nim-lang

What is the most elegant way to get hardware info, such us GPU name, CPU name, RAM in nim? I haven't found a library and not really sure how to implement it from pure nim

Upvotes: 1

Views: 727

Answers (1)

Dimitri Lesnoff
Dimitri Lesnoff

Reputation: 382

When you want to search for Nim packages, you should look first at:

  1. awesome-nim: A curated list of packages
  2. the nimble search functionality. Ex: nimble search hardware cpu I have found the pkg/sysinfo package and pkg/psutil-nim which does probably what you want.

Shell scripts are usually faster and more adapted for this kind of application. There are many CLI applications that you can adapt or leverage directly. On Linux, you can get hostname and model information with hostnamectl. There are other utilities that aggregate hardware information, the most well-known is probably neofetch. It has many variants, see: https://alternativeto.net/software/neofetch/

Based on neofetch, I have written a small script that works on Linux only:

import std/[strutils, strformat, osproc]

type
  MyComputerInfo = object
    os: string
    host: string
    kernel: string
    cpu: string
    gpu: string


proc cacheUnameInfo*(): tuple[os: string, host: string, kernel: string] =
  ## Only defined for posix systems
  when defined(posix):
    let (output, errorCode) = execCmdEx("uname -omnr")
    if errorCode != 0:
      echo fmt"`uname -omnr` command failed, with Error code: {errorCode}"
      quit(2)
    let outSeq: seq[string] = output.split(' ')
    var arch: string = outSeq[3]
    stripLineEnd(arch)
    let
      os = arch & ' ' & outSeq[2]
      host = outSeq[0]
      kernel = outSeq[1]
    return (os, host, kernel)

proc getGpuInfo*(): string =
  when defined(posix):
    var (gpu_driver_name, exitCode) = execCmdEx("""lspci -nnk | awk -F ': ' \ '/Display|3D|VGA/{nr[NR+2]}; NR in nr {printf $2 ", "; exit}'""")
    if exitCode == 0:
      gpu_driver_name = gpu_driver_name.split(",")[0]
      if gpu_driver_name == "nvidia":
        var (gpu_name, exitCodeSmi) = execCmdEx("nvidia-smi --query-gpu=name --format=csv,noheader")
        if exitCodeSmi != 0:
          echo "nvidia-smi command failed with exit code: {exitCodeSmi}"
          quit(2)
        return gpu_name
      return gpu_driver_name.toUpperAscii()
    else:
      echo fmt"GpuInfo error code: {exitCode}"
      quit(2)

proc getCpuInfo*(): string =
  when defined(posix):
    var (cpu_name, _) = execCmdEx("""cat /proc/cpuinfo | awk -F '\\s*: | @' '/model name|Hardware|Processor|^cpu model|chip type|^cpu type/ { cpu=$2; if ($1 == "Hardware") exit } END { print cpu }' "$cpu_file" """)
    return cpu_name

proc `$`(mci: MyComputerInfo): string =
  ## Nice Output of a `MyComputerInfo` object
  for name, val in fieldPairs(mci):
    if $val != "":
      result.add name.capitalizeAscii()
      result.add ": "
      result.add ($val).strip(leading=false, chars = {'\n'})
      result.add "\n"
  result.strip(leading=false, chars = {'\n'})

when isMainModule:
  var mci: MyComputerInfo
  (mci.os, mci.host, mci.kernel) = cacheUnameInfo()
  mci.gpu = getGpuInfo()
  mci.cpu = getcpuInfo()
  echo mci

On my computer, I get:

Os: GNU/Linux x86_64
Host: localhost
Kernel: 5.15.0-78-generic
Cpu: 11th Gen Intel(R) Core(TM) i5-1135G7
Gpu: HEWLETT-PACKARD COMPANY TIGERLAKE-LP GT2 [IRIS XE GRAPHICS] [103C:880D]

We could replace the awk's calls in execCmdEx by Nim parsing procedures for more Nim purity. We could add a configurator (with a CLI parser, or a DSL) so that the user can select the options he wants to print out. I leave the rest to you.

Upvotes: 3

Related Questions