Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ NVTOP Options and Interactive Commands
NVTOP has a builtin setup utility that provides a way to specialize the interface to your needs.
Simply press ``F2`` and select the options that are the best for you.

In the ``Chart`` section you can choose which metrics are plotted, including GPU and memory
utilization, temperature, power, clocks, and the **PCIe RX / TX load** (the receive and transmit
throughput as a percentage of the maximum link bandwidth).

![NVTOP Setup Window](/screenshot/Nvtop-config.png)

### Saving Preferences
Expand Down
2 changes: 2 additions & 0 deletions include/nvtop/interface_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ enum plot_information {
plot_gpu_clock_rate,
plot_gpu_mem_clock_rate,
plot_effective_load_rate,
plot_pcie_rx_rate,
plot_pcie_tx_rate,
plot_information_count
};

Expand Down
37 changes: 37 additions & 0 deletions include/nvtop/pcie_utilization.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
*
* Copyright (C) 2024 Maxime Schmitt <maxime.schmitt91@gmail.com>
*
* This file is part of Nvtop.
*
* Nvtop is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Nvtop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with nvtop. If not, see <http://www.gnu.org/licenses/>.
*
*/

#ifndef PCIE_UTILIZATION_H__
#define PCIE_UTILIZATION_H__

#include "nvtop/extract_gpuinfo_common.h"

// Returns the maximum unidirectional PCIe bandwidth in KB/s derived from the link
// generation and width, or 0 if it cannot be determined. The per-lane figures use the
// effective data rate after PCIe encoding overhead (8b/10b for gen 1/2, 128b/130b for
// gen 3+, FLIT for gen 6).
unsigned pcie_max_bandwidth_kbs(const struct gpuinfo_static_info *static_info);

// Converts an instantaneous PCIe throughput (KB/s) to a 0-100% load relative to the
// maximum link bandwidth. Returns 0 when the maximum bandwidth cannot be determined.
unsigned pcie_load_percent(unsigned value_kbs, const struct gpuinfo_static_info *static_info);

#endif // PCIE_UTILIZATION_H__
2 changes: 1 addition & 1 deletion manpage/nvtop.in
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ This section deals with general interface options. \fBColor support\fR and \fBin
This section deals with the devices display (top of the interface). You can \fBswitch the temperature scale to fahrenheit\fR and \fBset the encoder/decoder hiding timer\fR.
.TP
.I Chart
This section deals with the line plots (middle of the interface). You can \fBreverse the plot direction\fR and \fBselect which metric is being shown in the plots\fR.
This section deals with the line plots (middle of the interface). You can \fBreverse the plot direction\fR and \fBselect which metric is being shown in the plots\fR. The available metrics are GPU utilization, GPU memory utilization, encoder rate, decoder rate, temperature, power draw rate, fan speed, GPU clock rate, GPU memory clock rate, effective load rate and PCIe RX / TX load. The PCIe RX and TX load are the receive and transmit throughput expressed as a percentage of the maximum link bandwidth (link generation times link width).
.TP
.I Processes
This section deals with the process list (bottom of the interface). You can \fBselect the sort order\fR, \fBselect the metric by which to sort the processes by\fR and \fBselect which metric is displayed\fR.
Expand Down
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ add_executable(nvtop
interface_setup_win.c
interface_ring_buffer.c
extract_gpuinfo.c
pcie_utilization.c
time.c
plot.c
ini.c
Expand Down
15 changes: 15 additions & 0 deletions src/interface.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "nvtop/interface_options.h"
#include "nvtop/interface_ring_buffer.h"
#include "nvtop/interface_setup_win.h"
#include "nvtop/pcie_utilization.h"
#include "nvtop/plot.h"
#include "nvtop/time.h"

Expand Down Expand Up @@ -1736,6 +1737,14 @@ void save_current_data_to_ring(struct list_head *devices, struct nvtop_interface
data_val = device->dynamic_info.effective_load_rate;
}
break;
case plot_pcie_rx_rate:
if (GPUINFO_DYNAMIC_FIELD_VALID(&device->dynamic_info, pcie_rx))
data_val = pcie_load_percent(device->dynamic_info.pcie_rx, &device->static_info);
break;
case plot_pcie_tx_rate:
if (GPUINFO_DYNAMIC_FIELD_VALID(&device->dynamic_info, pcie_tx))
data_val = pcie_load_percent(device->dynamic_info.pcie_tx, &device->static_info);
break;
case plot_information_count:
break;
}
Expand Down Expand Up @@ -1805,6 +1814,12 @@ static unsigned populate_plot_data_from_ring_buffer(const struct nvtop_interface
case plot_effective_load_rate:
snprintf(plot_legend[in_processing], PLOT_MAX_LEGEND_SIZE, "GPU%u eff. load%%", dev_id);
break;
case plot_pcie_rx_rate:
snprintf(plot_legend[in_processing], PLOT_MAX_LEGEND_SIZE, "GPU%u PCIe RX%%", dev_id);
break;
case plot_pcie_tx_rate:
snprintf(plot_legend[in_processing], PLOT_MAX_LEGEND_SIZE, "GPU%u PCIe TX%%", dev_id);
break;
case plot_information_count:
break;
}
Expand Down
3 changes: 2 additions & 1 deletion src/interface_options.c
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,8 @@ static const char device_monitor[] = "Monitor";
static const char device_shown_value[] = "ShownInfo";
static const char *device_draw_vals[plot_information_count + 1] = {
"gpuRate", "gpuMemRate", "encodeRate", "decodeRate", "temperature",
"powerDrawRate", "fanSpeed", "gpuClockRate", "gpuMemClockRate", "effectiveLoadRate", "none"};
"powerDrawRate", "fanSpeed", "gpuClockRate", "gpuMemClockRate", "effectiveLoadRate",
"pcieRxRate", "pcieTxRate", "none"};

