1. Introduction

Although they’re often barebone, Linux machines sometimes have a graphical processing unit (GPU), also known as a video or graphics card. Be it for cryptocurrency mining, a gaming server, or just for a better desktop experience, active graphics card monitoring and control can be essential.

In this tutorial, we’ll discuss ways to check which GPU is currently active and in use. First, we describe some common video card setups. Next, ways to enumerate graphics controllers are explored. After that, we look at renderer information as a means to acquire GPU information. Finally, we delve into driver utilities and ways to list graphics usage by process.

We tested the code in this tutorial on Debian 11 (Bullseye) with GNU Bash 5.1.4. It should work in most POSIX-compliant environments.

2. GPU Setup

GPUs can vary widely in terms of their memory, speed, and performance. Because of this, machines sometimes have two or more of them.

For example, multi-monitor gaming can be optimized with dual, triple, or more video cards. In most cases, this means several of the same GPU. In other setups, cards can be different. For instance, with three-dimensional (3D) rendering, it matters whether we want live or static images.

On the other hand, cryptocurrency mining and other GPU-intensive applications are sensitive to failing hardware. In such setups, we should be able to easily see and fix faults.

Finally, GPUs can be discrete (external) or integrated (internal). When both types are available, the ability to switch between them is not only convenient but often required.

Of course, it’s vital to know the make and model of a card to find the right tools for the job.

3. Listing Devices With pciutils and lshw

Since the majority of video cards on the market run on PCI (Express), we can extract basic information targeting these bus architectures.

For instance, to find the graphics card model and make, we use lspci, part of the pciutils package:

