Merge pull request #203 from takeoverjp/feature-garbage-collect-inodeproc
Issue: #96 - Garbage collect inodeproc on each ui refresh.
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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() {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
15
src/main.cpp
15
src/main.cpp
@@ -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
|
||||||
|
|||||||
@@ -424,3 +424,5 @@ void remove_timed_out_processes() {
|
|||||||
previousproc = curproc;
|
previousproc = curproc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void garbage_collect_processes() { garbage_collect_inodeproc(); }
|
||||||
|
|||||||
@@ -145,4 +145,6 @@ void procclean();
|
|||||||
|
|
||||||
void remove_timed_out_processes();
|
void remove_timed_out_processes();
|
||||||
|
|
||||||
|
void garbage_collect_processes();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user