Performance issues on Linux usually arrive as slow logins, delayed API responses, stalled batch jobs, or terminals that pause between keystrokes. Capturing a few short pressure snapshots while the symptom is happening helps separate CPU contention, memory pressure, storage wait, and network delay before the evidence disappears.

Start with host-wide counters before chasing individual processes. uptime shows whether work is queueing, vmstat shows runnable tasks, blocked tasks, swap movement, and I/O wait during the sample window, and ps identifies the process IDs that can be inspected or handled next.

Treat the first pass as triage rather than a benchmark. Avoid heavy load tests on an already slow host, keep samples short, and tie any restart, priority change, or process kill to one observed signal instead of guessing from a single high number.

Steps to troubleshoot performance issues in Linux:

  1. Capture the current load averages.
    $ uptime
     20:42:51 up 1 day,  8:47,  0 users,  load average: 0.32, 0.46, 0.48

    The three load averages cover the last 1, 5, and 15 minutes. Load includes runnable work and tasks stuck in uninterruptible I/O sleep, so a high value is not always CPU saturation.

  2. Count the processors available to the current session.
    $ nproc
    8

    Compare load averages with the CPU count available to the process. Containers, CPU affinity, and scheduler limits can make this lower than the physical host CPU count.

  3. Sample run queue, blocked tasks, swap, and I/O wait with vmstat.
    $ vmstat 1 5
    procs -----------memory---------- ---swap-- -----io---- -system-- -------cpu-------
     r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st gu
     1  0      0 7497488 678080 3323428    0    0    17  1174  442    0  0  0 100  0  0  0
     0  0      0 7497488 678080 3323428    0    0     0     0  206  279  0  0 100  0  0  0
     0  0      0 7497488 678080 3323428    0    0     0     0  217  284  0  0 100  0  0  0
     0  0      0 7497488 678080 3323428    0    0     0     0  441  649  0  0 100  0  0  0
     0  0      0 7497488 678080 3323428    0    0     0     0  804 1041  0  0 100  0  0  0

    Ignore a one-off spike and read the interval rows together. Persistent r near or above CPU count points toward CPU queueing, b shows blocked tasks, si and so show swap activity, and wa shows CPU time spent waiting on I/O.

  4. Check available memory and swap state.
    $ free -h
                   total        used        free      shared  buff/cache   available
    Mem:            11Gi       966Mi       7.2Gi        29Mi       3.8Gi        10Gi
    Swap:          4.0Gi          0B       4.0Gi

    Low free memory is not pressure by itself when available remains high. Treat sustained swap-in activity from vmstat or growing pressure counters as a stronger signal.

  5. List the current CPU-heavy processes.
    $ ps -eo pid,user,stat,comm,pcpu,pmem --sort=-pcpu
        PID USER     STAT COMMAND         %CPU %MEM
       3782 app      R    python3         96.4  4.8
       2249 root     Sl   backup           8.1  1.0
          1 root     Ss   systemd          0.3  0.3
        686 message+ Ss   dbus-daemon      0.0  0.1
    ##### snipped #####

    The STAT column helps distinguish runnable tasks from blocked tasks. A D state usually means the task is waiting in uninterruptible I/O sleep.

  6. List the current resident-memory-heavy processes.
    $ ps -eo pid,user,stat,comm,rss,pmem --sort=-rss
        PID USER     STAT COMMAND           RSS %MEM
       3782 app      R    python3        524288  4.8
       2249 root     Sl   backup         112640  1.0
        311 root     Ss   systemd-journ   17368  0.4
          1 root     Ss   systemd         12660  0.3
    ##### snipped #####

    RSS is resident memory in KiB. Use it with %MEM to find processes holding physical memory, not just large virtual address spaces.

  7. Check per-device storage pressure when vmstat shows blocked tasks or I/O wait.
    $ iostat -xz 1 3
    Linux 6.12.76 (server) 	06/13/26 	(8 CPU)
    
    avg-cpu:  %user   %nice %system %iowait  %steal   %idle
               0.27    0.00    0.14    0.04    0.00   99.55
    
    Device            r/s     rkB/s   rrqm/s  %rrqm r_await rareq-sz     w/s     wkB/s   wrqm/s  %wrqm w_await wareq-sz     d/s     dkB/s   drqm/s  %drqm d_await dareq-sz     f/s f_await  aqu-sz  %util
    vda              0.47      4.43     0.21  30.41    0.38     9.41   11.80   1171.89    48.09  80.29    1.86    99.29    4.10  15979.95     0.00   0.00    0.12  3894.32    6.98    0.19    0.02   0.32
    ##### snipped #####

    iostat is usually provided by the sysstat package. High await or %util during the same window as application stalls points toward storage or virtual-disk latency.

  8. Measure network latency when only remote work is slow.
    $ ping -c 4 1.1.1.1
    PING 1.1.1.1 (1.1.1.1) 56(84) bytes of data.
    64 bytes from 1.1.1.1: icmp_seq=1 ttl=63 time=7.14 ms
    64 bytes from 1.1.1.1: icmp_seq=2 ttl=63 time=6.80 ms
    64 bytes from 1.1.1.1: icmp_seq=3 ttl=63 time=6.97 ms
    64 bytes from 1.1.1.1: icmp_seq=4 ttl=63 time=7.87 ms
    
    --- 1.1.1.1 ping statistics ---
    4 packets transmitted, 4 received, 0% packet loss, time 3012ms
    rtt min/avg/max/mdev = 6.797/7.194/7.871/0.409 ms

    Use the affected service hostname when DNS or load-balancer routing may be part of the slowdown. Use a stable comparison target only when the question is broader network path quality.

  9. Act on the confirmed bottleneck with the least disruptive change.

    For a non-critical CPU-heavy process, lower priority before killing it. For memory pressure, move or restart the leaking workload during an approved window. For storage wait, pause the heavy write job and check disk errors. For remote-only delay, continue with network outage checks.

  10. Repeat the vmstat sample after the change.
    $ vmstat 1 5
    procs -----------memory---------- ---swap-- -----io---- -system-- -------cpu-------
     r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st gu
     0  0      0 7499276 678080 3323432    0    0     0     0  229  315  0  0 100  0  0  0
     0  0      0 7499276 678080 3323432    0    0     0     0  226  305  0  0 100  0  0  0
     0  0      0 7499276 678080 3323432    0    0     0     0  311  425  0  0 100  0  0  0
     0  0      0 7499276 678080 3323432    0    0     0     0  218  296  0  0 100  0  0  0
     0  0      0 7499276 678080 3323432    0    0     0     0  232  318  0  0 100  0  0  0

    The original symptom should improve in the same window as the pressure signal. If the signal clears but the application remains slow, continue with application logs, service health, and dependency checks instead of repeating host-level triage.