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.


  • Moderators

    @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 seconds

    However 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 seconds

    This 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.


  • Moderators

    @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?


  • Moderators

    @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?


  • Moderators

    @Mike-Fidel QString uses implicit sharing as well. So, assigning a string to another one does not increase memory usage significantly.
    Is it

    QString varTest;
    for (int i = 0 ; i < 100000 ; i++)
    {
        varTest = var.toString();
    }
    

    or

    for (int i = 0 ; i < 100000 ; i++)
    {
        QString varTest = var.toString();
    }
    

    ?



  • @jsulm

    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 contains QString. Because if it does, shouldn't it take up more memory than just QString ? Because QVaraint is QString and something else ?



  • @Mike-Fidel
    @jsulm did use the word "significantly". I don't know whether someone is saying the whole of a QVariant is shared or just its content, but if it's the latter, yes, a QVaraint is a QString and something else, but the "something else" is relatively small, at least compared to, say, an "average" 42-byte string.



  • @JonB Got it, Thanks!


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.