Merge pull request #203 from takeoverjp/feature-garbage-collect-inodeproc

Issue: #96 - Garbage collect inodeproc on each ui refresh.
This commit is contained in:
Arnout Engelen
2021-02-17 15:26:49 +01:00
committed by GitHub
6 changed files with 93 additions and 1 deletions

View File

@@ -19,6 +19,7 @@ nethogs \- Net top tool grouping bandwidth per process
.RB [ "\-l" ] .RB [ "\-l" ]
.RB [ "\-f filter" ] .RB [ "\-f filter" ]
.RB [ "\-C" ] .RB [ "\-C" ]
.RB [ "\-g period" ]
.RI [device(s)] .RI [device(s)]
.SH DESCRIPTION .SH DESCRIPTION
NetHogs is a small 'net top' tool. Instead of breaking the traffic down per protocol or per subnet, like most such tools do, it groups bandwidth by process - and does not rely on a special kernel module to be loaded. So if there's suddenly a lot of network traffic, you can fire up NetHogs and immediately see which PID is causing this, and if it's some kind of spinning process, kill it. NetHogs is a small 'net top' tool. Instead of breaking the traffic down per protocol or per subnet, like most such tools do, it groups bandwidth by process - and does not rely on a special kernel module to be loaded. So if there's suddenly a lot of network traffic, you can fire up NetHogs and immediately see which PID is causing this, and if it's some kind of spinning process, kill it.
@@ -61,6 +62,9 @@ monitor all devices, even loopback/stopped ones.
\fB-C\fP \fB-C\fP
capture TCP and UDP. capture TCP and UDP.
.TP .TP
\fB-g\fP
garbage collection period in number of refresh. default is 50.
.TP
\fB-f\fP \fB-f\fP
EXPERIMENTAL: specify string pcap filter (like tcpdump). This may be removed or changed in a future version. EXPERIMENTAL: specify string pcap filter (like tcpdump). This may be removed or changed in a future version.
.TP .TP

View File

@@ -20,6 +20,7 @@
* *
*/ */
#include <algorithm>
#include <cerrno> #include <cerrno>
#include <climits> #include <climits>
#include <cstdio> #include <cstdio>
@@ -30,6 +31,7 @@
#include <fcntl.h> #include <fcntl.h>
#include <iostream> #include <iostream>
#include <map> #include <map>
#include <set>
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <sys/stat.h> #include <sys/stat.h>
@@ -224,6 +226,73 @@ void get_info_for_pid(const char *pid) {
closedir(dir); closedir(dir);
} }
static quad_t get_ms() {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return static_cast<quad_t>(ts.tv_sec) * 1000 + ts.tv_nsec / 1000000;
}
static void get_pids(std::set<pid_t> *pids) {
DIR *proc = opendir("/proc");
if (proc == 0) {
std::cerr << "Error reading /proc, needed to get pid set" << std::endl;
exit(1);
}
dirent *entry;
while ((entry = readdir(proc))) {
if (entry->d_type != DT_DIR)
continue;
if (!is_number(entry->d_name))
continue;
pids->insert(str2int(entry->d_name));
}
closedir(proc);
}
void garbage_collect_inodeproc() {
static quad_t last_ms = 0;
quad_t start_ms = 0;
if (bughuntmode) {
start_ms = get_ms();
if (last_ms) {
std::cout << "PERF: GC interval: " << start_ms - last_ms << "[ms]"
<< std::endl;
}
}
std::set<pid_t> pids;
get_pids(&pids);
if (pids.size() == 0) {
return;
}
for (std::map<unsigned long, prg_node *>::iterator it = inodeproc.begin();
it != inodeproc.end();) {
if (!it->second || pids.find(it->second->pid) != pids.end()) {
++it;
continue;
}
if (bughuntmode) {
std::cout << "GC prg_node (inode=" << it->first
<< ", pid=" << it->second->pid
<< ", cmdline=" << it->second->cmdline.c_str() << ")"
<< std::endl;
}
delete it->second;
inodeproc.erase(it++);
}
if (bughuntmode) {
last_ms = get_ms();
std::cout << "PERF: GC proctime: " << last_ms - start_ms << "[ms]"
<< std::endl;
}
}
/* updates the `inodeproc' inode-to-prg_node mapping /* updates the `inodeproc' inode-to-prg_node mapping
* for all processes in /proc */ * for all processes in /proc */
void reread_mapping() { void reread_mapping() {

View File

@@ -41,4 +41,6 @@ void prg_cache_clear();
// reread the inode-to-prg_node-mapping // reread the inode-to-prg_node-mapping
void reread_mapping(); void reread_mapping();
void garbage_collect_inodeproc();
#endif #endif

View File

@@ -46,6 +46,8 @@ static void help(bool iserror) {
output << " -a : monitor all devices, even loopback/stopped " output << " -a : monitor all devices, even loopback/stopped "
"ones.\n"; "ones.\n";
output << " -C : capture TCP and UDP.\n"; output << " -C : capture TCP and UDP.\n";
output << " -g : garbage collection period in number of refresh. "
"default is 50.\n";
output << " -f : EXPERIMENTAL: specify string pcap filter (like " output << " -f : EXPERIMENTAL: specify string pcap filter (like "
"tcpdump)." "tcpdump)."
" This may be removed or changed in a future version.\n"; " This may be removed or changed in a future version.\n";
@@ -140,9 +142,10 @@ int main(int argc, char **argv) {
int promisc = 0; int promisc = 0;
bool all = false; bool all = false;
char *filter = NULL; char *filter = NULL;
int garbage_collection_period = 50;
int opt; int opt;
while ((opt = getopt(argc, argv, "Vhbtpsd:v:c:laf:C")) != -1) { while ((opt = getopt(argc, argv, "Vhbtpsd:v:c:laf:Cg:")) != -1) {
switch (opt) { switch (opt) {
case 'V': case 'V':
versiondisplay(); versiondisplay();
@@ -184,6 +187,9 @@ int main(int argc, char **argv) {
case 'C': case 'C':
catchall = true; catchall = true;
break; break;
case 'g':
garbage_collection_period = (time_t)atoi(optarg);
break;
default: default:
help(true); help(true);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
@@ -294,6 +300,7 @@ int main(int argc, char **argv) {
struct dpargs *userdata = (dpargs *)malloc(sizeof(struct dpargs)); struct dpargs *userdata = (dpargs *)malloc(sizeof(struct dpargs));
// Main loop: // Main loop:
int refresh_count = 0;
while (1) { while (1) {
bool packets_read = false; bool packets_read = false;
@@ -322,6 +329,12 @@ int main(int argc, char **argv) {
ui_tick(); ui_tick();
} }
do_refresh(); do_refresh();
++refresh_count;
if ((garbage_collection_period > 0) &&
(refresh_count % garbage_collection_period == 0)) {
garbage_collect_processes();
}
} }
// if not packets, do a select() until next packet // if not packets, do a select() until next packet

View File

@@ -424,3 +424,5 @@ void remove_timed_out_processes() {
previousproc = curproc; previousproc = curproc;
} }
} }
void garbage_collect_processes() { garbage_collect_inodeproc(); }

View File

@@ -145,4 +145,6 @@ void procclean();
void remove_timed_out_processes(); void remove_timed_out_processes();
void garbage_collect_processes();
#endif #endif