Skip to content

Commit 6750117

Browse files
authored
Merge pull request #38 from MATF-Software-Verification/feature/massif-analysis-enhancements
Feature/massif analysis enhancements
2 parents 5e9e851 + eae1ae8 commit 6750117

19 files changed

Lines changed: 325 additions & 73 deletions

QT_Massif_App/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
4242
massifanalyzerthresholds.h massifanalyzerthresholds.cpp
4343
massifanalyzerthresholdswindow.h massifanalyzerthresholdswindow.cpp massifanalyzerthresholdswindow.ui
4444

45+
4546
)
4647
# Define target properties for Android with Qt 6 as:
4748
# set_property(TARGET QT_Massif_App APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR

QT_Massif_App/MassifAnalyzerThresholds.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class MassifAnalyzerThresholds : public QObject
1616
int highAllocationCount = 10;
1717
qint64 smallTotalAllocation = 5 * 1024 * 1024; // 5 MB
1818
double memoryJumpThreshold = 0.5; // 50%
19-
qint64 largeMemoryThreshold = 1000000000; // 1 GB
19+
qint64 largeMemoryThreshold = 1000 * 1024 * 1024; // 1 GB
2020
qint64 memoryFreeThreshold = 4 * 1024; // 4 KB
2121
double fragmentationThreshold = 0.10; // 10%
2222
int stabilizationWindowSize = 3;

