From fcf4dc9041da4c1eba18b0c03db61df273214987 Mon Sep 17 00:00:00 2001 From: Jesper Schmitz Mouridsen Date: Sun, 9 May 2021 23:42:49 +0200 Subject: [PATCH] FreeBSD support. --- CMakeLists.txt | 17 +++- config.h.in | 3 + cpustat.cpp | 244 ++++++++++++++++++++++++++++++++++++++++++++++++- cpustat.h | 10 +- cpustat_p.h | 26 ++++++ memstat.cpp | 87 +++++++++++++++++- memstat.h | 10 +- netstat.cpp | 84 +++++++++++++++++ 8 files changed, 467 insertions(+), 14 deletions(-) create mode 100644 config.h.in diff --git a/CMakeLists.txt b/CMakeLists.txt index 4e9480f..03b9ff4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,7 +27,15 @@ include(LXQtPreventInSourceBuilds) include(LXQtCreatePkgConfigFile) include(LXQtCreatePortableHeaders) include(LXQtCompilerSettings NO_POLICY_SCOPE) - +if(${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD") +include(CheckIncludeFiles) +include(CheckLibraryExists) +check_include_files("sys/socket.h;net/if.h;net/if_mib.h;net/if_types.h" HAVE_IF_H) +check_library_exists(kvm kvm_getswapinfo "kvm.h" HAVE_KVM_H) +check_library_exists(c sysctlbyname "sys/sysctl.h" HAVE_SYSCTL_H) +configure_file(config.h.in config.h) +add_definitions("-DHAVE_CONFIG_H=1") +endif() set(CMAKE_AUTOMOC ON) set(CMAKE_INCLUDE_CURRENT_DIR ON) @@ -79,8 +87,11 @@ add_library(${SYSSTAT_LIBRARY_NAME} ${SYSSTAT_SRCS} ${SYSSTAT_QM_FILES} ) - -target_link_libraries(${SYSSTAT_LIBRARY_NAME} Qt5::Core) +if(HAVE_SYSCTL_H AND HAVE_KVM_H) + target_link_libraries(${SYSSTAT_LIBRARY_NAME} c kvm Qt5::Core) +else() + target_link_libraries(${SYSSTAT_LIBRARY_NAME} Qt5::Core) +endif() set_target_properties(${SYSSTAT_LIBRARY_NAME} PROPERTIES VERSION ${SYSSTAT_VERSION} diff --git a/config.h.in b/config.h.in new file mode 100644 index 0000000..05211ac --- /dev/null +++ b/config.h.in @@ -0,0 +1,3 @@ +#cmakedefine HAVE_SYSCTL_H +#cmakedefine HAVE_IF_H +#cmakedefine HAVE_KVM_H diff --git a/cpustat.cpp b/cpustat.cpp index 0f4e87b..4191551 100644 --- a/cpustat.cpp +++ b/cpustat.cpp @@ -22,16 +22,65 @@ ** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ** ** END_COMMON_COPYRIGHT_HEADER */ - - #include - #include "cpustat.h" +#ifdef HAVE_SYSCTL_H +extern "C" +{ + #include + #include + #include + #include /* CPUSTATES */ + + #include + #include +} +#endif #include "cpustat_p.h" namespace SysStat { +#ifdef HAVE_SYSCTL_H +char *GetFirstFragment(char *string, const char *delim) +{ + char *token = NULL; + token = strsep(&string, delim); + if (token != NULL) + { + /* We need only the first fragment, so no loop! */ + return token; + } + else + return NULL; +} + +int GetCpu(void) +{ + static int mib[] = { CTL_HW, HW_NCPU }; + int buf; + size_t len = sizeof(int); + + if (sysctl(mib, 2, &buf, &len, NULL, 0) < 0) + return 0; + else + return buf; +} + +/* Frequence is in MHz */ +ulong CpuStatPrivate::CurrentFreq(QString mSource) +{ + ulong freq=0; + size_t len = sizeof(freq); + int i = mSource.mid(3).toInt(); + if (sysctl(mib2[i],4,&freq, &len, NULL, 0) < 0) { + perror("sysctl"); + return 0; + } + else + return freq; +} +#endif CpuStatPrivate::CpuStatPrivate(CpuStat *parent) : BaseStatPrivate(parent) , mMonitoring(CpuStat::LoadAndFrequency) @@ -39,7 +88,17 @@ CpuStatPrivate::CpuStatPrivate(CpuStat *parent) mSource = defaultSource(); connect(mTimer, SIGNAL(timeout()), SLOT(timeout())); - +#ifdef HAVE_SYSCTL_H + size_t flen=2; + size_t alen=4; + sysctlnametomib("kern.cp_times",mib0,&flen); + sysctlnametomib("kern.cp_time",mib1,&flen); + int ncpu = GetCpu(); + for (int i=0;i-1) { + + if (sysctlbyname(QString::fromLatin1("dev.cpu.%1.freq_levels").arg(source.midRef(3).toInt()).toStdString().c_str(), buf, &len, NULL, 0) < 0) + return; + } + t = strndup(buf, len); + if (t == NULL) + { + free(t); + return; + } + while ((tokens = strsep(&t, " ")) != NULL) + { + char *freq; + ulong res; + + freq = GetFirstFragment(tokens, "/"); + if (freq != NULL) + { + res = strtoul(freq, &freq, 10); + if (res > max) + { + max = res; + } + else + { + if ((min == 0) || (res < min)) + min = res; + } + } + + } + + free(t); + mBounds[source] = qMakePair(min, max); +#else bool ok = false; uint min = readAllFile(qPrintable(QString::fromLatin1("/sys/devices/system/cpu/%1/cpufreq/scaling_min_freq").arg(source))).toUInt(&ok); @@ -56,11 +160,34 @@ void CpuStatPrivate::addSource(const QString &source) if (ok) mBounds[source] = qMakePair(min, max); } +#endif } void CpuStatPrivate::updateSources() { mSources.clear(); +#ifdef HAVE_SYSCTL_H + mBounds.clear(); + int cpu; + + cpu = GetCpu(); + mSources.append(QString::fromLatin1("cpu")); + for (int i =0;i(cp_times[CP_USER+cpuNumber*CPUSTATES]); + current.nice = static_cast(cp_times[CP_NICE+cpuNumber*CPUSTATES]); + current.system = static_cast(cp_times[CP_SYS+cpuNumber*CPUSTATES]); + current.idle = static_cast(cp_times[CP_IDLE+cpuNumber*CPUSTATES]); + current.other = static_cast(cp_times[CP_INTR+cpuNumber*CPUSTATES]); + current.total = current.user + current.nice + current.system+current.idle+current.other; + float sumDelta = static_cast(current.total - mPrevious.total); + if ((mPrevious.total != 0) && ((sumDelta < mIntervalMin) || (sumDelta > mIntervalMax))) + { + if (mMonitoring == CpuStat::LoadAndFrequency) + { + float freqRate = 1.0; + ulong freq = CurrentFreq(mSource); + + if (mSource == QLatin1String("cpu")) { + freq=0; + for (Bounds::ConstIterator I = mBounds.constBegin(); I != mBounds.constEnd(); ++I) { + if (I.key() != QStringLiteral("cpu")) + { + freq += CurrentFreq(I.key()); + } + } + } + + if (freq > 0) + { + freqRate = static_cast(freq) / static_cast(mBounds[mSource].second); + emit update(0.0, 0.0, 0.0, 0.0, static_cast(freqRate), freq); + } + } else { + emit update(0.0, 0.0, 0.0, 0.0); + } + mPrevious.clear(); + } else { + if (mMonitoring == CpuStat::LoadAndFrequency) + { + float freqRate = 1.0; + ulong freq = CurrentFreq(mSource); + + if (freq > 0) + { + if (mSource == QLatin1String("cpu")) { + freq=0; + for (Bounds::ConstIterator I = mBounds.constBegin(); I != mBounds.constEnd(); ++I) { + if (I.key() != QStringLiteral("cpu")) + { + freq += CurrentFreq(I.key()); + } + } + } + freqRate = static_cast(freq) / static_cast(mBounds[mSource].second); + emit update( + static_cast(current.user - mPrevious.user ) / sumDelta, + static_cast(current.nice - mPrevious.nice ) / sumDelta, + static_cast(current.system - mPrevious.system) / sumDelta, + static_cast(current.other - mPrevious.other ) / sumDelta, + static_cast(freqRate), + freq); + + } + } + else + { + emit update( + static_cast(current.user - mPrevious.user ) / sumDelta, + static_cast(current.nice - mPrevious.nice ) / sumDelta, + static_cast(current.system - mPrevious.system) / sumDelta, + static_cast(current.other - mPrevious.other ) / sumDelta); + } + + mPrevious = current; + } + free(cp_times); + } + else + { + ulong freq = 0; + + freq = CurrentFreq(mSource); + if (freq > 0) + emit update(freq); + } +#else if ( (mMonitoring == CpuStat::LoadOnly) || (mMonitoring == CpuStat::LoadAndFrequency) ) { @@ -258,6 +493,7 @@ void CpuStatPrivate::timeout() } emit update(freq); } +#endif } QString CpuStatPrivate::defaultSource() diff --git a/cpustat.h b/cpustat.h index 11c15d1..db91868 100644 --- a/cpustat.h +++ b/cpustat.h @@ -27,14 +27,19 @@ #ifndef LIBSYSSTAT__CPU_STAT__INCLUDED #define LIBSYSSTAT__CPU_STAT__INCLUDED - +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif #include #include "basestat.h" namespace SysStat { - +#ifdef HAVE_SYSCTL_H + char *GetFirstFragment(char *string, const char *delim); + int GetCpu(void); +#endif class CpuStatPrivate; class SYSSTATSHARED_EXPORT CpuStat : public BaseStat @@ -54,7 +59,6 @@ class SYSSTATSHARED_EXPORT CpuStat : public BaseStat uint minFreq(const QString &source) const; uint maxFreq(const QString &source) const; - signals: void update(float user, float nice, float system, float other, float frequencyRate, uint frequency); void update(float user, float nice, float system, float other); diff --git a/cpustat_p.h b/cpustat_p.h index cca0089..d9242a7 100644 --- a/cpustat_p.h +++ b/cpustat_p.h @@ -27,6 +27,9 @@ #ifndef LIBSYSSTAT__CPU_STAT__PRIVATE__INCLUDED #define LIBSYSSTAT__CPU_STAT__PRIVATE__INCLUDED +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif #include #include @@ -52,8 +55,15 @@ class CpuStatPrivate : public BaseStatPrivate CpuStat::Monitoring monitoring() const; void setMonitoring(CpuStat::Monitoring value); +#ifdef HAVE_SYSCTL_H + ulong minFreq(const QString &source) const; + ulong maxFreq(const QString &source) const; + ulong CurrentFreq(const QString); + +#else uint minFreq(const QString &source) const; uint maxFreq(const QString &source) const; +#endif signals: void update(float user, float nice, float system, float other); @@ -74,12 +84,21 @@ private slots: { Values(); +#ifdef HAVE_SYSCTL_H + ulong user; + ulong nice; + ulong system; + ulong idle; + ulong other; + ulong total; +#else qulonglong user; qulonglong nice; qulonglong system; qulonglong idle; qulonglong other; qulonglong total; +#endif void sum(); @@ -89,7 +108,14 @@ private slots: CpuStat::Monitoring mMonitoring; +#ifdef HAVE_SYSCTL_H + typedef QMap > Bounds; + int mib0[2]; + int mib1[2]; + int mib2[512][4]; +#else typedef QMap > Bounds; +#endif Bounds mBounds; int mUserHz; diff --git a/memstat.cpp b/memstat.cpp index 684aba3..3f4ee77 100644 --- a/memstat.cpp +++ b/memstat.cpp @@ -26,10 +26,58 @@ #include "memstat.h" #include "memstat_p.h" +#if defined(HAVE_KVM_H) && defined(HAVE_SYSCTL_H) +extern "C" +{ + #include + #include + #include + #include + #include + #include +} +#endif namespace SysStat { +#ifdef HAVE_SYSCTL_H +int SwapDevices() +{ + int buf; + size_t len = sizeof(int); + + if (sysctlbyname("vm.nswapdev", &buf, &len, NULL, 0) < 0) + return 0; + else + return buf; +} + +qulonglong MemGetByBytes(QString property) +{ + qulonglong buf=0; + size_t len = sizeof(qulonglong); + + std::string s = property.toStdString(); + const char *name = s.c_str(); + + if (sysctlbyname(name, &buf, &len, NULL, 0) < 0) + return 0; + else + return buf; +} + +qulonglong MemGetByPages(QString name) +{ + qulonglong res = 0; + + + res = MemGetByBytes(name); + if (res > 0) + res = res * getpagesize(); + return res; +} +#endif MemStatPrivate::MemStatPrivate(MemStat *parent) : BaseStatPrivate(parent) { @@ -49,8 +97,39 @@ void MemStatPrivate::timeout() qulonglong memBuffers = 0; qulonglong memCached = 0; qulonglong swapTotal = 0; - qulonglong swapFree = 0; +#ifdef HAVE_SYSCTL_H + memTotal = MemGetByBytes(QLatin1String("hw.physmem")); + memFree = MemGetByPages(QLatin1String("vm.stats.vm.v_free_count")); + memBuffers = MemGetByBytes(QLatin1String("vfs.bufspace")); + memCached = MemGetByPages(QLatin1String("vm.stats.vm.v_inactive_count")); + +#endif +#ifdef HAVE_KVM_H + qulonglong swapUsed = 0; + kvm_t *kd; + struct kvm_swap kswap[16]; /* size taken from pstat/pstat.c */ + + kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, "kvm_open"); + if (kd == NULL) + kvm_close(kd); + + if (kvm_getswapinfo(kd, kswap, (sizeof(kswap) / sizeof(kswap[0])), SWIF_DEV_PREFIX) > 0) + { + int swapd = SwapDevices(); + /* TODO: loop over swap devives */ + if (swapd >= 1) + { + swapTotal = static_cast(kswap[0].ksw_total * getpagesize()); + swapUsed = static_cast(kswap[0].ksw_used * getpagesize()); + } + kvm_close(kd); + } + else + kvm_close(kd); +#endif +#ifndef HAVE_SYSCTL_H + qulonglong swapFree = 0; const QStringList rows = readAllFile("/proc/meminfo").split(QLatin1Char('\n'), Qt::SkipEmptyParts); for (const QString &row : rows) { @@ -72,6 +151,7 @@ void MemStatPrivate::timeout() swapFree = tokens[1].toULong(); } +#endif if (mSource == QLatin1String("memory")) { if (memTotal) @@ -88,8 +168,11 @@ void MemStatPrivate::timeout() { if (swapTotal) { +#ifndef HAVE_KVM_H float swapUsed_d = static_cast(swapTotal - swapFree) / static_cast(swapTotal); - +#else + float swapUsed_d = static_cast(swapUsed) / static_cast(swapTotal); +#endif emit swapUpdate(swapUsed_d); } } diff --git a/memstat.h b/memstat.h index e64af5c..6f4ed3a 100644 --- a/memstat.h +++ b/memstat.h @@ -27,7 +27,9 @@ #ifndef LIBSYSSTAT__MEM_STAT__INCLUDED #define LIBSYSSTAT__MEM_STAT__INCLUDED - +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif #include #include "basestat.h" @@ -36,7 +38,11 @@ namespace SysStat { class MemStatPrivate; - +#if defined(HAVE_SYSCTL_H) && defined(HAVE_KVM_H) + int SwapDevices(); + qulonglong MemGetByBytes(const QString property); + qulonglong MemGetByPages(const QString property); +#endif class SYSSTATSHARED_EXPORT MemStat : public BaseStat { Q_OBJECT diff --git a/netstat.cpp b/netstat.cpp index d5a96f5..b680fae 100644 --- a/netstat.cpp +++ b/netstat.cpp @@ -26,6 +26,21 @@ #include "netstat.h" #include "netstat_p.h" +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if defined(HAVE_SYSCTL_H) && defined(HAVE_IF_H) +extern "C" +{ + #include + #include + #include + #include /* PF_LINK */ + #include + #include +} +#endif namespace SysStat { @@ -37,6 +52,7 @@ NetStatPrivate::NetStatPrivate(NetStat *parent) connect(mTimer, SIGNAL(timeout()), SLOT(timeout())); +#ifndef HAVE_SYSCTL_H QStringList rows(readAllFile("/proc/net/dev").split(QLatin1Char('\n'), Qt::SkipEmptyParts)); @@ -50,12 +66,79 @@ NetStatPrivate::NetStatPrivate(NetStat *parent) mSources.append(tokens[0].trimmed()); } +#else + int count; + size_t len; + int cntifmib[] = { CTL_NET, PF_LINK, NETLINK_GENERIC, IFMIB_SYSTEM, IFMIB_IFCOUNT };// net.link.generic.system.ifcount; + len = sizeof(int); + if (sysctl(cntifmib, 5, &count, &len, NULL, 0) < 0) + perror("sysctl"); + + + struct ifmibdata ifmd; + size_t len1 = sizeof(ifmd); + for (int i=1; i<=count;i++) { + int name[] = { CTL_NET, PF_LINK, NETLINK_GENERIC, IFMIB_IFDATA, i, IFDATA_GENERAL }; + + if (sysctl(name, 6, &ifmd, &len1, NULL, 0) < 0) { + perror("sysctl"); + } + if ((ifmd.ifmd_data.ifi_type == IFT_ETHER) || (ifmd.ifmd_data.ifi_type == IFT_IEEE80211)) { + const char *iface = ifmd.ifmd_name; + mSources.append(QString::fromLatin1(iface)); + } + } +#endif } NetStatPrivate::~NetStatPrivate() = default; void NetStatPrivate::timeout() { +#if defined(HAVE_IF_H) && defined(HAVE_SYSCTL_H) + int count; + size_t len; + int name[] = { CTL_NET, PF_LINK, NETLINK_GENERIC, IFMIB_SYSTEM, IFMIB_IFCOUNT }; + struct ifmibdata ifmd; + + len = sizeof(int); + if (sysctl(name, 5, &count, &len, NULL, 0) < 0) + return; + + for (int i = 1; i <= count; i++) + { + len = sizeof(ifmd); + int name[] = { CTL_NET, PF_LINK, NETLINK_GENERIC, IFMIB_IFDATA, i, IFDATA_GENERAL }; + + if (sysctl(name, 6, &ifmd, &len, NULL, 0) < 0) + break; + + if ((ifmd.ifmd_data.ifi_type == IFT_ETHER) || (ifmd.ifmd_data.ifi_type == IFT_IEEE80211)) + { + const char *iface = ifmd.ifmd_name; + QString interfaceName = QString::fromLatin1(iface); + if ((ifmd.ifmd_data.ifi_link_state == LINK_STATE_UP) && (ifmd.ifmd_data.ifi_ipackets > 0)) + { + + + Values current; + current.received = ifmd.ifmd_data.ifi_ibytes; + current.transmitted = ifmd.ifmd_data.ifi_obytes; + + if (!mPrevious.contains(interfaceName)) + mPrevious.insert(interfaceName, Values()); + const Values &previous = mPrevious[interfaceName]; + + if (interfaceName == mSource) + emit update((( current.received - previous.received ) * 1000 ) / mTimer->interval(), (( current.transmitted - previous.transmitted ) * 1000 ) / mTimer->interval()); + + mPrevious[interfaceName] = current; + } else if(interfaceName == mSource) + emit(update(0,0)); + + } + } +#else QStringList rows(readAllFile("/proc/net/dev").split(QLatin1Char('\n'), Qt::SkipEmptyParts)); @@ -97,6 +180,7 @@ void NetStatPrivate::timeout() mPrevious[interfaceName] = current; } +#endif } QString NetStatPrivate::defaultSource()