Tag: ubuntu

  • The AMD R9700 – Ubuntu 24.04 Quickstart Guide

    The AMD R9700 – Ubuntu 24.04 Quickstart Guide

    ….and I bought an AMD GPU.

    It’s the first time I’ve gone non-Nvidia since before 2010 as I’ve been a Nvidia loyalist since the GeForce 256 back in 1999 (was 3dfx prior). But Nvidia GPU pricing on anything with decent VRAM has gotten absurd, even on the used market. I kept hearing that ROCm (Radeon Open Compute) support for inference has finally matured. So I decided to find out for myself.

    I picked up the AMD Radeon AI PRO R9700, 32GB. Not cheap, but brand new its cheaper than an RTX 3090 24gb from 2020.

    Since this is my first AMD in very long while, going to have to figure out drivers. So let’s get started. First lets gather some info by running the commands below.

    lspci -nn | grep -Ei 'VGA|Display|AMD|ATI'
    lsmod | grep amdgpu
    dmesg | grep -i amdgpu | tail -50

    Verify GPU Detection

    Prior to card swap, purged my Ubuntu 24.04 system of all Nvidia drivers and tools.

    Lets check to see if the card is detected properly

    lspci -nn | grep -Ei 'VGA|Display|AMD|ATI'

    This command searches the PCI device list for anything matching VGA, Display, AMD, or ATI. In the output below we see the following

    • 03:00.0 is the PCI id of the R9700 GPU
    • Vendor ID 1002 confirms AMD Device
    • 7551 is how the kernel identifies this GPU generation/device
    • The two PCI bridge entries show the GPU exposes an internal PCIe switch/bridge topology
    01:00.0 PCI bridge: AMD Navi 10 XL Upstream Port of PCI Express Switch
    02:00.0 PCI bridge: AMD Navi 10 XL Downstream Port of PCI Express Switch
    03:00.0 VGA compatible controller: AMD Device [1002:7551]
    03:00.1 Audio device: AMD Device [1002:ab40]

    The important takeaway is that Ubuntu already recognizes the R9700 correctly and the in-kernel AMDGPU driver is successfully initializing it.

    lsmod | grep amdgpu

    This command above shows whether the AMDGPU kernel module is loaded and what other kernel modules depend on it.

    amdgpu 21188608 26

    This tells us:

    • amdgpu is loaded
    • the module occupies roughly 21 MB of kernel module memory
    • 26 references/users currently depend on it
    dmesg | grep -i amdgpu | tail -50

    The command above shows the last 50 kernel messages associated with AMDGPU initialization.

    The most important things we see are:

    MEM ECC is active.

    The GPU’s VRAM ECC capability is active.

    VRAM: 32624M

    The kernel detects approximately 32 GB of VRAM.

    Detected VRAM RAM=32624M, BAR=32768M

    Preparing for ROCm Install

    First lets make sure that the kernel has created the ROCm compute device

     ls -l /dev/kfd
    crw-rw---- 1 root render 235, 0 Aug  9 16:20 /dev/kfd
    
    
    

    /dev/kfd is the Kernel Fusion Driver device that ROCm/HIP uses to submit compute workloads to the AMD GPU. AMD’s ROCm installation process relies on access through the render/video device groups.

    In the output above, you can see that the Kernel Fusion Driver is owned by root with group membership of render. We need to add my user to the render group. Note that I had to reboot to pick up the changes.

    sudo usermod -aG render cpaquin

    Now we can add the ROCm 7.2.2 package repo, which is two steps. This one below…

    sudo mkdir --parents --mode=0755 /etc/apt/keyrings
    wget https://repo.radeon.com/rocm/rocm.gpg.key -O - | \
    gpg --dearmor | sudo tee /etc/apt/keyrings/rocm.gpg > /dev/null

    And this next one to actually add the repo.

    sudo tee /etc/apt/sources.list.d/rocm.list <<'EOF'
    deb [arch=amd64 signed-by=/etc/apt/keyrings/rocm.gpg] https://repo.radeon.com/rocm/apt/7.2.2 noble main
    deb [arch=amd64 signed-by=/etc/apt/keyrings/rocm.gpg] https://repo.radeon.com/graphics/7.2.1/ubuntu noble main
    EOF

    Now let’s be smart and ensure that the repo was added properly.

    cat /etc/apt/sources.list.d/rocm.list
    deb [arch=amd64 signed-by=/etc/apt/keyrings/rocm.gpg] https://repo.radeon.com/rocm/apt/7.2.2 noble main
    deb [arch=amd64 signed-by=/etc/apt/keyrings/rocm.gpg] https://repo.radeon.com/graphics/7.2.1/ubuntu noble main

    Now before we install anything, per AMD recommendation, we need to pin the above repo priority. Pinning means settings which repository Ubuntu prefers when the same package is available from multiple repositories, which means prefer the AMD repos over Ubuntu repos for AMD bits and bobbles.

    sudo tee /etc/apt/preferences.d/rocm-pin-600 <<'EOF'
    Package: *
    Pin: release o=repo.radeon.com
    Pin-Priority: 600
    EOF

    Now we update metadata.

    sudo apt update

    We can see the repo preference via pinning below.

     apt policy rocm
    rocm:
      Installed: (none)
      Candidate: 7.2.2.70202-86~24.04
      Version table:
         7.2.2.70202-86~24.04 600
            600 https://repo.radeon.com/rocm/apt/7.2.2 noble/main amd64 Packages
    
    
    

    ROCm Install

    First, lets make sure we have the following installed.

    sudo apt install python3-setuptools python3-wheel

    Now we can install ROCm. It takes a bit so be patient, or don’t.

    sudo apt install rocm

    Now lets verify that ROCm can see the GPU

    rocminfo

    Truncated output below

    rocminfo
    ROCk module is loaded
    =====================
    HSA System Attributes
    =====================
    Runtime Version: 1.18
    Runtime Ext Version: 1.15
    System Timestamp Freq.: 1000.000000MHz
    Sig. Max Wait Duration: 18446744073709551615 (0xFFFFFFFFFFFFFFFF) (timestamp count)
    Machine Model: LARGE
    System Endianness: LITTLE
    Mwaitx: DISABLED
    XNACK enabled: NO
    DMAbuf Support: YES
    VMM Support: YES
    *******
    Agent 2
    *******
    Name: gfx1201
    Uuid: GPU-407fcdae2bc6b11d
    Marketing Name: AMD Radeon AI PRO R9700
    Vendor Name: AMD
    Feature: KERNEL_DISPATCH
    Profile: BASE_PROFILE
    Float Round Mode: NEAR
    Max Queue Number: 128(0x80)
    Queue Min Size: 64(0x40)
    Queue Max Size: 131072(0x20000)
    Queue Type: MULTI
    Node: 1
    Device Type: GPU

    And now run amd-smi.

    amd-smi
    +------------------------------------------------------------------------------+
    | AMD-SMI 26.2.2+671d39a71e amdgpu version: 7.0.0-28 ROCm version: 7.2.2 |
    | VBIOS version: 00158746 |
    | Platform: Linux Baremetal |
    |-------------------------------------+----------------------------------------|
    | BDF GPU-Name | Mem-Uti Temp UEC Power-Usage |
    | GPU HIP-ID OAM-ID Partition-Mode | GFX-Uti Fan Mem-Usage |
    |=====================================+========================================|
    | 0000:03:00.0 ...Radeon AI PRO R9700 | 1 % 31 °C 0 9/300 W |
    | 0 0 N/A N/A | 3 % 20.0 % 661/32624 MB |
    +-------------------------------------+----------------------------------------+
    +------------------------------------------------------------------------------+
    | Processes: |
    | GPU PID Process Name GTT_MEM VRAM_MEM MEM_USAGE CU % |
    |==============================================================================|
    | No running processes found |

    What we are looking at:

    • ROCm 7.2.2 is active.
    • The Radeon AI PRO R9700 is correctly identified.
    • Temperature is 31 °C.
    • Power draw is only 9 W / 300 W at idle.
    • Fan is at 20%.
    • VRAM usage is 661 MB / 32,624 MB, which is normal for the display/driver stack.
    • No uncorrectable ECC errors: UEC 0.
    • No compute processes are currently using the GPU.

    Test ROCm inside Docker

    Can a Docker container access the R9700 through ROCm? Lets find out.

    docker run --rm \
    --device=/dev/kfd \
    --device=/dev/dri \
    --group-add 992 \
    --group-add 44 \
    rocm/rocm-terminal:latest \
    rocminfo

    What this does:

    • starts a temporary AMD ROCm container
    • passes /dev/kfd into it for ROCm compute
    • passes /dev/dri into it for the GPU device nodes
    • gives the container the needed video (44) and render (992) group access
    • runs rocminfo inside the container
    • deletes the container afterward because of --rm

    If it works, we should see the same R9700 identification inside Docker that we saw on the host, including something like:


    Pytorch Test

    Next we’ll use AMD’s validated PyTorch container for ROCm 7.2 / Ubuntu 24.04 / Python 3.12 / PyTorch 2.9.1. AMD recommends Docker for PyTorch because the image already contains a tested PyTorch+ROCm combination.

    docker run --rm \
    --device=/dev/kfd \
    --device=/dev/dri \
    --group-add 992 \
    --group-add 44 \
    --security-opt seccomp=unconfined \
    --ipc=host \
    --shm-size 8G \
    rocm/pytorch:rocm7.2_ubuntu24.04_py3.12_pytorch_release_2.9.1 \
    python3 -c "import torch; print('PyTorch:', torch.__version__); print('ROCm:', torch.version.hip); print('GPU available:', torch.cuda.is_available()); print('GPU:', torch.cuda.get_device_name(0) if torch.cuda.is_available() else 'NONE')"

    This will likely download a fairly large container image the first time.

    What we want to see is essentially:

    PyTorch: 2.9.1+rocm7.2.0.git7e1940d4
    ROCm: 7.2.26015-fc0010cf6a
    GPU available: True
    GPU: AMD Radeon AI PRO R9700

    One potentially confusing point: PyTorch keeps the API name torch.cuda even when using AMD ROCm.

    torch.cuda.is_available() returning True means PyTorch has a usable GPU backend; on this container that backend is HIP/ROCm, not NVIDIA CUDA. AMD uses this same test in its ROCm PyTorch verification instructions.

    So the R9700 is now validated for actual ROCm/PyTorch compute inside Docker. Next Step VLLM and test some models.

  • How to Reconfigure Claude Code CLI when changing subscriptions

    How to Reconfigure Claude Code CLI when changing subscriptions

    My employer recently put the kibosh on personal home lab usage.

    No longer can employees who have invested time and money into building out a lab to learn and test our own products utilize their home lab to connect to any internal tool or service. You can not even access your work gmail on anything other than your company provided workstation or your monitored phone.

    Which apparently means that I can no longer use my work provided Claude code account from a non-company supplied workstation, as its a company provided tool.

    This was my original workflow

    A flowchart illustrating a software development process with five steps: starting with a laptop labeled 'Claude/Cursor', followed by 'Test & Deploy in Home Lab', then 'Fix Bugs and Secure', next 'Commit', and finally 'Clone Repo to Work Env'.

    Now my choices are to either “Test & Deploy on Company Hardware” or utilize my own subscriptions and do my initial development on whatever workstation I happen to be in front of at the time. I chose the latter, as I want to establish my own agentic workflows that are not dependent on employer provided subscriptions, and I want to utilize my own hardware without having to deal with hardware resource scheduling.

    So that takes us to where we are today.

    A broken Claude Code CLI, that fails to authenticate as my initial corp provided config seems to be pervasive across multiple env vars and conf files. So lets clean that up.

    Screenshot of a terminal interface displaying welcome message for Claude Code v2.1.195, with tips for getting started and recent updates.

    First step is to remove any env vars you find in the files below

    grep -rE "CLAUDE_CODE_USE_VERTEX|ANTHROPIC_VERTEX_PROJECT_ID|CLOUD_ML_REGION|VERTEX|vertex" \
    ~/.bashrc \
    ~/.zshrc \
    ~/.bash_profile \
    ~/.profile \
    ~/.config/environment.d/* \
    /etc/environment \
    /etc/profile.d/* \
    ~/.claude/settings.json \
    ~/.claude/settings.local.json \
    2>/dev/null

    We must go deeper.

    find ~ -maxdepth 3 -name ".env" 2>/dev/null | xargs grep -l -iE "vertex|CLAUDE_CODE" 2>/dev/null

    Any vars found here, delete.

    Let’s make sure I cleaned up all shell vars. If you find any – unset them. Then source your .bashrc to make sure they are not set there on login.

    env | grep -iE "vertex|gcloud|google|claude|anthropic"
    PWD=/home/cpaquin/.claude

    Same with claude logging, we can check the latest debug log and look for errors around a broken config (use /debug to enable).

    cat ~/.claude/debug/latest

    Once you have removed any detritus from your config/env simply re-launch Claude and authenticate via your method of choice.

    Login screen for Claude Code with options for account types: Claude account with subscription, Anthropic Console account, and 3rd-party platform.

  • CPU Overclocking on Ubuntu 24.04

    CPU Overclocking on Ubuntu 24.04

    One of my workstations has a Intel Core i7-8086K Special Edition CPU. Its a 40th-anniversary limited edition 6-core/12-thread Coffee-Lake processor launched in 2018 to commemorate the original Intel 8086 processor. The i7-8086K features a base clock speed of 4.0GHz and a boost speed of 5.0GHz.

    As this processor was not a standard mass-produced model, its a bit collectible in some strange circles. It was also the first Intel processor to hit 5.0GHz out of the box. Technically the i7-8086K is a “cherry-picked” or higher-binned version of the popular Intel Core i7-8700K. Because these chips were selected from the best-performing parts of the wafer, they typically require less voltage to run at high speeds. At the time enthusiasts were willing to pay a premium as these chips are much more likely to reach stable overclocks of 5.1 GHz to 5.3 GHz across all cores.

    Nowadays the Intel Core i7-8086K Special Edition CPU still maintains a “legacy premium” price, even on eBay where they are still over $100 per.

    So lets overclock it a bit.


    Installing CPU Frequency Tools in Ubuntu

    Lets start by installing the tools to allow us to modify the cpu governor and inspect CPU frequencies

    sudo apt install linux-tools-common linux-tools-$(uname -r) cpufrequtils

    Set CPU Governor to Performance

    The performance governor prevents Linux from aggressively downclocking the CPU.

    sudo cpupower frequency-set -g performance

    Set Overclock on Boot Via Systemd

    We want our overclock to be persistent across reboots, so we will create a systemd service that will run at boot-time.

    vim /etc/systemd/system/cpupower.service

    Copy/Paste the contents below in to the file we are creating above.

    [Unit]
    Description=CPU performance governor
    [Service]
    Type=oneshot
    ExecStart=/usr/bin/cpupower frequency-set -g performance
    [Install]
    WantedBy=multi-user.target

    Now we need to enable and start the service.

    sudo systemctl enable --now cpupower

    Confirm Overclock

    First we will run a quick frequency check. Here the CPU(s) scaling MHz indicates the percentage of the CPU’s maximum possible frequency that the system is currently running at (on average across cores). Meaning that the CPU is currently operating at ~42% of its maximum clock frequency across all CPUs.

    lscpu | grep MHz
    CPU(s) scaling MHz: 42%
    CPU max MHz: 5100.0000
    CPU min MHz: 800.0000

    Via the cpupower command we can we that we currently have one boosted core running at 5.07Ghz.

    root@raptor:/etc/chrony# cpupower frequency-info
    analyzing CPU 7:
    driver: intel_pstate
    CPUs which run at the same hardware frequency: 7
    CPUs which need to have their frequency coordinated by software: 7
    energy performance preference: performance
    hardware limits: 800 MHz - 5.10 GHz
    available cpufreq governors: performance powersave
    current policy: frequency should be within 800 MHz and 5.10 GHz.
    The governor "performance" may decide which speed to use
    within this range.
    current CPU frequency: 5.07 GHz (asserted by call to kernel)
    boost state support:
    Supported: yes
    Active: yes

    We can run the watch command against /proc/cpu info and watch frequencies change real-time.

    Terminal output displaying CPU frequencies in MHz, showing varying values for multiple CPU cores.

    Generate Load to Drive Up Frequencies

    In a second ssh window we will now install and run stress-ng to generate some load, while we continue to run our watch command above.

    sudo apt install stress-ng

    Once installed we run it as shown below

    Where:

    • –cpu 0 = use all online CPUs
    • matrixprod is a decent compute-heavy load

    In our watch window we can see we have all cores above 4.0GHz

    Terminal output showing CPU frequency readings in MHz, displaying values around 4399 to 4400 MHz.

    Checking CPU Temps

    My Intel Core i7-8086K Special Edition CPU has a pretty average cpu cooler/fan. Nothing fancy with heat-pipes and multiple fans, however I do have 8x 120mm case fans moving a lot of air through my case, while projecting nice purple glow. So lets check our CPU temps, first at rest and then under load.

    So we start by installing lm-sensors, and then detect available sensors. Sensors-detect will ask you a handful of questions, but you can usually stick with the defaults.

    sudo apt install lm-sensors
    sudo sensors-detect

    And now we check temps at rest

    ~# sensors
    coretemp-isa-0000
    Adapter: ISA adapter
    Package id 0: +34.0°C (high = +82.0°C, crit = +100.0°C)
    Core 0: +33.0°C (high = +82.0°C, crit = +100.0°C)
    Core 1: +33.0°C (high = +82.0°C, crit = +100.0°C)
    Core 2: +34.0°C (high = +82.0°C, crit = +100.0°C)
    Core 3: +36.0°C (high = +82.0°C, crit = +100.0°C)
    Core 4: +33.0°C (high = +82.0°C, crit = +100.0°C)
    Core 5: +33.0°C (high = +82.0°C, crit = +100.0°C)

    So lets kick off stress-ng to generate some load, which we ‘watch’ the output of the sensors command in another terminal window.

    stress-ng --cpu 0 --cpu-method matrixprod --timeout 60s --metrics-brief

    And we can see that we get a bit toasty. While these temperatures are high, they are not dangerous to see during a stress test. What we do know is that we do not have a lot of thermal headroom.

    Screenshot of system temperature readings from a tool showing CPU core temperatures with values in Celsius, indicating critical and high temperature thresholds.

    Stress-ng is built to generate worst-case thermal load when running, so I really and not concerned to see these temps when its running.

    Just to be sure, lets run turbostat and see if we see any throttling.

    sudo turbostat --interval 1

    Turbostat produces a lot of output, the table below will give you an idea of what you are looking at.

    ColumnWhat it ShowsWhat You Want to See
    PkgTmpCPU package temperatureIdeally <90 °C during sustained load
    CoreTmpPer-core temperatureSimilar to package temp; watch for cores hitting 95 °C+
    Avg_MHzAverage CPU frequency during the intervalShould rise close to the overclock max under load
    Bzy_MHzActual frequency while the core is busyShould approach the configured turbo (≈5 GHz)
    Busy%CPU utilization per coreNear 100% during stress-ng
    PkgWattTotal CPU package powerUseful to understand thermal load
    CorWattPower used by coresIndicates how much compute load is occurring

    For thermal events or power throttling we look for the following.

    ColumnMeaning
    ThermThrotThermal throttling events
    Pkg%pc2 / pc3 / pc6Package idle states (should drop during stress)
    Core%pc3 / pc6Core idle states

    If cpu performance/speed was throttled we would expect to see ThermThrot events.

    If you want a cleaner, and more succinct output from turbostat, try the one-liner below.

    sudo turbostat --interval 1 --quiet --show CPU,Busy%,Bzy_MHz,Avg_MHz,PkgTmp,CoreTmp,ThermThrot

    While we are not seeing any throttling events, we do see that across all CPU cores we have a BZY_MHz of 4400 MHz (not 5000MHz). Since our test workload is running across all cores/threads (12 logical CPUs in this case), the processor switches the the all-core turbo limit of 4.4GHz which is lower than the single core turbo frequency of ~5.0GHz. This is good news and shows we are stable across all cores, but does not allow us to hit the max turbo frequency for this cpu.

    So lets try that.

    Lets run a load on exactly one core.

    stress-ng --cpu 1 --taskset 0 --timeout 60

    In another terminal window we run our watch command, where we can see that we are in fact able to hit almost 5.1Ghz.

    sudo turbostat --interval 1 --show CPU,Bzy_MHz,PkgTmp
    CPU Bzy_MHz PkgTmp
    - 5098 53
    0 5099 53

    Cool, over 5.0GHz.

    Not that I am looking to push it any further above 5.0GHz, but if I was, a better cpu cooler would be the way to go (and possibly some tweaking in the bios). That being said, at our current speeds as we never got hot enough to see any throttling. May look for a glowing purple one anyway.

  • Setting up Chrony/NTP Server with GPS on Ubuntu 22.04

    Setting up Chrony/NTP Server with GPS on Ubuntu 22.04

    Introduction

    In this post I will cover setting up a ntp/chrony server on Ubuntu 22.04 using a Satellite GPS Receiver. I have also recently published another post on Chrony, which goes a bit more into basic commands. That post can be found here.


    Hardware

    Note: the GlobalSat BU-353-W11 does not support 1pps. It’s designed primarily for positioning and navigation, not precision timing. We can use it as our timesource for chrony, with a typical accuracy: ±50–150 ms. Good enough for a lab.


    Hardware Detection

    After plugging in the USB cable on the GNSS module, check for a new USB device.

    # lsusb
    Bus 001 Device 004: ID 1546:01a7 U-Blox AG [u-blox 7]

    Output from dmegs also shows the device was detected properly

    [347055.572498] usb 1-2.4: new full-speed USB device number 4 using tegra-xusb
    [347055.768706] cdc_acm 1-2.4:1.0: ttyACM0: USB ACM device
    [347055.768784] usbcore: registered new interface driver cdc_acm
    [347055.768788] cdc_acm: USB Abstract Control Model driver for USB modems and ISDN adapters

    In the output above you can see the device was detected ttyACM0. Now we need to confirm how the device was enumerated. As you can see the device is owned by root and the group is dialout

    # ls -l /dev/ttyACM*
    crw-rw---- 1 root dialout 166, 0 Dec 29 13:40 /dev/ttyACM0
    
    

    You can run a quick check to confirm that the device is functioning as shown below

    # cat /dev/ttyACM0
    $GPTXT,01,01,02,u-blox ag - www.u-blox.com*50
    
    $GPTXT,01,01,02,HW  UBX-G70xx   00070000 FF7FFFFFo*69
    
    $GPTXT,01,01,02,ROM CORE 1.00 (59842) Jun 27 2012 17:43:52*59
    
    $GPGGA,201055.00,3356.15827,N,08345.15611,W,2,12,0.80,280.0,M,-31.5,M,,0000*67
    
    -----------truncated----------------

    GPSD

    To use a GPS/GNSS antenna with chronyd on Linux for time synchronization and location sharing, we will use the gpsd service to manage the GPS hardware and make its data accessible to other applications, including chronyd

    Package Installation

    # sudo apt update
    # sudo apt install gpsd gpsd-clients chrony pps-tools 

    GPSD Configuration

    Identify the GPS device: The device will likely be /dev/ttyUSB0, /dev/ttyACM0, or similar. You can verify this by running cat /dev/ttyUSB0 (replace ttyUSB0 with your suspected device) and looking for NMEA strings (lines starting with $GPGGA, $GNRMC, etc.).

    Edit the gpsd configuration file: Open /etc/default/gpsd and set the DEVICES, GPSD_OPTIONS, and USBAUTO variables.

    START_DAEMON="true"
    GPSD_OPTIONS="-n -b"
    DEVICES="/dev/ttyACM0"
    USBAUTO="false"
    GPSD_SOCKET="/var/run/gpsd.sock"
    

    For reference here are configuration params for GPSD_OPTIONS

    FlagArgumentMeaningNotes
    -nnoneStart reading GPS immediatelyRequired for chrony/NTP
    -bnoneRead-only mode (no device writes)Recommended for USB pucks
    -NnoneRun in foregroundDebug only
    -D<level>Debug verbosityUse -D 2 or -D 3
    -F<path>Control socket pathNeeded for manual runs
    -s<baud>Force serial baud rateUART devices only
    -S<port>TCP listening portRare; usually disabled
    -GnoneAllow remote TCP clientsAvoid on servers
    -lnoneList drivers and exitDiagnostic
    -VnoneShow version and exitInformational
    -hnoneHelp outputReference

    Enable and start gpsd

    # sudo systemctl enable gpsd
    # sudo systemctl restart gpsd

    Verify gpsd is receiving data

    # cgps -s
    

    Output below

    Screen output from a GPSD client showing real-time GPS data, including time, latitude, longitude, altitude, speed, and satellite information.

    Interpreting the output from cgps

    High-Level Status (The Big Picture)

    • (Satellites) Seen / Used: 13 / 11
    • Fix: 3D DGPS FIX – means the receiver has solved all three spatial dimensions: (Latitude, Longitude, Altitude)
    • Time is valid
    • Position accuracy: ~5–10 feet horizontal

    Satellite Section (Right Pane)

    Seen 13 / Used 11
    

    This means:

    • The receiver can currently see 13 satellites
    • 11 of those are strong enough to be used in the solution

    This is quite a healthy signal for a device sitting inside up against a window.

    Anything above:

    • 4 used → valid 3D fix
    • 8+ used → very solid geometry
    • 10–12 used → excellent (we are here)

    Constellations

    • GP = GPS
      • U.S. GPS constellation
      • Medium Earth Orbit (≈20,200 km)
      • ~30 active satellites worldwide
    • SB = SBAS (WAAS corrections)
      • Satellite-Based Augmentation System
      • Broadcast correction data
      • Improve accuracy of GPS measurements
      • Do not provide independent position fixes

    The presence of SBAS satellites indicates differential reminder data is available, improving accuracy.

    Fix & Timing (Left Pane)

    Fix State

    Status: 3D DGPS FIX (1 secs)
    
    • 3D = Latitude, longitude, altitude solved
    • DGPS = WAAS corrections applied
    • (1 secs) = Fix age (very fresh)

    Time Quality

    Time: 2025-12-29T20:32:22.000Z
    Time offset: 0.078609772 s
    


    Chrony

    Install Chrony via apt

    # apt install chrony -y

    Configure Chrony

    Edit /etc/chrony/chrony.conf. This config has been tested on Ubuntu 22.04, YMMV on other Linux versions.

    ###############################################################################
    # Chrony configuration
    #
    # Purpose:
    # – Discipline system time using a USB GPS receiver via gpsd (NMEA-only)
    # – No PPS available, so accuracy is milliseconds (not microseconds)
    # – Act as a low-priority NTP server for the local network
    #
    # Notes:
    # – Chrony always operates internally in UTC
    # – GPS time is provided by gpsd over a UNIX socket
    ###############################################################################
    #——————————————————————————
    # Include additional configuration snippets
    #——————————————————————————
    # Allows drop-in configuration files (not required, but standard on Ubuntu)
    confdir /etc/chrony/conf.d
    ###############################################################################
    # Debug / observability
    ###############################################################################
    # Where chrony writes its own detailed log streams
    logdir /var/log/chrony
    # Enable detailed logs:
    # – tracking: disciplined clock state (offset/freq/skew, etc.)
    # – measurements: raw samples from sources (very useful for refclocks)
    # – statistics: aggregate stats per source
    log tracking measurements statistics
    # Log when chrony makes a clock correction bigger than the thresholds
    # (units: seconds). Helps correlate “why did time jump?” events.
    logchange 0.5
    #——————————————————————————
    # GPS reference clock (via gpsd)
    #——————————————————————————
    # Use gpsd's UNIX socket as a reference clock.
    #
    # SOCK /var/run/gpsd.sock
    # – Chrony does NOT talk to the GPS device directly
    # – gpsd parses NMEA and provides time samples
    #
    # refid GPS
    # – Human-readable label shown in chronyc output
    #
    # poll 4
    # – Poll interval = 2^4 seconds = 16 seconds
    #
    # precision 1e-1
    # – Declare expected precision (~100 ms)
    # – REQUIRED for NMEA-only GPS to avoid sample rejection
    #
    # delay 0.2
    # – Account for USB + NMEA sentence latency
    #
    # trust
    # – Explicitly allow chrony to accept this low-precision refclock
    #
    #refclock SOCK /run/gpsd.sock refid GPS poll 4 precision 1e-1 delay 0.2 trust prefer
    refclock SHM 0 refid GPS poll 4 precision 1e-1 delay 0.2 trust prefer
    #——————————————————————————
    # Standalone operation policy
    #——————————————————————————
    # Allow chrony to discipline the system clock even if:
    # – No network NTP servers are configured
    # – GPS is the only available reference
    #
    # Advertise this host as stratum 10 to NTP clients:
    # – Prevents it from being treated as an authoritative time source
    # – Avoids NTP loops
    # – Appropriate for NMEA-only GPS (no PPS)
    #
    local stratum 2
    #——————————————————————————
    # Clock stepping behavior
    #——————————————————————————
    # Allow the system clock to be stepped (jumped) instead of slewed
    # if the offset is larger than 1 second, but ONLY during startup
    # and only for the first 3 updates.
    #
    # This prevents long convergence times on boot while avoiding
    # disruptive time jumps during normal operation.
    #
    makestep 1.0 3
    #——————————————————————————
    # Frequency drift handling
    #——————————————————————————
    # Persist the measured frequency error of the system clock.
    #
    # This allows chrony to:
    # – Start with a good frequency estimate after reboot
    # – Converge faster
    # – Free-run more accurately if all time sources disappear
    #
    driftfile /var/lib/chrony/chrony.drift
    #——————————————————————————
    # NTP server behavior (serving time to clients)
    #——————————————————————————
    # Allow NTP clients from the local subnet to query this server
    #
    allow 10.1.10.0/24
    # Bind NTP service explicitly to this interface/address
    # (prevents listening on unintended interfaces)
    #
    bindaddress 10.1.10.11
    #——————————————————————————
    # Optional dynamic source handling
    #——————————————————————————
    # Allow chrony to use NTP servers provided via DHCP (if present)
    #
    sourcedir /run/chrony-dhcp
    # Allow additional NTP source files to be added modularly
    #
    sourcedir /etc/chrony/sources.d
    #——————————————————————————
    # Security and key material
    #——————————————————————————
    # File containing NTP authentication keys (if used)
    #
    keyfile /etc/chrony/chrony.keys
    # Directory used to store NTS (Network Time Security) cookies and keys
    #
    ntsdumpdir /var/lib/chrony
    #——————————————————————————
    # Logging
    #——————————————————————————
    # Directory where chrony logs are written
    #
    logdir /var/log/chrony
    # Uncomment the following line to enable detailed logging:
    # log tracking measurements statistics
    #——————————————————————————
    # Stability and safety controls
    #——————————————————————————
    # Prevent chrony from applying updates if clock estimates become unstable
    #
    maxupdateskew 100.0
    # Periodically sync the system time back to the hardware RTC
    # (every ~11 minutes)
    #
    rtcsync
    #——————————————————————————
    # Leap second handling
    #——————————————————————————
    # Obtain leap second and TAI-UTC offset information from the system
    # timezone database, operating in strict UTC mode.
    #
    leapsectz right/UTC
    view raw gistfile1.txt hosted with ❤ by GitHub

    Explanation of Chrony Config for GPSD

    OptionPurpose
    SOCK /var/run/gpsd.sockRead time from gpsd
    refid GPSLabel in chrony output
    poll 4Poll every 16 seconds
    precision 1e-1~100 ms accuracy (realistic for NMEA)
    delay 0.2USB + NMEA latency
    makestep 1.0 3Allow initial step corrections

    Start and Enable

    # systemctl enable chrony.service
    # systemctl start chrony.service

    After a few minutes, we should start to see pre-configured clients appear in the output of the command below

     # chronyc clients
    Hostname                      NTP   Drop Int IntL Last     Cmd   Drop Int  Last
    =============================================================================
    scar.lab                        5      0   6   -    30       0      0   -     -
    

    Chrony Client-side Setup

    Ubuntu Client

    $ sudo apt install chrony -y

    Configure the to listen to the chrony server address 10.1.10.10. Comment out any other server or pool directives in /etc/chrony/chrony.conf.

    server 10.1.10.11

    Start and enable the service.

    $ sudo systemctl enable chrony --now
    

    Check configured time source for chrony

    $ chronyc -n sources -v

    What the above output tells you

    • All NTP servers/pools configured for this client
    • Which source is currently selected
    • Reachability and time quality

    Key indicators

    SymbolMeaning
    ^*Current sync source
    ^+Candidate source
    ^-Reachable, not selected
    ^?Unusable / not trusted yet

    Cisco Catalyst Client Config

    Use the commands below to configure your Cisco switch to use the new timesource

    # Enter global configuration mode
    configure terminal
    
    # Define the NTP server
    ntp server 10.1.10.11
    
    # (Optional) Set the switch to use its own hardware clock if it loses sync
    ntp master 10
    
    # Exit and save
    end
    write memory
  • How to Install Instructlab + VLLM with Nvidia Cuda Support on Ubuntu 22.04

    How to Install Instructlab + VLLM with Nvidia Cuda Support on Ubuntu 22.04

    Installing Prerequisites

    We are installing on a very fresh install of Ubuntu 22.04 with an Nvidia 3070ti GPU. Nvidia Drivers were installed at build time. However lets check to see what version of the Nvidia driver we are currently running.

    $ nvidia-detector
    nvidia-driver-570

    While we are at it, let’s make sure that we have nvidia-smi installed which is included in the package shown below

    $ sudo apt install nvidia-utils-570
    

    We will need gcc, which the meta-package below will include (along with make and other dev tools).

    # sudo apt install build-essential -y

    Lets check what version of python we have installed.

    $ python3 --version
    Python 3.10.12
    

    Now install python-venv which is the python module that supports creating virtual environments. Reference the python version shown in the output in the step above

    # sudo apt install python3.10-venv -y

    Installing the Nvidia Cuda Toolkit

    Note: If you installed the nvidia-cuda-toolkit from default ubuntu noble repo, uninstall it first as that version is probably too old. Uninstall with “sudo apt purge nvidia-cuda* -y“

    “The NVIDIA CUDA Toolkit is a software development kit that helps users create GPU-accelerated applications. It includes libraries, compilers, debuggers, and optimization tools”. Since we have an Nvidia GPU we will install it as shown below.

    # wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/cuda-ubuntu2204.pin
    

    First we wget the Nvidia Cuda Repository pin as shown above. Then we move it to /etc/apt/preferences.d/ (shown below).

    This is a configuration file that is used to prioritize packages from the NVIDIA CUDA repository when installing CUDA on a Linux system. Basically it tells apt where to get the Cuda Toolkit.

    $ sudo mv cuda-ubuntu2204.pin /etc/apt/preferences.d/cuda-repository-pin-600

    Now we wget the repo. Note that this is a pretty hefty .deb and may take a few minutes.

    $ wget https://developer.download.nvidia.com/compute/cuda/12.8.0/local_installers/cuda-repo-ubuntu2204-12-8-local_12.8.0-570.86.10-1_amd64.deb

    And install it.

    $ sudo dpkg -i cuda-repo-ubuntu2204-12-8-local_12.8.0-570.86.10-1_amd64.deb
    $ sudo cp /var/cuda-repo-ubuntu2204-12-8-local/cuda-*-keyring.gpg /usr/share/keyrings/

    Finally we install the toolkit.

    $ sudo apt-get update
    $ sudo apt-get -y install cuda-toolkit-12-8
    $ sudo apt install cuda-runtime-12-8
    

    Nvidia states that you need to add the following env vars to your .bashrc, however you will also need to add them to your python virtual env — in venv/bin/activate. These variables will be needed during the install process below.

     export CUDA_HOME=/usr/local/cuda                           
     export PATH=${CUDA_HOME}/bin:${PATH}                       
     export LD_LIBRARY_PATH=${CUDA_HOME}/lib64:$LD_LIBRARY_PATH
    

    Installing Instructlab

    First we make a directory were we want our python virtual env to live.

    $ mkdir instructlab
    $ cd instructlab/

    Now we create the python virtual environment.

    
    $ python3 -m venv --upgrade-deps venv
    $ source venv/bin/activate

    Note that every time you want to use instructlab cli (ilab) post-install you must source the file above. venv/bin/activate

    The install guide found here has you run this command to clear out the pip package cache (for this one package. Not required for first install, but may be on subsequent install runs.

    $ pip cache remove llama_cpp_python

    We then run the 3 commands shown below. Apparently there is a known bug and we will not pick up these required packages as needed, so we need to install them manually, and in the order shown below.

    $ pip install --upgrade pip wheel setuptools
    $ pip install torch
    $ pip install flash-attn

    Now we are ready to install instructlab.

    $ pip install 'instructlab[cuda]' /
       -C cmake.args="-DLLAMA_CUDA=on" /
       -C cmake.args="-DLLAMA_NATIVE=off"

    Lets verify the install

    $ ilab --version
    ilab, version 0.24.0
    

    Installing vLLM

    The instructions have you wrap up the of Instructlab with a pip install of vllm, however this install will fail due as it cannot find nvcc without setting the env variables. So set the following env vars as shown below.

    $ export CUDA_HOME=/usr/local/cuda                           
    $ export PATH=${CUDA_HOME}/bin:${PATH}                       
    $ export LD_LIBRARY_PATH=${CUDA_HOME}/lib64:$LD_LIBRARY_PATH

    The instructions for installing instructlab with Nvidia Cuda support as documented on instructlab.ai currently have you pip install a very specific version of vllm (with cuda support), however I have found that this command will fail (at least on Fedora 40, Ubuntu 22.04, and Ubuntu 24.04) that command is shown below.

    $ pip install vllm@git+https://github.com/opendatahub-io/vllm@2024.08.01

    So this is a method that I have found to work around the issue.

    First run pip install on vllm

    $ pip install vllm

    Confirm vllm installed correctly.

    $ pip show vllm
    Name: vllm
    Version: 0.7.3
    Summary: A high-throughput and memory-efficient inference and serving engine for LLMs
    Home-page: https://github.com/vllm-project/vllm
    Author: vLLM Team
    Author-email: 
    License: Apache License
    
    Author-email: 
    License: Apache 2.0
    Location: /home/cpaquin/Workspace/instructlab/venv/lib/python3.10/site-packages
    Requires: aiohttp, cmake, fastapi, filelock, lm-format-enforcer, ninja, numpy, nvidia-ml-py, openai, outlines, pillow, prometheus-fastapi-instrumentator, prometheus_client, psutil, py-cpuinfo, pydantic, pyzmq, requests, sentencepiece, tiktoken, tokenizers, torch, torchvision, tqdm, transformers, typing_extensions, uvicorn, vllm-flash-attn, xformers
    

    Now remove vllm

    $ pip uninstall vllm

    Now run the original pip install command as documented

    $ pip install vllm@git+https://github.com/opendatahub-io/vllm@2024.08.01

    Now check vllm version, which we can see has cuda support

    $ pip show vllm
    Name: vllm
    Version: 0.5.2.3+cu128
    Summary: A high-throughput and memory-efficient inference and serving engine for LLMs
    Home-page: https://github.com/vllm-project/vllm
    Author: vLLM Team
    Author-email: 
    License: Apache 2.0
    Location: /home/cpaquin/Workspace/instructlab/venv/lib/python3.10/site-packages
    Requires: aiohttp, cmake, fastapi, filelock, lm-format-enforcer, ninja, numpy, nvidia-ml-py, openai, outlines, pillow, prometheus-fastapi-instrumentator, prometheus_client, psutil, py-cpuinfo, pydantic, pyzmq, requests, sentencepiece, tiktoken, tokenizers, torch, torchvision, tqdm, transformers, typing_extensions, uvicorn, vllm-flash-attn, xformers
    Required-by: 
    

    Testing VLLM

    Below is the command that I ran to test that vllm is working and is in fact, leveraging the GPU

    $ vllm serve "TinyLlama/TinyLlama-1.1B-Chat-v1.0" --dtype float16 --gpu-memory-utilization 0.8

    One up and running you will see output similar to what is shown below.

    INFO:     Started server process [1252947]
    INFO:     Waiting for application startup.
    INFO:     Application startup complete.
    INFO:     Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
    

    Testing Pytorch Module

    You can create and run the python script below to test if your GPU is identified correctly. This step is not required, but its handy in identifying potential issues with gpu/cuda.

    import torch
    print("CUDA available:", torch.cuda.is_available())
    print("CUDA version:", torch.version.cuda)
    print("Torch version:", torch.__version__)
    print("GPU count:", torch.cuda.device_count())
    print("GPU name:", torch.cuda.get_device_name(0) if torch.cuda.is_available() else "None")

    Output below for reference.

    $ python3 ./test.py 
    CUDA available: True
    CUDA version: 12.4
    Torch version: 2.5.1+cu124
    GPU count: 1
    GPU name: NVIDIA GeForce RTX 3070 Ti

    Instructlab Init and Setup

    Now that we have ilab installed we can initialize our environment with the command below. This command will download the Taxonomy repository to our local machine along with a config file. Apparently ilab init has a few default GPUs available to choose from, but since my current GPU is

    Our config file is located in our home directory, if you want to take a look. Note that our GPU, being a Nvidia RTX 3070 TI, will have differing config values than what we selected above (A100), so in a later step we will need to edit our config

    /home/cpaquin/.config/instructlab/config.yaml

    To see the info regarding your workstation, you can run the command below. We will use some of the data below to update our config

     ilab system info
    Platform:
      sys.version: 3.10.12 (main, Jan 17 2025, 14:35:34) [GCC 11.4.0]
      sys.platform: linux
      os.name: posix
      platform.release: 6.8.0-52-generic
      platform.machine: x86_64
      platform.node: scar-Z97-HD3
      platform.python_version: 3.10.12
      os-release.ID: ubuntu
      os-release.VERSION_ID: 22.04
      os-release.PRETTY_NAME: Ubuntu 22.04.5 LTS
      memory.total: 31.30 GB
      memory.available: 27.11 GB
      memory.used: 3.60 GB
    
    InstructLab:
      instructlab.version: 0.24.0
      instructlab-dolomite.version: 0.2.0
      instructlab-eval.version: 0.5.1
      instructlab-quantize.version: 0.1.0
      instructlab-schema.version: 0.4.2
      instructlab-sdg.version: 0.7.0
      instructlab-training.version: 0.7.0
    
    Torch:
      torch.version: 2.3.1+cu121
      torch.backends.cpu.capability: AVX2
      torch.version.cuda: 12.1
      torch.version.hip: None
      torch.cuda.available: True
      torch.backends.cuda.is_built: True
      torch.backends.mps.is_built: False
      torch.backends.mps.is_available: False
      torch.cuda.bf16: True
      torch.cuda.current.device: 0
      torch.cuda.0.name: NVIDIA GeForce RTX 3070 Ti
      torch.cuda.0.free: 7.1 GB
      torch.cuda.0.total: 7.7 GB
      torch.cuda.0.capability: 8.6 (see https://developer.nvidia.com/cuda-gpus#compute)
    
    llama_cpp_python:
      llama_cpp_python.version: 0.3.6
      llama_cpp_python.supports_gpu_offload: False
    

    Editing Generated Config

    Use the command below to edit the generated config.

    $ ilab config edit

    Here we go through the file and ensure that we are setting the number of GPUs correctly. We also modify some additonal settings that have differed from the default (as ilab thinks we now have a $40k GPU). Below is some of what we have configured.

    # Metadata pertaining to the specifics of the system which the Configuration is
    # meant to be applied to.
    metadata:
      # Manufacturer, Family, and SKU of the system CPU, ex: Apple M3 Max
      # Default: None
      cpu_info:
      # Amount of GPUs on the system, ex: 8
      # Default: None
      gpu_count: 1
      # Family of the system GPU, ex: H100
      # Default: None
      gpu_family: RTX 3070 TI
      # Manufacturer of the system GPU, ex: Nvidia
      # Default: None
      gpu_manufacturer: Nvidia
      # Specific SKU related information about the given GPU, ex: PCIe, NVL
      # Default: None
      gpu_sku:
    
    


    Working with Models

    Before we start working with a model, lets take a look at the ilab command parameters. We can see that we have several options such as download, list, test, train, chat, serve, etc.

    Lets download a model with the command below. The command below will download the default model sets in the config file

    $ ilab model download

    output below

    View your downloaded models via the command below

    $ ilab model list

    Now we serve the default model with the command below

    $ ilab model serve

    Open another terminal window and source the env file from the instructlab directory

    $ source venv/bin/activate
    

    Then run the command below to begin an interactive chat session

    $ ilab model chat

    References

    1. https://developer.nvidia.com/cuda-downloads?target_os=Linux&target_arch=x86_64&Distribution=Ubuntu&target_version=22.04&target_type=deb_local
    2. https://github.com/instructlab/instructlab/issues/2422
    3. https://github.com/instructlab/instructlab
    4. https://developers.redhat.com/blog/2024/06/12/getting-started-instructlab-generative-ai-model-tuning#getting_started_with_instructlab
    5. https://www.techtarget.com/searchcio/definition/synthetic-data#:~:text=Synthetic%20data%20is%20increasingly%20used,fresh%20domain%20knowledge%20and%20explainability.
    6. https://docs.nvidia.com/cuda/cuda-installation-guide-linux/#meta-packages
    7. https://docs.redhat.com/en/documentation/red_hat_enterprise_linux_ai/1.2/html/building_your_rhel_ai_environment/initializing_instructlab#initialize_ilab

  • Step-by-Step Nvidia CUDA Toolkit Installation Guide: Ubuntu 24.04

    Step-by-Step Nvidia CUDA Toolkit Installation Guide: Ubuntu 24.04

    “The NVIDIA CUDA Toolkit is a software development kit that helps users create GPU-accelerated applications. It includes libraries, compilers, debuggers, and optimization tools”. Since we have an Nvidia GPU we will install it as shown below.

    Note: If you installed the nvidia-cuda-toolkit from default ubuntu noble repo, uninstall it first as that we do not want conflicts. Uninstall with “sudo apt purge nvidia-cuda* -y“. More info on ubuntu repo install vs nvidia repo install later in post.

    # wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2404/x86_64/cuda-ubuntu2404.pin
    

    First we wget the Nvidia Cuda Repository pin as shown above. Then we move it to /etc/apt/preferences.d/ (shown below).

    This is a configuration file that is used to prioritize packages from the NVIDIA CUDA repository when installing CUDA on a Linux system. Basically it tells apt where to get the Cuda Toolkit.

    $ sudo mv cuda-ubuntu2404.pin /etc/apt/preferences.d/cuda-repository-pin-600

    Now we wget the repo. Note that this is a pretty hefty .deb and may take a few minutes.

    $ wget https://developer.download.nvidia.com/compute/cuda/12.8.0/local_installers/cuda-repo-ubuntu2404-12-8-local_12.8.0-570.86.10-1_amd64.deb

    And install it.

    $ sudo dpkg -i cuda-repo-ubuntu2404-12-8-local_12.8.0-570.86.10-1_amd64.deb
    $ sudo cp /var/cuda-repo-ubuntu2404-12-8-local/cuda-*-keyring.gpg /usr/share/keyrings/

    Finally we install the toolkit.

    $ sudo apt-get update
    $ sudo apt-get -y install cuda-toolkit-12-8
    $ sudo apt install cuda-runtime-12-8
    

    Update $Path

    Add the the following to your path

    /usr/local/cuda-12.8/bin

    Installing the Nvidia Cuda toolkit from Ubuntu Vs Nvidia

    The key differences between installing the NVIDIA CUDA Toolkit from the Ubuntu repositories vs. NVIDIA’s official website come down to version availability, ease of installation, and compatibility. Here’s are a few differences:

    1. Installing from Ubuntu Repositories (apt install nvidia-cuda-toolkit)

    Pros:

    • Easier installation – The package is well-integrated into Ubuntu’s package management (apt), meaning dependency resolution is generally smoother.
    • More stable – The versions in the repositories are tested against the Ubuntu ecosystem to ensure compatibility.
    • Automatic updates – Managed through apt, making it easier to keep up with system updates.

    Cons:

    • Often outdated – Ubuntu’s repositories may not have the latest CUDA version, which can be an issue if you need newer features or performance improvements.
    • Limited driver version control – The version of CUDA available in the Ubuntu repos may not always match the latest NVIDIA drivers, which can lead to compatibility issues.

    2. Installing from NVIDIA’s Official Website

    Pros:

    • Latest version – You get the newest CUDA Toolkit, which can include performance improvements, bug fixes, and new features.
    • Better control over versions – You can install specific versions to match requirements for AI/ML frameworks like TensorFlow or PyTorch.
    • More driver compatibility – NVIDIA ensures that the toolkit and drivers are aligned, reducing the risk of version mismatches.

    Cons:

    • More manual setup – You have to install dependencies manually, such as the correct NVIDIA driver, and configure paths properly.
    • Updates are not automatic – Unlike apt, updates need to be managed manually.
  • Step-by-Step Nvidia CUDA Toolkit Installation Guide: Ubuntu 22.04

    Step-by-Step Nvidia CUDA Toolkit Installation Guide: Ubuntu 22.04

    “The NVIDIA CUDA Toolkit is a software development kit that helps users create GPU-accelerated applications. It includes libraries, compilers, debuggers, and optimization tools”. Since we have an Nvidia GPU we will install it as shown below.

    Note: If you installed the nvidia-cuda-toolkit from default ubuntu noble repo, uninstall it first as that version is probably too old. Uninstall with “sudo apt purge nvidia-cuda* -y“

    # wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/cuda-ubuntu2204.pin
    

    First we wget the Nvidia Cuda Repository pin as shown above. Then we move it to /etc/apt/preferences.d/ (shown below).

    This is a configuration file that is used to prioritize packages from the NVIDIA CUDA repository when installing CUDA on a Linux system. Basically it tells apt where to get the Cuda Toolkit.

    $ sudo mv cuda-ubuntu2204.pin /etc/apt/preferences.d/cuda-repository-pin-600

    Now we wget the repo. Note that this is a pretty hefty .deb and may take a few minutes.

    $ wget https://developer.download.nvidia.com/compute/cuda/12.8.0/local_installers/cuda-repo-ubuntu2204-12-8-local_12.8.0-570.86.10-1_amd64.deb

    And install it.

    $ sudo dpkg -i cuda-repo-ubuntu2204-12-8-local_12.8.0-570.86.10-1_amd64.deb
    $ sudo cp /var/cuda-repo-ubuntu2204-12-8-local/cuda-*-keyring.gpg /usr/share/keyrings/

    Finally we install the toolkit.

    $ sudo apt-get update
    $ sudo apt-get -y install cuda-toolkit-12-8
    $ sudo apt install cuda-runtime-12-8
    

    Nvidia states that you need to add the following env vars to your .bashrc, however you will also need to add them to your python virtual env — in venv/bin/activate. These variables will be needed during the install process below.

     export CUDA_HOME=/usr/local/cuda                           
    export PATH=${CUDA_HOME}/bin:${PATH}
    export LD_LIBRARY_PATH=${CUDA_HOME}/lib64:$LD_LIBRARY_PATH

    Update $PATH

    The the following to your path

    /usr/local/cuda-12.8/bin

    Reference

    1. https://developer.nvidia.com/cuda-downloads