Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,22 @@
# 2.65.2

Changes:
* Memory usage calculations now exclude the ZFS ARC cache on Linux, FreeBSD, NetBSD, and SunOS. (#1995 / #2418, Memory)
* This prevents the Memory module from reporting artificially high memory usage on systems with the ZFS kmod enabled.

Bugfixes:
* The GPU module no longer pings sleeping dedicated GPUs on dual-GPU laptops. (#2419, GPU)
* As a result, PCIe link speed detection (introduced in v2.65.0) is now only enabled in `driverSpecific` mode.
* Fixed a crash when detecting hardware codec support with the `amdgpu` driver on Linux. (#2419, Codec, Linux)

Logos:
* Updated CachyOS_small
* Added Turkish

# 2.65.1

No changes

# 2.65.0

Changes:
Expand Down
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.12.0) # target_link_libraries with OBJECT libs & project homepage url

project(fastfetch
VERSION 2.65.1
VERSION 2.65.2
LANGUAGES C
DESCRIPTION "Fast neofetch-like system information tool"
HOMEPAGE_URL "https://github.com/fastfetch-cli/fastfetch"
Expand Down
6 changes: 6 additions & 0 deletions debian/changelog.tpl
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
fastfetch (2.65.1~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium

* Update to 2.65.1

-- Carter Li <zhangsongcui@live.cn> Wed, 24 Jun 2026 14:21:06 +0800
Comment thread
CarterLi marked this conversation as resolved.
Comment on lines +1 to +5

fastfetch (2.64.2~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium

* Update to 2.64.2
Expand Down
2 changes: 1 addition & 1 deletion debian/publish.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ SCRIPT_DIR="$(cd -- "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
ROOT_DIR="$(cd -- "$SCRIPT_DIR/.." >/dev/null 2>&1 && pwd)"
OUT_DIR="$(dirname "$ROOT_DIR")"
PPA="ppa:zhangsongcui3371/fastfetch"
CODENAMES=( jammy noble plucky questing resolute )
CODENAMES=( jammy noble plucky questing resolute stonking )
DRY_RUN=0

if [[ -d "$OUT_DIR/build" ]]; then
Expand Down
2 changes: 1 addition & 1 deletion presets/examples/13.jsonc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Inspired by Catnap
// Inspired by Catnap (https://github.com/iinsertNameHere/catnap)
{
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
"logo": {
Expand Down
2 changes: 1 addition & 1 deletion presets/examples/14.jsonc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Inspired by Catnap
// Inspired by Catnap (https://github.com/iinsertNameHere/catnap)
{
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
"logo": {
Expand Down
2 changes: 1 addition & 1 deletion presets/examples/15.jsonc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Inspired by Catnap
// Inspired by Catnap (https://github.com/iinsertNameHere/catnap)
{
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
"logo": {
Expand Down
2 changes: 1 addition & 1 deletion presets/examples/16.jsonc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Inspired by Catnap
// Inspired by Catnap (https://github.com/iinsertNameHere/catnap)
{
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
"logo": {
Expand Down
2 changes: 1 addition & 1 deletion src/common/impl/settings.c
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,7 @@ int ffSettingsGetSQLite3Int(const char* dbPath, const char* query) {
}

sqlite3* db;
if (data->ffsqlite3_open_v2(dbPath, &db, SQLITE_OPEN_READONLY, NULL) != SQLITE_OK) {
if (data->ffsqlite3_open_v2(dbPath, &db, SQLITE_OPEN_READONLY | SQLITE_OPEN_NOMUTEX, NULL) != SQLITE_OK) {
return 0;
}

Expand Down
2 changes: 1 addition & 1 deletion src/detection/codec/codec_linux.c
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ static const char* detectCodecByVaDrm(FFVAData* vaData, FFCodecOptions* options,
continue;
}

FF_AUTO_CLOSE_FD int fd = openat(drifd, entry->d_name, O_RDONLY | O_CLOEXEC);
FF_AUTO_CLOSE_FD int fd = openat(drifd, entry->d_name, O_RDWR | O_CLOEXEC);
if (fd < 0) {
continue;
}
Expand Down
3 changes: 3 additions & 0 deletions src/detection/gpu/gpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ typedef struct FFGPUResult {
uint64_t deviceId;
} FFGPUResult;

static_assert(sizeof(((FFGPUResult*) NULL)->pcieSpeed) == 8, "pcieSpeed is not 8 bytes");
static_assert(sizeof(((FFGPUResult*) NULL)->psMax) == 4, "psMax has padding");

const char* ffDetectGPU(const FFGPUOptions* options, FFlist* result);
const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus);

Expand Down
7 changes: 5 additions & 2 deletions src/detection/gpu/gpu_intel.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,15 +66,18 @@ const char* ffDetectIntelGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverRe
}

uint32_t deviceCount = 0;
if (igclData.ffctlEnumerateDevices(igclData.apiHandle, &deviceCount, NULL)) {
// ctlEnumerateDevices MUST be called with deviceCount = 0 and devices = NULL first,
// otherwise it will be silently ignored and return CTL_RESULT_SUCCESS with deviceCount and devices unmodified.
// VERY STRANGE BEHAVIOR
if (igclData.ffctlEnumerateDevices(igclData.apiHandle, &deviceCount, NULL) != CTL_RESULT_SUCCESS) {
return "ctlEnumerateDevices(NULL) failed";
}
if (deviceCount == 0) {
return "No Intel graphics adapter found";
}

FF_AUTO_FREE ctl_device_adapter_handle_t* devices = malloc(deviceCount * sizeof(*devices));
if (igclData.ffctlEnumerateDevices(igclData.apiHandle, &deviceCount, devices)) {
if (igclData.ffctlEnumerateDevices(igclData.apiHandle, &deviceCount, devices) != CTL_RESULT_SUCCESS) {
return "ctlEnumerateDevices(devices) failed";
}

Expand Down
62 changes: 32 additions & 30 deletions src/detection/gpu/gpu_linux.c
Original file line number Diff line number Diff line change
Expand Up @@ -410,34 +410,6 @@ static const char* detectPci(const FFGPUOptions* options, FFlist* gpus, FFstrbuf
pciDetectDriver(&gpu->driver, deviceDir, buffer, drmKey);
ffStrbufSubstrBefore(deviceDir, drmDirPathLength);

ffStrbufAppendS(deviceDir, "/max_link_speed");
if (ffReadFileBuffer(deviceDir->chars, buffer)) {
gpu->psMax.gen = pcieLinkSpeedToGen(buffer);
}
ffStrbufSubstrBefore(deviceDir, drmDirPathLength);

if (gpu->psMax.gen != FF_GPU_PCIE_SPEED_UNSET) {
ffStrbufAppendS(deviceDir, "/max_link_width");
if (ffReadFileBuffer(deviceDir->chars, buffer)) {
gpu->psMax.lanes = pcieWidthToLanes(buffer);
}
ffStrbufSubstrBefore(deviceDir, drmDirPathLength);
}

ffStrbufAppendS(deviceDir, "/current_link_speed");
if (ffReadFileBuffer(deviceDir->chars, buffer)) {
gpu->psCurr.gen = pcieLinkSpeedToGen(buffer);
}
ffStrbufSubstrBefore(deviceDir, drmDirPathLength);

if (gpu->psCurr.gen != FF_GPU_PCIE_SPEED_UNSET) {
ffStrbufAppendS(deviceDir, "/current_link_width");
if (ffReadFileBuffer(deviceDir->chars, buffer)) {
gpu->psCurr.lanes = pcieWidthToLanes(buffer);
}
ffStrbufSubstrBefore(deviceDir, drmDirPathLength);
}

if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_AMD) {
bool ok = false;
if (drmKey && options->driverSpecific) {
Expand Down Expand Up @@ -473,7 +445,7 @@ static const char* detectPci(const FFGPUOptions* options, FFlist* gpus, FFstrbuf
pciDetectTempGeneral(options, gpu, deviceDir, buffer);
pciDetectZxSpecific(options, gpu, deviceDir, buffer);
} else {
ffGPUDetectDriverSpecific(options, gpu, (FFGpuDriverPciBusId) {
ffGPUDetectDriverSpecific(options, gpu, (FFGpuDriverPciBusId){
.domain = pciDomain,
.bus = pciBus,
.device = pciDevice,
Expand All @@ -487,11 +459,41 @@ static const char* detectPci(const FFGPUOptions* options, FFlist* gpus, FFstrbuf

ffGPUFillVendorByDeviceName(gpu);

if (options->driverSpecific && gpu->pcieSpeed == FF_GPU_PCIE_SPEED_UNSET) {
Comment thread
CarterLi marked this conversation as resolved.
ffStrbufAppendS(deviceDir, "/max_link_speed");
if (ffReadFileBuffer(deviceDir->chars, buffer)) {
gpu->psMax.gen = pcieLinkSpeedToGen(buffer);
}
ffStrbufSubstrBefore(deviceDir, drmDirPathLength);

if (gpu->psMax.gen != FF_GPU_PCIE_SPEED_UNSET) {
ffStrbufAppendS(deviceDir, "/max_link_width");
if (ffReadFileBuffer(deviceDir->chars, buffer)) {
gpu->psMax.lanes = pcieWidthToLanes(buffer);
}
ffStrbufSubstrBefore(deviceDir, drmDirPathLength);
}

ffStrbufAppendS(deviceDir, "/current_link_speed");
if (ffReadFileBuffer(deviceDir->chars, buffer)) {
gpu->psCurr.gen = pcieLinkSpeedToGen(buffer);
}
ffStrbufSubstrBefore(deviceDir, drmDirPathLength);

if (gpu->psCurr.gen != FF_GPU_PCIE_SPEED_UNSET) {
ffStrbufAppendS(deviceDir, "/current_link_width");
if (ffReadFileBuffer(deviceDir->chars, buffer)) {
gpu->psCurr.lanes = pcieWidthToLanes(buffer);
}
ffStrbufSubstrBefore(deviceDir, drmDirPathLength);
}
}

return NULL;
}

#if __aarch64__
#include "detection/cpu/cpu.h"
#include "detection/cpu/cpu.h"

FF_A_UNUSED static const char* drmDetectAsahiSpecific(FFGPUResult* gpu, const char* name, FF_A_UNUSED FFstrbuf* buffer, FF_A_UNUSED const char* drmKey) {
if (sscanf(name, "agx-t%lu", &gpu->deviceId) == 1) {
Expand Down
14 changes: 14 additions & 0 deletions src/detection/gpu/gpu_mthreads.c
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,20 @@ const char* ffDetectMthreadsGpuInfo(const FFGpuDriverCondition* cond, FFGpuDrive
}
}

if (result.psCurr || result.psMax) {
MtmlPciInfo pciInfo;
if (mtmlData.ffmtmlDeviceGetPciInfo(device, &pciInfo) == MTML_SUCCESS) {
if (result.psCurr) {
result.psCurr->lanes = (uint16_t) pciInfo.pciCurWidth;
result.psCurr->gen = (uint16_t) pciInfo.pciCurGen;
}
if (result.psMax) {
result.psMax->lanes = (uint16_t) pciInfo.pciMaxWidth;
result.psMax->gen = (uint16_t) pciInfo.pciMaxGen;
}
}
}

return NULL;

#else
Expand Down
83 changes: 47 additions & 36 deletions src/detection/gpu/gpu_windows.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

#define GUID_DEVCLASS_DISPLAY_STRING L"{4d36e968-e325-11ce-bfc1-08002be10318}" // Found in <devguid.h>

static bool queryPciDeviceInfo(FFGPUResult* gpu, D3DKMT_DEVICE_IDS* outDeviceIds) {
static bool queryPciDeviceInfo(FFGPUResult* gpu, D3DKMT_DEVICE_IDS* outDeviceIds, bool queryPcieGen) {
FF_DEBUG("Query PCI device info: %08llX", gpu->deviceId);

static FFlist deviceIdsCache;
Expand Down Expand Up @@ -107,42 +107,44 @@ static bool queryPciDeviceInfo(FFGPUResult* gpu, D3DKMT_DEVICE_IDS* outDeviceIds
FF_DEBUG("Failed to get PCI bus number");
}

DEVPROPTYPE propType;
if (queryPcieGen) {
DEVPROPTYPE propType;

pciBufLen = sizeof(entry->maxLinkSpeed);
// Reports PCEe gen despite the PKEY name
CONFIGRET ret = CM_Get_DevNode_PropertyW(devInst, &DEVPKEY_PciDevice_MaxLinkSpeed, &propType, (PBYTE) &entry->maxLinkSpeed, &pciBufLen, 0);
if (ret == CR_SUCCESS) {
FF_DEBUG("PCIe max GEN: %u", entry->maxLinkSpeed);
} else {
FF_DEBUG("Failed to get PCIe max GEN: %s", ffDebugConfigRet(ret));
}

if (entry->maxLinkSpeed != FF_GPU_PCIE_SPEED_UNSET) {
pciBufLen = sizeof(entry->maxLinkWidth);
ret = CM_Get_DevNode_PropertyW(devInst, &DEVPKEY_PciDevice_MaxLinkWidth, &propType, (PBYTE) &entry->maxLinkWidth, &pciBufLen, 0);
pciBufLen = sizeof(entry->maxLinkSpeed);
// Reports PCIe gen despite the PKEY name
CONFIGRET ret = CM_Get_DevNode_PropertyW(devInst, &DEVPKEY_PciDevice_MaxLinkSpeed, &propType, (PBYTE) &entry->maxLinkSpeed, &pciBufLen, 0);
if (ret == CR_SUCCESS) {
FF_DEBUG("PCIe max link width: %u", entry->maxLinkWidth);
FF_DEBUG("PCIe max GEN: %u", entry->maxLinkSpeed);
} else {
FF_DEBUG("Failed to get PCIe max link width: %s", ffDebugConfigRet(ret));
FF_DEBUG("Failed to get PCIe max GEN: %s", ffDebugConfigRet(ret));
}
}

pciBufLen = sizeof(entry->currentLinkSpeed);
ret = CM_Get_DevNode_PropertyW(devInst, &DEVPKEY_PciDevice_CurrentLinkSpeed, &propType, (PBYTE) &entry->currentLinkSpeed, &pciBufLen, 0);
if (ret == CR_SUCCESS) {
FF_DEBUG("PCIe GEN: %u", entry->currentLinkSpeed);
} else {
FF_DEBUG("Failed to get PCIe GEN: %s", ffDebugConfigRet(ret));
}
if (entry->maxLinkSpeed != FF_GPU_PCIE_SPEED_UNSET) {
pciBufLen = sizeof(entry->maxLinkWidth);
ret = CM_Get_DevNode_PropertyW(devInst, &DEVPKEY_PciDevice_MaxLinkWidth, &propType, (PBYTE) &entry->maxLinkWidth, &pciBufLen, 0);
if (ret == CR_SUCCESS) {
FF_DEBUG("PCIe max link width: %u", entry->maxLinkWidth);
} else {
FF_DEBUG("Failed to get PCIe max link width: %s", ffDebugConfigRet(ret));
}
}

if (entry->currentLinkSpeed != FF_GPU_PCIE_SPEED_UNSET) {
pciBufLen = sizeof(entry->currentLinkWidth);
ret = CM_Get_DevNode_PropertyW(devInst, &DEVPKEY_PciDevice_CurrentLinkWidth, &propType, (PBYTE) &entry->currentLinkWidth, &pciBufLen, 0);
pciBufLen = sizeof(entry->currentLinkSpeed);
ret = CM_Get_DevNode_PropertyW(devInst, &DEVPKEY_PciDevice_CurrentLinkSpeed, &propType, (PBYTE) &entry->currentLinkSpeed, &pciBufLen, 0);
if (ret == CR_SUCCESS) {
FF_DEBUG("PCIe current link width: %u", entry->currentLinkWidth);
FF_DEBUG("PCIe GEN: %u", entry->currentLinkSpeed);
} else {
FF_DEBUG("Failed to get PCIe current link width: %s", ffDebugConfigRet(ret));
FF_DEBUG("Failed to get PCIe GEN: %s", ffDebugConfigRet(ret));
}

if (entry->currentLinkSpeed != FF_GPU_PCIE_SPEED_UNSET) {
pciBufLen = sizeof(entry->currentLinkWidth);
ret = CM_Get_DevNode_PropertyW(devInst, &DEVPKEY_PciDevice_CurrentLinkWidth, &propType, (PBYTE) &entry->currentLinkWidth, &pciBufLen, 0);
if (ret == CR_SUCCESS) {
FF_DEBUG("PCIe current link width: %u", entry->currentLinkWidth);
} else {
FF_DEBUG("Failed to get PCIe current link width: %s", ffDebugConfigRet(ret));
}
}
}
}
Expand All @@ -154,10 +156,13 @@ static bool queryPciDeviceInfo(FFGPUResult* gpu, D3DKMT_DEVICE_IDS* outDeviceIds
if (outDeviceIds->VendorID != -1u) {
*outDeviceIds = entry->deviceIds;
}
Comment on lines 156 to 158
gpu->psMax.gen = (uint16_t) entry->maxLinkSpeed;
gpu->psMax.lanes = (uint16_t) entry->maxLinkWidth;
gpu->psCurr.gen = (uint16_t) entry->currentLinkSpeed;
gpu->psCurr.lanes = (uint16_t) entry->currentLinkWidth;

if (queryPcieGen) {
gpu->psMax.gen = (uint16_t) entry->maxLinkSpeed;
gpu->psMax.lanes = (uint16_t) entry->maxLinkWidth;
gpu->psCurr.gen = (uint16_t) entry->currentLinkSpeed;
gpu->psCurr.lanes = (uint16_t) entry->currentLinkWidth;
}
return true;
}
}
Expand Down Expand Up @@ -371,9 +376,9 @@ ffGPUDetectWsl2
FF_DEBUG("KMTQAITYPE_PHYSICALADAPTERDEVICEIDS query failed for adapter #%u: %s", i, ffDebugNtStatus(status));
}

#if _WIN32
if (adapterAddress.BusNumber != -1u) {
if (queryPciDeviceInfo(gpu, &deviceIds.DeviceIds) && gpu->vendor.length == 0) {
#if _WIN32 && FF_WIN81_COMPAT
if (adapterAddress.BusNumber != -1u && (deviceIds.DeviceIds.VendorID == -1u || options->driverSpecific)) {
if (queryPciDeviceInfo(gpu, &deviceIds.DeviceIds, options->driverSpecific) && gpu->vendor.length == 0) {
ffStrbufSetStatic(&gpu->vendor, ffGPUGetVendorString(deviceIds.DeviceIds.VendorID));
}
}
Expand Down Expand Up @@ -448,6 +453,12 @@ ffGPUDetectWsl2
FF_DEBUG("Attempting to query vendor name via registry for adapter #%u", i);
queryVendorNameViaRegistry(&gpu->vendor, adapter->hAdapter);
}

#if !FF_WIN81_COMPAT
if (adapterAddress.BusNumber != -1u && options->driverSpecific && gpu->pcieSpeed == FF_GPU_PCIE_SPEED_UNSET) {
queryPciDeviceInfo(gpu, &deviceIds.DeviceIds, options->driverSpecific);
}
#endif
#endif

if (gpu->name.length == 0) {
Expand Down
9 changes: 8 additions & 1 deletion src/detection/memory/memory_bsd.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,15 @@ const char* ffDetectMemory(FFMemoryResult* ram) {

// vm.stats.vm.* are int values
int32_t pagesFree = ffSysctlGetInt("vm.stats.vm.v_free_count", 0) + ffSysctlGetInt("vm.stats.vm.v_inactive_count", 0) + ffSysctlGetInt("vm.stats.vm.v_cache_count", 0);
int64_t bytesCache = ffSysctlGetInt64("vfs.bufspace", 0);

ram->bytesUsed = ram->bytesTotal - (uint64_t) pagesFree * instance.state.platform.sysinfo.pageSize;
ram->bytesUsed = ram->bytesTotal - (uint64_t) pagesFree * instance.state.platform.sysinfo.pageSize - (uint64_t) bytesCache;

Comment on lines 11 to +15
int64_t bytesArc = ffSysctlGetInt64("kstat.zfs.misc.arcstats.size", 0);
if (bytesArc > 0) bytesArc -= ffSysctlGetInt64("kstat.zfs.misc.arcstats.c_min", 0);
if (bytesArc > 0 && (uint64_t) bytesArc < ram->bytesUsed) {
ram->bytesUsed -= (uint64_t) bytesArc;
}

return NULL;
}
Loading
Loading