From 4bc30e976af96988e449d73589442983fd969ad9 Mon Sep 17 00:00:00 2001 From: Andrea Mazzoleni Date: Wed, 4 Mar 2026 11:06:19 +0100 Subject: [PATCH] Gather access counters in Windows --- cmdline/mingw.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++ cmdline/unix.c | 4 +-- 2 files changed, 71 insertions(+), 3 deletions(-) diff --git a/cmdline/mingw.c b/cmdline/mingw.c index df9d55ba..420b706a 100644 --- a/cmdline/mingw.c +++ b/cmdline/mingw.c @@ -2390,6 +2390,61 @@ static int devtree(devinfo_t* parent, tommy_list* list) return 0; } +/** + * Compute disk usage by aggregating access statistics. + * + * On many Windows versions, these raw disk performance counters are disabled by default to save overhead. + * + * If DeviceIoControl call with IOCTL_DISK_PERFORMANCE returns zeros or fails, the counters are likely disabled. + * + * Run the following command from an elevated command prompt: + * + * diskperf -y + * + * This change usually requires a reboot to take effect at the driver level. + */ +static int devstat(uint64_t device, const char* name, const char* wfile, uint64_t* count) +{ + wchar_t conv_buf[CONV_MAX]; + HANDLE h; + BOOL ret; + DISK_PERFORMANCE ds; + DWORD bytes; + char file[128]; + + snprintf(file, sizeof(file), "/dev/pd%" PRIu64, device); + + /* open the volume */ + h = CreateFileW(convert(conv_buf, wfile), 0, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0); + if (h == INVALID_HANDLE_VALUE) { + DWORD error = GetLastError(); + windows_errno(error); + log_tag("device:%s:%s:error:%lu\n", file, name, error); + return -1; + } + + bytes = 0; + ret = DeviceIoControl(h, IOCTL_DISK_PERFORMANCE, NULL, 0, &ds, sizeof(ds), &bytes, NULL); + if (!ret) { + DWORD error = GetLastError(); + CloseHandle(h); + windows_errno(error); + log_tag("device:%s:%s:error:%lu\n", file, name, error); + return -1; + } + + if (!CloseHandle(h)) { + DWORD error = GetLastError(); + windows_errno(error); + log_tag("device:%s:%s:error:%lu\n", file, name, error); + return -1; + } + + *count = ds.ReadCount + ds.WriteCount; + + return 0; +} + /** * Read smartctl --scan from a stream. * Return 0 on success. @@ -2444,6 +2499,11 @@ static int smartctl_scan(FILE* f, tommy_list* list) pathprint(devinfo->file, sizeof(devinfo->file), "/dev/pd%" PRIu64, devinfo->device); pathprint(devinfo->wfile, sizeof(devinfo->wfile), "\\\\.\\PhysicalDrive%" PRIu64, devinfo->device); + /* retrieve access stat for the low level device */ + uint64_t access_stat; + if (devstat(device, devinfo->name, devinfo->wfile, &access_stat) == 0) + devinfo->access_stat = access_stat; + /* insert in the list */ tommy_list_insert_tail(list, &devinfo->node, devinfo); } @@ -3166,6 +3226,7 @@ int devquery(tommy_list* high, tommy_list* low, int operation, int others) /* for each device */ for (i = tommy_list_head(high); i != 0; i = i->next) { devinfo_t* devinfo = i->data; + uint64_t access_stat; if (devresolve(devinfo->mount, devinfo->file, sizeof(devinfo->file), devinfo->wfile, sizeof(devinfo->wfile)) != 0) { /* LCOV_EXCL_START */ @@ -3174,6 +3235,15 @@ int devquery(tommy_list* high, tommy_list* low, int operation, int others) /* LCOV_EXCL_STOP */ } + /* retrieve access stat for the high level device */ + if (devstat(devinfo->device, devinfo->name, devinfo->wfile, &access_stat) == 0) { + /* cumulate access stat in the first split */ + if (devinfo->split) + devinfo->split->access_stat += access_stat; + else + devinfo->access_stat += access_stat; + } + /* expand the tree of devices */ if (devtree(devinfo, low) != 0) { /* LCOV_EXCL_START */ diff --git a/cmdline/unix.c b/cmdline/unix.c index d43ca948..2b726ead 100644 --- a/cmdline/unix.c +++ b/cmdline/unix.c @@ -1544,10 +1544,8 @@ static int devscan(tommy_list* list) /* retrieve access stat for the low level device */ uint64_t access_stat; - if (devstat(device, &access_stat) == 0) { - /* cumulate access stat in the first split */ + if (devstat(device, &access_stat) == 0) devinfo->access_stat = access_stat; - } /* insert in the list */ tommy_list_insert_tail(list, &devinfo->node, devinfo);