From 702b9c8415097bdf299fea07b565665c68302dd3 Mon Sep 17 00:00:00 2001 From: Johnny Silverman Date: Mon, 3 Nov 2025 21:54:40 +0200 Subject: [PATCH 1/6] Use megabytes instead of gigabytes for size calculations internally. Change variable types to "int64_t" for megabyte calc. Add function "getSizeTextFromMegabytes" for generating size strings where it was repeated code. Optimize code to do less reading of reusable locale strings and read "logicalBlockSize" before reading other size parameters. --- include/mainwindow.h | 7 +++ src/mainwindow.cpp | 142 +++++++++++++++++++------------------------ 2 files changed, 71 insertions(+), 78 deletions(-) diff --git a/include/mainwindow.h b/include/mainwindow.h index e79c5ff..bc27452 100644 --- a/include/mainwindow.h +++ b/include/mainwindow.h @@ -95,4 +95,11 @@ private: void addSmartAttributesTable(const QJsonArray &attributes); void transformWindow(); void mousePressEvent(QMouseEvent*); + +private: + QString mbSymbol; + QString gbSymbol; + QString tbSymbol; + QString pbSymbol; + QString getMbToPrettyString(const int64_t &sizeInMbI64, const int &precisionInt, const bool &useGbBool); }; diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index d090a15..5e0e280 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -18,6 +18,7 @@ MainWindow::MainWindow(QWidget *parent) , ui(new Ui::MainWindow) , settings("qdiskinfo", "qdiskinfo") , initializing(true) + , mbSymbol("MB"), gbSymbol("GB"), tbSymbol("TB"), pbSymbol("PB") { ui->setupUi(this); @@ -145,6 +146,11 @@ MainWindow::MainWindow(QWidget *parent) delete temperatureValueHorizontal; delete healthStatusValueHorizontal; } + + mbSymbol = locale.formattedDataSize(1 << 20, 1, QLocale::DataSizeTraditionalFormat).split(' ')[1]; + gbSymbol = locale.formattedDataSize(1 << 30, 1, QLocale::DataSizeTraditionalFormat).split(' ')[1]; + tbSymbol = locale.formattedDataSize(qint64(1) << 40, 1, QLocale::DataSizeTraditionalFormat).split(' ')[1]; + pbSymbol = locale.formattedDataSize(qint64(1) << 50, 1, QLocale::DataSizeTraditionalFormat).split(' ')[1]; } MainWindow::~MainWindow() @@ -184,6 +190,11 @@ void MainWindow::updateNavigationButtons(qsizetype currentIndex) void MainWindow::updateUI(const QString ¤tDeviceName) { + mbSymbol = locale.formattedDataSize(1 << 20, 1, QLocale::DataSizeTraditionalFormat).split(' ')[1]; + gbSymbol = locale.formattedDataSize(1 << 30, 1, QLocale::DataSizeTraditionalFormat).split(' ')[1]; + tbSymbol = locale.formattedDataSize(qint64(1) << 40, 1, QLocale::DataSizeTraditionalFormat).split(' ')[1]; + pbSymbol = locale.formattedDataSize(qint64(1) << 50, 1, QLocale::DataSizeTraditionalFormat).split(' ')[1]; + QVector diskItems; bool firstTime = true; @@ -238,17 +249,10 @@ void MainWindow::updateUI(const QString ¤tDeviceName) QString health; QColor healthColor; - double diskCapacityGB = localObj.value("user_capacity").toObject().value("bytes").toDouble() / 1e9; - QString gbSymbol = locale.formattedDataSize(1 << 30, 1, QLocale::DataSizeTraditionalFormat).split(' ')[1]; - QString tbSymbol = locale.formattedDataSize(qint64(1) << 40, 1, QLocale::DataSizeTraditionalFormat).split(' ')[1]; - QString diskCapacityString; - int diskCapacityGbInt = static_cast(diskCapacityGB); + double diskCapacityMB = localObj.value("user_capacity").toObject().value("bytes").toDouble() / 1e6; + int64_t diskCapacityMbI64 = static_cast(diskCapacityMB); bool useGB = ui->actionUse_GB_instead_of_TB->isChecked(); - if (diskCapacityGbInt < 1000 || useGB) { - diskCapacityString = locale.toString(diskCapacityGB, 'f', 1) + " " + gbSymbol; - } else { - diskCapacityString = QString::number(diskCapacityGbInt/1000) + " " + tbSymbol; - } + QString diskCapacityString = getMbToPrettyString(diskCapacityMbI64, 0, useGB); QJsonObject temperatureObj = localObj["temperature"].toObject(); int temperatureInt = temperatureObj["current"].toInt(); @@ -433,23 +437,16 @@ void MainWindow::populateWindow(const QJsonObject &localObj, const QString &heal QJsonObject nvmeLog = localObj["nvme_smart_health_information_log"].toObject(); QString modelName = localObj["model_name"].toString(); QString firmwareVersion = localObj["firmware_version"].toString("----"); - double diskCapacityGB = localObj.value("user_capacity").toObject().value("bytes").toDouble() / 1e9; - int diskCapacityGbInt = static_cast(diskCapacityGB); + double diskCapacityMB = localObj.value("user_capacity").toObject().value("bytes").toDouble() / 1e6; + int64_t diskCapacityMbI64 = static_cast(diskCapacityMB); int powerCycleCountInt = localObj["power_cycle_count"].toInt(-1); QJsonObject temperatureObj = localObj["temperature"].toObject(); int temperatureInt = temperatureObj["current"].toInt(); - int totalWritesInt = 0; - int totalReadsInt = 0; + int64_t totalMbWritesI64 = 0; + int64_t totalMbReadsI64 = 0; bool useGB = ui->actionUse_GB_instead_of_TB->isChecked(); - QString gbSymbol = locale.formattedDataSize(1 << 30, 1, QLocale::DataSizeTraditionalFormat).split(' ')[1]; - QString tbSymbol = locale.formattedDataSize(qint64(1) << 40, 1, QLocale::DataSizeTraditionalFormat).split(' ')[1]; - QString diskCapacityString; - if (diskCapacityGbInt < 1000 || useGB) { - diskCapacityString = locale.toString(diskCapacityGB, 'f', 1) + " " + gbSymbol; - } else { - diskCapacityString = QString::number(diskCapacityGbInt/1000) + " " + tbSymbol; - } + QString diskCapacityString = getMbToPrettyString(diskCapacityMbI64, 0, useGB); QString totalReads; QString totalWrites; @@ -474,8 +471,8 @@ void MainWindow::populateWindow(const QJsonObject &localObj, const QString &heal modelName = localObj["scsi_model_name"].toString(); powerCycleCountInt = localObj["scsi_start_stop_cycle_counter"].toObject().value("accumulated_load_unload_cycles").toInt(); firmwareVersion = localObj["scsi_revision"].toString("----"); - totalReadsInt = scsiErrorCounterLog.value("read").toObject().value("gigabytes_processed").toString().split(",").first().toInt(); - totalWritesInt = scsiErrorCounterLog.value("write").toObject().value("gigabytes_processed").toString().split(",").first().toInt(); + totalMbReadsI64 = scsiErrorCounterLog.value("read").toObject().value("gigabytes_processed").toString().split(",").first().toInt() * 1000; + totalMbWritesI64 = scsiErrorCounterLog.value("write").toObject().value("gigabytes_processed").toString().split(",").first().toInt() * 1000; } bool nvmeHasSelfTest = false; @@ -591,6 +588,7 @@ void MainWindow::populateWindow(const QJsonObject &localObj, const QString &heal powerOnHoursLineEdit->setText(powerOnTime); powerOnHoursLineEdit->setAlignment(Qt::AlignRight); + int logicalBlockSize = localObj["logical_block_size"].toInt(); if (!isNvme) { for (const QJsonValue &attr : std::as_const(attributes)) { QJsonObject attrObj = attr.toObject(); @@ -602,57 +600,46 @@ void MainWindow::populateWindow(const QJsonObject &localObj, const QString &heal } else if (attrObj["id"] == 241) { if (attrObj["name"] == "Total_Writes_GB") { int gigabytes = attrObj["raw"].toObject()["value"].toInt(); - totalWritesInt = gigabytes; + totalMbWritesI64 = gigabytes * 1000; } else if (attrObj["name"] == "Host_Writes_32MiB") { - double gigabytes = (attrObj["raw"].toObject()["value"].toInt() * 32 * 1024.0 * 1024.0) / 1e9; - totalWritesInt = static_cast(gigabytes); + double megabytes = (attrObj["raw"].toObject()["value"].toInt() * 32 * 1024.0 * 1024.0) / 1e6; + totalMbWritesI64 = static_cast(megabytes); } else if (attrObj["name"] == "Total_LBAs_Written") { - int logicalBlockSize = localObj["logical_block_size"].toInt(); qlonglong lbaWritten = attrObj["raw"].toObject()["value"].toVariant().toLongLong(); - qlonglong gigabytes = (lbaWritten * logicalBlockSize) / 1e9; - int gigabytesInt = static_cast(gigabytes); - if (!gigabytesInt) { - gigabytesInt = static_cast(lbaWritten); - } - totalWritesInt = gigabytesInt; + double megabytes = double(lbaWritten * logicalBlockSize) / 1e6; + totalMbWritesI64 = static_cast(megabytes); } else if (attrObj["name"] == "Host_Writes_GiB" || attrObj["name"] == "Lifetime_Writes_GiB") { double gibibytes = attrObj["raw"].toObject()["value"].toDouble(); double bytesPerGiB = static_cast(1ULL << 30); - double bytesPerGB = 1e9; - double conversionFactor = bytesPerGiB / bytesPerGB; - double gigabytes = gibibytes * conversionFactor; - totalWritesInt = static_cast(gigabytes); + double bytesPerMB = 1e6; + double conversionFactor = bytesPerGiB / bytesPerMB; + double megabytes = gibibytes * conversionFactor; + totalMbWritesI64 = static_cast(megabytes); } } else if (attrObj["id"] == 242) { if (attrObj["name"] == "Total_Reads_GB") { int gigabytes = attrObj["raw"].toObject()["value"].toInt(); - totalReadsInt = gigabytes; + totalMbReadsI64 = gigabytes * 1000; } else if (attrObj["name"] == "Host_Reads_32MiB") { - double gigabytes = (attrObj["raw"].toObject()["value"].toInt() * 32 * 1024.0 * 1024.0) / 1e9; - totalReadsInt = static_cast(gigabytes); + double megabytes = (attrObj["raw"].toObject()["value"].toInt() * 32 * 1024 * 1024) / 1e6; + totalMbReadsI64 = static_cast(megabytes); } else if (attrObj["name"] == "Total_LBAs_Read") { - int logicalBlockSize = localObj["logical_block_size"].toInt(); qlonglong lbaRead = attrObj["raw"].toObject()["value"].toVariant().toLongLong(); - qlonglong gigabytes = (lbaRead * logicalBlockSize) / 1e9; - int gigabytesInt = static_cast(gigabytes); - if (!gigabytesInt) { - gigabytesInt = static_cast(lbaRead); - } - totalReadsInt = gigabytesInt; + double megabytes = double(lbaRead * logicalBlockSize) / 1e6; + totalMbReadsI64 = static_cast(megabytes); } else if (attrObj["name"] == "Host_Reads_GiB" || attrObj["name"] == "Lifetime_Reads_GiB") { double gibibytes = attrObj["raw"].toObject()["value"].toDouble(); double bytesPerGiB = static_cast(1ULL << 30); - double bytesPerGB = 1e9; - double conversionFactor = bytesPerGiB / bytesPerGB; - double gigabytes = gibibytes * conversionFactor; - totalReadsInt = static_cast(gigabytes); + double bytesPerMB = 1e6; + double conversionFactor = bytesPerGiB / bytesPerMB; + double megabytes = gibibytes * conversionFactor; + totalMbReadsI64 = static_cast(megabytes); } } else if (attrObj["id"] == 246) { // MX500 if (attrObj["name"] == "Total_LBAs_Written") { - int logicalBlockSize = localObj["logical_block_size"].toInt(); qlonglong lbaWritten = attrObj["raw"].toObject()["value"].toVariant().toLongLong(); - qlonglong gigabytes = (lbaWritten * logicalBlockSize) / 1e9; - totalWritesInt = static_cast(gigabytes); + double megabytes = double(lbaWritten * logicalBlockSize) / 1e6; + totalMbWritesI64 = static_cast(megabytes); } } else if (attrObj["name"] == "Remaining_Lifetime_Perc") { int percentageUsed = attrObj["raw"].toObject()["value"].toInt(); @@ -682,14 +669,15 @@ void MainWindow::populateWindow(const QJsonObject &localObj, const QString &heal for (auto smartItem = nvmeLog.begin(); smartItem != nvmeLog.end(); ++smartItem) { QString key = smartItem.key(); QJsonValue value = smartItem.value(); + // it appears that NVME drives report data_units as logical_block_size*1000 bytes if (key == "data_units_written") { double dataUnitsWritten = value.toDouble(); - double gigabytes = (dataUnitsWritten * 512) / 1'000'000; - totalWritesInt = static_cast(gigabytes); + double megabytes = (dataUnitsWritten * logicalBlockSize) / 1000; + totalMbWritesI64 = static_cast(megabytes); } else if (key == "data_units_read") { double dataUnitsRead = value.toDouble(); - double gigabytes = (dataUnitsRead * 512) / 1'000'000; - totalReadsInt = static_cast(gigabytes); + double megabytes = (dataUnitsRead * logicalBlockSize) / 1000; + totalMbReadsI64 = static_cast(megabytes); } else if (key == "percentage_used") { int percentageUsed = 100 - value.toInt(); percentage = QString::number(percentageUsed) + " %"; @@ -697,25 +685,8 @@ void MainWindow::populateWindow(const QJsonObject &localObj, const QString &heal } } - if (totalReadsInt) { - if (totalReadsInt < 1000 || useGB) { - totalReads = QString::number(totalReadsInt) + " " + gbSymbol; - } else { - totalReads = QString::number(totalReadsInt/1000.0, 'f', 1) + " " + tbSymbol; - } - } else { - totalReads = "----"; - } - - if (totalWritesInt) { - if (totalWritesInt < 1000 || useGB) { - totalWrites = QString::number(totalWritesInt) + " " + gbSymbol; - } else { - totalWrites = QString::number(totalWritesInt/1000.0, 'f', 1) + " " + tbSymbol; - } - } else { - totalWrites = "----"; - } + totalReads = getMbToPrettyString(totalMbReadsI64, 1, useGB); + totalWrites = getMbToPrettyString(totalMbWritesI64, 1, useGB); totalReadsLineEdit->setText(totalReads); totalReadsLineEdit->setAlignment(Qt::AlignRight); @@ -1480,3 +1451,18 @@ void MainWindow::on_actionSave_Image_triggered() screenshot.save(QFileDialog::getSaveFileName(this, tr("Save Image"), "QDiskInfo_" + deviceNodeLineEdit->text().section('/', -1) + ".png", tr("PNG Files (*.png)"))); } +QString MainWindow::getMbToPrettyString(const int64_t &sizeInMbI64, const int &precisionInt, const bool &useGbBool) +{ + if (!sizeInMbI64) + return "----"; + + int precision = precisionInt ? (useGbBool ? 1 : precisionInt) : 0; + double sizeInMB = double(sizeInMbI64); + if (sizeInMbI64 < 1000) + return QString::number(sizeInMbI64) + " " + mbSymbol; + else if (sizeInMbI64 < 1000000 || useGbBool) + return QString::number(sizeInMB/1e3, 'f', precision) + " " + gbSymbol; + else if (sizeInMbI64 < 1000000000) + return QString::number(sizeInMB/1e6, 'f', precision) + " " + tbSymbol; + return QString::number(sizeInMB/1e9, 'f', precision) + " " + pbSymbol; +} From 557d6db0409d9eb06fa49cd6666758900a7539a2 Mon Sep 17 00:00:00 2001 From: Johnny Silverman Date: Tue, 4 Nov 2025 02:45:07 +0200 Subject: [PATCH 2/6] Change "getMbToPrettyString" to const function --- include/mainwindow.h | 2 +- src/mainwindow.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/mainwindow.h b/include/mainwindow.h index bc27452..ad4572c 100644 --- a/include/mainwindow.h +++ b/include/mainwindow.h @@ -101,5 +101,5 @@ private: QString gbSymbol; QString tbSymbol; QString pbSymbol; - QString getMbToPrettyString(const int64_t &sizeInMbI64, const int &precisionInt, const bool &useGbBool); + QString getMbToPrettyString(const int64_t &sizeInMbI64, const int &precisionInt, const bool &useGbBool) const; }; diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 5e0e280..6cea9fc 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1451,7 +1451,7 @@ void MainWindow::on_actionSave_Image_triggered() screenshot.save(QFileDialog::getSaveFileName(this, tr("Save Image"), "QDiskInfo_" + deviceNodeLineEdit->text().section('/', -1) + ".png", tr("PNG Files (*.png)"))); } -QString MainWindow::getMbToPrettyString(const int64_t &sizeInMbI64, const int &precisionInt, const bool &useGbBool) +QString MainWindow::getMbToPrettyString(const int64_t &sizeInMbI64, const int &precisionInt, const bool &useGbBool) const { if (!sizeInMbI64) return "----"; From bd6f95feb1158d8e7494dd4821b9020e3ba7ec8f Mon Sep 17 00:00:00 2001 From: Johnny Silverman Date: Tue, 4 Nov 2025 02:56:48 +0200 Subject: [PATCH 3/6] Use const values for precision to improve code readability --- src/mainwindow.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 6cea9fc..9f81f36 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -13,6 +13,9 @@ #include #include +const int PRECISION_TOTALS_TO_STR = 2; +const int PRECISION_CAPACITY_TO_STR = 0; + MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) @@ -252,7 +255,7 @@ void MainWindow::updateUI(const QString ¤tDeviceName) double diskCapacityMB = localObj.value("user_capacity").toObject().value("bytes").toDouble() / 1e6; int64_t diskCapacityMbI64 = static_cast(diskCapacityMB); bool useGB = ui->actionUse_GB_instead_of_TB->isChecked(); - QString diskCapacityString = getMbToPrettyString(diskCapacityMbI64, 0, useGB); + QString diskCapacityString = getMbToPrettyString(diskCapacityMbI64, PRECISION_CAPACITY_TO_STR, useGB); QJsonObject temperatureObj = localObj["temperature"].toObject(); int temperatureInt = temperatureObj["current"].toInt(); @@ -446,7 +449,7 @@ void MainWindow::populateWindow(const QJsonObject &localObj, const QString &heal int64_t totalMbReadsI64 = 0; bool useGB = ui->actionUse_GB_instead_of_TB->isChecked(); - QString diskCapacityString = getMbToPrettyString(diskCapacityMbI64, 0, useGB); + QString diskCapacityString = getMbToPrettyString(diskCapacityMbI64, PRECISION_CAPACITY_TO_STR, useGB); QString totalReads; QString totalWrites; @@ -685,8 +688,8 @@ void MainWindow::populateWindow(const QJsonObject &localObj, const QString &heal } } - totalReads = getMbToPrettyString(totalMbReadsI64, 1, useGB); - totalWrites = getMbToPrettyString(totalMbWritesI64, 1, useGB); + totalReads = getMbToPrettyString(totalMbReadsI64, PRECISION_TOTALS_TO_STR, useGB); + totalWrites = getMbToPrettyString(totalMbWritesI64, PRECISION_TOTALS_TO_STR, useGB); totalReadsLineEdit->setText(totalReads); totalReadsLineEdit->setAlignment(Qt::AlignRight); From 35d7ed9c8a10ec9a1713672ce732edfce372d123 Mon Sep 17 00:00:00 2001 From: Johnny Silverman Date: Fri, 7 Nov 2025 18:47:49 +0200 Subject: [PATCH 4/6] Add workaround for drives which report `LBAs` read/written but instead report in 32MiB blocks. --- src/mainwindow.cpp | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 9f81f36..d2dac04 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -607,10 +607,6 @@ void MainWindow::populateWindow(const QJsonObject &localObj, const QString &heal } else if (attrObj["name"] == "Host_Writes_32MiB") { double megabytes = (attrObj["raw"].toObject()["value"].toInt() * 32 * 1024.0 * 1024.0) / 1e6; totalMbWritesI64 = static_cast(megabytes); - } else if (attrObj["name"] == "Total_LBAs_Written") { - qlonglong lbaWritten = attrObj["raw"].toObject()["value"].toVariant().toLongLong(); - double megabytes = double(lbaWritten * logicalBlockSize) / 1e6; - totalMbWritesI64 = static_cast(megabytes); } else if (attrObj["name"] == "Host_Writes_GiB" || attrObj["name"] == "Lifetime_Writes_GiB") { double gibibytes = attrObj["raw"].toObject()["value"].toDouble(); double bytesPerGiB = static_cast(1ULL << 30); @@ -618,6 +614,17 @@ void MainWindow::populateWindow(const QJsonObject &localObj, const QString &heal double conversionFactor = bytesPerGiB / bytesPerMB; double megabytes = gibibytes * conversionFactor; totalMbWritesI64 = static_cast(megabytes); + } else if (attrObj["name"] == "Total_LBAs_Written") { + qlonglong lbaWritten = attrObj["raw"].toObject()["value"].toVariant().toLongLong(); + double megabytes = double(logicalBlockSize * lbaWritten) / 1e6; + totalMbWritesI64 = static_cast(megabytes); + // workaround: for drives that report different value with bad attribute name + // Check if total MB writes are less than power on hours + if (totalMbWritesI64 / powerOnTimeInt == 0) { + // Assume it's 32MiB chunks reported as LBAs + megabytes = (double(lbaWritten * 32) * 1024.0 * 1024.0) / 1e6; + totalMbWritesI64 = static_cast(megabytes); + } } } else if (attrObj["id"] == 242) { if (attrObj["name"] == "Total_Reads_GB") { @@ -626,10 +633,6 @@ void MainWindow::populateWindow(const QJsonObject &localObj, const QString &heal } else if (attrObj["name"] == "Host_Reads_32MiB") { double megabytes = (attrObj["raw"].toObject()["value"].toInt() * 32 * 1024 * 1024) / 1e6; totalMbReadsI64 = static_cast(megabytes); - } else if (attrObj["name"] == "Total_LBAs_Read") { - qlonglong lbaRead = attrObj["raw"].toObject()["value"].toVariant().toLongLong(); - double megabytes = double(lbaRead * logicalBlockSize) / 1e6; - totalMbReadsI64 = static_cast(megabytes); } else if (attrObj["name"] == "Host_Reads_GiB" || attrObj["name"] == "Lifetime_Reads_GiB") { double gibibytes = attrObj["raw"].toObject()["value"].toDouble(); double bytesPerGiB = static_cast(1ULL << 30); @@ -637,6 +640,17 @@ void MainWindow::populateWindow(const QJsonObject &localObj, const QString &heal double conversionFactor = bytesPerGiB / bytesPerMB; double megabytes = gibibytes * conversionFactor; totalMbReadsI64 = static_cast(megabytes); + } else if (attrObj["name"] == "Total_LBAs_Read") { + qlonglong lbaRead = attrObj["raw"].toObject()["value"].toVariant().toLongLong(); + double megabytes = double(logicalBlockSize * lbaRead) / 1e6; + totalMbReadsI64 = static_cast(megabytes); + // workaround for drives that report different value with bad attribute name + // Check if total MB reads are less than power on hours + if (totalMbReadsI64 / powerOnTimeInt == 0) { + // Assume it's 32MiB chunks reported as LBAs + megabytes = (double(lbaRead * 32) * 1024.0 * 1024.0) / 1e6; + totalMbReadsI64 = static_cast(megabytes); + } } } else if (attrObj["id"] == 246) { // MX500 if (attrObj["name"] == "Total_LBAs_Written") { From 81ac60768f0eecc22684a3400bc8b592db4bb206 Mon Sep 17 00:00:00 2001 From: Johnny Silverman Date: Sat, 8 Nov 2025 16:11:57 +0200 Subject: [PATCH 5/6] Read all information about devices in smartctl (not only SMART). --- src/utils.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utils.cpp b/src/utils.cpp index ae4416e..3e4b4c0 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -99,7 +99,7 @@ QPair utils::scanDevices(bool initializing) for (const QJsonValue &value : std::as_const(devices)) { QJsonObject device = value.toObject(); QString deviceName = device["name"].toString(); - commandList.append((smartctlPath + " --all --json=o %1").arg(deviceName)); + commandList.append((smartctlPath + " -x --json=o %1").arg(deviceName)); } QString command = commandList.join(" ; "); @@ -139,7 +139,7 @@ QString utils::initiateSelfTest(const QString &testType, const QString &deviceNo QProcess process; QString command = getSmartctlPath(); QStringList arguments; - arguments << command << "--json=o" << "-t" << testType << deviceNode; + arguments << command << "--json=o" << "-x" << "-t" << testType << deviceNode; process.start("pkexec", arguments); process.waitForFinished(-1); From 9fd1ac07667914eb8f82c24ac63c32ab858e8809 Mon Sep 17 00:00:00 2001 From: Johnny Silverman Date: Sat, 8 Nov 2025 16:12:51 +0200 Subject: [PATCH 6/6] Parse through "ata_device_statistics" for devices which report incorrect reads/writes or don't report them at all in legacy attributes. --- src/mainwindow.cpp | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index d2dac04..2deda9f 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -672,6 +672,42 @@ void MainWindow::populateWindow(const QJsonObject &localObj, const QString &heal } } } + + // Some devices don't report or report incorrect reads/writes in legacy + // attributes, so we look for that data in ata_device_statistics. + // We do this after parsing through the legacy attributes + // to override possibly incorrect calculations. + QJsonObject ata_device_statistics = localObj["ata_device_statistics"].toObject(); + if (!ata_device_statistics.empty()) + { + QJsonArray pages = ata_device_statistics["pages"].toArray(); + for (const QJsonValue &pageval : std::as_const(pages)) + { + QJsonObject page = pageval.toObject(); + if (page["name"] == "General Statistics") + { + QJsonArray general_statistics = page["table"].toArray(); + for (const QJsonValue &stat : std::as_const(general_statistics)) + { + QJsonObject statObj = stat.toObject(); + QString key = statObj["name"].toString(); + QJsonValue value = statObj["value"]; + + if (key == "Logical Sectors Read") { + double logicalSectorsRead = value.toDouble(); + double megabytes = logicalSectorsRead * logicalBlockSize / 1e6; + totalMbReadsI64 = static_cast(megabytes); + } else if (key == "Logical Sectors Written") { + double logicalSectorsWritten = value.toDouble(); + double megabytes = logicalSectorsWritten * logicalBlockSize / 1e6; + totalMbWritesI64 = static_cast(megabytes); + } + } + break; // no need looking into other pages + } + } + } + if (percentage.isEmpty() && rotationRate == "---- (SSD)") { // Workaround for some drives which have this and another attribute for (const QJsonValue &attr : std::as_const(attributes)) { QJsonObject attrObj = attr.toObject();