* [ITP] btop
@ 2024-01-24 15:22 Takashi Yano
2024-01-25 15:11 ` Jon Turney
0 siblings, 1 reply; 3+ messages in thread
From: Takashi Yano @ 2024-01-24 15:22 UTC (permalink / raw)
To: cygwin-apps
[-- Attachment #1: Type: text/plain, Size: 208 bytes --]
I'd like to propose a new package btop, which is a feature-rich
resource monitor. btop is ready for many Linux distributions
including Fedora.
Thanks in advance.
--
Takashi Yano <takashi.yano@nifty.ne.jp>
[-- Attachment #2: btop.cygport --]
[-- Type: text/plain, Size: 427 bytes --]
NAME="btop"
VERSION=1.3.0
RELEASE=1
LICENSE="Apache-2.0"
CATEGORY="System"
SUMMARY="Resource monitor with rich features."
DESCRIPTION="Resource monitor that shows usage and stats for processor, memory, disks, network and processes."
HOMEPAGE="https://github.com/aristocratos/btop"
SRC_URI="https://github.com/aristocratos/btop/archive/refs/tags/v${VERSION}.tar.gz"
PATCH_URI="fix-gcc13-warnings.patch"
inherit cmake
[-- Attachment #3: btop-1.3.0-1.src.patch --]
[-- Type: text/plain, Size: 22615 bytes --]
--- origsrc/btop-1.3.0/CMakeLists.txt 2024-01-07 23:23:01.000000000 +0900
+++ src/btop-1.3.0/CMakeLists.txt 2024-01-24 21:19:32.514670900 +0900
@@ -66,6 +66,8 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeB
target_sources(btop PRIVATE src/freebsd/btop_collect.cpp)
elseif(LINUX)
target_sources(btop PRIVATE src/linux/btop_collect.cpp)
+elseif(CYGWIN)
+ target_sources(btop PRIVATE src/linux/btop_collect.cpp)
else()
message(FATAL_ERROR "${CMAKE_SYSTEM_NAME} is not supported")
endif()
@@ -184,6 +186,8 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeB
find_package(kvm REQUIRED)
target_link_libraries(btop elf::elf kvm::kvm)
endif()
+elseif(CMAKE_SYSTEM_NAME STREQUAL "CYGWIN")
+ target_link_libraries(btop pdh iphlpapi)
endif()
install(TARGETS btop RUNTIME)
--- origsrc/btop-1.3.0/Makefile 2024-01-07 23:23:01.000000000 +0900
+++ src/btop-1.3.0/Makefile 2024-01-24 21:19:32.514670900 +0900
@@ -34,7 +34,7 @@ else
ARCH ?= $(shell $(CXX) -dumpmachine | cut -d "-" -f 1)
endif
-override PLATFORM_LC := $(shell echo $(PLATFORM) | tr '[:upper:]' '[:lower:]')
+override PLATFORM_LC := $(shell echo $(PLATFORM) | tr '[:upper:]' '[:lower:]' | sed 's/-.*$$//' )
#? GPU Support
ifeq ($(PLATFORM_LC)$(ARCH),linuxx86_64)
@@ -141,6 +141,11 @@ else ifeq ($(PLATFORM_LC),openbsd)
override ADDFLAGS += -lkvm
export MAKE = gmake
SU_GROUP := wheel
+else ifeq ($(PLATFORM_LC),cygwin_nt)
+ PLATFORM_DIR := linux
+ THREADS := $(shell getconf _NPROCESSORS_ONLN 2>/dev/null || echo 1)
+ override ADDFLAGS += -lpdh -liphlpapi
+ SU_GROUP := Administrators
else
$(error $(shell printf "\033[1;91mERROR: \033[97mUnsupported platform ($(PLATFORM))\033[0m"))
endif
--- origsrc/btop-1.3.0/src/btop.cpp 2024-01-07 23:23:01.000000000 +0900
+++ src/btop-1.3.0/src/btop.cpp 2024-01-24 21:19:32.524679000 +0900
@@ -16,6 +16,10 @@ indent = tab
tab-size = 4
*/
+#ifdef __CYGWIN__
+#define _GNU_SOURCE 1
+#endif
+
#include <algorithm>
#include <csignal>
#include <clocale>
--- origsrc/btop-1.3.0/src/btop_config.cpp 2024-01-07 23:23:01.000000000 +0900
+++ src/btop-1.3.0/src/btop_config.cpp 2024-01-24 21:19:32.524679000 +0900
@@ -16,6 +16,10 @@ indent = tab
tab-size = 4
*/
+#ifdef __CYGWIN__
+#define _GNU_SOURCE
+#endif
+
#include <array>
#include <atomic>
#include <fstream>
@@ -284,7 +288,11 @@ namespace Config {
{"swap_disk", true},
{"show_disks", true},
{"only_physical", true},
+#ifdef __CYGWIN__
+ {"use_fstab", false},
+#else
{"use_fstab", true},
+#endif
{"zfs_hide_datasets", false},
{"show_io_stat", true},
{"io_mode", false},
--- origsrc/btop-1.3.0/src/btop_input.cpp 2024-01-07 23:23:01.000000000 +0900
+++ src/btop-1.3.0/src/btop_input.cpp 2024-01-24 21:19:32.524679000 +0900
@@ -16,6 +16,10 @@ indent = tab
tab-size = 4
*/
+#ifdef __CYGWIN__
+#define _GNU_SOURCE 1
+#endif
+
#include <limits>
#include <ranges>
#include <vector>
--- origsrc/btop-1.3.0/src/btop_menu.cpp 2024-01-07 23:23:01.000000000 +0900
+++ src/btop-1.3.0/src/btop_menu.cpp 2024-01-24 21:19:32.524679000 +0900
@@ -16,6 +16,10 @@ indent = tab
tab-size = 4
*/
+#ifdef __CYGWIN__
+#define _GNU_SOURCE
+#endif
+
#include <deque>
#include <unordered_map>
#include <array>
--- origsrc/btop-1.3.0/src/btop_tools.cpp 2024-01-07 23:23:01.000000000 +0900
+++ src/btop-1.3.0/src/btop_tools.cpp 2024-01-24 21:19:32.524679000 +0900
@@ -16,6 +16,10 @@ indent = tab
tab-size = 4
*/
+#ifdef __CYGWIN__
+#define _GNU_SOURCE 1
+#endif
+
#include <cmath>
#include <codecvt>
#include <iostream>
--- origsrc/btop-1.3.0/src/linux/btop_collect.cpp 2024-01-07 23:23:01.000000000 +0900
+++ src/btop-1.3.0/src/linux/btop_collect.cpp 2024-01-24 21:19:32.534678900 +0900
@@ -16,6 +16,10 @@ indent = tab
tab-size = 4
*/
+#ifdef __CYGWIN__
+#define _GNU_SOURCE
+#endif
+
#include <cstdlib>
#include <unordered_map>
#include <unordered_set>
@@ -43,6 +47,102 @@ tab-size = 4
#include <pwd.h>
#endif
+#ifdef __CYGWIN__
+typedef uint32_t DWORD;
+typedef long long LONGLONG;
+typedef unsigned long ULONG;
+typedef unsigned long ULONG_PTR;
+typedef long LONG;
+typedef unsigned int UINT;
+typedef uint8_t BYTE;
+typedef char CHAR;
+typedef int BOOL;
+typedef void *HANDLE;
+typedef void *HQUERY;
+typedef void *HCOUNTER;
+typedef struct {
+ DWORD dwLowDateTime;
+ DWORD dwHighDateTime;
+} FILETIME;
+typedef struct {
+ DWORD CStatus;
+ FILETIME TimeStamp;
+ LONGLONG FirstValue;
+ LONGLONG SecondValue;
+ DWORD MultiCount;
+} PDH_RAW_COUNTER;
+#define PDH_FMT_DOUBLE ((DWORD) 0x00000200)
+typedef struct {
+ DWORD CStatus;
+ union {
+ long longValue;
+ double doubleValue;
+ LONGLONG largeValue;
+ char *AnsiStringValue;
+ wchar_t *WideStringValue;
+ };
+} PDH_FMT_COUNTERVALUE;
+typedef struct {
+ char *String[4*4];
+} IP_ADDRESS_STRING, IP_MASK_STRING;
+typedef struct _IP_ADDR_STRING {
+ struct _IP_ADDR_STRING *Next;
+ IP_ADDRESS_STRING IpAddress;
+ IP_MASK_STRING IpMask;
+ DWORD Context;
+} IP_ADDR_STRING, *PIP_ADDR_STRING;
+#define MAX_ADAPTER_ADDRESS_LENGTH 8
+#define MAX_ADAPTER_NAME_LENGTH 256
+#define MAX_ADAPTER_DESCRIPTION_LENGTH 128
+typedef struct _IP_ADAPTER_INFO {
+ struct _IP_ADAPTER_INFO *Next;
+ DWORD ComboIndex;
+ char AdapterName[MAX_ADAPTER_NAME_LENGTH + 4];
+ char Description[MAX_ADAPTER_DESCRIPTION_LENGTH + 4];
+ UINT AddressLength;
+ BYTE Address[MAX_ADAPTER_ADDRESS_LENGTH];
+ DWORD Index;
+ UINT Type;
+ UINT DhcpEnabled;
+ PIP_ADDR_STRING CurrentIpAddress;
+ IP_ADDR_STRING IpAddressList;
+ IP_ADDR_STRING GatewayList;
+ IP_ADDR_STRING DhcpServer;
+ BOOL HaveWins;
+ IP_ADDR_STRING PrimaryWinsServer;
+ IP_ADDR_STRING SecondaryWinsServer;
+ time_t LeaseObtained;
+ time_t LeaseExpires;
+} IP_ADAPTER_INFO;
+#define MAX_PATH 260
+typedef struct {
+ DWORD dwSize;
+ DWORD cntUsage;
+ DWORD th32ProcessID;
+ ULONG_PTR th32DefaultHeapID;
+ DWORD th32ModuleID;
+ DWORD cntThreads;
+ DWORD th32ParentProcessID;
+ LONG pcPriClassBase;
+ DWORD dwFlags;
+ CHAR szExeFile[MAX_PATH];
+} PROCESSENTRY32;
+#define TH32CS_SNAPPROCESS 0x00000002
+extern "C" {
+ ULONG GetAdaptersInfo(IP_ADAPTER_INFO *, ULONG *);
+ DWORD PdhOpenQuery(char *, DWORD *, HQUERY *);
+ DWORD PdhAddCounterA(HQUERY, char *, DWORD *, HCOUNTER *);
+ DWORD PdhCollectQueryData(HQUERY);
+ DWORD PdhGetRawCounterValue(HCOUNTER, DWORD *, PDH_RAW_COUNTER *);
+ DWORD PdhGetFormattedCounterValue(HCOUNTER, DWORD, DWORD *, PDH_FMT_COUNTERVALUE *);
+ DWORD PdhCalculateCounterFromRawValue(HCOUNTER, DWORD, PDH_RAW_COUNTER *, PDH_RAW_COUNTER *, PDH_FMT_COUNTERVALUE *);
+ DWORD PdhCloseQuery(HQUERY);
+ HANDLE CreateToolhelp32Snapshot(DWORD, DWORD);
+ BOOL Process32First(HANDLE, PROCESSENTRY32 *);
+ BOOL Process32Next(HANDLE, PROCESSENTRY32 *);
+}
+#endif
+
#include "../btop_shared.hpp"
#include "../btop_config.hpp"
#include "../btop_tools.hpp"
@@ -232,11 +332,15 @@ namespace Shared {
}
}
+#ifdef __CYGWIN__
+ pageSize = 4096;
+#else
pageSize = sysconf(_SC_PAGE_SIZE);
if (pageSize <= 0) {
pageSize = 4096;
Logger::warning("Could not get system page size. Defaulting to 4096, processes memory usage might be incorrect.");
}
+#endif
clkTck = sysconf(_SC_CLK_TCK);
if (clkTck <= 0) {
@@ -1632,6 +1736,9 @@ namespace Mem {
static vector<string> ignore_list;
double uptime = system_uptime();
auto free_priv = Config::getB("disk_free_priv");
+#ifdef __CYGWIN__
+ string root_dev;
+#endif
try {
auto& disks_filter = Config::getS("disks_filter");
bool filter_exclude = false;
@@ -1639,7 +1746,9 @@ namespace Mem {
auto only_physical = Config::getB("only_physical");
auto zfs_hide_datasets = Config::getB("zfs_hide_datasets");
auto& disks = mem.disks;
+#ifndef __CYGWIN__
static std::unordered_map<string, future<pair<disk_info, int>>> disks_stats_promises;
+#endif
ifstream diskread;
vector<string> filter;
@@ -1693,6 +1802,18 @@ namespace Mem {
}
//? Get mounts from /etc/mtab or /proc/self/mounts
+#ifdef __CYGWIN__
+ diskread.open((fs::exists("/etc/mtab") ? fs::path("/etc/mtab") : Shared::procPath / "self/mounts"));
+ if (diskread.good()) {
+ string dev, mountpoint, fstype;
+ while (not diskread.eof()) {
+ diskread >> dev >> mountpoint >> fstype;
+ diskread.ignore(SSmax, '\n');
+ if (mountpoint == "/") root_dev = dev;
+ }
+ diskread.close();
+ }
+#endif
diskread.open((fs::exists("/etc/mtab") ? fs::path("/etc/mtab") : Shared::procPath / "self/mounts"));
if (diskread.good()) {
vector<string> found;
@@ -1715,6 +1836,9 @@ namespace Mem {
//? Skip ZFS datasets if zfs_hide_datasets option is enabled
size_t zfs_dataset_name_start = 0;
if (fstype == "zfs" && (zfs_dataset_name_start = dev.find('/')) != std::string::npos && zfs_hide_datasets) continue;
+#ifdef __CYGWIN__
+ if (not (mountpoint == "/") and dev.starts_with(root_dev)) continue;
+#endif
if ((not use_fstab and not only_physical)
or (use_fstab and v_contains(fstab, mountpoint))
@@ -1779,6 +1903,23 @@ namespace Mem {
diskread.close();
//? Get disk/partition stats
+#ifdef __CYGWIN__
+ /* Cygwin has a bug that handle leak occurs if std::async is used. */
+ for (auto& [mountpoint, disk] : disks) {
+ if (std::error_code ec; not fs::exists(mountpoint, ec) or v_contains(ignore_list, mountpoint)) continue;
+ struct statvfs vfs;
+ if (statvfs(mountpoint.c_str(), &vfs) < 0) {
+ Logger::warning("Failed to get disk/partition stats for mount \""+ mountpoint + "\" with statvfs error code: " + to_string(errno) + ". Ignoring...");
+ ignore_list.push_back(mountpoint);
+ continue;
+ }
+ disk.total = vfs.f_blocks * vfs.f_frsize;
+ disk.free = (free_priv ? vfs.f_bfree : vfs.f_bavail) * vfs.f_frsize;
+ disk.used = disk.total - disk.free;
+ disk.used_percent = round((double)disk.used * 100 / disk.total);
+ disk.free_percent = 100 - disk.used_percent;
+ }
+#else
for (auto it = disks.begin(); it != disks.end(); ) {
auto &[mountpoint, disk] = *it;
if (v_contains(ignore_list, mountpoint) or disk.name == "swap") {
@@ -1821,6 +1962,7 @@ namespace Mem {
});
++it;
}
+#endif
//? Setup disks order in UI and add swap if enabled
mem.disks_order.clear();
@@ -1846,6 +1988,72 @@ namespace Mem {
#endif
//? Get disks IO
+#ifdef __CYGWIN__
+ /* Cygwin does not have means to provide statistics of disk I/O.
+ Because there is no other choice, use WIN32API instead. */
+ int64_t bytes_read, bytes_write;
+ disk_ios = 0;
+ static std::unordered_map<string, PDH_RAW_COUNTER> RawCounterReadTimeOld, RawCounterWriteTimeOld;
+ for (auto& [mountpoint, disk] : disks) {
+ char perf_counter_read[1024], perf_counter_write[1024];
+ char perf_counter_read_time[1024], perf_counter_write_time[1024];
+ HQUERY hQuery;
+ HCOUNTER hCounterRead, hCounterWrite;
+ HCOUNTER hCounterReadTime, hCounterWriteTime;
+ PDH_RAW_COUNTER RawCounterRead, RawCounterWrite;
+ PDH_RAW_COUNTER RawCounterReadTime, RawCounterWriteTime;
+ PDH_FMT_COUNTERVALUE FmtCounterReadTime, FmtCounterWriteTime;
+ string dev = disk.dev;
+
+ if (dev.empty() or dev.find(':') == std::string::npos) continue;
+
+ sprintf(perf_counter_read, "\\LogicalDisk(%s)\\Disk Read Bytes/sec", dev.substr(0, 2).c_str());
+ sprintf(perf_counter_write, "\\LogicalDisk(%s)\\Disk Write Bytes/sec", dev.substr(0, 2).c_str());
+ sprintf(perf_counter_read_time, "\\LogicalDisk(%s)\\%% Disk Read Time", dev.substr(0, 2).c_str());
+ sprintf(perf_counter_write_time, "\\LogicalDisk(%s)\\%% Disk Write Time", dev.substr(0, 2).c_str());
+
+ PdhOpenQuery(NULL, 0, &hQuery);
+ PdhAddCounterA(hQuery, perf_counter_read, 0, &hCounterRead);
+ PdhAddCounterA(hQuery, perf_counter_write, 0, &hCounterWrite);
+ PdhAddCounterA(hQuery, perf_counter_read_time, 0, &hCounterReadTime);
+ PdhAddCounterA(hQuery, perf_counter_write_time, 0, &hCounterWriteTime);
+ PdhCollectQueryData(hQuery);
+ PdhGetRawCounterValue(hCounterRead, NULL, &RawCounterRead);
+ PdhGetRawCounterValue(hCounterWrite, NULL, &RawCounterWrite);
+ PdhGetRawCounterValue(hCounterReadTime, NULL, &RawCounterReadTime);
+ PdhGetRawCounterValue(hCounterWriteTime, NULL, &RawCounterWriteTime);
+
+ if (RawCounterReadTimeOld.find(mountpoint) == RawCounterReadTimeOld.end()) {
+ FmtCounterReadTime.doubleValue = 0;
+ } else {
+ PdhCalculateCounterFromRawValue(hCounterReadTime, PDH_FMT_DOUBLE,
+ &RawCounterReadTime, &RawCounterReadTimeOld[mountpoint], &FmtCounterReadTime);
+ }
+ if (RawCounterWriteTimeOld.find(mountpoint) == RawCounterWriteTimeOld.end()) {
+ FmtCounterWriteTime.doubleValue = 0;
+ } else {
+ PdhCalculateCounterFromRawValue(hCounterWriteTime, PDH_FMT_DOUBLE,
+ &RawCounterWriteTime, &RawCounterWriteTimeOld[mountpoint], &FmtCounterWriteTime);
+ }
+ PdhCloseQuery(hQuery);
+
+ RawCounterReadTimeOld[mountpoint] = RawCounterReadTime;
+ RawCounterWriteTimeOld[mountpoint] = RawCounterWriteTime;
+
+ bytes_read = RawCounterRead.FirstValue;
+ disk.io_read.push_back(max((int64_t)0, bytes_read - disk.old_io.at(0)));
+ disk.old_io.at(0) = bytes_read;
+ while (cmp_greater(disk.io_read.size(), width * 2)) disk.io_read.pop_front();
+
+ bytes_write = RawCounterWrite.FirstValue;
+ disk.io_write.push_back(max((int64_t)0, bytes_write - disk.old_io.at(1)));
+ disk.old_io.at(1) = bytes_write;
+ while (cmp_greater(disk.io_write.size(), width * 2)) disk.io_write.pop_front();
+
+ disk.io_activity.push_back(clamp((long)round(FmtCounterReadTime.doubleValue + FmtCounterWriteTime.doubleValue), 0l, 100l));
+ while (cmp_greater(disk.io_activity.size(), width * 2)) disk.io_activity.pop_front();
+ }
+#else
int64_t sectors_read, sectors_write, io_ticks, io_ticks_temp;
disk_ios = 0;
for (auto& [ignored, disk] : disks) {
@@ -1929,6 +2137,7 @@ namespace Mem {
}
diskread.close();
}
+#endif
old_uptime = uptime;
}
catch (const std::exception& e) {
@@ -2121,6 +2330,9 @@ namespace Net {
//? Iteration over all items in getifaddrs() list
for (auto* ifa = if_wrap(); ifa != nullptr; ifa = ifa->ifa_next) {
if (ifa->ifa_addr == nullptr) continue;
+#ifdef __CYGWIN__
+ if ((ifa->ifa_flags & IFF_RUNNING) == 0) continue;
+#endif
family = ifa->ifa_addr->sa_family;
const auto& iface = ifa->ifa_name;
@@ -2162,6 +2374,80 @@ namespace Net {
}
//? Get total recieved and transmitted bytes + device address if no ip was found
+#ifdef __CYGWIN__
+ /* Cygwin does not have means to provide statistics of network interfaces.
+ Because there is no other choice, use WIN32API instead. */
+ do {
+ char buf[65536];
+ ULONG adapters_size = sizeof(buf);
+ IP_ADAPTER_INFO *adapters = (IP_ADAPTER_INFO *) buf;
+ GetAdaptersInfo(adapters, &adapters_size);
+
+ for (const auto& iface : interfaces) {
+ char perf_counter_download[1024], perf_counter_upload[1024];
+ HQUERY hQuery;
+ HCOUNTER hCounterDown, hCounterUp;
+ PDH_RAW_COUNTER RawCounterDown, RawCounterUp;
+ for (IP_ADAPTER_INFO *p = adapters; p; p = p->Next) {
+ if (p->AdapterName == iface) {
+ char *q = p->Description;
+ while ((q = strchr(q, '('))) *q = '[';
+ q = p->Description;
+ while ((q = strchr(q, ')'))) *q = ']';
+ sprintf(perf_counter_download, "\\Network Interface(%s)\\Bytes Received/sec", p->Description);
+ sprintf(perf_counter_upload, "\\Network Interface(%s)\\Bytes Sent/sec", p->Description);
+ break;
+ }
+ }
+ PdhOpenQuery(NULL, 0, &hQuery);
+ PdhAddCounterA(hQuery, perf_counter_download, 0, &hCounterDown);
+ PdhAddCounterA(hQuery, perf_counter_upload, 0, &hCounterUp);
+ PdhCollectQueryData(hQuery);
+ PdhGetRawCounterValue(hCounterDown, NULL, &RawCounterDown);
+ PdhGetRawCounterValue(hCounterUp, NULL, &RawCounterUp);
+ PdhCloseQuery(hQuery);
+ for (const string dir : {"download", "upload"}) {
+ auto& saved_stat = net.at(iface).stat.at(dir);
+ auto& bandwidth = net.at(iface).bandwidth.at(dir);
+ uint64_t val{};
+
+ val = (dir == "download") ? RawCounterDown.FirstValue : RawCounterUp.FirstValue;
+
+ //? Update speed, total and top values
+ if (val < saved_stat.last) {
+ saved_stat.rollover += saved_stat.last;
+ saved_stat.last = 0;
+ }
+ if (cmp_greater((unsigned long long)saved_stat.rollover + (unsigned long long)val, numeric_limits<uint64_t>::max())) {
+ saved_stat.rollover = 0;
+ saved_stat.last = 0;
+ }
+ saved_stat.speed = round((double)(val - saved_stat.last) / ((double)(new_timestamp - timestamp) / 1000));
+ if (saved_stat.speed > saved_stat.top) saved_stat.top = saved_stat.speed;
+ if (saved_stat.offset > val + saved_stat.rollover) saved_stat.offset = 0;
+ saved_stat.total = (val + saved_stat.rollover) - saved_stat.offset;
+ saved_stat.last = val;
+
+ //? Add values to graph
+ bandwidth.push_back(saved_stat.speed);
+ while (cmp_greater(bandwidth.size(), width * 2)) bandwidth.pop_front();
+
+ //? Set counters for auto scaling
+ if (net_auto and selected_iface == iface) {
+ if (net_sync and saved_stat.speed < net.at(iface).stat.at(dir == "download" ? "upload" : "download").speed) continue;
+ if (saved_stat.speed > graph_max[dir]) {
+ ++max_count[dir][0];
+ if (max_count[dir][1] > 0) --max_count[dir][1];
+ }
+ else if (graph_max[dir] > 10 << 10 and saved_stat.speed < graph_max[dir] / 10) {
+ ++max_count[dir][1];
+ if (max_count[dir][0] > 0) --max_count[dir][0];
+ }
+ }
+ }
+ }
+ } while (false);
+#else
for (const auto& iface : interfaces) {
if (net.at(iface).ipv4.empty() and net.at(iface).ipv6.empty())
net.at(iface).ipv4 = readfile("/sys/class/net/" + iface + "/address");
@@ -2210,6 +2496,7 @@ namespace Net {
}
}
}
+#endif
//? Clean up net map if needed
if (net.size() > interfaces.size()) {
@@ -2376,6 +2663,28 @@ namespace Proc {
while (cmp_greater(detailed.mem_bytes.size(), width)) detailed.mem_bytes.pop_front();
+#ifdef __CYGWIN__
+ /* Cygwin does not have means to provide statistics of I/O.
+ Because there is no other choice, use WIN32API instead. */
+ char perf_counter_read[1024], perf_counter_write[1024];
+ HQUERY hQuery;
+ HCOUNTER hCounterRead, hCounterWrite;
+ PDH_RAW_COUNTER RawCounterRead, RawCounterWrite;
+
+ sprintf(perf_counter_read, "\\Process(%s)\\IO Read Bytes/sec", p_info->name.c_str());
+ sprintf(perf_counter_write, "\\Process(%s)\\IO Write Bytes/sec", p_info->name.c_str());
+
+ PdhOpenQuery(NULL, 0, &hQuery);
+ PdhAddCounterA(hQuery, perf_counter_read, 0, &hCounterRead);
+ PdhAddCounterA(hQuery, perf_counter_write, 0, &hCounterWrite);
+ PdhCollectQueryData(hQuery);
+ PdhGetRawCounterValue(hCounterRead, NULL, &RawCounterRead);
+ PdhGetRawCounterValue(hCounterWrite, NULL, &RawCounterWrite);
+ PdhCloseQuery(hQuery);
+
+ detailed.io_read = floating_humanizer(RawCounterRead.FirstValue);
+ detailed.io_write = floating_humanizer(RawCounterWrite.FirstValue);
+#else
//? Get bytes read and written from proc/[pid]/io
if (fs::exists(pid_path / "io")) {
d_read.open(pid_path / "io");
@@ -2400,6 +2709,7 @@ namespace Proc {
catch (const std::out_of_range&) {}
d_read.close();
}
+#endif
}
//* Collects and sorts process information from /proc
@@ -2486,6 +2796,11 @@ namespace Proc {
else throw std::runtime_error("Failure to read /proc/stat");
pread.close();
+#ifdef __CYGWIN__
+ /* Cygwin does not have means to provide number of thread in the process.
+ Because there is no other choice, use WIN32API instead. */
+ HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+#endif
//? Iterate over all pids in /proc
for (const auto& d: fs::directory_iterator(Shared::procPath)) {
if (Runner::stopping)
@@ -2517,10 +2832,12 @@ namespace Proc {
//? Get program name, command and username
if (no_cache) {
+#ifndef __CYGWIN__
pread.open(d.path() / "comm");
if (not pread.good()) continue;
getline(pread, new_proc.name);
pread.close();
+#endif
//? Check for whitespace characters in name and set offset to get correct fields from stat file
new_proc.name_offset = rng::count(new_proc.name, ' ');
@@ -2547,6 +2864,10 @@ namespace Proc {
pread.ignore();
getline(pread, uid, '\t');
break;
+#ifdef __CYGWIN__
+ } else if (line == "Name") {
+ pread >> std::skipws >> new_proc.name;
+#endif
} else {
pread.ignore(SSmax, '\n');
}
@@ -2635,6 +2956,27 @@ namespace Proc {
pread.close();
+#ifdef __CYGWIN__
+ /* Cygwin does not have means to provide number of thread in the process.
+ Because there is no other choice, use WIN32API instead. */
+ pread.open(d.path() / "winpid");
+ if (pread.good()) {
+ DWORD winpid;
+ PROCESSENTRY32 pe;
+ pread >> winpid;
+ pread.close();
+ pe.dwSize = sizeof(PROCESSENTRY32);
+ if (Process32First(snap, &pe)) {
+ do {
+ if (pe.th32ProcessID == winpid) {
+ new_proc.threads = pe.cntThreads;
+ break;
+ }
+ } while (Process32Next(snap, &pe));
+ }
+ }
+#endif
+
if (should_filter_kernel and new_proc.ppid == KTHREADD) {
kernels_procs.emplace(new_proc.pid);
found.pop_back();
[-- Attachment #4: fix-gcc13-warnings.patch --]
[-- Type: text/plain, Size: 4909 bytes --]
diff -ru origsrc/btop-1.3.0/src/btop_draw.cpp src/btop-1.3.0/src/btop_draw.cpp
--- origsrc/btop-1.3.0/src/btop_draw.cpp 2024-01-07 23:23:01.000000000 +0900
+++ src/btop-1.3.0/src/btop_draw.cpp 2024-01-24 23:21:05.802983100 +0900
@@ -797,7 +797,7 @@
+ Theme::g("cpu").at(clamp(safeVal(cpu.cpu_percent, "total"s).back(), 0ll, 100ll)) + rjust(to_string(safeVal(cpu.cpu_percent, "total"s).back()), 4) + Theme::c("main_fg") + '%';
if (show_temps) {
const auto [temp, unit] = celsius_to(safeVal(cpu.temp, 0).back(), temp_scale);
- const auto& temp_color = Theme::g("temp").at(clamp(safeVal(cpu.temp, 0).back() * 100 / cpu.temp_max, 0ll, 100ll));
+ const auto temp_color = Theme::g("temp").at(clamp(safeVal(cpu.temp, 0).back() * 100 / cpu.temp_max, 0ll, 100ll));
if ((b_column_size > 1 or b_columns > 1) and temp_graphs.size() >= 1ll)
out += ' ' + Theme::c("inactive_fg") + graph_bg * 5 + Mv::l(5) + temp_color
+ temp_graphs.at(0)(safeVal(cpu.temp, 0), data_same or redraw);
@@ -823,7 +823,7 @@
if (show_temps and not hide_cores and std::cmp_greater_equal(temp_graphs.size(), n)) {
const auto [temp, unit] = celsius_to(safeVal(cpu.temp, n+1).back(), temp_scale);
- const auto& temp_color = Theme::g("temp").at(clamp(safeVal(cpu.temp, n+1).back() * 100 / cpu.temp_max, 0ll, 100ll));
+ const auto temp_color = Theme::g("temp").at(clamp(safeVal(cpu.temp, n+1).back() * 100 / cpu.temp_max, 0ll, 100ll));
if (b_column_size > 1)
out += ' ' + Theme::c("inactive_fg") + graph_bg * 5 + Mv::l(5)
+ temp_graphs.at(n+1)(safeVal(cpu.temp, n+1), data_same or redraw);
@@ -1273,7 +1273,7 @@
for (const auto& mount : mem.disks_order) {
if (not disks.contains(mount)) continue;
if (cy > height - 3) break;
- const auto& disk = safeVal(disks, mount);
+ const auto disk = safeVal(disks, mount);
if (disk.io_read.empty()) continue;
const string total = floating_humanizer(disk.total, not big_disk);
out += Mv::to(y+1+cy, x+1+cx) + divider + Theme::c("title") + Fx::b + uresize(disk.name, disks_width - 8) + Mv::to(y+1+cy, x+cx + disks_width - total.size())
@@ -1312,7 +1312,7 @@
for (const auto& mount : mem.disks_order) {
if (not disks.contains(mount)) continue;
if (cy > height - 3) break;
- const auto& disk = safeVal(disks, mount);
+ const auto disk = safeVal(disks, mount);
if (disk.name.empty() or not disk_meters_used.contains(mount)) continue;
auto comb_val = (not disk.io_read.empty() ? disk.io_read.back() + disk.io_write.back() : 0ll);
const string human_io = (comb_val > 0 ? (disk.io_write.back() > 0 and big_disk ? "â¼"s : ""s) + (disk.io_read.back() > 0 and big_disk ? "â²"s : ""s)
@@ -1604,8 +1604,8 @@
out += Mv::to(d_y, d_x - 1) + Theme::c("proc_box") + Symbols::div_up + Mv::to(y, d_x - 1) + Symbols::div_down + Theme::c("div_line");
for (const int& i : iota(1, 8)) out += Mv::to(d_y + i, d_x - 1) + Symbols::v_line;
- const string& t_color = (not alive or selected > 0 ? Theme::c("inactive_fg") : Theme::c("title"));
- const string& hi_color = (not alive or selected > 0 ? t_color : Theme::c("hi_fg"));
+ const string t_color = (not alive or selected > 0 ? Theme::c("inactive_fg") : Theme::c("title"));
+ const string hi_color = (not alive or selected > 0 ? t_color : Theme::c("hi_fg"));
const string hide = (selected > 0 ? t_color + "hide " : Theme::c("title") + "hide " + Theme::c("hi_fg"));
int mouse_x = d_x + 2;
out += Mv::to(d_y, d_x + 1);
diff -ru origsrc/btop-1.3.0/src/btop_menu.cpp src/btop-1.3.0/src/btop_menu.cpp
--- origsrc/btop-1.3.0/src/btop_menu.cpp 2024-01-07 23:23:01.000000000 +0900
+++ src/btop-1.3.0/src/btop_menu.cpp 2024-01-24 23:19:42.301762700 +0900
@@ -801,12 +805,12 @@
string msgBox::operator()() {
string out;
int pos = width / 2 - (boxtype == 0 ? 6 : 14);
- auto& first_color = (selected == 0 ? Theme::c("hi_fg") : Theme::c("div_line"));
+ auto first_color = (selected == 0 ? Theme::c("hi_fg") : Theme::c("div_line"));
out = Mv::d(1) + Mv::r(pos) + Fx::b + first_color + button_left + (selected == 0 ? Theme::c("title") : Theme::c("main_fg") + Fx::ub)
+ (boxtype == 0 ? " Ok " : " Yes ") + first_color + button_right;
mouse_mappings["button1"] = Input::Mouse_loc{y + height - 4, x + pos + 1, 3, 12 + (boxtype > 0 ? 1 : 0)};
if (boxtype > 0) {
- auto& second_color = (selected == 1 ? Theme::c("hi_fg") : Theme::c("div_line"));
+ auto second_color = (selected == 1 ? Theme::c("hi_fg") : Theme::c("div_line"));
out += Mv::r(2) + second_color + button_left + (selected == 1 ? Theme::c("title") : Theme::c("main_fg") + Fx::ub)
+ " No " + second_color + button_right;
mouse_mappings["button2"] = Input::Mouse_loc{y + height - 4, x + pos + 15 + (boxtype > 0 ? 1 : 0), 3, 12};
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [ITP] btop
2024-01-24 15:22 [ITP] btop Takashi Yano
@ 2024-01-25 15:11 ` Jon Turney
2024-01-26 3:31 ` Takashi Yano
0 siblings, 1 reply; 3+ messages in thread
From: Jon Turney @ 2024-01-25 15:11 UTC (permalink / raw)
To: Takashi Yano; +Cc: cygwin-apps
On 24/01/2024 15:22, Takashi Yano via Cygwin-apps wrote:
> I'd like to propose a new package btop, which is a feature-rich
> resource monitor. btop is ready for many Linux distributions
> including Fedora.
>
Thanks.
>
> +#ifdef __CYGWIN__
> +#define _GNU_SOURCE 1
> +#endif
> +
I'd suggest adding -D_GNU_SOURCE=1 to CPPFLAGS, rather than patching
this in everywhere it's needed.
(Setting this unconditionally could be added to the build system
somewhere, which is theoretically upstreamable, since it's only not
needed on linux for :reasons:)
> +#ifdef __CYGWIN__
> +typedef uint32_t DWORD
Is it not possible to just #include <windows.h> here? If not, perhaps a
comment why the definitions are copied would nice.
Otherwise, this looks great. I added this to your packages.
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [ITP] btop
2024-01-25 15:11 ` Jon Turney
@ 2024-01-26 3:31 ` Takashi Yano
0 siblings, 0 replies; 3+ messages in thread
From: Takashi Yano @ 2024-01-26 3:31 UTC (permalink / raw)
To: cygwin-apps
On Thu, 25 Jan 2024 15:11:12 +0000
Jon Turney wrote:
> On 24/01/2024 15:22, Takashi Yano via Cygwin-apps wrote:
> > +#ifdef __CYGWIN__
> > +#define _GNU_SOURCE 1
> > +#endif
> > +
>
> I'd suggest adding -D_GNU_SOURCE=1 to CPPFLAGS, rather than patching
> this in everywhere it's needed.
>
> (Setting this unconditionally could be added to the build system
> somewhere, which is theoretically upstreamable, since it's only not
> needed on linux for :reasons:)
Sounds good! Thanks.
I'll add it to CMakeLists.txt and Makfile for CYGWIN for the time being.
> > +#ifdef __CYGWIN__
> > +typedef uint32_t DWORD
>
> Is it not possible to just #include <windows.h> here? If not, perhaps a
> comment why the definitions are copied would nice.
When I included <windows.h> here, many conflicts occured between
posix headers and w32api headers.
However, now I have found that including w32api headers after all
the posix headers and typedef IN6_ADDR like:
#ifdef __CYGWIN__
#include <windows.h>
#include <pdh.h>
#include <tlhelp32.h>
typedef struct {
union {
u_char Byte[16];
u_short Word[8];
} u;
} IN6_ADDR;
#include <iphlpapi.h>
#endif
solves the conflicts. Thanks!
--
Takashi Yano <takashi.yano@nifty.ne.jp>
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2024-01-26 3:31 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-01-24 15:22 [ITP] btop Takashi Yano
2024-01-25 15:11 ` Jon Turney
2024-01-26 3:31 ` Takashi Yano
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).