aboutsummaryrefslogtreecommitdiffstats
path: root/linux
diff options
context:
space:
mode:
authorDaniel Lange <DLange@git.local>2020-08-27 07:48:10 +0200
committerDaniel Lange <DLange@git.local>2020-08-27 07:48:10 +0200
commitf3147ea2d1598914c2db53e8cfb34c8ff81e2ff4 (patch)
tree3ee82b2af2ab3d38b6e4b07f3994516aac72f742 /linux
parentdf568a576f7b44ac5a2b9b7222c7f39d9932f626 (diff)
downloaddebian_htop-f3147ea2d1598914c2db53e8cfb34c8ff81e2ff4.tar.gz
debian_htop-f3147ea2d1598914c2db53e8cfb34c8ff81e2ff4.tar.bz2
debian_htop-f3147ea2d1598914c2db53e8cfb34c8ff81e2ff4.zip
New upstream version 3.0.0upstream/3.0.0
Diffstat (limited to 'linux')
-rw-r--r--linux/Battery.c38
-rw-r--r--linux/Battery.h2
-rw-r--r--linux/IOPriority.c3
-rw-r--r--linux/IOPriority.h3
-rw-r--r--linux/IOPriorityPanel.c1
-rw-r--r--linux/IOPriorityPanel.h5
-rw-r--r--linux/LinuxCRT.c2
-rw-r--r--linux/LinuxCRT.h2
-rw-r--r--linux/LinuxProcess.c55
-rw-r--r--linux/LinuxProcess.h33
-rw-r--r--linux/LinuxProcessList.c344
-rw-r--r--linux/LinuxProcessList.h33
-rw-r--r--linux/Platform.c57
-rw-r--r--linux/Platform.h21
-rw-r--r--linux/PressureStallMeter.c133
-rw-r--r--linux/PressureStallMeter.h25
16 files changed, 632 insertions, 125 deletions
diff --git a/linux/Battery.c b/linux/Battery.c
index aedacab..4014a50 100644
--- a/linux/Battery.c
+++ b/linux/Battery.c
@@ -64,7 +64,7 @@ static unsigned long int parseBatInfo(const char *fileName, const unsigned short
}
char* line = NULL;
- for (unsigned short int i = 0; i < lineNum; i++) {
+ for (unsigned short int j = 0; j < lineNum; j++) {
free(line);
line = String_readLine(file);
if (!line) break;
@@ -78,7 +78,7 @@ static unsigned long int parseBatInfo(const char *fileName, const unsigned short
const unsigned long int foundNum = atoi(foundNumStr);
free(foundNumStr);
free(line);
-
+
total += foundNum;
}
@@ -175,7 +175,7 @@ static inline ssize_t xread(int fd, void *buf, size_t count) {
}
static void Battery_getSysData(double* level, ACPresence* isOnAC) {
-
+
*level = 0;
*isOnAC = AC_ERROR;
@@ -193,17 +193,27 @@ static void Battery_getSysData(double* level, ACPresence* isOnAC) {
char* entryName = (char *) dirEntry->d_name;
const char filePath[50];
- if (entryName[0] == 'B' && entryName[1] == 'A' && entryName[2] == 'T') {
-
+ xSnprintf((char *) filePath, sizeof filePath, SYS_POWERSUPPLY_DIR "/%s/type", entryName);
+ int fd1 = open(filePath, O_RDONLY);
+ if (fd1 == -1)
+ continue;
+
+ char type[8];
+ ssize_t typelen = xread(fd1, type, 7);
+ close(fd1);
+ if (typelen < 1)
+ continue;
+
+ if (type[0] == 'B' && type[1] == 'a' && type[2] == 't') {
xSnprintf((char *) filePath, sizeof filePath, SYS_POWERSUPPLY_DIR "/%s/uevent", entryName);
- int fd = open(filePath, O_RDONLY);
- if (fd == -1) {
+ int fd2 = open(filePath, O_RDONLY);
+ if (fd2 == -1) {
closedir(dir);
return;
}
char buffer[1024];
- ssize_t buflen = xread(fd, buffer, 1023);
- close(fd);
+ ssize_t buflen = xread(fd2, buffer, 1023);
+ close(fd2);
if (buflen < 1) {
closedir(dir);
return;
@@ -247,20 +257,20 @@ static void Battery_getSysData(double* level, ACPresence* isOnAC) {
if (*isOnAC != AC_ERROR) {
continue;
}
-
+
xSnprintf((char *) filePath, sizeof filePath, SYS_POWERSUPPLY_DIR "/%s/online", entryName);
- int fd = open(filePath, O_RDONLY);
- if (fd == -1) {
+ int fd3 = open(filePath, O_RDONLY);
+ if (fd3 == -1) {
closedir(dir);
return;
}
char buffer[2] = "";
for(;;) {
- ssize_t res = read(fd, buffer, 1);
+ ssize_t res = read(fd3, buffer, 1);
if (res == -1 && errno == EINTR) continue;
break;
}
- close(fd);
+ close(fd3);
if (buffer[0] == '0') {
*isOnAC = AC_ABSENT;
} else if (buffer[0] == '1') {
diff --git a/linux/Battery.h b/linux/Battery.h
index cfb6c32..261cff0 100644
--- a/linux/Battery.h
+++ b/linux/Battery.h
@@ -29,6 +29,6 @@ Linux battery readings written by Ian P. Hands (iphands@gmail.com, ihands@redhat
// READ FROM /sys
// ----------------------------------------
-void Battery_getData(double* level, ACPresence* isOnAC);
+extern void Battery_getData(double* level, ACPresence* isOnAC);
#endif
diff --git a/linux/IOPriority.c b/linux/IOPriority.c
index dd7c84a..087f7f9 100644
--- a/linux/IOPriority.c
+++ b/linux/IOPriority.c
@@ -4,7 +4,7 @@ htop - IOPriority.c
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
-Based on ionice,
+Based on ionice,
Copyright (C) 2005 Jens Axboe <jens@axboe.dk>
Released under the terms of the GNU General Public License version 2
*/
@@ -38,4 +38,3 @@ typedef int IOPriority;
#define IOPriority_Idle IOPriority_tuple(IOPRIO_CLASS_IDLE, 7)
}*/
-
diff --git a/linux/IOPriority.h b/linux/IOPriority.h
index 148e344..a4733e8 100644
--- a/linux/IOPriority.h
+++ b/linux/IOPriority.h
@@ -8,7 +8,7 @@ htop - IOPriority.h
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
-Based on ionice,
+Based on ionice,
Copyright (C) 2005 Jens Axboe <jens@axboe.dk>
Released under the terms of the GNU General Public License version 2
*/
@@ -39,5 +39,4 @@ typedef int IOPriority;
#define IOPriority_Idle IOPriority_tuple(IOPRIO_CLASS_IDLE, 7)
-
#endif
diff --git a/linux/IOPriorityPanel.c b/linux/IOPriorityPanel.c
index 2b315b8..22735bb 100644
--- a/linux/IOPriorityPanel.c
+++ b/linux/IOPriorityPanel.c
@@ -41,4 +41,3 @@ Panel* IOPriorityPanel_new(IOPriority currPrio) {
IOPriority IOPriorityPanel_getIOPriority(Panel* this) {
return (IOPriority) ( ((ListItem*) Panel_getSelected(this))->key );
}
-
diff --git a/linux/IOPriorityPanel.h b/linux/IOPriorityPanel.h
index 9f77a4d..906296e 100644
--- a/linux/IOPriorityPanel.h
+++ b/linux/IOPriorityPanel.h
@@ -13,9 +13,8 @@ in the source distribution for its full text.
#include "IOPriority.h"
#include "ListItem.h"
-Panel* IOPriorityPanel_new(IOPriority currPrio);
-
-IOPriority IOPriorityPanel_getIOPriority(Panel* this);
+extern Panel* IOPriorityPanel_new(IOPriority currPrio);
+extern IOPriority IOPriorityPanel_getIOPriority(Panel* this);
#endif
diff --git a/linux/LinuxCRT.c b/linux/LinuxCRT.c
index 5b2a21f..c65b782 100644
--- a/linux/LinuxCRT.c
+++ b/linux/LinuxCRT.c
@@ -17,7 +17,7 @@ void CRT_handleSIGSEGV(int sgn) {
(void) sgn;
CRT_done();
#ifdef __linux
- fprintf(stderr, "\n\nhtop " VERSION " aborting. Please report bug at http://hisham.hm/htop\n");
+ fprintf(stderr, "\n\nhtop " VERSION " aborting. Please report bug at https://htop.dev\n");
#ifdef HAVE_EXECINFO_H
size_t size = backtrace(backtraceArray, sizeof(backtraceArray) / sizeof(void *));
fprintf(stderr, "\n Please include in your report the following backtrace: \n");
diff --git a/linux/LinuxCRT.h b/linux/LinuxCRT.h
index f8c43e4..966dfec 100644
--- a/linux/LinuxCRT.h
+++ b/linux/LinuxCRT.h
@@ -12,6 +12,6 @@ in the source distribution for its full text.
#ifdef HAVE_EXECINFO_H
#endif
-void CRT_handleSIGSEGV(int sgn);
+extern void CRT_handleSIGSEGV(int sgn);
#endif
diff --git a/linux/LinuxProcess.c b/linux/LinuxProcess.c
index 09ccbe1..3a15049 100644
--- a/linux/LinuxProcess.c
+++ b/linux/LinuxProcess.c
@@ -1,6 +1,7 @@
/*
htop - LinuxProcess.c
(C) 2014 Hisham H. Muhammad
+(C) 2020 Red Hat, Inc. All Rights Reserved.
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
@@ -15,6 +16,7 @@ in the source distribution for its full text.
#include <unistd.h>
#include <string.h>
#include <sys/syscall.h>
+#include <time.h>
/*{
@@ -23,6 +25,7 @@ in the source distribution for its full text.
#define PROCESS_FLAG_LINUX_VSERVER 0x0400
#define PROCESS_FLAG_LINUX_CGROUP 0x0800
#define PROCESS_FLAG_LINUX_OOM 0x1000
+#define PROCESS_FLAG_LINUX_SMAPS 0x2000
typedef enum UnsupportedProcessFields {
FLAGS = 9,
@@ -86,7 +89,10 @@ typedef enum LinuxProcessFields {
PERCENT_IO_DELAY = 117,
PERCENT_SWAP_DELAY = 118,
#endif
- LAST_PROCESSFIELD = 119,
+ M_PSS = 119,
+ M_SWAP = 120,
+ M_PSSWP = 121,
+ LAST_PROCESSFIELD = 122,
} LinuxProcessField;
#include "IOPriority.h"
@@ -102,10 +108,14 @@ typedef struct LinuxProcess_ {
unsigned long long int cutime;
unsigned long long int cstime;
long m_share;
+ long m_pss;
+ long m_swap;
+ long m_psswp;
long m_trs;
long m_drs;
long m_lrs;
long m_dt;
+ unsigned long long starttime;
#ifdef HAVE_TASKSTATS
unsigned long long io_rchar;
unsigned long long io_wchar;
@@ -115,7 +125,7 @@ typedef struct LinuxProcess_ {
unsigned long long io_write_bytes;
unsigned long long io_cancelled_write_bytes;
unsigned long long io_rate_read_time;
- unsigned long long io_rate_write_time;
+ unsigned long long io_rate_write_time;
double io_rate_read_bps;
double io_rate_write_bps;
#endif
@@ -143,7 +153,7 @@ typedef struct LinuxProcess_ {
} LinuxProcess;
#ifndef Process_isKernelThread
-#define Process_isKernelThread(_process) ((LinuxProcess*)(_process)->isKernelThread)
+#define Process_isKernelThread(_process) (((LinuxProcess*)(_process))->isKernelThread)
#endif
#ifndef Process_isUserlandThread
@@ -152,6 +162,9 @@ typedef struct LinuxProcess_ {
}*/
+/* semi-global */
+long long btime;
+
ProcessFieldData Process_fields[] = {
[0] = { .name = "", .title = NULL, .description = NULL, .flags = 0, },
[PID] = { .name = "PID", .title = " PID ", .description = "Process/thread ID", .flags = 0, },
@@ -199,7 +212,7 @@ ProcessFieldData Process_fields[] = {
[M_DRS] = { .name = "M_DRS", .title = " DATA ", .description = "Size of the data segment plus stack usage of the process", .flags = 0, },
[M_LRS] = { .name = "M_LRS", .title = " LIB ", .description = "The library size of the process", .flags = 0, },
[M_DT] = { .name = "M_DT", .title = " DIRTY ", .description = "Size of the dirty pages of the process", .flags = 0, },
- [ST_UID] = { .name = "ST_UID", .title = " UID ", .description = "User ID of the process owner", .flags = 0, },
+ [ST_UID] = { .name = "ST_UID", .title = " UID ", .description = "User ID of the process owner", .flags = 0, },
[PERCENT_CPU] = { .name = "PERCENT_CPU", .title = "CPU% ", .description = "Percentage of the CPU time the process used in the last sampling", .flags = 0, },
[PERCENT_MEM] = { .name = "PERCENT_MEM", .title = "MEM% ", .description = "Percentage of the memory the process is using, based on resident memory size", .flags = 0, },
[USER] = { .name = "USER", .title = "USER ", .description = "Username of the process owner (or user ID if name cannot be determined)", .flags = 0, },
@@ -235,6 +248,9 @@ ProcessFieldData Process_fields[] = {
[PERCENT_IO_DELAY] = { .name = "PERCENT_IO_DELAY", .title = "IOD% ", .description = "Block I/O delay %", .flags = 0, },
[PERCENT_SWAP_DELAY] = { .name = "PERCENT_SWAP_DELAY", .title = "SWAPD% ", .description = "Swapin delay %", .flags = 0, },
#endif
+ [M_PSS] = { .name = "M_PSS", .title = " PSS ", .description = "proportional set size, same as M_RESIDENT but each page is divided by the number of processes sharing it.", .flags = PROCESS_FLAG_LINUX_SMAPS, },
+ [M_SWAP] = { .name = "M_SWAP", .title = " SWAP ", .description = "Size of the process's swapped pages", .flags = PROCESS_FLAG_LINUX_SMAPS, },
+ [M_PSSWP] = { .name = "M_PSSWP", .title = " PSSWP ", .description = "shows proportional swap share of this mapping, Unlike \"Swap\", this does not take into account swapped out page of underlying shmem objects.", .flags = PROCESS_FLAG_LINUX_SMAPS, },
[LAST_PROCESSFIELD] = { .name = "*** report bug! ***", .title = NULL, .description = NULL, .flags = 0, },
};
@@ -299,12 +315,12 @@ IOPriority LinuxProcess_updateIOPriority(LinuxProcess* this) {
return ioprio;
}
-bool LinuxProcess_setIOPriority(LinuxProcess* this, IOPriority ioprio) {
+bool LinuxProcess_setIOPriority(LinuxProcess* this, Arg ioprio) {
// Other OSes masquerading as Linux (NetBSD?) don't have this syscall
#ifdef SYS_ioprio_set
- syscall(SYS_ioprio_set, IOPRIO_WHO_PROCESS, this->super.pid, ioprio);
+ syscall(SYS_ioprio_set, IOPRIO_WHO_PROCESS, this->super.pid, ioprio.i);
#endif
- return (LinuxProcess_updateIOPriority(this) == ioprio);
+ return (LinuxProcess_updateIOPriority(this) == ioprio.i);
}
#ifdef HAVE_DELAYACCT
@@ -340,10 +356,20 @@ void LinuxProcess_writeField(Process* this, RichString* str, ProcessField field)
case M_LRS: Process_humanNumber(str, lp->m_lrs * PAGE_SIZE_KB, coloring); return;
case M_TRS: Process_humanNumber(str, lp->m_trs * PAGE_SIZE_KB, coloring); return;
case M_SHARE: Process_humanNumber(str, lp->m_share * PAGE_SIZE_KB, coloring); return;
+ case M_PSS: Process_humanNumber(str, lp->m_pss, coloring); return;
+ case M_SWAP: Process_humanNumber(str, lp->m_swap, coloring); return;
+ case M_PSSWP: Process_humanNumber(str, lp->m_psswp, coloring); return;
case UTIME: Process_printTime(str, lp->utime); return;
case STIME: Process_printTime(str, lp->stime); return;
case CUTIME: Process_printTime(str, lp->cutime); return;
case CSTIME: Process_printTime(str, lp->cstime); return;
+ case STARTTIME: {
+ struct tm date;
+ time_t starttimewall = btime + (lp->starttime / sysconf(_SC_CLK_TCK));
+ (void) localtime_r(&starttimewall, &date);
+ strftime(buffer, n, ((starttimewall > time(NULL) - 86400) ? "%R " : "%b%d "), &date);
+ break;
+ }
#ifdef HAVE_TASKSTATS
case RCHAR: Process_colorNumber(str, lp->io_rchar, coloring); return;
case WCHAR: Process_colorNumber(str, lp->io_wchar, coloring); return;
@@ -383,7 +409,7 @@ void LinuxProcess_writeField(Process* this, RichString* str, ProcessField field)
attr = CRT_colors[PROCESS_HIGH_PRIORITY];
xSnprintf(buffer, n, "R%1d ", IOPriority_data(lp->ioPriority));
} else if (klass == IOPRIO_CLASS_IDLE) {
- attr = CRT_colors[PROCESS_LOW_PRIORITY];
+ attr = CRT_colors[PROCESS_LOW_PRIORITY];
xSnprintf(buffer, n, "id ");
} else {
xSnprintf(buffer, n, "?? ");
@@ -424,10 +450,22 @@ long LinuxProcess_compare(const void* v1, const void* v2) {
return (p2->m_trs - p1->m_trs);
case M_SHARE:
return (p2->m_share - p1->m_share);
+ case M_PSS:
+ return (p2->m_pss - p1->m_pss);
+ case M_SWAP:
+ return (p2->m_swap - p1->m_swap);
+ case M_PSSWP:
+ return (p2->m_psswp - p1->m_psswp);
case UTIME: diff = p2->utime - p1->utime; goto test_diff;
case CUTIME: diff = p2->cutime - p1->cutime; goto test_diff;
case STIME: diff = p2->stime - p1->stime; goto test_diff;
case CSTIME: diff = p2->cstime - p1->cstime; goto test_diff;
+ case STARTTIME: {
+ if (p1->starttime == p2->starttime)
+ return (p1->super.pid - p2->super.pid);
+ else
+ return (p1->starttime - p2->starttime);
+ }
#ifdef HAVE_TASKSTATS
case RCHAR: diff = p2->io_rchar - p1->io_rchar; goto test_diff;
case WCHAR: diff = p2->io_wchar - p1->io_wchar; goto test_diff;
@@ -476,4 +514,3 @@ long LinuxProcess_compare(const void* v1, const void* v2) {
bool Process_isThread(Process* this) {
return (Process_isUserlandThread(this) || Process_isKernelThread(this));
}
-
diff --git a/linux/LinuxProcess.h b/linux/LinuxProcess.h
index d75fe89..7c0a11f 100644
--- a/linux/LinuxProcess.h
+++ b/linux/LinuxProcess.h
@@ -5,6 +5,7 @@
/*
htop - LinuxProcess.h
(C) 2014 Hisham H. Muhammad
+(C) 2020 Red Hat, Inc. All Rights Reserved.
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
@@ -15,6 +16,7 @@ in the source distribution for its full text.
#define PROCESS_FLAG_LINUX_VSERVER 0x0400
#define PROCESS_FLAG_LINUX_CGROUP 0x0800
#define PROCESS_FLAG_LINUX_OOM 0x1000
+#define PROCESS_FLAG_LINUX_SMAPS 0x2000
typedef enum UnsupportedProcessFields {
FLAGS = 9,
@@ -78,7 +80,10 @@ typedef enum LinuxProcessFields {
PERCENT_IO_DELAY = 117,
PERCENT_SWAP_DELAY = 118,
#endif
- LAST_PROCESSFIELD = 119,
+ M_PSS = 119,
+ M_SWAP = 120,
+ M_PSSWP = 121,
+ LAST_PROCESSFIELD = 122,
} LinuxProcessField;
#include "IOPriority.h"
@@ -94,10 +99,14 @@ typedef struct LinuxProcess_ {
unsigned long long int cutime;
unsigned long long int cstime;
long m_share;
+ long m_pss;
+ long m_swap;
+ long m_psswp;
long m_trs;
long m_drs;
long m_lrs;
long m_dt;
+ unsigned long long starttime;
#ifdef HAVE_TASKSTATS
unsigned long long io_rchar;
unsigned long long io_wchar;
@@ -107,7 +116,7 @@ typedef struct LinuxProcess_ {
unsigned long long io_write_bytes;
unsigned long long io_cancelled_write_bytes;
unsigned long long io_rate_read_time;
- unsigned long long io_rate_write_time;
+ unsigned long long io_rate_write_time;
double io_rate_read_bps;
double io_rate_write_bps;
#endif
@@ -143,15 +152,18 @@ typedef struct LinuxProcess_ {
#endif
+/* semi-global */
+extern long long btime;
+
extern ProcessFieldData Process_fields[];
extern ProcessPidColumn Process_pidColumns[];
extern ProcessClass LinuxProcess_class;
-LinuxProcess* LinuxProcess_new(Settings* settings);
+extern LinuxProcess* LinuxProcess_new(Settings* settings);
-void Process_delete(Object* cast);
+extern void Process_delete(Object* cast);
/*
[1] Note that before kernel 2.6.26 a process that has not asked for
@@ -163,19 +175,18 @@ extern io_priority;
*/
#define LinuxProcess_effectiveIOPriority(p_) (IOPriority_class(p_->ioPriority) == IOPRIO_CLASS_NONE ? IOPriority_tuple(IOPRIO_CLASS_BE, (p_->super.nice + 20) / 5) : p_->ioPriority)
-IOPriority LinuxProcess_updateIOPriority(LinuxProcess* this);
+extern IOPriority LinuxProcess_updateIOPriority(LinuxProcess* this);
-bool LinuxProcess_setIOPriority(LinuxProcess* this, IOPriority ioprio);
+extern bool LinuxProcess_setIOPriority(LinuxProcess* this, Arg ioprio);
#ifdef HAVE_DELAYACCT
-void LinuxProcess_printDelay(float delay_percent, char* buffer, int n);
+extern void LinuxProcess_printDelay(float delay_percent, char* buffer, int n);
#endif
-void LinuxProcess_writeField(Process* this, RichString* str, ProcessField field);
-
-long LinuxProcess_compare(const void* v1, const void* v2);
+extern void LinuxProcess_writeField(Process* this, RichString* str, ProcessField field);
-bool Process_isThread(Process* this);
+extern long LinuxProcess_compare(const void* v1, const void* v2);
+extern bool Process_isThread(Process* this);
#endif
diff --git a/linux/LinuxProcessList.c b/linux/LinuxProcessList.c
index 2edd042..6d3d034 100644
--- a/linux/LinuxProcessList.c
+++ b/linux/LinuxProcessList.c
@@ -28,8 +28,7 @@ in the source distribution for its full text.
#include <fcntl.h>
#ifdef MAJOR_IN_MKDEV
#include <sys/mkdev.h>
-#elif defined(MAJOR_IN_SYSMACROS) || \
- (defined(HAVE_SYS_SYSMACROS_H) && HAVE_SYS_SYSMACROS_H)
+#elif defined(MAJOR_IN_SYSMACROS)
#include <sys/sysmacros.h>
#endif
@@ -46,6 +45,9 @@ in the source distribution for its full text.
/*{
#include "ProcessList.h"
+#include "zfs/ZfsArcStats.h"
+
+extern long long btime;
typedef struct CPUData_ {
unsigned long long int totalTime;
@@ -60,7 +62,7 @@ typedef struct CPUData_ {
unsigned long long int softIrqTime;
unsigned long long int stealTime;
unsigned long long int guestTime;
-
+
unsigned long long int totalPeriod;
unsigned long long int userPeriod;
unsigned long long int systemPeriod;
@@ -73,6 +75,8 @@ typedef struct CPUData_ {
unsigned long long int softIrqPeriod;
unsigned long long int stealPeriod;
unsigned long long int guestPeriod;
+
+ double frequency;
} CPUData;
typedef struct TtyDriver_ {
@@ -84,20 +88,27 @@ typedef struct TtyDriver_ {
typedef struct LinuxProcessList_ {
ProcessList super;
-
+
CPUData* cpus;
TtyDriver* ttyDrivers;
-
+ bool haveSmapsRollup;
+
#ifdef HAVE_DELAYACCT
struct nl_sock *netlink_socket;
int netlink_family;
#endif
+
+ ZfsArcStats zfs;
} LinuxProcessList;
#ifndef PROCDIR
#define PROCDIR "/proc"
#endif
+#ifndef PROCCPUINFOFILE
+#define PROCCPUINFOFILE PROCDIR "/cpuinfo"
+#endif
+
#ifndef PROCSTATFILE
#define PROCSTATFILE PROCDIR "/stat"
#endif
@@ -106,12 +117,16 @@ typedef struct LinuxProcessList_ {
#define PROCMEMINFOFILE PROCDIR "/meminfo"
#endif
+#ifndef PROCARCSTATSFILE
+#define PROCARCSTATSFILE PROCDIR "/spl/kstat/zfs/arcstats"
+#endif
+
#ifndef PROCTTYDRIVERSFILE
#define PROCTTYDRIVERSFILE PROCDIR "/tty/drivers"
#endif
#ifndef PROC_LINE_LENGTH
-#define PROC_LINE_LENGTH 512
+#define PROC_LINE_LENGTH 4096
#endif
}*/
@@ -230,26 +245,41 @@ static void LinuxProcessList_initNetlinkSocket(LinuxProcessList* this) {
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, uid_t userId) {
LinuxProcessList* this = xCalloc(1, sizeof(LinuxProcessList));
ProcessList* pl = &(this->super);
+
ProcessList_init(pl, Class(LinuxProcess), usersTable, pidWhiteList, userId);
-
LinuxProcessList_initTtyDrivers(this);
#ifdef HAVE_DELAYACCT
LinuxProcessList_initNetlinkSocket(this);
#endif
+ // Check for /proc/*/smaps_rollup availability (improves smaps parsing speed, Linux 4.14+)
+ FILE* file = fopen(PROCDIR "/self/smaps_rollup", "r");
+ if(file != NULL) {
+ this->haveSmapsRollup = true;
+ fclose(file);
+ } else {
+ this->haveSmapsRollup = false;
+ }
+
// Update CPU count:
- FILE* file = fopen(PROCSTATFILE, "r");
+ file = fopen(PROCSTATFILE, "r");
if (file == NULL) {
CRT_fatalError("Cannot open " PROCSTATFILE);
}
- char buffer[PROC_LINE_LENGTH + 1];
- int cpus = -1;
+ int cpus = 0;
do {
- cpus++;
- char * s = fgets(buffer, PROC_LINE_LENGTH, file);
- (void) s;
- } while (String_startsWith(buffer, "cpu"));
+ char buffer[PROC_LINE_LENGTH + 1];
+ if (fgets(buffer, PROC_LINE_LENGTH + 1, file) == NULL) {
+ CRT_fatalError("No btime in " PROCSTATFILE);
+ } else if (String_startsWith(buffer, "cpu")) {
+ cpus++;
+ } else if (String_startsWith(buffer, "btime ")) {
+ sscanf(buffer, "btime %lld\n", &btime);
+ break;
+ }
+ } while(true);
+
fclose(file);
pl->cpuCount = MAX(cpus - 1, 1);
@@ -259,7 +289,6 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, ui
this->cpus[i].totalTime = 1;
this->cpus[i].totalPeriod = 1;
}
-
return pl;
}
@@ -312,7 +341,7 @@ static bool LinuxProcessList_readStatFile(Process *process, const char* dirname,
location += 2;
char *end = strrchr(location, ')');
if (!end) return false;
-
+
int commsize = end - location;
memcpy(command, location, commsize);
command[commsize] = '\0';
@@ -355,19 +384,22 @@ static bool LinuxProcessList_readStatFile(Process *process, const char* dirname,
location += 1;
process->nlwp = strtol(location, &location, 10);
location += 1;
- for (int i=0; i<17; i++) location = strchr(location, ' ')+1;
+ location = strchr(location, ' ')+1;
+ lp->starttime = strtoll(location, &location, 10);
+ location += 1;
+ for (int i=0; i<15; i++) location = strchr(location, ' ')+1;
process->exit_signal = strtol(location, &location, 10);
location += 1;
assert(location != NULL);
process->processor = strtol(location, &location, 10);
-
+
process->time = lp->utime + lp->stime;
-
+
return true;
}
-static bool LinuxProcessList_statProcessDir(Process* process, const char* dirname, char* name, time_t curTime) {
+static bool LinuxProcessList_statProcessDir(Process* process, const char* dirname, char* name) {
char filename[MAX_NAME+1];
filename[MAX_NAME] = '\0';
@@ -377,13 +409,6 @@ static bool LinuxProcessList_statProcessDir(Process* process, const char* dirnam
if (statok == -1)
return false;
process->st_uid = sstat.st_uid;
-
- struct tm date;
- time_t ctime = sstat.st_ctime;
- process->starttime_ctime = ctime;
- (void) localtime_r((time_t*) &ctime, &date);
- strftime(process->starttime_show, 7, ((ctime > curTime - 86400) ? "%R " : "%b%d "), &date);
-
return true;
}
@@ -409,7 +434,7 @@ static void LinuxProcessList_readIoFile(LinuxProcess* process, const char* dirna
process->io_rate_write_time = -1LL;
return;
}
-
+
char buffer[1024];
ssize_t buflen = xread(fd, buffer, 1023);
close(fd);
@@ -426,7 +451,7 @@ static void LinuxProcessList_readIoFile(LinuxProcess* process, const char* dirna
process->io_rchar = strtoull(line+7, NULL, 10);
else if (strncmp(line+1, "ead_bytes: ", 11) == 0) {
process->io_read_bytes = strtoull(line+12, NULL, 10);
- process->io_rate_read_bps =
+ process->io_rate_read_bps =
((double)(process->io_read_bytes - last_read))/(((double)(now - process->io_rate_read_time))/1000);
process->io_rate_read_time = now;
}
@@ -436,7 +461,7 @@ static void LinuxProcessList_readIoFile(LinuxProcess* process, const char* dirna
process->io_wchar = strtoull(line+7, NULL, 10);
else if (strncmp(line+1, "rite_bytes: ", 12) == 0) {
process->io_write_bytes = strtoull(line+13, NULL, 10);
- process->io_rate_write_bps =
+ process->io_rate_write_bps =
((double)(process->io_write_bytes - last_write))/(((double)(now - process->io_rate_write_time))/1000);
process->io_rate_write_time = now;
}
@@ -483,6 +508,62 @@ static bool LinuxProcessList_readStatmFile(LinuxProcess* process, const char* di
return (errno == 0);
}
+static bool LinuxProcessList_readSmapsFile(LinuxProcess* process, const char* dirname, const char* name, bool haveSmapsRollup) {
+ //http://elixir.free-electrons.com/linux/v4.10/source/fs/proc/task_mmu.c#L719
+ //kernel will return data in chunks of size PAGE_SIZE or less.
+
+ char buffer[PAGE_SIZE];// 4k
+ char *start,*end;
+ ssize_t nread=0;
+ int tmp=0;
+ if(haveSmapsRollup) {// only available in Linux 4.14+
+ snprintf(buffer, PAGE_SIZE-1, "%s/%s/smaps_rollup", dirname, name);
+ } else {
+ snprintf(buffer, PAGE_SIZE-1, "%s/%s/smaps", dirname, name);
+ }
+ int fd = open(buffer, O_RDONLY);
+ if (fd == -1)
+ return false;
+
+ process->m_pss = 0;
+ process->m_swap = 0;
+ process->m_psswp = 0;
+
+ while ( ( nread = read(fd,buffer, sizeof(buffer)) ) > 0 ){
+ start = (char *)&buffer;
+ end = start + nread;
+ do{//parse 4k block
+
+ if( (tmp = (end - start)) > 0 &&
+ (start = memmem(start,tmp,"\nPss:",5)) != NULL )
+ {
+ process->m_pss += strtol(start+5, &start, 10);
+ start += 3;//now we must be at the end of line "Pss: 0 kB"
+ }else
+ break; //read next 4k block
+
+ if( (tmp = (end - start)) > 0 &&
+ (start = memmem(start,tmp,"\nSwap:",6)) != NULL )
+ {
+ process->m_swap += strtol(start+6, &start, 10);
+ start += 3;
+ }else
+ break;
+
+ if( (tmp = (end - start)) > 0 &&
+ (start = memmem(start,tmp,"\nSwapPss:",9)) != NULL )
+ {
+ process->m_psswp += strtol(start+9, &start, 10);
+ start += 3;
+ }else
+ break;
+
+ }while(1);
+ }//while read
+ close(fd);
+ return true;
+}
+
#ifdef HAVE_OPENVZ
static void LinuxProcessList_readOpenVZData(LinuxProcess* process, const char* dirname, const char* name) {
@@ -658,7 +739,7 @@ static void LinuxProcessList_readDelayAcctData(LinuxProcessList* this, LinuxProc
process->cpu_delay_percent = -1LL;
return;
}
-
+
if (nl_recvmsgs_default(this->netlink_socket) < 0) {
return;
}
@@ -682,14 +763,18 @@ static bool LinuxProcessList_readCmdlineFile(Process* process, const char* dirna
int fd = open(filename, O_RDONLY);
if (fd == -1)
return false;
-
+
char command[4096+1]; // max cmdline length on Linux
int amtRead = xread(fd, command, sizeof(command) - 1);
close(fd);
- int tokenEnd = 0;
+ int tokenEnd = 0;
int lastChar = 0;
if (amtRead == 0) {
- ((LinuxProcess*)process)->isKernelThread = true;
+ if (process->state == 'Z') {
+ process->basenameOffset = 0;
+ } else {
+ ((LinuxProcess*)process)->isKernelThread = true;
+ }
return true;
} else if (amtRead < 0) {
return false;
@@ -709,7 +794,7 @@ static bool LinuxProcessList_readCmdlineFile(Process* process, const char* dirna
}
command[lastChar + 1] = '\0';
process->basenameOffset = tokenEnd;
- setCommand(process, command, lastChar);
+ setCommand(process, command, lastChar + 1);
return true;
}
@@ -723,13 +808,13 @@ static char* LinuxProcessList_updateTtyDevice(TtyDriver* ttyDrivers, unsigned in
i++;
if ((!ttyDrivers[i].path) || maj < ttyDrivers[i].major) {
break;
- }
+ }
if (maj > ttyDrivers[i].major) {
continue;
}
if (min < ttyDrivers[i].minorFrom) {
break;
- }
+ }
if (min > ttyDrivers[i].minorTo) {
continue;
}
@@ -737,11 +822,11 @@ static char* LinuxProcessList_updateTtyDevice(TtyDriver* ttyDrivers, unsigned in
struct stat sstat;
char* fullPath;
for(;;) {
- asprintf(&fullPath, "%s/%d", ttyDrivers[i].path, idx);
+ xAsprintf(&fullPath, "%s/%d", ttyDrivers[i].path, idx);
int err = stat(fullPath, &sstat);
if (err == 0 && major(sstat.st_rdev) == maj && minor(sstat.st_rdev) == min) return fullPath;
free(fullPath);
- asprintf(&fullPath, "%s%d", ttyDrivers[i].path, idx);
+ xAsprintf(&fullPath, "%s%d", ttyDrivers[i].path, idx);
err = stat(fullPath, &sstat);
if (err == 0 && major(sstat.st_rdev) == maj && minor(sstat.st_rdev) == min) return fullPath;
free(fullPath);
@@ -752,7 +837,7 @@ static char* LinuxProcessList_updateTtyDevice(TtyDriver* ttyDrivers, unsigned in
if (err == 0 && tty_nr == sstat.st_rdev) return strdup(ttyDrivers[i].path);
}
char* out;
- asprintf(&out, "/dev/%u:%u", maj, min);
+ xAsprintf(&out, "/dev/%u:%u", maj, min);
return out;
}
@@ -762,7 +847,6 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, const char*
struct dirent* entry;
Settings* settings = pl->settings;
- time_t curTime = tv.tv_sec;
#ifdef HAVE_TASKSTATS
unsigned long long now = tv.tv_sec*1000LL+tv.tv_usec/1000LL;
#endif
@@ -788,17 +872,17 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, const char*
// filename is a number: process directory
int pid = atoi(name);
-
+
if (parent && pid == parent->pid)
continue;
- if (pid <= 0)
+ if (pid <= 0)
continue;
bool preExisting = false;
Process* proc = ProcessList_getProcess(pl, pid, &preExisting, (Process_New) LinuxProcess_new);
proc->tgid = parent ? parent->pid : pid;
-
+
LinuxProcess* lp = (LinuxProcess*) proc;
char subdirname[MAX_NAME+1];
@@ -813,6 +897,21 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, const char*
if (! LinuxProcessList_readStatmFile(lp, dirname, name))
goto errorReadingProcess;
+ if ((settings->flags & PROCESS_FLAG_LINUX_SMAPS) && !Process_isKernelThread(proc)){
+ if (!parent){
+ // Read smaps file of each process only every second pass to improve performance
+ static int smaps_flag = 0;
+ if ((pid & 1) == smaps_flag){
+ LinuxProcessList_readSmapsFile(lp, dirname, name, this->haveSmapsRollup);
+ }
+ if (pid == 1) {
+ smaps_flag = !smaps_flag;
+ }
+ } else {
+ lp->m_pss = ((LinuxProcess*)parent)->m_pss;
+ }
+ }
+
proc->show = ! ((hideKernelThreads && Process_isKernelThread(proc)) || (hideUserlandThreads && Process_isUserlandThread(proc)));
char command[MAX_NAME+1];
@@ -834,7 +933,7 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, const char*
if(!preExisting) {
- if (! LinuxProcessList_statProcessDir(proc, dirname, name, curTime))
+ if (! LinuxProcessList_statProcessDir(proc, dirname, name))
goto errorReadingProcess;
proc->user = UsersTable_getRef(pl->usersTable, proc->st_uid);
@@ -844,7 +943,7 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, const char*
LinuxProcessList_readOpenVZData(lp, dirname, name);
}
#endif
-
+
#ifdef HAVE_VSERVER
if (settings->flags & PROCESS_FLAG_LINUX_VSERVER) {
LinuxProcessList_readVServerData(lp, dirname, name);
@@ -872,7 +971,7 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, const char*
if (settings->flags & PROCESS_FLAG_LINUX_CGROUP)
LinuxProcessList_readCGroupFile(lp, dirname, name);
#endif
-
+
if (settings->flags & PROCESS_FLAG_LINUX_OOM)
LinuxProcessList_readOomData(lp, dirname, name);
@@ -925,30 +1024,30 @@ static inline void LinuxProcessList_scanMemoryInfo(ProcessList* this) {
char buffer[128];
while (fgets(buffer, 128, file)) {
- #define tryRead(label, variable) (String_startsWith(buffer, label) && sscanf(buffer + strlen(label), " %32llu kB", variable))
+ #define tryRead(label, variable) do { if (String_startsWith(buffer, label) && sscanf(buffer + strlen(label), " %32llu kB", variable)) { break; } } while(0)
switch (buffer[0]) {
case 'M':
- if (tryRead("MemTotal:", &this->totalMem)) {}
- else if (tryRead("MemFree:", &this->freeMem)) {}
- else if (tryRead("MemShared:", &this->sharedMem)) {}
+ tryRead("MemTotal:", &this->totalMem);
+ tryRead("MemFree:", &this->freeMem);
+ tryRead("MemShared:", &this->sharedMem);
break;
case 'B':
- if (tryRead("Buffers:", &this->buffersMem)) {}
+ tryRead("Buffers:", &this->buffersMem);
break;
case 'C':
- if (tryRead("Cached:", &this->cachedMem)) {}
+ tryRead("Cached:", &this->cachedMem);
break;
case 'S':
switch (buffer[1]) {
case 'w':
- if (tryRead("SwapTotal:", &this->totalSwap)) {}
- else if (tryRead("SwapFree:", &swapFree)) {}
+ tryRead("SwapTotal:", &this->totalSwap);
+ tryRead("SwapFree:", &swapFree);
break;
case 'h':
- if (tryRead("Shmem:", &shmem)) {}
+ tryRead("Shmem:", &shmem);
break;
case 'R':
- if (tryRead("SReclaimable:", &sreclaimable)) {}
+ tryRead("SReclaimable:", &sreclaimable);
break;
}
break;
@@ -962,6 +1061,68 @@ static inline void LinuxProcessList_scanMemoryInfo(ProcessList* this) {
fclose(file);
}
+static inline void LinuxProcessList_scanZfsArcstats(LinuxProcessList* lpl) {
+ unsigned long long int dbufSize;
+ unsigned long long int dnodeSize;
+ unsigned long long int bonusSize;
+
+ FILE* file = fopen(PROCARCSTATSFILE, "r");
+ if (file == NULL) {
+ lpl->zfs.enabled = 0;
+ return;
+ }
+ char buffer[128];
+ while (fgets(buffer, 128, file)) {
+ #define tryRead(label, variable) do { if (String_startsWith(buffer, label) && sscanf(buffer + strlen(label), " %*2u %32llu", variable)) { break; } } while(0)
+ #define tryReadFlag(label, variable, flag) do { if (String_startsWith(buffer, label) && sscanf(buffer + strlen(label), " %*2u %32llu", variable)) { flag = 1; break; } else { flag = 0; } } while(0)
+ switch (buffer[0]) {
+ case 'c':
+ tryRead("c_max", &lpl->zfs.max);
+ tryReadFlag("compressed_size", &lpl->zfs.compressed, lpl->zfs.isCompressed);
+ break;
+ case 'u':
+ tryRead("uncompressed_size", &lpl->zfs.uncompressed);
+ break;
+ case 's':
+ tryRead("size", &lpl->zfs.size);
+ break;
+ case 'h':
+ tryRead("hdr_size", &lpl->zfs.header);
+ break;
+ case 'd':
+ tryRead("dbuf_size", &dbufSize);
+ tryRead("dnode_size", &dnodeSize);
+ break;
+ case 'b':
+ tryRead("bonus_size", &bonusSize);
+ break;
+ case 'a':
+ tryRead("anon_size", &lpl->zfs.anon);
+ break;
+ case 'm':
+ tryRead("mfu_size", &lpl->zfs.MFU);
+ tryRead("mru_size", &lpl->zfs.MRU);
+ break;
+ }
+ #undef tryRead
+ #undef tryReadFlag
+ }
+ fclose(file);
+
+ lpl->zfs.enabled = (lpl->zfs.size > 0 ? 1 : 0);
+ lpl->zfs.size /= 1024;
+ lpl->zfs.max /= 1024;
+ lpl->zfs.MFU /= 1024;
+ lpl->zfs.MRU /= 1024;
+ lpl->zfs.anon /= 1024;
+ lpl->zfs.header /= 1024;
+ lpl->zfs.other = (dbufSize + dnodeSize + bonusSize) / 1024;
+ if ( lpl->zfs.isCompressed ) {
+ lpl->zfs.compressed /= 1024;
+ lpl->zfs.uncompressed /= 1024;
+ }
+}
+
static inline double LinuxProcessList_scanCPUTime(LinuxProcessList* this) {
FILE* file = fopen(PROCSTATFILE, "r");
@@ -1026,18 +1187,87 @@ static inline double LinuxProcessList_scanCPUTime(LinuxProcessList* this) {
cpuData->stealTime = steal;
cpuData->guestTime = virtalltime;
cpuData->totalTime = totaltime;
+
}
double period = (double)this->cpus[0].totalPeriod / cpus;
fclose(file);
return period;
}
+static inline double LinuxProcessList_scanCPUFrequency(LinuxProcessList* this) {
+ ProcessList* pl = (ProcessList*) this;
+ Settings* settings = pl->settings;
+
+ int cpus = this->super.cpuCount;
+ assert(cpus > 0);
+
+ for (int i = 0; i <= cpus; i++) {
+ CPUData* cpuData = &(this->cpus[i]);
+ cpuData->frequency = -1;
+ }
+
+ int numCPUsWithFrequency = 0;
+ double totalFrequency = 0;
+
+ if (settings->showCPUFrequency) {
+ FILE* file = fopen(PROCCPUINFOFILE, "r");
+ if (file == NULL) {
+ CRT_fatalError("Cannot open " PROCCPUINFOFILE);
+ }
+
+ int cpuid = -1;
+ double frequency;
+ while (!feof(file)) {
+ char buffer[PROC_LINE_LENGTH];
+ char *ok = fgets(buffer, PROC_LINE_LENGTH, file);
+ if (!ok) break;
+
+ if (
+ (sscanf(buffer, "processor : %d", &cpuid) == 1) ||
+ (sscanf(buffer, "processor: %d", &cpuid) == 1)
+ ) {
+ if (cpuid < 0 || cpuid > (cpus - 1)) {
+ char tmpbuffer[64];
+ xSnprintf(tmpbuffer, sizeof(tmpbuffer), PROCCPUINFOFILE " contains out-of-range CPU number %d", cpuid);
+ CRT_fatalError(tmpbuffer);
+ }
+ } else if (
+ (sscanf(buffer, "cpu MHz : %lf", &frequency) == 1) ||
+ (sscanf(buffer, "cpu MHz: %lf", &frequency) == 1)
+ ) {
+ if (cpuid < 0) {
+ CRT_fatalError(PROCCPUINFOFILE " is malformed: cpu MHz line without corresponding processor line");
+ }
+
+ int cpu = cpuid + 1;
+ CPUData* cpuData = &(this->cpus[cpu]);
+ cpuData->frequency = frequency;
+ numCPUsWithFrequency++;
+ totalFrequency += frequency;
+ } else if (buffer[0] == '\n') {
+ cpuid = -1;
+ }
+ }
+ fclose(file);
+
+ if (numCPUsWithFrequency > 0) {
+ this->cpus[0].frequency = totalFrequency / numCPUsWithFrequency;
+ }
+ }
+
+ double period = (double)this->cpus[0].totalPeriod / cpus;
+ return period;
+}
+
void ProcessList_goThroughEntries(ProcessList* super) {
LinuxProcessList* this = (LinuxProcessList*) super;
LinuxProcessList_scanMemoryInfo(super);
+ LinuxProcessList_scanZfsArcstats(this);
double period = LinuxProcessList_scanCPUTime(this);
+ LinuxProcessList_scanCPUFrequency(this);
+
struct timeval tv;
gettimeofday(&tv, NULL);
LinuxProcessList_recurseProcTree(this, PROCDIR, NULL, period, tv);
diff --git a/linux/LinuxProcessList.h b/linux/LinuxProcessList.h
index 0851a10..86e9d3f 100644
--- a/linux/LinuxProcessList.h
+++ b/linux/LinuxProcessList.h
@@ -10,8 +10,7 @@ in the source distribution for its full text.
*/
#ifdef MAJOR_IN_MKDEV
-#elif defined(MAJOR_IN_SYSMACROS) || \
- (defined(HAVE_SYS_SYSMACROS_H) && HAVE_SYS_SYSMACROS_H)
+#elif defined(MAJOR_IN_SYSMACROS)
#endif
#ifdef HAVE_DELAYACCT
@@ -19,6 +18,9 @@ in the source distribution for its full text.
#include "ProcessList.h"
+#include "zfs/ZfsArcStats.h"
+
+extern long long btime;
typedef struct CPUData_ {
unsigned long long int totalTime;
@@ -33,7 +35,7 @@ typedef struct CPUData_ {
unsigned long long int softIrqTime;
unsigned long long int stealTime;
unsigned long long int guestTime;
-
+
unsigned long long int totalPeriod;
unsigned long long int userPeriod;
unsigned long long int systemPeriod;
@@ -46,6 +48,8 @@ typedef struct CPUData_ {
unsigned long long int softIrqPeriod;
unsigned long long int stealPeriod;
unsigned long long int guestPeriod;
+
+ double frequency;
} CPUData;
typedef struct TtyDriver_ {
@@ -57,20 +61,27 @@ typedef struct TtyDriver_ {
typedef struct LinuxProcessList_ {
ProcessList super;
-
+
CPUData* cpus;
TtyDriver* ttyDrivers;
-
+ bool haveSmapsRollup;
+
#ifdef HAVE_DELAYACCT
struct nl_sock *netlink_socket;
int netlink_family;
#endif
+
+ ZfsArcStats zfs;
} LinuxProcessList;
#ifndef PROCDIR
#define PROCDIR "/proc"
#endif
+#ifndef PROCCPUINFOFILE
+#define PROCCPUINFOFILE PROCDIR "/cpuinfo"
+#endif
+
#ifndef PROCSTATFILE
#define PROCSTATFILE PROCDIR "/stat"
#endif
@@ -79,12 +90,16 @@ typedef struct LinuxProcessList_ {
#define PROCMEMINFOFILE PROCDIR "/meminfo"
#endif
+#ifndef PROCARCSTATSFILE
+#define PROCARCSTATSFILE PROCDIR "/spl/kstat/zfs/arcstats"
+#endif
+
#ifndef PROCTTYDRIVERSFILE
#define PROCTTYDRIVERSFILE PROCDIR "/tty/drivers"
#endif
#ifndef PROC_LINE_LENGTH
-#define PROC_LINE_LENGTH 512
+#define PROC_LINE_LENGTH 4096
#endif
@@ -96,9 +111,9 @@ typedef struct LinuxProcessList_ {
#endif
-ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, uid_t userId);
+extern ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, uid_t userId);
-void ProcessList_delete(ProcessList* pl);
+extern void ProcessList_delete(ProcessList* pl);
#ifdef HAVE_TASKSTATS
@@ -121,6 +136,6 @@ void ProcessList_delete(ProcessList* pl);
#endif
-void ProcessList_goThroughEntries(ProcessList* super);
+extern void ProcessList_goThroughEntries(ProcessList* super);
#endif
diff --git a/linux/Platform.c b/linux/Platform.c
index ab90ca7..0f59fed 100644
--- a/linux/Platform.c
+++ b/linux/Platform.c
@@ -19,8 +19,11 @@ in the source distribution for its full text.
#include "TasksMeter.h"
#include "LoadAverageMeter.h"
#include "UptimeMeter.h"
+#include "PressureStallMeter.h"
#include "ClockMeter.h"
#include "HostnameMeter.h"
+#include "zfs/ZfsArcMeter.h"
+#include "zfs/ZfsCompressedArcMeter.h"
#include "LinuxProcess.h"
#include <math.h>
@@ -41,7 +44,7 @@ in the source distribution for its full text.
#define CLAMP(x,low,high) (((x)>(high))?(high):(((x)<(low))?(low):(x)))
#endif
-ProcessField Platform_defaultFields[] = { PID, USER, PRIORITY, NICE, M_SIZE, M_RESIDENT, M_SHARE, STATE, PERCENT_CPU, PERCENT_MEM, TIME, COMM, 0 };
+ProcessField Platform_defaultFields[] = { PID, USER, PRIORITY, NICE, M_SIZE, M_RESIDENT, (int)M_SHARE, STATE, PERCENT_CPU, PERCENT_MEM, TIME, COMM, 0 };
//static ProcessField defaultIoFields[] = { PID, IO_PRIORITY, USER, IO_READ_RATE, IO_WRITE_RATE, IO_RATE, COMM, 0 };
@@ -91,12 +94,12 @@ static Htop_Reaction Platform_actionSetIOPriority(State* st) {
LinuxProcess* p = (LinuxProcess*) Panel_getSelected(panel);
if (!p) return HTOP_OK;
- IOPriority ioprio = p->ioPriority;
- Panel* ioprioPanel = IOPriorityPanel_new(ioprio);
- void* set = Action_pickFromVector(st, ioprioPanel, 21);
+ IOPriority ioprio1 = p->ioPriority;
+ Panel* ioprioPanel = IOPriorityPanel_new(ioprio1);
+ void* set = Action_pickFromVector(st, ioprioPanel, 21, true);
if (set) {
- IOPriority ioprio = IOPriorityPanel_getIOPriority(ioprioPanel);
- bool ok = MainPanel_foreachProcess((MainPanel*)panel, (MainPanel_ForeachProcessFn) LinuxProcess_setIOPriority, (Arg){ .i = ioprio }, NULL);
+ IOPriority ioprio2 = IOPriorityPanel_getIOPriority(ioprioPanel);
+ bool ok = MainPanel_foreachProcess((MainPanel*)panel, (MainPanel_ForeachProcessFn) LinuxProcess_setIOPriority, (Arg){ .i = ioprio2 }, NULL);
if (!ok)
beep();
}
@@ -121,11 +124,21 @@ MeterClass* Platform_meterTypes[] = {
&HostnameMeter_class,
&AllCPUsMeter_class,
&AllCPUs2Meter_class,
+ &AllCPUs4Meter_class,
&LeftCPUsMeter_class,
&RightCPUsMeter_class,
&LeftCPUs2Meter_class,
&RightCPUs2Meter_class,
+ &LeftCPUs4Meter_class,
+ &RightCPUs4Meter_class,
&BlankMeter_class,
+ &PressureStallCPUSomeMeter_class,
+ &PressureStallIOSomeMeter_class,
+ &PressureStallIOFullMeter_class,
+ &PressureStallMemorySomeMeter_class,
+ &PressureStallMemoryFullMeter_class,
+ &ZfsArcMeter_class,
+ &ZfsCompressedArcMeter_class,
NULL
};
@@ -192,6 +205,9 @@ double Platform_setCPUValues(Meter* this, int cpu) {
}
percent = CLAMP(percent, 0.0, 100.0);
if (isnan(percent)) percent = 0.0;
+
+ v[CPU_METER_FREQUENCY] = cpuData->frequency;
+
return percent;
}
@@ -213,6 +229,17 @@ void Platform_setSwapValues(Meter* this) {
this->values[0] = pl->usedSwap;
}
+void Platform_setZfsArcValues(Meter* this) {
+ LinuxProcessList* lpl = (LinuxProcessList*) this->pl;
+
+ ZfsArcMeter_readStats(this, &(lpl->zfs));
+}
+
+void Platform_setZfsCompressedArcValues(Meter* this) {
+ LinuxProcessList* lpl = (LinuxProcessList*) this->pl;
+
+ ZfsCompressedArcMeter_readStats(this, &(lpl->zfs));
+}
char* Platform_getProcessEnv(pid_t pid) {
char procname[32+1];
xSnprintf(procname, 32, "/proc/%d/environ", pid);
@@ -237,3 +264,21 @@ char* Platform_getProcessEnv(pid_t pid) {
}
return env;
}
+
+void Platform_getPressureStall(const char *file, bool some, double* ten, double* sixty, double* threehundred) {
+ *ten = *sixty = *threehundred = 0;
+ char procname[128+1];
+ xSnprintf(procname, 128, PROCDIR "/pressure/%s", file);
+ FILE *fd = fopen(procname, "r");
+ if (!fd) {
+ *ten = *sixty = *threehundred = NAN;
+ return;
+ }
+ int total = fscanf(fd, "some avg10=%32lf avg60=%32lf avg300=%32lf total=%*f ", ten, sixty, threehundred);
+ if (!some) {
+ total = fscanf(fd, "full avg10=%32lf avg60=%32lf avg300=%32lf total=%*f ", ten, sixty, threehundred);
+ }
+ (void) total;
+ assert(total == 3);
+ fclose(fd);
+}
diff --git a/linux/Platform.h b/linux/Platform.h
index b0456e5..bf163a5 100644
--- a/linux/Platform.h
+++ b/linux/Platform.h
@@ -27,22 +27,27 @@ extern const SignalItem Platform_signals[];
extern const unsigned int Platform_numberOfSignals;
-void Platform_setBindings(Htop_Action* keys);
+extern void Platform_setBindings(Htop_Action* keys);
extern MeterClass* Platform_meterTypes[];
-int Platform_getUptime();
+extern int Platform_getUptime();
-void Platform_getLoadAverage(double* one, double* five, double* fifteen);
+extern void Platform_getLoadAverage(double* one, double* five, double* fifteen);
-int Platform_getMaxPid();
+extern int Platform_getMaxPid();
-double Platform_setCPUValues(Meter* this, int cpu);
+extern double Platform_setCPUValues(Meter* this, int cpu);
-void Platform_setMemoryValues(Meter* this);
+extern void Platform_setMemoryValues(Meter* this);
-void Platform_setSwapValues(Meter* this);
+extern void Platform_setSwapValues(Meter* this);
-char* Platform_getProcessEnv(pid_t pid);
+extern void Platform_setZfsArcValues(Meter* this);
+
+extern void Platform_setZfsCompressedArcValues(Meter* this);
+extern char* Platform_getProcessEnv(pid_t pid);
+
+extern void Platform_getPressureStall(const char *file, bool some, double* ten, double* sixty, double* threehundred);
#endif
diff --git a/linux/PressureStallMeter.c b/linux/PressureStallMeter.c
new file mode 100644
index 0000000..56055bf
--- /dev/null
+++ b/linux/PressureStallMeter.c
@@ -0,0 +1,133 @@
+/*
+htop - PressureStallMeter.c
+(C) 2004-2011 Hisham H. Muhammad
+(C) 2019 Ran Benita
+Released under the GNU GPL, see the COPYING file
+in the source distribution for its full text.
+*/
+
+#include "PressureStallMeter.h"
+#include "Platform.h"
+#include "CRT.h"
+
+#include <string.h>
+
+/*{
+#include "Meter.h"
+}*/
+
+static int PressureStallMeter_attributes[] = {
+ PRESSURE_STALL_TEN, PRESSURE_STALL_SIXTY, PRESSURE_STALL_THREEHUNDRED
+};
+
+static void PressureStallMeter_updateValues(Meter* this, char* buffer, int len) {
+ const char *file;
+ if (strstr(Meter_name(this), "CPU")) {
+ file = "cpu";
+ } else if (strstr(Meter_name(this), "IO")) {
+ file = "io";
+ } else {
+ file = "memory";
+ }
+
+ bool some;
+ if (strstr(Meter_name(this), "Some")) {
+ some = true;
+ } else {
+ some = false;
+ }
+
+ Platform_getPressureStall(file, some, &this->values[0], &this->values[1], &this->values[2]);
+ xSnprintf(buffer, len, "xxxx %.2lf%% %.2lf%% %.2lf%%", this->values[0], this->values[1], this->values[2]);
+}
+
+static void PressureStallMeter_display(Object* cast, RichString* out) {
+ Meter* this = (Meter*)cast;
+ char buffer[20];
+ xSnprintf(buffer, sizeof(buffer), "%.2lf%% ", this->values[0]);
+ RichString_write(out, CRT_colors[PRESSURE_STALL_TEN], buffer);
+ xSnprintf(buffer, sizeof(buffer), "%.2lf%% ", this->values[1]);
+ RichString_append(out, CRT_colors[PRESSURE_STALL_SIXTY], buffer);
+ xSnprintf(buffer, sizeof(buffer), "%.2lf%% ", this->values[2]);
+ RichString_append(out, CRT_colors[PRESSURE_STALL_THREEHUNDRED], buffer);
+}
+
+MeterClass PressureStallCPUSomeMeter_class = {
+ .super = {
+ .extends = Class(Meter),
+ .delete = Meter_delete,
+ .display = PressureStallMeter_display,
+ },
+ .updateValues = PressureStallMeter_updateValues,
+ .defaultMode = TEXT_METERMODE,
+ .maxItems = 3,
+ .total = 100.0,
+ .attributes = PressureStallMeter_attributes,
+ .name = "PressureStallCPUSome",
+ .uiName = "Pressure Stall Information, some CPU",
+ .caption = "Some CPU pressure: "
+};
+
+MeterClass PressureStallIOSomeMeter_class = {
+ .super = {
+ .extends = Class(Meter),
+ .delete = Meter_delete,
+ .display = PressureStallMeter_display,
+ },
+ .updateValues = PressureStallMeter_updateValues,
+ .defaultMode = TEXT_METERMODE,
+ .maxItems = 3,
+ .total = 100.0,
+ .attributes = PressureStallMeter_attributes,
+ .name = "PressureStallIOSome",
+ .uiName = "Pressure Stall Information, some IO",
+ .caption = "Some IO pressure: "
+};
+
+MeterClass PressureStallIOFullMeter_class = {
+ .super = {
+ .extends = Class(Meter),
+ .delete = Meter_delete,
+ .display = PressureStallMeter_display,
+ },
+ .updateValues = PressureStallMeter_updateValues,
+ .defaultMode = TEXT_METERMODE,
+ .maxItems = 3,
+ .total = 100.0,
+ .attributes = PressureStallMeter_attributes,
+ .name = "PressureStallIOFull",
+ .uiName = "Pressure Stall Information, full IO",
+ .caption = "Full IO pressure: "
+};
+
+MeterClass PressureStallMemorySomeMeter_class = {
+ .super = {
+ .extends = Class(Meter),
+ .delete = Meter_delete,
+ .display = PressureStallMeter_display,
+ },
+ .updateValues = PressureStallMeter_updateValues,
+ .defaultMode = TEXT_METERMODE,
+ .maxItems = 3,
+ .total = 100.0,
+ .attributes = PressureStallMeter_attributes,
+ .name = "PressureStallMemorySome",
+ .uiName = "Pressure Stall Information, some memory",
+ .caption = "Some Mem pressure: "
+};
+
+MeterClass PressureStallMemoryFullMeter_class = {
+ .super = {
+ .extends = Class(Meter),
+ .delete = Meter_delete,
+ .display = PressureStallMeter_display,
+ },
+ .updateValues = PressureStallMeter_updateValues,
+ .defaultMode = TEXT_METERMODE,
+ .maxItems = 3,
+ .total = 100.0,
+ .attributes = PressureStallMeter_attributes,
+ .name = "PressureStallMemoryFull",
+ .uiName = "Pressure Stall Information, full memory",
+ .caption = "Full Mem pressure: "
+};
diff --git a/linux/PressureStallMeter.h b/linux/PressureStallMeter.h
new file mode 100644
index 0000000..22b8b97
--- /dev/null
+++ b/linux/PressureStallMeter.h
@@ -0,0 +1,25 @@
+/* Do not edit this file. It was automatically generated. */
+
+#ifndef HEADER_PressureStallMeter
+#define HEADER_PressureStallMeter
+/*
+htop - PressureStallMeter.h
+(C) 2004-2011 Hisham H. Muhammad
+(C) 2019 Ran Benita
+Released under the GNU GPL, see the COPYING file
+in the source distribution for its full text.
+*/
+
+#include "Meter.h"
+
+extern MeterClass PressureStallCPUSomeMeter_class;
+
+extern MeterClass PressureStallIOSomeMeter_class;
+
+extern MeterClass PressureStallIOFullMeter_class;
+
+extern MeterClass PressureStallMemorySomeMeter_class;
+
+extern MeterClass PressureStallMemoryFullMeter_class;
+
+#endif

© 2014-2024 Faster IT GmbH | imprint | privacy policy