diff --git a/Makefile.am b/Makefile.am index 83ada450..600f2afc 100644 --- a/Makefile.am +++ b/Makefile.am @@ -46,6 +46,7 @@ myhtopsources = \ MemoryMeter.c \ Meter.c \ MetersPanel.c \ + NetworkIOMeter.c \ Object.c \ OpenFilesScreen.c \ Panel.c \ @@ -97,6 +98,7 @@ myhtopheaders = \ MemoryMeter.h \ Meter.h \ MetersPanel.h \ + NetworkIOMeter.h \ Object.h \ OpenFilesScreen.h \ Panel.h \ diff --git a/NetworkIOMeter.c b/NetworkIOMeter.c new file mode 100644 index 00000000..07c7dc97 --- /dev/null +++ b/NetworkIOMeter.c @@ -0,0 +1,89 @@ +#include "NetworkIOMeter.h" + +#include "CRT.h" +#include "Platform.h" + + +static const int NetworkIOMeter_attributes[] = { + METER_VALUE_IOREAD, + METER_VALUE_IOWRITE, +}; + +static unsigned long int cached_rxb_diff = 0; +static unsigned long int cached_rxp_diff = 0; +static unsigned long int cached_txb_diff = 0; +static unsigned long int cached_txp_diff = 0; + +static void NetworkIOMeter_updateValues(ATTR_UNUSED Meter* this, char* buffer, int len) { + static unsigned long int cached_rxb_total = 0; + static unsigned long int cached_rxp_total = 0; + static unsigned long int cached_txb_total = 0; + static unsigned long int cached_txp_total = 0; + static unsigned long long int cached_last_update = 0; + + struct timeval tv; + gettimeofday(&tv, NULL); + unsigned long long int timeInMilliSeconds = (unsigned long long int)tv.tv_sec * 1000 + (unsigned long long int)tv.tv_usec / 1000; + unsigned long long int passedTimeInMs = timeInMilliSeconds - cached_last_update; + + /* update only every 500ms */ + if (passedTimeInMs > 500) { + unsigned long int bytesReceived, packetsReceived, bytesTransmitted, packetsTransmitted; + + Platform_getNetworkIO(&bytesReceived, &packetsReceived, &bytesTransmitted, &packetsTransmitted); + + cached_rxb_diff = (bytesReceived - cached_rxb_total) / 1024; /* Meter_humanUnit() expects unit in kilo */ + cached_rxb_diff = 1000.0 * cached_rxb_diff / passedTimeInMs; /* convert to per second */ + cached_rxb_total = bytesReceived; + + cached_rxp_diff = packetsReceived - cached_rxp_total; + cached_rxp_total = packetsReceived; + + cached_txb_diff = (bytesTransmitted - cached_txb_total) / 1024; /* Meter_humanUnit() expects unit in kilo */ + cached_txb_diff = 1000.0 * cached_txb_diff / passedTimeInMs; /* convert to per second */ + cached_txb_total = bytesTransmitted; + + cached_txp_diff = packetsTransmitted - cached_txp_total; + cached_txp_total = packetsTransmitted; + + cached_last_update = timeInMilliSeconds; + } + + char bufferBytesReceived[12], bufferBytesTransmitted[12]; + Meter_humanUnit(bufferBytesReceived, cached_rxb_diff, sizeof(bufferBytesReceived)); + Meter_humanUnit(bufferBytesTransmitted, cached_txb_diff, sizeof(bufferBytesTransmitted)); + xSnprintf(buffer, len, "rx:%siB/s tx:%siB/s", bufferBytesReceived, bufferBytesTransmitted); +} + +static void NetworkIOMeter_display(ATTR_UNUSED const Object* cast, RichString* out) { + char buffer[32]; + + RichString_write(out, CRT_colors[METER_TEXT], "rx: "); + Meter_humanUnit(buffer, cached_rxb_diff, sizeof(buffer)); + RichString_append(out, CRT_colors[METER_VALUE_IOREAD], buffer); + RichString_append(out, CRT_colors[METER_VALUE_IOREAD], "iB/s"); + + RichString_append(out, CRT_colors[METER_TEXT], " tx: "); + Meter_humanUnit(buffer, cached_txb_diff, sizeof(buffer)); + RichString_append(out, CRT_colors[METER_VALUE_IOWRITE], buffer); + RichString_append(out, CRT_colors[METER_VALUE_IOWRITE], "iB/s"); + + xSnprintf(buffer, sizeof(buffer), " (%lu/%lu packets) ", cached_rxp_diff, cached_txp_diff); + RichString_append(out, CRT_colors[METER_TEXT], buffer); +} + +const MeterClass NetworkIOMeter_class = { + .super = { + .extends = Class(Meter), + .delete = Meter_delete, + .display = NetworkIOMeter_display + }, + .updateValues = NetworkIOMeter_updateValues, + .defaultMode = TEXT_METERMODE, + .maxItems = 0, + .total = 100.0, + .attributes = NetworkIOMeter_attributes, + .name = "NetworkIO", + .uiName = "Network IO", + .caption = "Network: " +}; diff --git a/NetworkIOMeter.h b/NetworkIOMeter.h new file mode 100644 index 00000000..311b5e64 --- /dev/null +++ b/NetworkIOMeter.h @@ -0,0 +1,8 @@ +#ifndef HEADER_NetworkIOMeter +#define HEADER_NetworkIOMeter + +#include "Meter.h" + +extern const MeterClass NetworkIOMeter_class; + +#endif /* HEADER_NetworkIOMeter */ diff --git a/darwin/Platform.c b/darwin/Platform.c index 99787a27..26bcbad2 100644 --- a/darwin/Platform.c +++ b/darwin/Platform.c @@ -315,3 +315,14 @@ void Platform_getDiskIO(unsigned long int *bytesRead, unsigned long int *bytesWr // TODO *bytesRead = *bytesWrite = *msTimeSpend = 0; } + +void Platform_getNetworkIO(unsigned long int *bytesReceived, + unsigned long int *packetsReceived, + unsigned long int *bytesTransmitted, + unsigned long int *packetsTransmitted) { + // TODO + *bytesReceived = 0; + *packetsReceived = 0; + *bytesTransmitted = 0; + *packetsTransmitted = 0; +} diff --git a/darwin/Platform.h b/darwin/Platform.h index 9b7a324b..d953b51c 100644 --- a/darwin/Platform.h +++ b/darwin/Platform.h @@ -50,4 +50,9 @@ char* Platform_getProcessEnv(pid_t pid); void Platform_getDiskIO(unsigned long int *bytesRead, unsigned long int *bytesWrite, unsigned long int *msTimeSpend); +void Platform_getNetworkIO(unsigned long int *bytesReceived, + unsigned long int *packetsReceived, + unsigned long int *bytesTransmitted, + unsigned long int *packetsTransmitted); + #endif diff --git a/dragonflybsd/Platform.c b/dragonflybsd/Platform.c index 6eb1e99c..eb172513 100644 --- a/dragonflybsd/Platform.c +++ b/dragonflybsd/Platform.c @@ -215,3 +215,14 @@ void Platform_getDiskIO(unsigned long int *bytesRead, unsigned long int *bytesWr // TODO *bytesRead = *bytesWrite = *msTimeSpend = 0; } + +void Platform_getNetworkIO(unsigned long int *bytesReceived, + unsigned long int *packetsReceived, + unsigned long int *bytesTransmitted, + unsigned long int *packetsTransmitted) { + // TODO + *bytesReceived = 0; + *packetsReceived = 0; + *bytesTransmitted = 0; + *packetsTransmitted = 0; +} diff --git a/dragonflybsd/Platform.h b/dragonflybsd/Platform.h index 3dc1eb1e..50187aa4 100644 --- a/dragonflybsd/Platform.h +++ b/dragonflybsd/Platform.h @@ -44,4 +44,9 @@ char* Platform_getProcessEnv(pid_t pid); void Platform_getDiskIO(unsigned long int *bytesRead, unsigned long int *bytesWrite, unsigned long int *msTimeSpend); +void Platform_getNetworkIO(unsigned long int *bytesReceived, + unsigned long int *packetsReceived, + unsigned long int *bytesTransmitted, + unsigned long int *packetsTransmitted); + #endif diff --git a/freebsd/Platform.c b/freebsd/Platform.c index 2288d2f2..7827d521 100644 --- a/freebsd/Platform.c +++ b/freebsd/Platform.c @@ -18,11 +18,14 @@ in the source distribution for its full text. #include "DateMeter.h" #include "DateTimeMeter.h" #include "HostnameMeter.h" +#include "NetworkIOMeter.h" #include "zfs/ZfsArcMeter.h" #include "zfs/ZfsCompressedArcMeter.h" #include "FreeBSDProcess.h" #include "FreeBSDProcessList.h" +#include +#include #include #include #include @@ -107,6 +110,7 @@ const MeterClass* const Platform_meterTypes[] = { &BlankMeter_class, &ZfsArcMeter_class, &ZfsCompressedArcMeter_class, + &NetworkIOMeter_class, NULL }; @@ -230,3 +234,50 @@ void Platform_getDiskIO(unsigned long int *bytesRead, unsigned long int *bytesWr // TODO *bytesRead = *bytesWrite = *msTimeSpend = 0; } + +void Platform_getNetworkIO(unsigned long int *bytesReceived, + unsigned long int *packetsReceived, + unsigned long int *bytesTransmitted, + unsigned long int *packetsTransmitted) { + int r; + + // get number of interfaces + int count; + size_t countLen = sizeof(count); + const int countMib[] = { CTL_NET, PF_LINK, NETLINK_GENERIC, IFMIB_SYSTEM, IFMIB_IFCOUNT }; + + r = sysctl(countMib, ARRAYSIZE(countMib), &count, &countLen, NULL, 0); + if (r < 0) { + *bytesReceived = 0; + *packetsReceived = 0; + *bytesTransmitted = 0; + *packetsTransmitted = 0; + return; + } + + unsigned long int bytesReceivedSum = 0, packetsReceivedSum = 0, bytesTransmittedSum = 0, packetsTransmittedSum = 0; + + for (int i = 1; i <= count; i++) { + struct ifmibdata ifmd; + size_t ifmdLen = sizeof(ifmd); + + const int dataMib[] = { CTL_NET, PF_LINK, NETLINK_GENERIC, IFMIB_IFDATA, i, IFDATA_GENERAL }; + + r = sysctl(dataMib, ARRAYSIZE(dataMib), &ifmd, &ifmdLen, NULL, 0); + if (r < 0) + continue; + + if (ifmd.ifmd_flags & IFF_LOOPBACK) + continue; + + bytesReceivedSum += ifmd.ifmd_data.ifi_ibytes; + packetsReceivedSum += ifmd.ifmd_data.ifi_ipackets; + bytesTransmittedSum += ifmd.ifmd_data.ifi_obytes; + packetsTransmittedSum += ifmd.ifmd_data.ifi_opackets; + } + + *bytesReceived = bytesReceivedSum; + *packetsReceived = packetsReceivedSum; + *bytesTransmitted = bytesTransmittedSum; + *packetsTransmitted = packetsTransmittedSum; +} diff --git a/freebsd/Platform.h b/freebsd/Platform.h index feda7416..bd1a38ef 100644 --- a/freebsd/Platform.h +++ b/freebsd/Platform.h @@ -47,4 +47,9 @@ char* Platform_getProcessEnv(pid_t pid); void Platform_getDiskIO(unsigned long int *bytesRead, unsigned long int *bytesWrite, unsigned long int *msTimeSpend); +void Platform_getNetworkIO(unsigned long int *bytesReceived, + unsigned long int *packetsReceived, + unsigned long int *bytesTransmitted, + unsigned long int *packetsTransmitted); + #endif diff --git a/linux/Platform.c b/linux/Platform.c index c7826418..6a3ffab2 100644 --- a/linux/Platform.c +++ b/linux/Platform.c @@ -25,6 +25,7 @@ in the source distribution for its full text. #include "DateMeter.h" #include "DateTimeMeter.h" #include "HostnameMeter.h" +#include "NetworkIOMeter.h" #include "zfs/ZfsArcMeter.h" #include "zfs/ZfsCompressedArcMeter.h" #include "LinuxProcess.h" @@ -140,6 +141,7 @@ const MeterClass* const Platform_meterTypes[] = { &ZfsArcMeter_class, &ZfsCompressedArcMeter_class, &DiskIOMeter_class, + &NetworkIOMeter_class, &SELinuxMeter_class, NULL }; @@ -338,3 +340,46 @@ void Platform_getDiskIO(unsigned long int *bytesRead, unsigned long int *bytesWr *bytesWrite = 512 * write_sum; *msTimeSpend = timeSpend_sum; } + +void Platform_getNetworkIO(unsigned long int *bytesReceived, + unsigned long int *packetsReceived, + unsigned long int *bytesTransmitted, + unsigned long int *packetsTransmitted) { + FILE *fd = fopen(PROCDIR "/net/dev", "r"); + if (!fd) { + *bytesReceived = 0; + *packetsReceived = 0; + *bytesTransmitted = 0; + *packetsTransmitted = 0; + return; + } + + unsigned long int bytesReceivedSum = 0, packetsReceivedSum = 0, bytesTransmittedSum = 0, packetsTransmittedSum = 0; + char lineBuffer[512]; + while (fgets(lineBuffer, sizeof(lineBuffer), fd)) { + char interfaceName[32]; + unsigned long int bytesReceivedParsed, packetsReceivedParsed, bytesTransmittedParsed, packetsTransmittedParsed; + if (fscanf(fd, "%31s %lu %lu %*u %*u %*u %*u %*u %*u %lu %lu %*u %*u %*u %*u %*u %*u", + interfaceName, + &bytesReceivedParsed, + &packetsReceivedParsed, + &bytesTransmittedParsed, + &packetsTransmittedParsed) != 5) + continue; + + if (0 == strcmp(interfaceName, "lo:")) + continue; + + bytesReceivedSum += bytesReceivedParsed; + packetsReceivedSum += packetsReceivedParsed; + bytesTransmittedSum += bytesTransmittedParsed; + packetsTransmittedSum += packetsTransmittedParsed; + } + + fclose(fd); + + *bytesReceived = bytesReceivedSum; + *packetsReceived = packetsReceivedSum; + *bytesTransmitted = bytesTransmittedSum; + *packetsTransmitted = packetsTransmittedSum; +} diff --git a/linux/Platform.h b/linux/Platform.h index 66a60d8b..007cd32b 100644 --- a/linux/Platform.h +++ b/linux/Platform.h @@ -46,4 +46,9 @@ void Platform_getPressureStall(const char *file, bool some, double* ten, double* void Platform_getDiskIO(unsigned long int *bytesRead, unsigned long int *bytesWrite, unsigned long int *msTimeSpend); +void Platform_getNetworkIO(unsigned long int *bytesReceived, + unsigned long int *packetsReceived, + unsigned long int *bytesTransmitted, + unsigned long int *packetsTransmitted); + #endif diff --git a/openbsd/Platform.c b/openbsd/Platform.c index 4c2ebdfb..7723ebc5 100644 --- a/openbsd/Platform.c +++ b/openbsd/Platform.c @@ -296,3 +296,14 @@ void Platform_getDiskIO(unsigned long int *bytesRead, unsigned long int *bytesWr // TODO *bytesRead = *bytesWrite = *msTimeSpend = 0; } + +void Platform_getNetworkIO(unsigned long int *bytesReceived, + unsigned long int *packetsReceived, + unsigned long int *bytesTransmitted, + unsigned long int *packetsTransmitted) { + // TODO + *bytesReceived = 0; + *packetsReceived = 0; + *bytesTransmitted = 0; + *packetsTransmitted = 0; +} diff --git a/openbsd/Platform.h b/openbsd/Platform.h index c71d490e..b3edf6e8 100644 --- a/openbsd/Platform.h +++ b/openbsd/Platform.h @@ -45,4 +45,9 @@ char* Platform_getProcessEnv(pid_t pid); void Platform_getDiskIO(unsigned long int *bytesRead, unsigned long int *bytesWrite, unsigned long int *msTimeSpend); +void Platform_getNetworkIO(unsigned long int *bytesReceived, + unsigned long int *packetsReceived, + unsigned long int *bytesTransmitted, + unsigned long int *packetsTransmitted); + #endif diff --git a/solaris/Platform.c b/solaris/Platform.c index ef0d4123..4203a964 100644 --- a/solaris/Platform.c +++ b/solaris/Platform.c @@ -268,3 +268,14 @@ void Platform_getDiskIO(unsigned long int *bytesRead, unsigned long int *bytesWr // TODO *bytesRead = *bytesWrite = *msTimeSpend = 0; } + +void Platform_getNetworkIO(unsigned long int *bytesReceived, + unsigned long int *packetsReceived, + unsigned long int *bytesTransmitted, + unsigned long int *packetsTransmitted) { + // TODO + *bytesReceived = 0; + *packetsReceived = 0; + *bytesTransmitted = 0; + *packetsTransmitted = 0; +} diff --git a/solaris/Platform.h b/solaris/Platform.h index a9b7712d..130c70cd 100644 --- a/solaris/Platform.h +++ b/solaris/Platform.h @@ -65,4 +65,9 @@ char* Platform_getProcessEnv(pid_t pid); void Platform_getDiskIO(unsigned long int *bytesRead, unsigned long int *bytesWrite, unsigned long int *msTimeSpend); +void Platform_getNetworkIO(unsigned long int *bytesReceived, + unsigned long int *packetsReceived, + unsigned long int *bytesTransmitted, + unsigned long int *packetsTransmitted); + #endif diff --git a/unsupported/Platform.c b/unsupported/Platform.c index 6e8968f1..cc28fd8f 100644 --- a/unsupported/Platform.c +++ b/unsupported/Platform.c @@ -144,3 +144,13 @@ char* Platform_getProcessEnv(pid_t pid) { void Platform_getDiskIO(unsigned long int *bytesRead, unsigned long int *bytesWrite, unsigned long int *msTimeSpend) { *bytesRead = *bytesWrite = *msTimeSpend = 0; } + +void Platform_getNetworkIO(unsigned long int *bytesReceived, + unsigned long int *packetsReceived, + unsigned long int *bytesTransmitted, + unsigned long int *packetsTransmitted) { + *bytesReceived = 0; + *packetsReceived = 0; + *bytesTransmitted = 0; + *packetsTransmitted = 0; +} diff --git a/unsupported/Platform.h b/unsupported/Platform.h index f24dcf4c..1049919d 100644 --- a/unsupported/Platform.h +++ b/unsupported/Platform.h @@ -49,4 +49,9 @@ char* Platform_getProcessEnv(pid_t pid); void Platform_getDiskIO(unsigned long int *bytesRead, unsigned long int *bytesWrite, unsigned long int *msTimeSpend); +void Platform_getNetworkIO(unsigned long int *bytesReceived, + unsigned long int *packetsReceived, + unsigned long int *bytesTransmitted, + unsigned long int *packetsTransmitted); + #endif