mirror of https://github.com/xzeldon/htop.git
Calculate library size (M_LRS column) from maps file
This commit is contained in:
parent
46a2e8ac63
commit
7f18b352b0
|
@ -9,6 +9,8 @@ in the source distribution for its full text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <unistd.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include "Object.h"
|
#include "Object.h"
|
||||||
|
@ -113,7 +115,7 @@ typedef struct ProcessFieldData_ {
|
||||||
const char* name;
|
const char* name;
|
||||||
const char* title;
|
const char* title;
|
||||||
const char* description;
|
const char* description;
|
||||||
int flags;
|
uint32_t flags;
|
||||||
} ProcessFieldData;
|
} ProcessFieldData;
|
||||||
|
|
||||||
// Implemented in platform-specific code:
|
// Implemented in platform-specific code:
|
||||||
|
|
|
@ -90,7 +90,7 @@ static void Settings_defaultMeters(Settings* this, int initialCpuCount) {
|
||||||
this->columns[1].modes[r++] = TEXT_METERMODE;
|
this->columns[1].modes[r++] = TEXT_METERMODE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void readFields(ProcessField* fields, int* flags, const char* line) {
|
static void readFields(ProcessField* fields, uint32_t* flags, const char* line) {
|
||||||
char* trim = String_trim(line);
|
char* trim = String_trim(line);
|
||||||
char** ids = String_split(trim, ' ', NULL);
|
char** ids = String_split(trim, ' ', NULL);
|
||||||
free(trim);
|
free(trim);
|
||||||
|
|
|
@ -27,7 +27,7 @@ typedef struct Settings_ {
|
||||||
MeterColumnSettings columns[2];
|
MeterColumnSettings columns[2];
|
||||||
|
|
||||||
ProcessField* fields;
|
ProcessField* fields;
|
||||||
int flags;
|
uint32_t flags;
|
||||||
int colorScheme;
|
int colorScheme;
|
||||||
int delay;
|
int delay;
|
||||||
|
|
||||||
|
|
|
@ -73,7 +73,7 @@ ProcessFieldData Process_fields[] = {
|
||||||
[M_SHARE] = { .name = "M_SHARE", .title = " SHR ", .description = "Size of the process's shared pages", .flags = 0, },
|
[M_SHARE] = { .name = "M_SHARE", .title = " SHR ", .description = "Size of the process's shared pages", .flags = 0, },
|
||||||
[M_TRS] = { .name = "M_TRS", .title = " CODE ", .description = "Size of the text segment of the process", .flags = 0, },
|
[M_TRS] = { .name = "M_TRS", .title = " CODE ", .description = "Size of the text segment of the process", .flags = 0, },
|
||||||
[M_DRS] = { .name = "M_DRS", .title = " DATA ", .description = "Size of the data segment plus stack usage of the process", .flags = 0, },
|
[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 (unused since Linux 2.6; always 0)", .flags = 0, },
|
[M_LRS] = { .name = "M_LRS", .title = " LIB ", .description = "The library size of the process (calculated from memory maps)", .flags = PROCESS_FLAG_LINUX_LRS_FIX, },
|
||||||
[M_DT] = { .name = "M_DT", .title = " DIRTY ", .description = "Size of the dirty pages of the process (unused since Linux 2.6; always 0)", .flags = 0, },
|
[M_DT] = { .name = "M_DT", .title = " DIRTY ", .description = "Size of the dirty pages of the process (unused since Linux 2.6; always 0)", .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_CPU] = { .name = "PERCENT_CPU", .title = "CPU% ", .description = "Percentage of the CPU time the process used in the last sampling", .flags = 0, },
|
||||||
|
|
|
@ -19,14 +19,15 @@ in the source distribution for its full text.
|
||||||
#include "Settings.h"
|
#include "Settings.h"
|
||||||
|
|
||||||
|
|
||||||
#define PROCESS_FLAG_LINUX_IOPRIO 0x0100
|
#define PROCESS_FLAG_LINUX_IOPRIO 0x00000100
|
||||||
#define PROCESS_FLAG_LINUX_OPENVZ 0x0200
|
#define PROCESS_FLAG_LINUX_OPENVZ 0x00000200
|
||||||
#define PROCESS_FLAG_LINUX_VSERVER 0x0400
|
#define PROCESS_FLAG_LINUX_VSERVER 0x00000400
|
||||||
#define PROCESS_FLAG_LINUX_CGROUP 0x0800
|
#define PROCESS_FLAG_LINUX_CGROUP 0x00000800
|
||||||
#define PROCESS_FLAG_LINUX_OOM 0x1000
|
#define PROCESS_FLAG_LINUX_OOM 0x00001000
|
||||||
#define PROCESS_FLAG_LINUX_SMAPS 0x2000
|
#define PROCESS_FLAG_LINUX_SMAPS 0x00002000
|
||||||
#define PROCESS_FLAG_LINUX_CTXT 0x4000
|
#define PROCESS_FLAG_LINUX_CTXT 0x00004000
|
||||||
#define PROCESS_FLAG_LINUX_SECATTR 0x8000
|
#define PROCESS_FLAG_LINUX_SECATTR 0x00008000
|
||||||
|
#define PROCESS_FLAG_LINUX_LRS_FIX 0x00010000
|
||||||
|
|
||||||
typedef enum UnsupportedProcessFields {
|
typedef enum UnsupportedProcessFields {
|
||||||
FLAGS = 9,
|
FLAGS = 9,
|
||||||
|
|
|
@ -13,6 +13,7 @@ in the source distribution for its full text.
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <inttypes.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -23,6 +24,7 @@ in the source distribution for its full text.
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <sys/utsname.h>
|
||||||
|
|
||||||
#ifdef HAVE_DELAYACCT
|
#ifdef HAVE_DELAYACCT
|
||||||
#include <linux/netlink.h>
|
#include <linux/netlink.h>
|
||||||
|
@ -479,7 +481,74 @@ static void LinuxProcessList_readIoFile(LinuxProcess* process, const char* dirna
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool LinuxProcessList_readStatmFile(LinuxProcess* process, const char* dirname, const char* name) {
|
typedef struct LibraryData {
|
||||||
|
uint64_t size;
|
||||||
|
bool exec;
|
||||||
|
} LibraryData;
|
||||||
|
|
||||||
|
static void LinuxProcessList_calcLibSize_helper(ATTR_UNUSED hkey_t key, void* value, void* data) {
|
||||||
|
if (!data)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!value)
|
||||||
|
return;
|
||||||
|
|
||||||
|
LibraryData* v = (LibraryData *)value;
|
||||||
|
uint64_t* d = (uint64_t *)data;
|
||||||
|
if (!v->exec)
|
||||||
|
return;
|
||||||
|
|
||||||
|
*d += v->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t LinuxProcessList_calcLibSize(const char* dirname, const char* name) {
|
||||||
|
char filename[MAX_NAME+1];
|
||||||
|
xSnprintf(filename, sizeof(filename), "%s/%s/maps", dirname, name);
|
||||||
|
FILE* mapsfile = fopen(filename, "r");
|
||||||
|
if (!mapsfile)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
Hashtable* ht = Hashtable_new(64, true);
|
||||||
|
|
||||||
|
char buffer[1024];
|
||||||
|
while (fgets(buffer, sizeof(buffer), mapsfile)) {
|
||||||
|
uint64_t map_start;
|
||||||
|
uint64_t map_end;
|
||||||
|
char map_perm[16];
|
||||||
|
uint32_t map_dummy;
|
||||||
|
int map_devmaj;
|
||||||
|
int map_devmin;
|
||||||
|
uint64_t map_inode;
|
||||||
|
|
||||||
|
if (7 != sscanf(buffer, "%"PRIx64"-%"PRIx64" %4s %"PRIx32" %d:%d %" PRIu64,
|
||||||
|
&map_start, &map_end, map_perm, &map_dummy,
|
||||||
|
&map_devmaj, &map_devmin, &map_inode))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!map_inode)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
LibraryData * libdata;
|
||||||
|
libdata = Hashtable_get(ht, map_inode);
|
||||||
|
if (!libdata) {
|
||||||
|
libdata = xCalloc(1, sizeof(LibraryData));
|
||||||
|
Hashtable_put(ht, map_inode, libdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
libdata->size += map_end - map_start;
|
||||||
|
libdata->exec |= 'x' == map_perm[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t total_size = 0;
|
||||||
|
Hashtable_foreach(ht, LinuxProcessList_calcLibSize_helper, &total_size);
|
||||||
|
|
||||||
|
Hashtable_delete(ht);
|
||||||
|
|
||||||
|
fclose(mapsfile);
|
||||||
|
return total_size / CRT_pageSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool LinuxProcessList_readStatmFile(LinuxProcess* process, const char* dirname, const char* name, bool performLookup) {
|
||||||
char filename[MAX_NAME + 1];
|
char filename[MAX_NAME + 1];
|
||||||
xSnprintf(filename, sizeof(filename), "%s/%s/statm", dirname, name);
|
xSnprintf(filename, sizeof(filename), "%s/%s/statm", dirname, name);
|
||||||
FILE* statmfile = fopen(filename, "r");
|
FILE* statmfile = fopen(filename, "r");
|
||||||
|
@ -495,6 +564,9 @@ static bool LinuxProcessList_readStatmFile(LinuxProcess* process, const char* di
|
||||||
&process->m_drs,
|
&process->m_drs,
|
||||||
&process->m_dt);
|
&process->m_dt);
|
||||||
fclose(statmfile);
|
fclose(statmfile);
|
||||||
|
if (r == 7 && !process->m_lrs && performLookup) {
|
||||||
|
process->m_lrs = LinuxProcessList_calcLibSize(dirname, name);
|
||||||
|
}
|
||||||
return r == 7;
|
return r == 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1193,7 +1265,7 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, const char*
|
||||||
if (settings->flags & PROCESS_FLAG_IO)
|
if (settings->flags & PROCESS_FLAG_IO)
|
||||||
LinuxProcessList_readIoFile(lp, dirname, name, now);
|
LinuxProcessList_readIoFile(lp, dirname, name, now);
|
||||||
|
|
||||||
if (! LinuxProcessList_readStatmFile(lp, dirname, name))
|
if (!LinuxProcessList_readStatmFile(lp, dirname, name, !!(settings->flags & PROCESS_FLAG_LINUX_LRS_FIX)))
|
||||||
goto errorReadingProcess;
|
goto errorReadingProcess;
|
||||||
|
|
||||||
if ((settings->flags & PROCESS_FLAG_LINUX_SMAPS) && !Process_isKernelThread(proc)) {
|
if ((settings->flags & PROCESS_FLAG_LINUX_SMAPS) && !Process_isKernelThread(proc)) {
|
||||||
|
|
Loading…
Reference in New Issue