$ lspci
00:00.0 Host bridge: Intel Corporation 440BX/ZX/DX - 82443BX/ZX/DX Host bridge (AGP disabled) (rev 03)
00:03.0 VGA compatible controller: Intel Corporation Haswell-ULT Integrated Graphics Controller (rev 0b)
00:07.0 ISA bridge: Intel Corporation 82371AB/EB/MB PIIX4 ISA (rev 01)
00:07.1 IDE interface: Intel Corporation 82371AB/EB/MB PIIX4 IDE (rev 01)
00:07.3 Bridge: Intel Corporation 82371AB/EB/MB PIIX4 ACPI (rev 02)
01:00.0 Display controller: Advanced Micro Devices, Inc. [AMD/ATI] Sun LE [Radeon HD 8550M / R5
02:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller (rev 10)

Here, we see there are two GPUs: one external and one – integrated. Moreover, we know their exact manufacturer and type from the text after VGA compatible controller and Display Controller.

Alternatively, we can use the lshw (List Hardware) tool:

$ lshw -C display
  *-display
       description: VGA compatible controller
       product: Hyper-V virtual VGA
       vendor: Microsoft Corporation
       physical id: 8
       bus info: pci@0000:00:08.0
       version: 00
       width: 32 bits
       clock: 33MHz
       capabilities: vga_controller bus_master
       configuration: driver=hyperv_fb latency=0
       resources: irq:11 memory:f8000000-fbffffff memory:c0000-dffff
  *-graphics
       product: hyperv_fb
       physical id: 1
       logical name: /dev/fb0
       capabilities: fb
       configuration: depth=32 resolution=1024,768

Note the above output is from a virtual machine. However, the product and vendor should show the data we’re after.

Let’s look at another way to get these details, but via OpenGL and Mesa.

4. Display Renderer Information

Once we have the hardware as identified by the system, we can review it based on the display renderer. For this purpose, we can use glxinfo (Graphics Library Extension Information):

 $ glxinfo -B
name of display: :0
display: :0  screen: 0
[...]
OpenGL vendor string: X.Org
OpenGL renderer string: AMD RV620 (DRM 2.50.0 / 5.10.12-arch1-1, LLVM 11.0.1)
[...]

Note that we need to have a display open to acquire its properties. In fact, this means we’re actually seeing the GPU used to render a display, i.e., the active video card for it.

Alternatively, we can run xrandr with its –listproviders switch:

$ xrandr --listproviders
Providers: number : 2
Provider 0: id: 0x11f cap: 0x1, Source Output crtcs: 4 outputs: 6 associated providers: 0 name:NVIDIA-0
Provider 1: id: 0x52 cap: 0x2, Sink Output crtcs: 3 outputs: 3 associated providers: 0 name:modesetting

The output of xrandr depends on the current configuration and physical connections. In particular, NVIDIA-0 above means we’re using that driver for the current display.

In general, the tool we use for more in-depth checks strongly depends on the used drivers.

5. GPU Utilities

Indeed, the best way to manage a GPU is via targeted tools. Since the video card market is a duopoly, we’re going to look at the two major vendors.

5.1. NVIDIA

For this brand, the main utilities are in the nvidia-utils or general driver package. In particular, nvidia-smi can supply ample data:

$ nvidia-smi
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 390.14                 Driver Version: 390.14                    |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  GeForce GTX TIT...  Off  | 0000:04:00.0     Off |                  N/A |
| 21%   50C    P8    31W / 250W |  11666MiB / 16280MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
|   1  GeForce GTX TIT...  Off  | 0000:06:00.0     Off |                  N/A |
| 21%   60C    P8    18W / 250W |    666MiB / 16280MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
|   2  GeForce GTX TIT...  Off  | 0000:07:00.0     Off |                  N/A |
| 25%   66C    P2    72W / 250W |   8656MiB / 12207MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+

+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
| GPU        PID    Type   Process name                                 Usage |
|=============================================================================|
|   1        666       G   /usr/bin/X                                 587 MiB |
|   0        667       C   perl                                     11307 MiB |
[...]
+-----------------------------------------------------------------------------+

We see three NVIDIA cards with different amounts of memory usage on each. Also, the bottom table shows processes using a video card.

In fact, the first column is a reference to the top table and contains the GPU number in use. Because of this, we have an overview and statistics of graphic card activity and usage.

5.2. AMD

Likewise, the aticonfig in the legacy ATI/AMD Catalyst drivers package can serve a similar purpose:

$ aticonfig --odgc --odgt
Default Adapter - AMD Radeon HD 7970
                            Core (MHz)   Memory (MHz)
           Current Clocks :     880         1375
             Current Peak :     880         1375
  Configurable Peak Range : [800-1000]   [1300-1600]
                 GPU load :    66%

Default Adapter - AMD Radeon HD 7970
           Sensor 0: Temperature - 66.60 C

Notice the scarcity of data in this case. Moreover, the newer AMDGPU All-Open and AMDGPU-Pro drivers do not yet seem to provide such tools.

With this output at hand, let’s explore more ways to check which the active GPU is and what it’s working on.

6. More Active Video Card Detection Methods

With NVIDIA, to ensure we run a display or tool with a discrete card, we can use optirun (Optimized Run) or its successor primusrun, both parts of bumblebee packages:

$ primusrun glxinfo | grep OpenGL
OpenGL vendor string: NVIDIA Corporation
OpenGL renderer string: GeForce 940M/PCIe/SSE2
OpenGL core profile version string: 4.5.0 NVIDIA 387.34
OpenGL core profile shading language version string: 4.50 NVIDIA
OpenGL core profile context flags: (none)
OpenGL core profile profile mask: core profile
OpenGL core profile extensions:
OpenGL version string: 4.6.0 NVIDIA 387.34
OpenGL shading language version string: 4.60 NVIDIA
OpenGL context flags: (none)
OpenGL profile mask: (none)
OpenGL extensions:

We see that a GeForce card is the active NVIDIA GPU. As of this writing, no similar tool exists for AMD.

Furthermore, we can confirm which process is using an external card via the radeontop or nvtop tools. The latter provides tons of data and options:

$ nvtop
 Device 0 [NVIDIA GeForce GTX 1060 6GB] PCIe GEN 3@ 8x RX: 328.1 MiB/s TX: 28.32 MiB/s
 GPU 1518MHz MEM 4006mhz TEMP  45 C FAN  27% POW  28 / 120 W
 GPU[|||                     12%] MEM[||                0.404Gi/5.933Gi]
 Device 1 [NVIDIA GeForce GTX 1060 6GB] PCIe GEN 1@ 8x RX: 0.000 KiB/s TX: 0.000 KiB/s
 GPU 139MHz  MEM 405MHz  TEMP  30 C FAN  33% POW   6 / 120 W
Setup       Chart Options              Metric Displayed in Graph (NVIDIA GeForce GTX 1060)
General     [ ] Reverse plot direction Maximum of 4 metrics per GPU
Devices      -> Displayed all GPUs     [*] GPU utilization rate
Chart     >  -> Displayed GPU 0        [ ] GPU memory utilization rate
Processes    -> Displayed GPU 1        [*] GPU encoder rate
                                       [ ] GPU decoder rate
                                       [ ] GPU temperature
                                       [ ] Power draw rate (current/max)
                                       [ ] Fan speed
                                       [ ] GPU clock rate
                                       [ ] GPU memory clock rate
                                                                                           
                                                                                           
EnterToggle ESCExit Arrow keysNavigate Menu +/-Increment/Decrement Values F12Save Config

In contrast, radeontop is fairly limited:

$ radeontop
      radeontop v1.2-29-g50cc248, running on VEGA10 bus 44, 120 samples/sec      
                                                                                 
                    Graphics pipe  81,67% |]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]
------------------------------------------+--------------------------------------
                     Event engine   0,00% |                                      
      Vertex Grouper + Tesselator  10,00% |]]]
                                          |                                      
                Texture addresser  41,67% |]]]]]]]]]]]]]]]                       
                                          |                                      
                    Shared Export  52,50% |]]]]]]]]]]]]]]]]]]]
      Sequencer Instruction Cache   1,67% |
              Shader Interpolator  55,00% |]]]]]]]]]]]]]]]]]]]]
                                          |                                      
                   Scan Converter  57,50% |]]]]]]]]]]]]]]]]]]]]]
               Primitive Assembly  13,33% |]]]]
                                          |                                      
                      Depth Block  50,00% |]]]]]]]]]]]]]]]]]
                      Color Block  50,00% |]]]]]]]]]]]]]]]]]
                                          |                                      
                496M / 8143M VRAM   6,10% |]]
                 153M / 8166M GTT   1,87% |
       0,95G / 0,94G Memory Clock 100,00% |]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]
       1,77G / 1,75G Shader Clock 101,33% |]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]
[...]

Obviously, both aim to copy the interface of the Linux top. Active cards are identified via their memory usage.

In the case of radeontop with multiple GPUs, we have to choose the bus via -b (–bus) to view details for a given card.

7. Summary

In this article, we looked at options to check and monitor the active video card of a Linux system. In conclusion, there are both universal and specialized ways to get this data, with the latter depending on drivers and external utilities.