Value-based classes: struct vs shared-data

David Faure faure at kde.org
Fri Sep 29 14:31:35 CEST 2006


I'm considering changing KFileItem to be a value-based class, to solve ownership issues that lead to crashes in kde3.

The first question that came to mind was: should I make it ref-counted (QSharedData) 
or just a simple struct-like set of members given that those members use implicitly
shared types anyway (QString etc.)

Obviously, struct-like means cheaper constructor (no new),
but more expensive copy constructor (has to change many refcounts instead of one).

So the question is how that balance goes - which solution offers the best compromise.

I wrote the test program below, and I got the following results:

QDEBUG : KFileItemTest::testPerformance() CTOR: Simple struct: 20
QDEBUG : KFileItemTest::testPerformance() CTOR: With QSharedDataPointer: 24
QDEBUG : KFileItemTest::testPerformance() COPY CTOR: Simple struct (direct copy of the data): 11
QDEBUG : KFileItemTest::testPerformance() COPY CTOR: With QSharedDataPointer: 1

The copy constructor is -10- times slower with the individual members have to be
copied, despite the implicit sharing for most of them (and the others are basic integral types).
The normal constructor is 20% slower. Looks like QSharedData is the best solution then.

Any mistakes in my test? ;)

====

class TestKFileItemPrivate : public QSharedData
{
public:
  KIO::UDSEntry m_entry;
  KUrl m_url;
  QString m_strName;
  QString m_strText;
  mutable QString m_user, m_group;
  mutable QString m_strLowerCaseName;
  KMimeType::Ptr m_pMimeType;
  mode_t m_fileMode;
  mode_t m_permissions;
  bool m_bMarked:1;
  bool m_bLink:1;
  bool m_bIsLocalUrl:1;
  bool m_bMimeTypeKnown:1;
  enum { Auto, Hidden, Shown } m_hidden:3;
  QString m_guessedMimeType;
  mutable QString m_access;
  QString m_iconName;
  QMap<const void*, void*> m_extra;
  mutable KFileMetaInfo m_metaInfo;
  enum { Modification = 0, Access = 1, Creation = 2, NumFlags = 3 };
  mutable time_t m_time[3];
  mutable KIO::filesize_t m_size;
};

class TestKFileItem
{
public:
    TestKFileItem() { d = new TestKFileItemPrivate; d->m_bMarked = true; }

    bool marked() const { return d->m_bMarked; }
private:
    QSharedDataPointer<TestKFileItemPrivate> d;
};

#include <time.h>
#include <sys/time.h>

void KFileItemTest::testPerformance()
{
    static const int count = 10000000;


    // Normal constructor
    {
        time_t start = time(0);
        for (uint i = 0; i < count; ++i) {
            TestKFileItemPrivate item;
            item.m_bMarked = true;
            Q_ASSERT(item.m_bMarked);
        }
        qDebug("CTOR: Simple struct: %ld", time(0) - start);
    }

    {
        time_t start = time(0);
        for (uint i = 0; i < count; ++i) {
            TestKFileItem item;
            Q_ASSERT(item.marked());
        }
        qDebug("CTOR: With QSharedDataPointer: %ld", time(0) - start);
    }

    // Copy constructor
    {
        TestKFileItemPrivate item;
        item.m_bMarked = true;

        time_t start = time(0);
        for (uint i = 0; i < count; ++i) {
            TestKFileItemPrivate item2 = item;
            Q_ASSERT(item2.m_bMarked);
        }
        qDebug("COPY CTOR: Simple struct (direct copy of the data): %ld", time(0) - start);
    }

    {
        TestKFileItem item;
        time_t start = time(0);
        for (uint i = 0; i < count; ++i) {
            TestKFileItem item2 = item;
            Q_ASSERT(item2.marked());
        }
        qDebug("COPY CTOR: With QSharedDataPointer: %ld", time(0) - start);
    }
}



-- 
David Faure, faure at kde.org, sponsored by Trolltech to work on KDE,
Konqueror (http://www.konqueror.org), and KOffice (http://www.koffice.org).



More information about the Kde-optimize mailing list