summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMilian Wolff <milian.wolff@kdab.com>2017-02-28 23:25:37 +0100
committerMilian Wolff <milian.wolff@kdab.com>2017-03-21 14:48:34 +0000
commiteea91238f58075ec6e991f874be3f057664ba147 (patch)
tree3639bd5297c608e4f660f8b123df40f3ef7d7a67
parent2f1f3e46942b6bdd2c69e3057de19118cc6f3bb7 (diff)
Refactor PerfElfMap to make it easier to change its internals
Instead of leaking the implementation details such as the QMap iterators in the API, always return an ElfInfo struct. This requires us to add the address to the ElfInfo, essentially duplicating the data that is already used for the QMap key. But this only marginally increases memory consumption, and does not decrease performance significantly. Also, future commits to improve the performance will probably require this anyways. The code in the symbol table that so far relied on accessing the mapping internals directly via the iterators is moved into the elfmap directly. This also allows us to test this part of the code, and enables us to hide the internals. One exception is the iteration over all elf infos, which is required to guess the target architecture. This is still possible, but now uses a simpler foreach loop over all elf infos, which also makes it possible to change the underlying data type seamlessly in the future. To simplify the testing process, ElfInfo also gets a proper QDebug streaming operator as well as a QTest::toString overload. The test is updated accordingly, to leverage this new API. Furthermore, the testing code is simplified by removing the boolean found parameter in the ElfInfo ctor. Instead, it is now initialized by calling `file.isFile()` internally. To show that the performance impact of this change is negleglible, please compare the following benchmark results to those of the previous two commits: PASS : TestElfMap::benchRegisterElfDisjunct(10) RESULT : TestElfMap::benchRegisterElfDisjunct():"10": 0.0017 msecs per iteration (total: 58, iterations: 32768) PASS : TestElfMap::benchRegisterElfDisjunct(100) RESULT : TestElfMap::benchRegisterElfDisjunct():"100": 0.037 msecs per iteration (total: 77, iterations: 2048) PASS : TestElfMap::benchRegisterElfDisjunct(1000) RESULT : TestElfMap::benchRegisterElfDisjunct():"1000": 3.8 msecs per iteration (total: 61, iterations: 16) PASS : TestElfMap::benchRegisterElfDisjunct(2000) RESULT : TestElfMap::benchRegisterElfDisjunct():"2000": 21 msecs per iteration (total: 85, iterations: 4) PASS : TestElfMap::benchRegisterElfOverlapping(10) RESULT : TestElfMap::benchRegisterElfOverlapping():"10": 0.0040 msecs per iteration (total: 66, iterations: 16384) PASS : TestElfMap::benchRegisterElfOverlapping(100) RESULT : TestElfMap::benchRegisterElfOverlapping():"100": 0.086 msecs per iteration (total: 89, iterations: 1024) PASS : TestElfMap::benchRegisterElfOverlapping(1000) RESULT : TestElfMap::benchRegisterElfOverlapping():"1000": 9.7 msecs per iteration (total: 78, iterations: 8) PASS : TestElfMap::benchRegisterElfOverlapping(2000) RESULT : TestElfMap::benchRegisterElfOverlapping():"2000": 35.2 msecs per iteration (total: 141, iterations: 4) PASS : TestElfMap::benchRegisterElfExpanding(10) RESULT : TestElfMap::benchRegisterElfExpanding():"10": 0.0019 msecs per iteration (total: 63, iterations: 32768) PASS : TestElfMap::benchRegisterElfExpanding(100) RESULT : TestElfMap::benchRegisterElfExpanding():"100": 0.043 msecs per iteration (total: 90, iterations: 2048) PASS : TestElfMap::benchRegisterElfExpanding(1000) RESULT : TestElfMap::benchRegisterElfExpanding():"1000": 4.6 msecs per iteration (total: 74, iterations: 16) PASS : TestElfMap::benchRegisterElfExpanding(2000) RESULT : TestElfMap::benchRegisterElfExpanding():"2000": 22 msecs per iteration (total: 91, iterations: 4) PASS : TestElfMap::benchFindElfDisjunct(10) RESULT : TestElfMap::benchFindElfDisjunct():"10": 0.0029 msecs per iteration (total: 98, iterations: 32768) PASS : TestElfMap::benchFindElfDisjunct(100) RESULT : TestElfMap::benchFindElfDisjunct():"100": 0.031 msecs per iteration (total: 65, iterations: 2048) PASS : TestElfMap::benchFindElfDisjunct(1000) RESULT : TestElfMap::benchFindElfDisjunct():"1000": 0.40 msecs per iteration (total: 52, iterations: 128) PASS : TestElfMap::benchFindElfDisjunct(2000) RESULT : TestElfMap::benchFindElfDisjunct():"2000": 0.85 msecs per iteration (total: 55, iterations: 64) PASS : TestElfMap::benchFindElfOverlapping(10) RESULT : TestElfMap::benchFindElfOverlapping():"10": 0.0032 msecs per iteration (total: 53, iterations: 16384) PASS : TestElfMap::benchFindElfOverlapping(100) RESULT : TestElfMap::benchFindElfOverlapping():"100": 0.041 msecs per iteration (total: 85, iterations: 2048) PASS : TestElfMap::benchFindElfOverlapping(1000) RESULT : TestElfMap::benchFindElfOverlapping():"1000": 0.48 msecs per iteration (total: 62, iterations: 128) PASS : TestElfMap::benchFindElfOverlapping(2000) RESULT : TestElfMap::benchFindElfOverlapping():"2000": 1.0 msecs per iteration (total: 65, iterations: 64) PASS : TestElfMap::benchFindElfExpanding(10) RESULT : TestElfMap::benchFindElfExpanding():"10": 0.0060 msecs per iteration (total: 99, iterations: 16384) PASS : TestElfMap::benchFindElfExpanding(100) RESULT : TestElfMap::benchFindElfExpanding():"100": 0.67 msecs per iteration (total: 87, iterations: 128) PASS : TestElfMap::benchFindElfExpanding(1000) RESULT : TestElfMap::benchFindElfExpanding():"1000": 120 msecs per iteration (total: 120, iterations: 1) PASS : TestElfMap::benchFindElfExpanding(2000) RESULT : TestElfMap::benchFindElfExpanding():"2000": 696 msecs per iteration (total: 696, iterations: 1) Change-Id: Id48eb38cc8615b6fa08e84bc4bb6d342b58290b4 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
-rw-r--r--app/perfelfmap.cpp42
-rw-r--r--app/perfelfmap.h38
-rw-r--r--app/perfsymboltable.cpp61
-rw-r--r--app/perfsymboltable.h4
-rw-r--r--tests/auto/elfmap/tst_elfmap.cpp183
5 files changed, 192 insertions, 136 deletions
diff --git a/app/perfelfmap.cpp b/app/perfelfmap.cpp
index b10026a..13273dd 100644
--- a/app/perfelfmap.cpp
+++ b/app/perfelfmap.cpp
@@ -21,6 +21,21 @@
#include "perfelfmap.h"
#include "perfdata.h"
+#include <QDebug>
+
+QDebug operator<<(QDebug stream, const PerfElfMap::ElfInfo& info)
+{
+ stream.nospace() << "ElfInfo{"
+ << "file=" << info.file.fileName() << ", "
+ << "found=" << info.found << ", "
+ << "addr=" << info.addr << ", "
+ << "len=" << info.length << ", "
+ << "pgoff=" << info.pgoff << ", "
+ << "timeAdded=" << info.timeAdded << ", "
+ << "timeOverwritten=" << info.timeOverwritten << "}";
+ return stream.space();
+}
+
bool PerfElfMap::registerElf(const quint64 addr, const quint64 len, quint64 pgoff,
const quint64 time, const QFileInfo &fullPath)
{
@@ -42,13 +57,13 @@ bool PerfElfMap::registerElf(const quint64 addr, const quint64 len, quint64 pgof
// reinsert any fragments of it that remain.
if (i.key() < addr) {
- fragments.insertMulti(i.key(), ElfInfo(i->file, addr - i.key(), i->pgoff, time,
- i->timeOverwritten, i->found));
+ fragments.insertMulti(i.key(), ElfInfo(i->file, i.key(), addr - i.key(), i->pgoff,
+ time, i->timeOverwritten));
}
if (iEnd > addrEnd) {
- fragments.insertMulti(addrEnd, ElfInfo(i->file, iEnd - addrEnd,
+ fragments.insertMulti(addrEnd, ElfInfo(i->file, addrEnd, iEnd - addrEnd,
i->pgoff + addrEnd - i.key(), time,
- i->timeOverwritten, i->found));
+ i->timeOverwritten));
}
i->timeOverwritten = time;
}
@@ -79,29 +94,38 @@ bool PerfElfMap::registerElf(const quint64 addr, const quint64 len, quint64 pgof
}
m_elfs.unite(fragments);
- m_elfs.insertMulti(addr, ElfInfo(fullPath, len, pgoff, time, overwritten, isFile));
+ m_elfs.insertMulti(addr, ElfInfo(fullPath, addr, len, pgoff, time, overwritten));
return cacheInvalid;
}
-PerfElfMap::ConstIterator PerfElfMap::findElf(quint64 ip, quint64 timestamp) const
+PerfElfMap::ElfInfo PerfElfMap::findElf(quint64 ip, quint64 timestamp) const
{
QMap<quint64, ElfInfo>::ConstIterator i = m_elfs.upperBound(ip);
if (i == m_elfs.constEnd() || i.key() != ip) {
if (i != m_elfs.constBegin())
--i;
else
- return m_elfs.constEnd();
+ return {};
}
while (true) {
if (i->timeAdded <= timestamp && i->timeOverwritten > timestamp)
- return (i.key() + i->length > ip) ? i : m_elfs.constEnd();
+ return (i.key() + i->length > ip) ? i.value() : ElfInfo();
if (i == m_elfs.constBegin())
- return m_elfs.constEnd();
+ return {};
--i;
}
}
+bool PerfElfMap::isAddressInRange(quint64 addr) const
+{
+ if (m_elfs.isEmpty())
+ return false;
+
+ const auto &first = m_elfs.first();
+ const auto &last = m_elfs.last();
+ return first.addr <= addr && addr < (last.addr + last.length);
+}
diff --git a/app/perfelfmap.h b/app/perfelfmap.h
index 33b0ed5..4991943 100644
--- a/app/perfelfmap.h
+++ b/app/perfelfmap.h
@@ -28,12 +28,30 @@ class PerfElfMap
{
public:
struct ElfInfo {
- ElfInfo(const QFileInfo &file = QFileInfo(), quint64 length = 0, quint64 pgoff = 0,
- quint64 timeAdded = 0,
- quint64 timeOverwritten = std::numeric_limits<quint64>::max(), bool found = true) :
- file(file), length(length), pgoff(pgoff), timeAdded(timeAdded),
- timeOverwritten(timeOverwritten), found(found) {}
+ ElfInfo(const QFileInfo &file = QFileInfo(), quint64 addr = 0, quint64 length = 0,
+ quint64 pgoff = 0, quint64 timeAdded = 0,
+ quint64 timeOverwritten = std::numeric_limits<quint64>::max()) :
+ file(file), addr(addr), length(length), pgoff(pgoff), timeAdded(timeAdded),
+ timeOverwritten(timeOverwritten), found(file.isFile()) {}
+
+ bool isValid() const
+ {
+ return length > 0;
+ }
+
+ bool operator==(const ElfInfo& rhs) const
+ {
+ return found == rhs.found
+ && (!found || file == rhs.file)
+ && addr == rhs.addr
+ && length == rhs.length
+ && pgoff == rhs.pgoff
+ && timeAdded == rhs.timeAdded
+ && timeOverwritten == rhs.timeOverwritten;
+ }
+
QFileInfo file;
+ quint64 addr;
quint64 length;
quint64 pgoff;
quint64 timeAdded;
@@ -46,25 +64,29 @@ public:
bool registerElf(quint64 addr, quint64 len, quint64 pgoff, quint64 time,
const QFileInfo &fullPath);
- ConstIterator findElf(quint64 ip, quint64 timestamp) const;
+ ElfInfo findElf(quint64 ip, quint64 timestamp) const;
bool isEmpty() const
{
return m_elfs.isEmpty();
}
- ConstIterator constBegin() const
+ ConstIterator begin() const
{
return m_elfs.constBegin();
}
- ConstIterator constEnd() const
+ ConstIterator end() const
{
return m_elfs.constEnd();
}
+ bool isAddressInRange(quint64 addr) const;
+
private:
QMultiMap<quint64, ElfInfo> m_elfs; // needs to be sorted
};
+QDebug operator<<(QDebug stream, const PerfElfMap::ElfInfo& info);
+
#endif
diff --git a/app/perfsymboltable.cpp b/app/perfsymboltable.cpp
index b54ff76..48d6613 100644
--- a/app/perfsymboltable.cpp
+++ b/app/perfsymboltable.cpp
@@ -339,38 +339,38 @@ void PerfSymbolTable::parseDwarf(Dwarf_Die *cudie, Dwarf_Addr bias, qint32 binar
}
}
-static void reportError(PerfElfMap::ConstIterator i, const char *message)
+static void reportError(const PerfElfMap::ElfInfo& info, const char *message)
{
- qWarning() << "failed to report" << i.value().file.absoluteFilePath() << "for"
- << hex << i.key() << dec << ":" << message;
+ qWarning() << "failed to report" << info.file.absoluteFilePath() << "for"
+ << hex << info.addr << dec << ":" << message;
}
-Dwfl_Module *PerfSymbolTable::reportElf(PerfElfMap::ConstIterator i)
+Dwfl_Module *PerfSymbolTable::reportElf(const PerfElfMap::ElfInfo& info)
{
- if (i == m_elfs.constEnd() || !i.value().found)
+ if (!info.isValid() || !info.found)
return nullptr;
- if (i.value().pgoff > 0) {
- reportError(i, "Cannot report file fragments");
+ if (info.pgoff > 0) {
+ reportError(info, "Cannot report file fragments");
return nullptr;
}
Dwfl_Module *ret = dwfl_report_elf(
- m_dwfl, i.value().file.fileName().toLocal8Bit().constData(),
- i.value().file.absoluteFilePath().toLocal8Bit().constData(), -1, i.key(),
+ m_dwfl, info.file.fileName().toLocal8Bit().constData(),
+ info.file.absoluteFilePath().toLocal8Bit().constData(), -1, info.addr,
false);
if (!ret)
- reportError(i, dwfl_errmsg(dwfl_errno()));
+ reportError(info, dwfl_errmsg(dwfl_errno()));
- if (m_lastMmapAddedTime < i->timeAdded)
- m_lastMmapAddedTime = i->timeAdded;
- if (m_nextMmapOverwrittenTime > i->timeOverwritten)
- m_nextMmapOverwrittenTime = i->timeOverwritten;
+ if (m_lastMmapAddedTime < info.timeAdded)
+ m_lastMmapAddedTime = info.timeAdded;
+ if (m_nextMmapOverwrittenTime > info.timeOverwritten)
+ m_nextMmapOverwrittenTime = info.timeOverwritten;
return ret;
}
-PerfElfMap::ConstIterator PerfSymbolTable::findElf(quint64 ip, quint64 timestamp) const
+PerfElfMap::ElfInfo PerfSymbolTable::findElf(quint64 ip, quint64 timestamp) const
{
return m_elfs.findElf(ip, timestamp);
}
@@ -392,12 +392,12 @@ int PerfSymbolTable::lookupFrame(Dwarf_Addr ip, quint64 timestamp, bool isKernel
quint64 elfStart = 0;
- auto elfIt = findElf(ip, timestamp);
- if (elfIt != m_elfs.constEnd()) {
- binaryId = m_unwind->resolveString(elfIt.value().file.fileName().toLocal8Bit());
- elfStart = elfIt.key();
+ const auto& elf = findElf(ip, timestamp);
+ if (elf.isValid()) {
+ binaryId = m_unwind->resolveString(elf.file.fileName().toLocal8Bit());
+ elfStart = elf.addr;
if (m_dwfl && !mod)
- mod = reportElf(elfIt);
+ mod = reportElf(elf);
}
PerfUnwind::Location addressLocation(
@@ -539,12 +539,7 @@ void PerfSymbolTable::updatePerfMap()
bool PerfSymbolTable::containsAddress(quint64 address) const
{
- if (m_elfs.isEmpty())
- return false;
-
- const auto last = (--m_elfs.constEnd());
- const auto first = m_elfs.constBegin();
- return first.key() <= address && last.key() + last.value().length > address;
+ return m_elfs.isAddressInRange(address);
}
Dwfl *PerfSymbolTable::attachDwfl(quint64 timestamp, void *arg)
@@ -555,14 +550,14 @@ Dwfl *PerfSymbolTable::attachDwfl(quint64 timestamp, void *arg)
return m_dwfl; // Already attached, nothing to do
// Report some random elf, so that dwfl guesses the target architecture.
- for (auto it = m_elfs.constBegin(), end = m_elfs.constEnd(); it != end; ++it) {
- if (!it->found || it->timeAdded > timestamp || it->timeOverwritten <= timestamp)
+ for (const auto &elf : m_elfs) {
+ if (!elf.found || elf.timeAdded > timestamp || elf.timeOverwritten <= timestamp)
continue;
- if (dwfl_report_elf(m_dwfl, it.value().file.fileName().toLocal8Bit().constData(),
- it.value().file.absoluteFilePath().toLocal8Bit().constData(), -1,
- it.key(), false)) {
- m_lastMmapAddedTime = it->timeAdded;
- m_nextMmapOverwrittenTime = it->timeOverwritten;
+ if (dwfl_report_elf(m_dwfl, elf.file.fileName().toLocal8Bit().constData(),
+ elf.file.absoluteFilePath().toLocal8Bit().constData(), -1,
+ elf.addr, false)) {
+ m_lastMmapAddedTime = elf.timeAdded;
+ m_nextMmapOverwrittenTime = elf.timeOverwritten;
break;
}
}
diff --git a/app/perfsymboltable.h b/app/perfsymboltable.h
index 3f12f31..c60852e 100644
--- a/app/perfsymboltable.h
+++ b/app/perfsymboltable.h
@@ -56,11 +56,11 @@ public:
void registerElf(const PerfRecordMmap &mmap, const QString &appPath,
const QString &systemRoot, const QString &extraLibsPath);
- PerfElfMap::ConstIterator findElf(quint64 ip, quint64 timestamp) const;
+ PerfElfMap::ElfInfo findElf(quint64 ip, quint64 timestamp) const;
// Report an mmap to dwfl and parse it for symbols and inlines, or simply return it if dwfl has
// it already
- Dwfl_Module *reportElf(PerfElfMap::ConstIterator i);
+ Dwfl_Module *reportElf(const PerfElfMap::ElfInfo& elf);
// Look up a frame and all its inline parents and append them to the given vector.
// If the frame hits an elf that hasn't been reported, yet, report it.
diff --git a/tests/auto/elfmap/tst_elfmap.cpp b/tests/auto/elfmap/tst_elfmap.cpp
index f92b303..68e0c5a 100644
--- a/tests/auto/elfmap/tst_elfmap.cpp
+++ b/tests/auto/elfmap/tst_elfmap.cpp
@@ -24,49 +24,69 @@
#include "perfelfmap.h"
+namespace {
+bool registerElf(PerfElfMap *map, const PerfElfMap::ElfInfo &info)
+{
+ return map->registerElf(info.addr, info.length, info.pgoff, info.timeAdded,
+ info.file);
+}
+}
+
+namespace QTest {
+template<>
+char *toString(const PerfElfMap::ElfInfo &info)
+{
+ QString string;
+ QDebug stream(&string);
+ stream << info;
+ return qstrdup(qPrintable(string));
+}
+}
+
class TestElfMap : public QObject
{
Q_OBJECT
private slots:
void testNoOverlap()
{
+ const PerfElfMap::ElfInfo invalid;
+
PerfElfMap map;
QVERIFY(map.isEmpty());
- QVERIFY(!map.registerElf(100, 10, 0, 0, {}));
+ const PerfElfMap::ElfInfo first({}, 100, 10, 0, 0);
+
+ QVERIFY(!registerElf(&map, first));
QVERIFY(!map.isEmpty());
- QCOMPARE(map.constBegin().key(), 100ull);
- QCOMPARE(map.constBegin()->length, 10ull);
- QCOMPARE(map.constBegin()->timeAdded, 0ull);
-
- QCOMPARE(map.findElf(99, 0), map.constEnd());
- QCOMPARE(map.findElf(100, 0), map.constBegin());
- QCOMPARE(map.findElf(109, 0), map.constBegin());
- QCOMPARE(map.findElf(110, 0), map.constEnd());
- QCOMPARE(map.findElf(105, 1), map.constBegin());
-
- QVERIFY(!map.registerElf(0, 10, 0, 1, {}));
-
- QCOMPARE(map.constBegin().key(), 0ull);
- QCOMPARE(map.constBegin()->length, 10ull);
- QCOMPARE(map.constBegin()->timeAdded, 1ull);
-
- auto first = map.constBegin();
- auto second = first + 1;
-
- QCOMPARE(map.findElf(0, 0), map.constEnd());
- QCOMPARE(map.findElf(0, 1), first);
- QCOMPARE(map.findElf(5, 1), first);
- QCOMPARE(map.findElf(9, 1), first);
- QCOMPARE(map.findElf(10, 0), map.constEnd());
- QCOMPARE(map.findElf(5, 2), first);
-
- QCOMPARE(map.findElf(99, 0), map.constEnd());
- QCOMPARE(map.findElf(100, 0), second);
- QCOMPARE(map.findElf(109, 0), second);
- QCOMPARE(map.findElf(110, 0), map.constEnd());
- QCOMPARE(map.findElf(105, 1), second);
+ QCOMPARE(std::distance(map.begin(), map.end()), 1);
+ QCOMPARE(*map.begin(), first);
+
+ QCOMPARE(map.findElf(99, 0), invalid);
+ QCOMPARE(map.findElf(100, 0), first);
+ QCOMPARE(map.findElf(109, 0), first);
+ QCOMPARE(map.findElf(110, 0), invalid);
+ QCOMPARE(map.findElf(105, 1), first);
+
+ const PerfElfMap::ElfInfo second({}, 0, 10, 0, 1);
+ QVERIFY(!registerElf(&map, second));
+
+ QCOMPARE(std::distance(map.begin(), map.end()), 2);
+ QCOMPARE(*map.begin(), second);
+ QCOMPARE(*(map.begin()+1), first);
+
+ QCOMPARE(map.findElf(0, 0), invalid);
+ QCOMPARE(map.findElf(0, 1), second);
+ QCOMPARE(map.findElf(5, 1), second);
+ QCOMPARE(map.findElf(9, 1), second);
+ QCOMPARE(map.findElf(10, 0), invalid);
+ QCOMPARE(map.findElf(5, 2), second);
+
+ QCOMPARE(map.findElf(99, 0), invalid);
+ QCOMPARE(map.findElf(100, 0), first);
+ QCOMPARE(map.findElf(109, 0), first);
+ QCOMPARE(map.findElf(110, 0), invalid);
+ QCOMPARE(map.findElf(105, 1), first);
}
void testOverwrite()
@@ -89,66 +109,36 @@ private slots:
QFileInfo file2(tmpFile2.fileName());
QCOMPARE(file2.isFile(), secondIsFile);
+ const PerfElfMap::ElfInfo first(file1, 95, 20, 0, 0, 1);
+ const PerfElfMap::ElfInfo second(file1, 105, 20, 0, 1, 2);
+ const PerfElfMap::ElfInfo third(file2, 100, 20, 0, 2);
+
PerfElfMap map;
if (!reversed) {
- QVERIFY(!map.registerElf(95, 20, 0, 0, file1));
- QCOMPARE(map.registerElf(105, 20, 0, 1, file1), firstIsFile);
- QCOMPARE(map.registerElf(100, 20, 0, 2, file2), firstIsFile || secondIsFile);
+ QCOMPARE(registerElf(&map, first), false);
+ QCOMPARE(registerElf(&map, second), firstIsFile);
+ QCOMPARE(registerElf(&map, third), firstIsFile || secondIsFile);
} else {
- QVERIFY(!map.registerElf(100, 20, 0, 2, file2));
- QCOMPARE(map.registerElf(105, 20, 0, 1, file1), firstIsFile || secondIsFile);
- QCOMPARE(map.registerElf(95, 20, 0, 0, file1), firstIsFile || secondIsFile);
+ QCOMPARE(registerElf(&map, third), false);
+ QCOMPARE(registerElf(&map, second), firstIsFile || secondIsFile);
+ QCOMPARE(registerElf(&map, first), firstIsFile || secondIsFile);
}
- auto first = map.findElf(110, 0);
- QCOMPARE(first.key(), 95ull);
- QCOMPARE(first->length, 20ull);
- QCOMPARE(first->pgoff, 0ull);
- QCOMPARE(first->timeAdded, 0ull);
- QCOMPARE(first->timeOverwritten, 1ull);
- QCOMPARE(first->file, file1);
-
- auto second = map.findElf(110, 1);
- QCOMPARE(second.key(), 105ull);
- QCOMPARE(second->length, 20ull);
- QCOMPARE(second->pgoff, 0ull);
- QCOMPARE(second->timeAdded, 1ull);
- QCOMPARE(second->timeOverwritten, 2ull);
- QCOMPARE(second->file, file1);
-
- auto third = map.findElf(110, 2);
- QCOMPARE(third.key(), 100ull);
- QCOMPARE(third->length, 20ull);
- QCOMPARE(third->pgoff, 0ull);
- QCOMPARE(third->timeAdded, 2ull);
- QCOMPARE(third->timeOverwritten, std::numeric_limits<quint64>::max());
- QCOMPARE(third->file, file2);
+ QCOMPARE(map.findElf(110, 0), first);
+
+ QCOMPARE(map.findElf(110, 1), second);
+ QCOMPARE(map.findElf(110, 2), third);
QCOMPARE(map.findElf(110, 3), third);
- auto fragment1 = map.findElf(97, 1);
- QCOMPARE(fragment1.key(), 95ull);
- QCOMPARE(fragment1->length, 10ull);
- QCOMPARE(fragment1->pgoff, 0ull);
- QCOMPARE(fragment1->timeAdded, 1ull);
- QCOMPARE(fragment1->timeOverwritten, 2ull);
- QCOMPARE(fragment1->file, file1);
-
- auto fragment2 = map.findElf(122, 2);
- QCOMPARE(fragment2.key(), 120ull);
- QCOMPARE(fragment2->length, 5ull);
- QCOMPARE(fragment2->pgoff, 15ull);
- QCOMPARE(fragment2->timeAdded, 2ull);
- QCOMPARE(fragment2->timeOverwritten, std::numeric_limits<quint64>::max());
- QCOMPARE(fragment2->file, file1);
-
- auto fragment3 = map.findElf(97, 2);
- QCOMPARE(fragment3.key(), 95ull);
- QCOMPARE(fragment3->length, 5ull);
- QCOMPARE(fragment3->pgoff, 0ull);
- QCOMPARE(fragment3->timeAdded, 2ull);
- QCOMPARE(fragment3->timeOverwritten, std::numeric_limits<quint64>::max());
- QCOMPARE(fragment3->file, file1);
+ const PerfElfMap::ElfInfo fragment1(file1, 95, 10, 0, 1, 2);
+ QCOMPARE(map.findElf(97, 1), fragment1);
+
+ const PerfElfMap::ElfInfo fragment2(file1, 120, 5, 15, 2);
+ QCOMPARE(map.findElf(122, 2), fragment2);
+
+ const PerfElfMap::ElfInfo fragment3(file1, 95, 5, 0, 2);
+ QCOMPARE(map.findElf(97, 2), fragment3);
}
void testOverwrite_data()
@@ -170,6 +160,31 @@ private slots:
QTest::newRow("reversed-no-files") << true << false << false;
}
+ void testIsAddressInRange()
+ {
+ PerfElfMap map;
+ QVERIFY(!map.isAddressInRange(10));
+
+ const PerfElfMap::ElfInfo first({}, 10, 10, 0, 0);
+ QVERIFY(!registerElf(&map, first));
+ QVERIFY(!map.isAddressInRange(9));
+ QVERIFY(map.isAddressInRange(10));
+ QVERIFY(map.isAddressInRange(19));
+ QVERIFY(!map.isAddressInRange(20));
+
+ const PerfElfMap::ElfInfo second({}, 30, 10, 0, 1);
+ QVERIFY(!registerElf(&map, second));
+ QVERIFY(!map.isAddressInRange(9));
+ QVERIFY(map.isAddressInRange(10));
+ QVERIFY(map.isAddressInRange(19));
+ QVERIFY(map.isAddressInRange(30));
+ QVERIFY(map.isAddressInRange(39));
+ QVERIFY(!map.isAddressInRange(40));
+ // gaps are also within range
+ QVERIFY(map.isAddressInRange(20));
+ QVERIFY(map.isAddressInRange(29));
+ }
+
void benchRegisterElfDisjunct()
{
QFETCH(int, numElfMaps);