Низкая производительность QVector и повышенное использование памяти ⇐ C++
Низкая производительность QVector и повышенное использование памяти
I few years back I tested QVector and std::vector side by side, and was living with the impression the two are in the same ballpark of performance, in fact in some cases QVector was edging out.
Until yesterday, when I ran a quick compliance test for a custom container, just to discover some major performance regression.
class TestQVector { QVector data; public: uint count() const { return data.size(); } uint size(uint d) const { return data[d].size(); } uint create() { unit res = count(); data.push_back({}); return res; } void add(uint d, uint i, uint v) { data[d].insert(i, v); } void set(uint d, uint i, uint v) { data[d] = v; } void rem(uint d, uint i) { data[d].remove(i); } uword sum() { uword res = 0; for (const auto & dt : data) { for (const auto & it : dt) { res += it; } } return res; } }; class TestVector { std::vector data; public: uint count() const { return data.size(); } uint size(uint d) const { return data[d].size(); } uint create() { unit res = count(); data.push_back({}); return res; } void add(uint d, uint i, uint v) { data[d].insert(data[d].begin() + i, v); } void set(uint d, uint i, uint v) { data[d] = v; } void rem(uint d, uint i) { data[d].erase(data[d].begin() + i); } uword sum() { uword res = 0; for (const auto & dt : data) { for (const auto & it : dt) { res += it; } } return res; } }; The actual test uses a persistent pseudo-random sequence to execute 100M data operations, with the ratio odds of 1/3/3/2 to respectively allocate new data, insert element in random data, modify an element or insert a new if empty, and to remove a value if not empty. And the respective results:
std::vector: test 1 completed in 4902ms checksum: 79149386424587854, data count: 13725497, sum time: 30ms 723mb qvector: test 1 completed in 5259ms checksum: 79149386424587854, data count: 13725497, sum time: 80ms 1141mb custom dense: test 1 completed in 15314ms checksum: 79149386424587854, data count: 13725497, sum time: 33ms 641mb The largest difference here is the testing time for the custom container, but that's expected since it doesn't use any spare capacity, it does a lot more reallocation.
The second largest difference is that QVector takes almost 3 times as much time to traverse.. for reasons unknown...
And last but certainly not least, there's the memory use...
The dense container object is 16 bytes, as opposed to 24 bytes for std::vector, so at the given number of containers, I expect ~100mb of overhead over the dense container, which is precisely the result.
But QVector ends up using nearly twice as much memory. And even if all the vectors are trimmed to their actual capacity during the summing stage, only about half of the unexpected overhead goes away.
Is this some performance degradation? Has QVector dramatically changed? Note that in Qt6, QVector is just an alias for QList, and QList in Qt5 wasn't great, and I was under the impression it underwent some improvement for Qt6.
Furthermore, even if QVector::squeeze() isn't for some reason releasing all over-provisioned memory, that shouldn't be a major factor contributor to the slow iterating...
It doesn't seem to be leaking the memory, as after the test object is destroyed I am getting back the expected amount of memory.
There's no implicit sharing taking place at any time, there's no code path in the test interface.
Clarification:
This question is not about what's wrong with my code. It is a question directed at people who dabble in Qt and keep up with its design changes.
The test interface is provided in full, there's nothing else taking place aside from a pseudo random sequence of those operations. The test has external dependencies on unrelated stuff like project related macroses and PRNGs, that constitute an above trivial amount to make a portable example, and even then - it would not produce the exact test sequence.
The issue at hand is not the test itself, but the performance discrepancies exhibited during basic and logically correct use of the particular container.
There's no shame in not knowing and moving away, not so sure about complaining about stuff that is outside the scope of the question.
Источник: https://stackoverflow.com/questions/781 ... memory-use
I few years back I tested QVector and std::vector side by side, and was living with the impression the two are in the same ballpark of performance, in fact in some cases QVector was edging out.
Until yesterday, when I ran a quick compliance test for a custom container, just to discover some major performance regression.
class TestQVector { QVector data; public: uint count() const { return data.size(); } uint size(uint d) const { return data[d].size(); } uint create() { unit res = count(); data.push_back({}); return res; } void add(uint d, uint i, uint v) { data[d].insert(i, v); } void set(uint d, uint i, uint v) { data[d] = v; } void rem(uint d, uint i) { data[d].remove(i); } uword sum() { uword res = 0; for (const auto & dt : data) { for (const auto & it : dt) { res += it; } } return res; } }; class TestVector { std::vector data; public: uint count() const { return data.size(); } uint size(uint d) const { return data[d].size(); } uint create() { unit res = count(); data.push_back({}); return res; } void add(uint d, uint i, uint v) { data[d].insert(data[d].begin() + i, v); } void set(uint d, uint i, uint v) { data[d] = v; } void rem(uint d, uint i) { data[d].erase(data[d].begin() + i); } uword sum() { uword res = 0; for (const auto & dt : data) { for (const auto & it : dt) { res += it; } } return res; } }; The actual test uses a persistent pseudo-random sequence to execute 100M data operations, with the ratio odds of 1/3/3/2 to respectively allocate new data, insert element in random data, modify an element or insert a new if empty, and to remove a value if not empty. And the respective results:
std::vector: test 1 completed in 4902ms checksum: 79149386424587854, data count: 13725497, sum time: 30ms 723mb qvector: test 1 completed in 5259ms checksum: 79149386424587854, data count: 13725497, sum time: 80ms 1141mb custom dense: test 1 completed in 15314ms checksum: 79149386424587854, data count: 13725497, sum time: 33ms 641mb The largest difference here is the testing time for the custom container, but that's expected since it doesn't use any spare capacity, it does a lot more reallocation.
The second largest difference is that QVector takes almost 3 times as much time to traverse.. for reasons unknown...
And last but certainly not least, there's the memory use...
The dense container object is 16 bytes, as opposed to 24 bytes for std::vector, so at the given number of containers, I expect ~100mb of overhead over the dense container, which is precisely the result.
But QVector ends up using nearly twice as much memory. And even if all the vectors are trimmed to their actual capacity during the summing stage, only about half of the unexpected overhead goes away.
Is this some performance degradation? Has QVector dramatically changed? Note that in Qt6, QVector is just an alias for QList, and QList in Qt5 wasn't great, and I was under the impression it underwent some improvement for Qt6.
Furthermore, even if QVector::squeeze() isn't for some reason releasing all over-provisioned memory, that shouldn't be a major factor contributor to the slow iterating...
It doesn't seem to be leaking the memory, as after the test object is destroyed I am getting back the expected amount of memory.
There's no implicit sharing taking place at any time, there's no code path in the test interface.
Clarification:
This question is not about what's wrong with my code. It is a question directed at people who dabble in Qt and keep up with its design changes.
The test interface is provided in full, there's nothing else taking place aside from a pseudo random sequence of those operations. The test has external dependencies on unrelated stuff like project related macroses and PRNGs, that constitute an above trivial amount to make a portable example, and even then - it would not produce the exact test sequence.
The issue at hand is not the test itself, but the performance discrepancies exhibited during basic and logically correct use of the particular container.
There's no shame in not knowing and moving away, not so sure about complaining about stuff that is outside the scope of the question.
Источник: https://stackoverflow.com/questions/781 ... memory-use
-
- Похожие темы
- Ответы
- Просмотры
- Последнее сообщение