diff options
author | Milian Wolff <milian.wolff@kdab.com> | 2017-02-28 23:25:37 +0100 |
---|---|---|
committer | Milian Wolff <milian.wolff@kdab.com> | 2017-03-21 14:48:34 +0000 |
commit | eea91238f58075ec6e991f874be3f057664ba147 (patch) | |
tree | 3639bd5297c608e4f660f8b123df40f3ef7d7a67 /tests | |
parent | 2f1f3e46942b6bdd2c69e3057de19118cc6f3bb7 (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>
Diffstat (limited to 'tests')
-rw-r--r-- | tests/auto/elfmap/tst_elfmap.cpp | 183 |
1 files changed, 99 insertions, 84 deletions
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); |