static int nvtop_option_ini_handler(void *user, const char *section, const char *name, const char *value) {
struct nvtop_option_ini_data *ini_data = (struct nvtop_option_ini_data *)user;
Expand Down
6 changes: 3 additions & 3 deletions src/interface_setup_win.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,9 @@ static const char *setup_chart_all_gpu_description = "Displayed all GPUs";
static const char *setup_chart_gpu_description = "Displayed GPU";

static const char *setup_chart_gpu_value_descriptions[plot_information_count] = {
"GPU utilization rate", "GPU memory utilization rate", "GPU encoder rate", "GPU decoder rate",
"GPU temperature", "Power draw rate (current/max)", "Fan speed", "GPU clock rate",
"GPU memory clock rate", "Effective load rate"};
"GPU utilization rate", "GPU memory utilization rate", "GPU encoder rate", "GPU decoder rate",
"GPU temperature", "Power draw rate (current/max)", "Fan speed", "GPU clock rate",
"GPU memory clock rate", "Effective load rate", "PCIe RX load rate", "PCIe TX load rate"};

static const char *chart_color_names[] = {"Red", "Cyan", "Green", "Yellow", "Blue", "Magenta", "White"};
static const unsigned chart_color_names_count = ARRAY_SIZE(chart_color_names);
Expand Down
60 changes: 60 additions & 0 deletions src/pcie_utilization.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
*
* Copyright (C) 2024 Maxime Schmitt <maxime.schmitt91@gmail.com>
*
* This file is part of Nvtop.
*
* Nvtop is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Nvtop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with nvtop. If not, see <http://www.gnu.org/licenses/>.
*
*/

#include "nvtop/pcie_utilization.h"

unsigned pcie_max_bandwidth_kbs(const struct gpuinfo_static_info *static_info) {
if (!GPUINFO_STATIC_FIELD_VALID(static_info, max_pcie_gen) ||
!GPUINFO_STATIC_FIELD_VALID(static_info, max_pcie_link_width))
return 0;
unsigned per_lane_kbs;
switch (static_info->max_pcie_gen) {
case 1:
per_lane_kbs = 250000u;
break;
case 2:
per_lane_kbs = 500000u;
break;
case 3:
per_lane_kbs = 984600u;
break;
case 4:
per_lane_kbs = 1969000u;
break;
case 5:
per_lane_kbs = 3938000u;
break;
case 6:
per_lane_kbs = 7563000u;
break;
default:
return 0;
}
return per_lane_kbs * static_info->max_pcie_link_width;
}