QT_Massif_App/Parser.cpp

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ std::pair<QMap<QString, QString>, QVector<Snapshot>> Parser::parseMassifFile(con
3232

3333
if (line.trimmed().startsWith("n")) {
3434
QRegularExpression detailedAllocRegex(R"(n\d+:\s+(\d+)\s+0x[0-9A-Fa-f]+:\s+(.+)\s+\((.+):(\d+)\))");
35-
// (npr. "n1: 4000 (heap allocation functions) malloc/new/new[], --alloc-fns, etc.")
35+
// (example "n1: 4000 (heap allocation functions) malloc/new/new[], --alloc-fns, etc.")
3636
QRegularExpression summaryAllocRegex(R"(n\d+:\s+(\d+)\s+\(.+\))");
3737
static QRegularExpression stdlibFunctionRegex(R"(^(std::|__gnu_cxx::|boost::|__|_Z|_IO_|_dl_|call_init|construct<|operator new|operator delete))");
3838

@@ -45,9 +45,6 @@ std::pair<QMap<QString, QString>, QVector<Snapshot>> Parser::parseMassifFile(con
4545
entry.sourceFile = match.captured(3);
4646
entry.line = match.captured(4).toInt();
4747

48-
//std::cout << entry.bytes << " bytes, " << entry.function.toStdString()
49-
// << " " << entry.sourceFile.toStdString() << ":" << entry.line << std::endl;
50-
5148
bool isFromStdLib = stdlibFunctionRegex.match(entry.function).hasMatch();
5249
bool hasValidSourceFile = !entry.sourceFile.isEmpty()
5350
&& (entry.sourceFile.endsWith(".cpp") || entry.sourceFile.endsWith(".cc")
@@ -67,13 +64,8 @@ std::pair<QMap<QString, QString>, QVector<Snapshot>> Parser::parseMassifFile(con
6764
entry.sourceFile = "";
6865
entry.line = 0;
6966

70-
//std::cout << entry.bytes << " bytes, summary allocation line" << std::endl;
71-
7267
snapshot.allocations.append(entry);
7368
}
74-
else {
75-
qDebug() << "Failed to match allocation line:" << line;
76-
}
7769
}
7870
else if (line.contains(headerRegex, &match)) {
7971
header[match.captured(1)] = match.captured(2);
@@ -106,8 +98,6 @@ std::pair<QMap<QString, QString>, QVector<Snapshot>> Parser::parseMassifFile(con
10698
}
10799

108100

109-
// this function groups allocations with functions summing the amount of memory allocated in those functions
110-
// the problem is right now we have every function mentioned, and in more complex programs that will include STL etc..
111101
QMap<QString, FunctionAllocSummary> Parser::summarizeAllocationsByFunction(const QVector<Snapshot>& snapshots) {
112102
QMap<QString, FunctionAllocSummary> functionTotals;
113103

QT_Massif_App/mainwindow.cpp

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include "./ui_mainwindow.h"
44
#include <QDir>
55
#include <QStyle>
6+
#include <QSystemTrayIcon>
67

78
MainWindow::MainWindow(QWidget *parent)
89
: QMainWindow(parent)
@@ -13,6 +14,15 @@ MainWindow::MainWindow(QWidget *parent)
1314
{
1415
ui->setupUi(this);
1516
ui->btMassifOptions->setToolTip("Configure Massif settings");
17+
ui->btMassifAnalyzerParameters->setToolTip("Configure thresholds for report analysis");
18+
setWindowIcon(QApplication::style()->standardIcon(QStyle::SP_DriveNetIcon));
19+
QSystemTrayIcon *trayIcon = new QSystemTrayIcon(this);
20+
QIcon icon = QApplication::style()->standardIcon(QStyle::SP_DriveNetIcon);
21+
trayIcon->setIcon(icon);
22+
trayIcon->show();
23+
24+
this->setWindowFlags(windowFlags() & ~Qt::WindowMaximizeButtonHint);
25+
this->setFixedSize(this->size());
1626
}
1727

1828
MainWindow::~MainWindow()
@@ -24,15 +34,6 @@ void MainWindow::on_btLoadFile_clicked()
2434
{
2535
fileSelector->selectFile(this, mode);
2636

27-
// Just for debugging
28-
//QMessageBox msgBox;
29-
// msgBox.setText(massifRunner->getFileName() +
30-
// "\n with path \n" + massifRunner->getFilePath() +
31-
// "\n " + massifRunner->getProgram() +
32-
// "\n " + massifRunner->convertWindowsPathToWsl(massifRunner->getFilePath()) +
33-
// "\n " + massifRunner->convertWindowsPathToWsl(massifRunner->getMassifFilesDir()));
34-
// msgBox.exec();
35-
3637
this->ui->leFileName->setText(fileSelector->getFileName());
3738
}
3839

@@ -71,6 +72,7 @@ void MainWindow::on_btExecute_clicked()
7172
void MainWindow::on_btMassifOptions_clicked()
7273
{
7374
MassifOptionsWindow massifOptionsWindow;
75+
massifOptionsWindow.setOptionsFields(massifRunner->getOptions());
7476

7577
QObject::connect(&massifOptionsWindow, &MassifOptionsWindow::optionsChanged, this, &MainWindow::setMassifOptions);
7678

QT_Massif_App/mainwindow.ui

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
</rect>
1212
</property>
1313
<property name="windowTitle">
14-
<string>MainWindow</string>
14+
<string>2024_Research_Massif_Check</string>
1515
</property>
1616
<widget class="QWidget" name="centralwidget">
1717
<widget class="QPushButton" name="btLoadFile">

QT_Massif_App/massifanalyzer.cpp

Lines changed: 20 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -60,16 +60,16 @@ QString MassifAnalyzer::detectMemoryLeaks(const QVector<Snapshot>& snapshots, Ma
6060
}
6161

6262
if (heapJump >= MEMORY_JUMP_THRESHOLD) {
63-
result += QString("Info: Heap memory jump between snapshot %1 and snapshot %2 is %3%\n")
63+
result += QString("ℹ️ [Info] Heap memory jump between snapshot %1 and snapshot %2 is %3%\n")
6464
.arg(previousSnapshot.snapshot)
6565
.arg(snap.snapshot)
6666
.arg(heapJump * 100, 0, 'f', 2);
6767

6868
if (isMemoryStabilized(snapshots, i, WINDOWS_SIZE_TRESHOLD)) {
69-
result += QString("Note: Memory stabilized after snapshot %1\n")
69+
result += QString("📝 [Note] Memory stabilized after snapshot %1\n")
7070
.arg(snap.snapshot);
7171
} else {
72-
result += QString("Warning: Memory continues to grow after snapshot %1\n")
72+
result += QString("⚠️ [Warning] Memory continues to grow after snapshot %1\n")
7373
.arg(snap.snapshot);
7474
}
7575
}
@@ -86,21 +86,21 @@ QString MassifAnalyzer::detectMemoryLeaks(const QVector<Snapshot>& snapshots, Ma
8686
}
8787

8888
if (stackJump > MEMORY_JUMP_THRESHOLD) {
89-
result += QString("Info: Stack memory jump between snapshot %1 and snapshot %2 is %3%\n")
89+
result += QString("ℹ️ [Info] Stack memory jump between snapshot %1 and snapshot %2 is %3%\n")
9090
.arg(previousSnapshot.snapshot)
9191
.arg(snap.snapshot)
9292
.arg(stackJump * 100, 0, 'f', 2);
9393
}
9494
}
9595

9696
if (snap.mem_heap_B > LARGE_MEMORY_THRESHOLD) {
97-
result += QString("Warning: Large heap memory detected in snapshot %1: %2 MB\n")
97+
result += QString("⚠️ [Warning] Large heap memory detected in snapshot %1: %2 MB\n")
9898
.arg(snap.snapshot)
9999
.arg(snap.mem_heap_B / BYTES_TO_MB);
100100
}
101101

102102
if (snap.mem_stacks_B > LARGE_MEMORY_THRESHOLD) {
103-
result += QString("Warning: Large stack memory detected in snapshot %1: %2 MB\n")
103+
result += QString("⚠️ [Warning] Large stack memory detected in snapshot %1: %2 MB\n")
104104
.arg(snap.snapshot)
105105
.arg(snap.mem_stacks_B / BYTES_TO_MB);
106106
}
@@ -111,35 +111,24 @@ QString MassifAnalyzer::detectMemoryLeaks(const QVector<Snapshot>& snapshots, Ma
111111
hasPreviousSnapshot = true;
112112
}
113113

114-
if (snap.mem_heap_B > 0) { // da ne deliš sa nulom
114+
if (snap.mem_heap_B > 0) { // not to divide with 0
115115
double fragmentationRatio = static_cast<double>(snap.mem_heap_extra_B) / snap.mem_heap_B;
116116

117117
if (fragmentationRatio > FRAGMENTATION_THRESHOLD) {
118-
result += QString("Warning: Possible heap fragmentation in snapshot %1: extra memory is %2% of heap\n")
118+
result += QString("⚠️ [Warning] Possible heap fragmentation in snapshot %1: extra memory is %2% of heap\n")
119119
.arg(snap.snapshot)
120120
.arg(fragmentationRatio * 100, 0, 'f', 2);
121121
}
122122
}
123123

124124
if (i == snapshots.size() - 1){
125125
if (snap.mem_heap_B > MEMORY_FREE_THRESHOLD) {
126-
result += QString("Warning: Memory not fully freed at the end! Heap usage: %1 bytes\n")
126+
result += QString("⚠️ [Warning] Memory not fully freed at the end! Heap usage: %1 bytes\n")
127127
.arg(snap.mem_heap_B);
128128
} else {
129-
result += QString("Info: Memory fully freed at the end.\n");
129+
result += QString("ℹ️ [Info] Memory fully freed at the end.\n");
130130
}
131131
}
132-
133-
// if (!snap.allocations.isEmpty()) {
134-
// result += QString("Top allocations in snapshot %1\n").arg(snap.snapshot);
135-
// for (const AllocationEntry& alloc : snap.allocations) {
136-
// result += QString("%1 bytes in %2 at %3 : %4\n")
137-
// .arg(alloc.bytes)
138-
// .arg(alloc.function)
139-
// .arg(alloc.sourceFile)
140-
// .arg(alloc.line);
141-
// }
142-
// }
143132
}
144133

145134
return result;
@@ -155,24 +144,24 @@ QString MassifAnalyzer::generateFunctionAllocationReport(const QMap<QString, Fun
155144
for (auto it = functionSummary.constBegin(); it != functionSummary.constEnd(); ++it) {
156145
const FunctionAllocSummary& summary = it.value();
157146

158-
result += QString("Function '%1' allocated total %2 bytes in %3 allocations.\n")
147+
result += QString("📌 [Function] \n ℹ️ [Info] Function '%1' allocated total %2 bytes in %3 allocations.\n")
159148
.arg(summary.function)
160149
.arg(summary.totalBytes)
161150
.arg(summary.count);
162151

163152
// Warn if a function allocates a lot of memory
164153
if (summary.totalBytes > HIGH_MEMORY_THRESHOLD) {
165-
result += QString("Warning: Function '%1' is responsible for a large memory allocation (over 100MB).\n")
154+
result += QString(" ⚠️ [Warning] Function '%1' is responsible for a large memory allocation (over 100MB).\n")
166155
.arg(summary.function);
167156
}
168157

169158
if (summary.count > HIGH_ALLOCATION_COUNT) {
170159
if (summary.totalBytes < SMALL_TOTAL_ALLOCATION) {
171-
result += QString("Note: Function '%1' performs many small allocations (%2); consider optimizing with preallocation or pooling.\n")
160+
result += QString(" 📝 [Note] Function '%1' performs many small allocations (%2); consider optimizing with preallocation or pooling.\n")
172161
.arg(summary.function)
173162
.arg(summary.count);
174163
} else {
175-
result += QString("Note: Function '%1' performs many allocations (%2); consider checking for inefficiencies.\n")
164+
result += QString(" 📝 [Note] Function '%1' performs many allocations (%2); consider checking for inefficiencies.\n")
176165
.arg(summary.function)
177166
.arg(summary.count);
178167
}
@@ -181,5 +170,11 @@ QString MassifAnalyzer::generateFunctionAllocationReport(const QMap<QString, Fun
181170
result += "\n";
182171
}
183172

173+
result += "📝 [Note] Lines are ignored if:\n"
174+
" - They refer to unnamed or unknown functions.\n"
175+
" - Their memory allocation is below a configured threshold (default: 1.00% of total memory).\n"
176+
" - They are structurally malformed or unsupported by the current parser.\n"
177+
" - They match known standard library or internal functions (e.g., `std::`, `__gnu_cxx::`, `boost::`, `operator new`, etc.).";
178+
184179
return result;
185180
}

QT_Massif_App/massifanalyzerthresholdswindow.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,37 @@ MassifAnalyzerThresholdsWindow::MassifAnalyzerThresholdsWindow(QWidget *parent)
66
, ui(new Ui::MassifAnalyzerThresholdsWindow)
77
{
88
ui->setupUi(this);
9+
QPixmap pixmap = QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation).pixmap(16, 16);
10+
ui->lbHighMemoryThresholdHelp->setPixmap(pixmap);
11+
ui->lbHighMemoryThresholdHelp->setToolTip("The minimum size (in MB) of a single allocation that is considered 'large'."
12+
" Used to detect unusually big memory blocks.");
13+
14+
ui->lbHighAllocationCountHelp->setPixmap(pixmap);
15+
ui->lbHighAllocationCountHelp->setToolTip("The number of individual allocations above which a function or test is flagged as 'frequently allocating'."
16+
" Helps spot allocation-heavy code.");
17+
18+
ui->lbSmallTotalAllocationHelp->setPixmap(pixmap);
19+
ui->lbSmallTotalAllocationHelp->setToolTip("Total allocated memory (in MB) below which a test is considered memory-light. Useful for skipping trivial tests.");
20+
21+
ui->lbMemoryJumpThresholdHelp->setPixmap(pixmap);
22+
ui->lbMemoryJumpThresholdHelp->setToolTip("The minimum percentage increase between two snapshots required to flag a sudden memory usage spike."
23+
" Expressed as a percentage.");
24+
25+
ui->lbLargeMemoryThresholdHelp->setPixmap(pixmap);
26+
ui->lbLargeMemoryThresholdHelp->setToolTip("Defines what is considered extremely large memory usage overall (in MB)."
27+
" Helps filter out heavy tests or data-heavy functions.");
28+
29+
ui->lbMemoryFreeThresholdHelp->setPixmap(pixmap);
30+
ui->lbMemoryFreeThresholdHelp->setToolTip("The minimum drop in memory (in KB) between snapshots that indicates a significant deallocation event.");
31+
32+
ui->lbFragmentationThresholdHelp->setPixmap(pixmap);
33+
ui->lbFragmentationThresholdHelp->setToolTip("The ratio of extra heap memory (unused but reserved) to actual used heap memory,"
34+
" above which fragmentation is suspected. Expressed as a percentage.");
35+
36+
ui->lbStabilizationSensitivityHelp->setPixmap(pixmap);
37+
ui->lbStabilizationSensitivityHelp->setToolTip("Number of consecutive snapshots to check after a detected memory jump to confirm if heap memory usage has stabilized.");
38+
39+
this->setFixedSize(this->size());
940
}
1041

1142
void MassifAnalyzerThresholdsWindow::setThresholdsFields(MassifAnalyzerThresholds *thresholds)

QT_Massif_App/massifanalyzerthresholdswindow.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#define MASSIFANALYZERTHRESHOLDSWINDOW_H
33

44
#include <QDialog>
5+
#include <QStyle>
56
#include "massifanalyzerthresholds.h"
67

78
namespace Ui {

0 commit comments

Comments
 (0)