diff --git a/Makefile.am b/Makefile.am index fe70eef1..4317f74e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -126,6 +126,7 @@ myhtopheaders = \ # ----- linux_platform_headers = \ + linux/HugePageMeter.h \ linux/IOPriority.h \ linux/IOPriorityPanel.h \ linux/LibSensors.h \ @@ -145,6 +146,7 @@ linux_platform_headers = \ if HTOP_LINUX AM_LDFLAGS += -rdynamic myhtopplatsources = \ + linux/HugePageMeter.c \ linux/IOPriorityPanel.c \ linux/LibSensors.c \ linux/LinuxProcess.c \ diff --git a/linux/HugePageMeter.c b/linux/HugePageMeter.c new file mode 100644 index 00000000..e546c79a --- /dev/null +++ b/linux/HugePageMeter.c @@ -0,0 +1,63 @@ +/* +htop - HugePageMeter.c +(C) 2021 htop dev team +Released under the GNU GPLv2, see the COPYING file +in the source distribution for its full text. +*/ + +#include "HugePageMeter.h" + +#include "LinuxProcessList.h" + +#include "CRT.h" +#include "Object.h" +#include "RichString.h" + + +static const int HugePageMeter_attributes[] = { + MEMORY_USED, +}; + +static void HugePageMeter_updateValues(Meter* this, char* buffer, size_t size) { + int written; + + const LinuxProcessList* lpl = (const LinuxProcessList*) this->pl; + this->total = lpl->totalHugePageMem; + this->values[0] = lpl->totalHugePageMem - lpl->freeHugePageMem; + + written = Meter_humanUnit(buffer, this->values[0], size); + METER_BUFFER_CHECK(buffer, size, written); + + METER_BUFFER_APPEND_CHR(buffer, size, '/'); + + Meter_humanUnit(buffer, this->total, size); +} + +static void HugePageMeter_display(const Object* cast, RichString* out) { + char buffer[50]; + const Meter* this = (const Meter*)cast; + + RichString_writeAscii(out, CRT_colors[METER_TEXT], ":"); + Meter_humanUnit(buffer, this->total, sizeof(buffer)); + RichString_appendAscii(out, CRT_colors[METER_VALUE], buffer); + + RichString_appendAscii(out, CRT_colors[METER_TEXT], " used:"); + Meter_humanUnit(buffer, this->values[0], sizeof(buffer)); + RichString_appendAscii(out, CRT_colors[MEMORY_USED], buffer); +} + +const MeterClass HugePageMeter_class = { + .super = { + .extends = Class(Meter), + .delete = Meter_delete, + .display = HugePageMeter_display, + }, + .updateValues = HugePageMeter_updateValues, + .defaultMode = BAR_METERMODE, + .maxItems = 1, + .total = 100.0, + .attributes = HugePageMeter_attributes, + .name = "HugePages", + .uiName = "HugePages", + .caption = "HP" +}; diff --git a/linux/HugePageMeter.h b/linux/HugePageMeter.h new file mode 100644 index 00000000..2aa4085b --- /dev/null +++ b/linux/HugePageMeter.h @@ -0,0 +1,14 @@ +#ifndef HEADER_HugePageMeter +#define HEADER_HugePageMeter +/* +htop - HugePageMeter.h +(C) 2021 htop dev team +Released under the GNU GPLv2, see the COPYING file +in the source distribution for its full text. +*/ + +#include "Meter.h" + +extern const MeterClass HugePageMeter_class; + +#endif /* HEADER_HugePageMeter */ diff --git a/linux/LinuxProcessList.c b/linux/LinuxProcessList.c index c136c0fa..78ae6649 100644 --- a/linux/LinuxProcessList.c +++ b/linux/LinuxProcessList.c @@ -1531,6 +1531,57 @@ static inline void LinuxProcessList_scanMemoryInfo(ProcessList* this) { fclose(file); } +static void LinuxProcessList_scanHugePages(LinuxProcessList* this) { + this->totalHugePageMem = 0; + this->freeHugePageMem = 0; + + DIR* dir = opendir("/sys/kernel/mm/hugepages"); + if (!dir) + return; + + const struct dirent* entry; + while ((entry = readdir(dir)) != NULL) { + const char* name = entry->d_name; + + /* Ignore all non-directories */ + if (entry->d_type != DT_DIR && entry->d_type != DT_UNKNOWN) + continue; + + if (!String_startsWith(name, "hugepages-")) + continue; + + char* endptr; + unsigned long int hugePageSize = strtoul(name + strlen("hugepages-"), &endptr, 10); + if (!endptr || *endptr != 'k') + continue; + + char content[64]; + char hugePagePath[128]; + ssize_t r; + + xSnprintf(hugePagePath, sizeof(hugePagePath), "/sys/kernel/mm/hugepages/%s/nr_hugepages", name); + r = xReadfile(hugePagePath, content, sizeof(content)); + if (r <= 0) + continue; + + unsigned long long int total = strtoull(content, NULL, 10); + if (total == 0) + continue; + + xSnprintf(hugePagePath, sizeof(hugePagePath), "/sys/kernel/mm/hugepages/%s/free_hugepages", name); + r = xReadfile(hugePagePath, content, sizeof(content)); + if (r <= 0) + continue; + + unsigned long long int free = strtoull(content, NULL, 10); + + this->totalHugePageMem += total * hugePageSize; + this->freeHugePageMem += free * hugePageSize; + } + + closedir(dir); +} + static inline void LinuxProcessList_scanZramInfo(LinuxProcessList* this) { unsigned long long int totalZram = 0; unsigned long long int usedZramComp = 0; @@ -1854,6 +1905,7 @@ void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) { const Settings* settings = super->settings; LinuxProcessList_scanMemoryInfo(super); + LinuxProcessList_scanHugePages(this); LinuxProcessList_scanZfsArcstats(this); LinuxProcessList_updateCPUcount(this); LinuxProcessList_scanZramInfo(this); diff --git a/linux/LinuxProcessList.h b/linux/LinuxProcessList.h index 09b84afa..b34810bb 100644 --- a/linux/LinuxProcessList.h +++ b/linux/LinuxProcessList.h @@ -72,6 +72,9 @@ typedef struct LinuxProcessList_ { int netlink_family; #endif + unsigned long long int totalHugePageMem; + unsigned long long int freeHugePageMem; + ZfsArcStats zfs; ZramStats zram; } LinuxProcessList; diff --git a/linux/Platform.c b/linux/Platform.c index 7077f08d..e5a87552 100644 --- a/linux/Platform.c +++ b/linux/Platform.c @@ -30,6 +30,7 @@ in the source distribution for its full text. #include "DateTimeMeter.h" #include "DiskIOMeter.h" #include "HostnameMeter.h" +#include "HugePageMeter.h" #include "IOPriority.h" #include "IOPriorityPanel.h" #include "LinuxProcess.h" @@ -161,6 +162,7 @@ const MeterClass* const Platform_meterTypes[] = { &LoadMeter_class, &MemoryMeter_class, &SwapMeter_class, + &HugePageMeter_class, &TasksMeter_class, &UptimeMeter_class, &BatteryMeter_class, @@ -284,8 +286,8 @@ void Platform_setMemoryValues(Meter* this) { long int usedMem = pl->usedMem; long int buffersMem = pl->buffersMem; long int cachedMem = pl->cachedMem; - usedMem -= buffersMem + cachedMem; - this->total = pl->totalMem; + usedMem -= buffersMem + cachedMem + lpl->totalHugePageMem; + this->total = pl->totalMem - lpl->totalHugePageMem; this->values[0] = usedMem; this->values[1] = buffersMem; this->values[2] = cachedMem;