unsigned pcie_load_percent(unsigned value_kbs, const struct gpuinfo_static_info *static_info) {
unsigned max_bw = pcie_max_bandwidth_kbs(static_info);
if (max_bw == 0)
return 0;
unsigned percent = (unsigned)((unsigned long long)value_kbs * 100u / max_bw);
return percent > 100u ? 100u : percent;
}
1 change: 1 addition & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ if (BUILD_TESTING AND GTest_FOUND)
${PROJECT_SOURCE_DIR}/src/interface_layout_selection.c
${PROJECT_SOURCE_DIR}/src/extract_processinfo_fdinfo.c
${PROJECT_SOURCE_DIR}/src/interface_options.c
${PROJECT_SOURCE_DIR}/src/pcie_utilization.c
${PROJECT_SOURCE_DIR}/src/ini.c
)
target_include_directories(testLib PUBLIC
Expand Down
56 changes: 56 additions & 0 deletions tests/interfaceTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
extern "C" {
#include "nvtop/interface.h"
#include "nvtop/interface_layout_selection.h"
#include "nvtop/pcie_utilization.h"
}

static std::ostream &operator<<(std::ostream &os, const struct window_position &win) {
Expand Down Expand Up @@ -200,6 +201,61 @@ TEST(InterfaceLayout, FixInfiniteLoop) {

TEST(InterfaceLayout, LayoutSelection_test_fail_case1) { test_with_terminal_size(32, 3, 55, 16, 1760); }

namespace {

// Build a gpuinfo_static_info with valid max PCIe gen / width fields.
struct gpuinfo_static_info make_static_info(unsigned gen, unsigned width) {
struct gpuinfo_static_info info = {};
SET_GPUINFO_STATIC(&info, max_pcie_gen, gen);
SET_GPUINFO_STATIC(&info, max_pcie_link_width, width);
return info;
}

} // namespace

TEST(PcieUtilization, MaxBandwidthPerGeneration) {
// Per-lane effective rate (KB/s) multiplied by the link width.
struct gpuinfo_static_info gen1 = make_static_info(1, 16);
struct gpuinfo_static_info gen2 = make_static_info(2, 16);
struct gpuinfo_static_info gen3 = make_static_info(3, 16);
struct gpuinfo_static_info gen4 = make_static_info(4, 16);
struct gpuinfo_static_info gen5 = make_static_info(5, 16);
struct gpuinfo_static_info gen6 = make_static_info(6, 16);
struct gpuinfo_static_info gen5x4 = make_static_info(5, 4);
EXPECT_EQ(pcie_max_bandwidth_kbs(&gen1), 250000u * 16u);
EXPECT_EQ(pcie_max_bandwidth_kbs(&gen2), 500000u * 16u);
EXPECT_EQ(pcie_max_bandwidth_kbs(&gen3), 984600u * 16u);
EXPECT_EQ(pcie_max_bandwidth_kbs(&gen4), 1969000u * 16u);
EXPECT_EQ(pcie_max_bandwidth_kbs(&gen5), 3938000u * 16u);
EXPECT_EQ(pcie_max_bandwidth_kbs(&gen6), 7563000u * 16u);
// Width scales the bandwidth linearly.
EXPECT_EQ(pcie_max_bandwidth_kbs(&gen5x4), 3938000u * 4u);
}

TEST(PcieUtilization, MaxBandwidthUnknownReturnsZero) {
// Unsupported / unknown generation.
struct gpuinfo_static_info gen7 = make_static_info(7, 16);
EXPECT_EQ(pcie_max_bandwidth_kbs(&gen7), 0u);
// Missing validity flags.
struct gpuinfo_static_info no_info = {};
EXPECT_EQ(pcie_max_bandwidth_kbs(&no_info), 0u);
}

TEST(PcieUtilization, LoadPercentClampsAndScales) {
struct gpuinfo_static_info info = make_static_info(5, 16); // 63,008,000 KB/s max
unsigned max_bw = 3938000u * 16u;
EXPECT_EQ(pcie_load_percent(0u, &info), 0u);
EXPECT_EQ(pcie_load_percent(max_bw / 2u, &info), 50u);
EXPECT_EQ(pcie_load_percent(max_bw, &info), 100u);
// Above the theoretical max is clamped to 100%.
EXPECT_EQ(pcie_load_percent(max_bw * 2u, &info), 100u);
}

TEST(PcieUtilization, LoadPercentNoMaxReturnsZero) {
struct gpuinfo_static_info no_info = {};
EXPECT_EQ(pcie_load_percent(1000000u, &no_info), 0u);
}

#ifdef THOROUGH_TESTING

TEST(InterfaceLayout, CheckManyTermSize) {
Expand Down