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