Skip to content

Instantly share code, notes, and snippets.

@kokizzu
Created July 28, 2014 14:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kokizzu/97618566f6d70d038fa4 to your computer and use it in GitHub Desktop.
Save kokizzu/97618566f6d70d038fa4 to your computer and use it in GitHub Desktop.
modified netmon applet
/* opyright (C) 2010 Ciriaco Garcia de Celis
*
* This program is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License (GPL) for more details.
*
* You should have received a copy of the GNU GPL along with this
* program. If not, see <http://www.gnu.org/licenses/>.
*/
// compile with "g++ -O3 -lrt netmon.cpp -o netmon"
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <ctime>
#include <climits>
#include <cctype>
#define STATE_FILE_BASE "/dev/shm/netmon"
int exitapp(int exitcode) {
char errmsg[64];
sprintf(errmsg, "ERROR code %d", exitcode);
write(1, errmsg, strlen(errmsg));
exit(exitcode);
return exitcode;
}
const int BLOCK_SIZE = 512;
struct disk_stat {
long long read, write;
double r_rate, w_rate;
char name[16];
};
const int MAX_STAT = 32;
class disk_stats {
disk_stat stat[MAX_STAT];
int total;
public:
disk_stats() : total(0) {}
const char* parse(const char* line, double seconds) {
if(total>=MAX_STAT) exitapp(11);
static char cad[256], buffer[256];
long long dummy;
disk_stat &ds = stat[total];
sscanf(line,"%lld %lld %s %lld %lld %lld %lld %lld %lld %lld",
&dummy,&dummy,ds.name,&dummy,&dummy,&ds.read,&dummy,&dummy,&dummy,&ds.write);
int len = strlen(ds.name);
if(!dummy) return 0;
if(isdigit(ds.name[len-1])) return 0;
long long prev_read = 0, prev_write = 0;
sprintf(cad,"%s.%s.%d",STATE_FILE_BASE,ds.name,getuid());
int fd = open(cad, O_RDWR | O_CREAT, 0664);
if (fd < 0) exitapp(9);
int bytes = read(fd, buffer, sizeof(buffer)-1);
if (bytes < 0) exitapp(10);
buffer[bytes] = 0;
sscanf(buffer,"%lld %lld",&prev_read,&prev_write);
lseek(fd, 0, SEEK_SET);
sprintf(buffer,"%lld %lld",ds.read,ds.write);
write(fd, buffer, 64);
close(fd);
ds.r_rate = (ds.read-prev_read)/seconds*BLOCK_SIZE/1024/1024;
ds.w_rate = (ds.write-prev_write)/seconds*BLOCK_SIZE/1024/1024;
if(ds.r_rate>0) {
if(ds.w_rate>0) sprintf(buffer," | %s: %3.0lf %3.0lf",ds.name,ds.r_rate,ds.w_rate);
else sprintf(buffer," | %s: %3.0lf .",ds.name,ds.r_rate);
} else {
if(ds.w_rate>0) sprintf(buffer," | %s: . %3.0lf",ds.name,ds.w_rate);
else sprintf(buffer," | %s: . .",ds.name);
}
++total;
return buffer;
}
};
int main(int argc, char** argv) {
if (argc < 2) {
printf("usage: %s <network_interface>\n", argv[0]);
return 1;
}
char buffer[4096], cad[256], *ni, *nf;
// read network information
int fd = open("/proc/net/dev", O_RDONLY);
if (fd < 0) return exitapp(2);
int bytes = read(fd, buffer, sizeof(buffer)-1);
close(fd);
if (bytes < 0) return exitapp(3);
buffer[bytes] = 0;
timespec tp;
clock_gettime(CLOCK_MONOTONIC, &tp);
long long nanoseconds = tp.tv_sec * 1000000000LL + tp.tv_nsec;
long long recv_bytes=LLONG_MAX, sent_bytes=LLONG_MAX;
bool networkAvailable = false;
// search for the proper network interface
strcpy(cad, argv[1]);
strcat(cad, ":");
char *pif = strstr(buffer, cad);
if (pif) {
networkAvailable = true;
// jump to the received bytes field
ni = pif + strlen(cad);
while (*ni && ((*ni == ' ') || (*ni == '\t'))) ni++;
for (nf = ni; *nf && (*nf != ' ') && (*nf != '\t'); nf++);
*nf++ = 0;
// get the received bytes
recv_bytes = atoll(ni);
// jump to the sent bytes field
for (int skip = 0; skip < 8; skip++) {
ni = nf;
while (*ni && ((*ni == ' ') || (*ni == '\t'))) ni++;
for (nf = ni; *nf && (*nf != ' ') && (*nf != '\t'); nf++);
if (!*nf) break;
*nf++ = 0;
}
// get the sent bytes
sent_bytes = atoll(ni);
}
long long user_mode_time=0, user_mode_nice_time=0, system_mode_time=0, idle_time=0;
// read CPU information
fd = open("/proc/stat", O_RDONLY);
if (fd < 0) return exitapp(4);
bytes = read(fd, buffer, sizeof(buffer)-1);
close(fd);
if (bytes < 0) return exitapp(5);
buffer[bytes] = 0;
pif = strstr(buffer, "cpu ");
if (pif) {
ni = pif + 3;
while (*ni && ((*ni == ' ') || (*ni == '\t'))) ni++;
for (nf = ni; *nf && (*nf != ' ') && (*nf != '\t'); nf++);
*nf++ = 0;
// get the user mode time
user_mode_time = atoll(ni);
ni = nf;
while (*ni && ((*ni == ' ') || (*ni == '\t'))) ni++;
for (nf = ni; *nf && (*nf != ' ') && (*nf != '\t'); nf++);
*nf++ = 0;
// get the user mode nice time
user_mode_nice_time = atoll(ni);
ni = nf;
while (*ni && ((*ni == ' ') || (*ni == '\t'))) ni++;
for (nf = ni; *nf && (*nf != ' ') && (*nf != '\t'); nf++);
*nf++ = 0;
// get the system mode time
system_mode_time = atoll(ni);
ni = nf;
while (*ni && ((*ni == ' ') || (*ni == '\t'))) ni++;
for (nf = ni; *nf && (*nf != ' ') && (*nf != '\t'); nf++);
*nf++ = 0;
// get the idle time
idle_time = atoll(ni);
}
// read the received/sent bytes, date and CPU usage stored by a previous execution
sprintf(cad, "%s.%s.%d", STATE_FILE_BASE, argv[1], getuid());
fd = open(cad, O_RDWR | O_CREAT, 0664);
if (fd < 0) return exitapp(6);
bytes = read(fd, buffer, sizeof(buffer)-1);
if (bytes < 0) {
close(fd);
return exitapp(7);
}
long long prev_recv_bytes = 0, prev_sent_bytes = 0, prev_nanoseconds = -1;
long long prev_user_mode_time = 0, prev_user_mode_nice_time = 0, prev_system_mode_time = 0, prev_idle_time = -1;
if (bytes > 0) {
prev_recv_bytes = atoll(buffer);
prev_sent_bytes = atoll(buffer+20);
prev_nanoseconds = atoll(buffer+40);
prev_user_mode_time = atoll(buffer+60);
prev_user_mode_nice_time = atoll(buffer+80);
prev_system_mode_time = atoll(buffer+100);
prev_idle_time = atoll(buffer+120);
}
// store in the file the current values for later use
sprintf(buffer, "%019lld\n%019lld\n%019lld\n%019lld\n%019lld\n%019lld\n%019lld\n",
recv_bytes, sent_bytes, nanoseconds,
user_mode_time, user_mode_nice_time, system_mode_time, idle_time);
lseek(fd, 0, SEEK_SET);
write(fd, buffer, 140);
close(fd);
// generate the result
strcpy(buffer, "<txt>");
long long elapsed = nanoseconds - prev_nanoseconds;
if (elapsed < 1) elapsed = 1;
double seconds = elapsed / 1000000000.0;
// NETWORK
bool hasNet = networkAvailable && (prev_nanoseconds >= 0) && (recv_bytes >= prev_recv_bytes) && (sent_bytes >= prev_sent_bytes);
if (!networkAvailable) {
sprintf(cad, " %s is down", argv[1]);
strcat(buffer, cad);
} else if (!hasNet) {
strcat(buffer, "D: - U: - ");
} else {
long long sent = sent_bytes - prev_sent_bytes;
long long received = recv_bytes - prev_recv_bytes;
long inbps = (long) (8 * received / seconds + 999) / 8 / 1024; // adding 999 ensures "1" for any rate above 0
long outbps = (long) (8 * sent / seconds + 999) / 8 / 1024;
if (inbps < 1024) sprintf(cad, "D: %5ld KB/s ", inbps);
else sprintf(cad, "D: %5.0lf MB/s ", inbps/1024.0);
strcat(buffer, cad);
if (outbps < 1024) sprintf(cad, " | U: %5ld KB/s ", outbps);
else sprintf(cad, " | U: %5.0lf MB/s ", outbps/1024.0);
strcat(buffer, cad);
}
long long cpu_used = user_mode_time + user_mode_nice_time + system_mode_time
- (prev_user_mode_time + prev_user_mode_nice_time + prev_system_mode_time);
long long total_cpu = cpu_used + (idle_time - prev_idle_time);
int total_ram = 0, ram_used = 0;
bool hasCPU = (prev_idle_time >= 0) && (total_cpu > 0);
// CPU
if (!hasCPU) sprintf(cad, " | CPU: %3lld",total_cpu);
else sprintf(cad, " | CPU: %3.0lf%%", cpu_used * 100.0 / total_cpu);
strcat(buffer, cad);
// RAM
FILE *meminfo = fopen("/proc/meminfo", "r");
if(meminfo) {
char line[256];
while(fgets(line, sizeof(line), meminfo)) {
if(!total_ram && sscanf(line, "MemTotal: %d kB", &total_ram));
if(sscanf(line, "Active: %d kB", &ram_used) == 1) {
sprintf(cad," | RAM: %5d MB",ram_used/1024);
break;
}
}
fclose(meminfo);
if(!ram_used) sprintf(cad, " RAM: %5d MB",total_ram);
strcat(buffer,cad);
}
// DISK
FILE *diskstat = fopen("/proc/diskstats","rt");
disk_stats dss;
if(diskstat) {
char line[512];
while(fgets(line,sizeof(line),diskstat)) {
const char *cad = dss.parse(line,seconds);
if(!cad) continue;
strcat(buffer, cad);
}
fclose(diskstat);
}
strcat(buffer, "</txt><tool>");
// TOOLTIPS
bool useNet = networkAvailable && hasNet;
if (useNet) {
sprintf(cad, " %s:\n %.2f MB received \n %.2f MB sent ",
argv[1], recv_bytes/1024.0/1024, sent_bytes/1024.0/1024);
strcat(buffer, cad);
}
if (hasCPU) {
if (useNet) strcat(buffer, "\n");
long long total_used_cpu = user_mode_time + user_mode_nice_time + system_mode_time;
sprintf(cad, " CPU usage:\n %5.1f%% since boot \n",
total_used_cpu * 100.0 / (total_used_cpu + idle_time));
strcat(buffer, cad);
}
sprintf(cad, " RAM usage:\n %5.1f%% of %d MB",
ram_used * 100.0 / total_ram, total_ram / 1024 );
strcat(buffer, cad);
strcat(buffer, "</tool>");
write(1, buffer, strlen(buffer));
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment