Solved QVariant conversions (.toString() .toInt()) performance.
-
Greetings.
I wanted to ask if there is a significant performance overhead when using `QVariant' conversion methods. For example if there is a significant difference in performance when using:
QVariant var = QVariant("MyString"); qDebug() << var.toString();
Versus
QString str = "MyString"; qDebug() << str;
I'm more interested in the performance impact of the conversion operation
.toString()
,.toInt()
etc than the object instantiation. -
@Mike-Fidel You could write a simple benchmark to measure the difference.
I think var.toString() will be slower as it creates a new QString instance each time it is called. -
@jsulm This is the benchmark I did:
int main(int argc, char *argv[]) { QElapsedTimer variantTimer; QElapsedTimer stringTimer; QVariant var = QVariant("My String"); QString string = "My String"; QString stringTest; QString varTest; stringTimer.start(); for (int i = 0 ; i < 100000 ; i++) { stringTest = string; } std::cout << "string took " << stringTimer.nsecsElapsed() << " nano seconds " << std::endl; variantTimer.start(); for (int i = 0 ; i < 100000 ; i++) { varTest = var.toString(); } std::cout << "Variant took " << variantTimer.nsecsElapsed() << " nano seconds " << std::endl; }
Output I got:
string took 2084675 nano seconds
Variant took 4343839 nano secondsHowever if you include the deceleration of QString inside the loop like so:
int main(int argc, char *argv[]) { QElapsedTimer variantTimer; QElapsedTimer stringTimer; QVariant var = QVariant("My String"); QString string = "My String"; //QString stringTest; //QString varTest; stringTimer.start(); for (int i = 0 ; i < 100000 ; i++) { QString stringTest = string; } std::cout << "string took " << stringTimer.nsecsElapsed() << " nano seconds " << std::endl; variantTimer.start(); for (int i = 0 ; i < 100000 ; i++) { QString varTest = var.toString(); } std::cout << "Variant took " << variantTimer.nsecsElapsed() << " nano seconds " << std::endl; }
I get the following output:
string took 4607827 nano seconds
Variant took 2628095 nano secondsThis confuses me. It seems that Variant is quicker if you declare the variable inside the loop.
Also the conclusion I draw from this is that performance impact of the conversion methods are largely negligible. And if your implementation requires that you use an definition with the .toString() conversion(Such as
QString x = myVar.toString()
), you are better off using QVariant. -
@Mike-Fidel Probably I was wrong: QVariant already contains a QString
-
Isn't QString and QVariant each Implicitly Shared ?
that means
for (int i = 0 ; i < 100000 ; i++) { stringTest = string; }
does basicaly nothing? Decrese and Increase of shared pointer count
where as
for (int i = 0 ; i < 100000 ; i++) { varTest = var.toString(); }
is an actual convertion => Construction of a QString and copy of data(from Qvariant)?
-
@jsulm said in QVariant conversions (.toString() .toInt()) performance.:
@Mike-Fidel Probably I was wrong: QVariant already contains a QString
So QVariant might be faster, but costs more memory?
-
@Mike-Fidel It should not cost more memory because of implicit sharing as @J-Hilk mentioned.
-
@jsulm said in QVariant conversions (.toString() .toInt()) performance.:
@Mike-Fidel It should not cost more memory because of implicit sharing as @J-Hilk mentioned.
Could you elaborate? As far as I understand "Implicit Sharing" means that on assignment a pointer is passed, and only on write a copy occurs.
So in
for (int i = 0 ; i < 100000 ; i++) { stringTest = string; }
And in
for (int i = 0 ; i < 100000 ; i++) { varTest = var.toString(); }
The memory fingerprint of 'varTest' and 'stringTest' should be the same. But you said that QVariant already contains a QString, shouldn't it take up more memory?
Also How does implicit sharing explains QVariant being faster when the deceleration is made inside the loop?
-
@Mike-Fidel QString uses implicit sharing as well. So, assigning a string to another one does not increase memory usage significantly.
Is itQString varTest; for (int i = 0 ; i < 100000 ; i++) { varTest = var.toString(); }
or
for (int i = 0 ; i < 100000 ; i++) { QString varTest = var.toString(); }
?
-
QString uses implicit sharing as well. So, assigning a string to another one does not increase memory usage significantly.
Yes I understand, However I'm confused by what you said that
QVariant
already containsQString
. Because if it does, shouldn't it take up more memory than justQString
? BecauseQVaraint
isQString
and something else ? -
@Mike-Fidel
@jsulm did use the word "significantly". I don't know whether someone is saying the whole of aQVariant
is shared or just its content, but if it's the latter, yes, aQVaraint
is aQString
and something else, but the "something else" is relatively small, at least compared to, say, an "average" 42-byte string. -
@JonB Got it, Thanks!