diff --git a/src/corelib/tools/qhash.cpp b/src/corelib/tools/qhash.cpp index f14fac00b8..18d1cee0eb 100644 --- a/src/corelib/tools/qhash.cpp +++ b/src/corelib/tools/qhash.cpp @@ -60,6 +60,7 @@ #include #include #include +#include #ifndef QT_BOOTSTRAPPED #include @@ -93,10 +94,69 @@ QT_BEGIN_NAMESPACE (for instance, gcc 4.4 does that even at -O0). */ +#ifdef __SSE4_2__ +static inline bool hasFastCrc32() +{ + return true; +} + +template +static uint crc32(const Char *ptr, size_t len, uint h) +{ + // The CRC32 instructions from Nehalem calculate a 32-bit CRC32 checksum + const uchar *p = reinterpret_cast(ptr); + const uchar *const e = p + (len * sizeof(Char)); +# ifdef Q_PROCESSOR_X86_64 + // The 64-bit instruction still calculates only 32-bit, but without this + // variable GCC 4.9 still tries to clear the high bits on every loop + qulonglong h2 = h; + + p += 8; + for ( ; p <= e; p += 8) + h2 = _mm_crc32_u64(h2, *reinterpret_cast(p - 8)); + h = h2; + p -= 8; + + len = e - p; + if (len & 4) { + h = _mm_crc32_u32(h, *reinterpret_cast(p)); + p += 4; + } +# else + p += 4; + for ( ; p <= e; p += 4) + h = _mm_crc32_u32(h, *reinterpret_cast(p)); + p -= 4; + len = e - p; +# endif + if (len & 2) { + h = _mm_crc32_u16(h, *reinterpret_cast(p)); + p += 2; + } + if (sizeof(Char) == 1 && len & 1) + h = _mm_crc32_u8(h, *p); + return h; +} +#else +static inline bool hasFastCrc32() +{ + return false; +} + +static uint crc32(...) +{ + Q_UNREACHABLE(); + return 0; +} +#endif + static inline uint hash(const uchar *p, int len, uint seed) Q_DECL_NOTHROW { uint h = seed; + if (hasFastCrc32()) + return crc32(p, size_t(len), h); + for (int i = 0; i < len; ++i) h = 31 * h + p[i]; @@ -107,6 +167,9 @@ static inline uint hash(const QChar *p, int len, uint seed) Q_DECL_NOTHROW { uint h = seed; + if (hasFastCrc32()) + return crc32(p, size_t(len), h); + for (int i = 0; i < len; ++i) h = 31 * h + p[i].unicode(); diff --git a/tests/benchmarks/corelib/tools/qhash/main.cpp b/tests/benchmarks/corelib/tools/qhash/main.cpp index a39ced19fe..b173724aed 100644 --- a/tests/benchmarks/corelib/tools/qhash/main.cpp +++ b/tests/benchmarks/corelib/tools/qhash/main.cpp @@ -55,13 +55,28 @@ class tst_QHash : public QObject private slots: void initTestCase(); + void qhash_current_data() { data(); } + void qhash_current() { qhash_template(); } + void qhash_qt50_data() { data(); } + void qhash_qt50() { qhash_template(); } void qhash_qt4_data() { data(); } - void qhash_qt4(); - void javaString_data() { data(); } - void javaString(); + void qhash_qt4() { qhash_template(); } + void qhash_javaString_data() { data(); } + void qhash_javaString() { qhash_template(); } + + void hashing_current_data() { data(); } + void hashing_current() { hashing_template(); } + void hashing_qt50_data() { data(); } + void hashing_qt50() { hashing_template(); } + void hashing_qt4_data() { data(); } + void hashing_qt4() { hashing_template(); } + void hashing_javaString_data() { data(); } + void hashing_javaString() { hashing_template(); } private: void data(); + template void qhash_template(); + template void hashing_template(); QStringList smallFilePaths; QStringList uuids; @@ -76,7 +91,7 @@ private: void tst_QHash::initTestCase() { // small list of file paths - QFile smallPathsData("paths_small_data.txt"); + QFile smallPathsData(QFINDTESTDATA("paths_small_data.txt")); QVERIFY(smallPathsData.open(QIODevice::ReadOnly)); smallFilePaths = QString::fromLatin1(smallPathsData.readAll()).split(QLatin1Char('\n')); QVERIFY(!smallFilePaths.isEmpty()); @@ -133,12 +148,12 @@ void tst_QHash::data() QTest::newRow("numbers") << numbers; } -void tst_QHash::qhash_qt4() +template void tst_QHash::qhash_template() { QFETCH(QStringList, items); - QHash hash; + QHash hash; - QList realitems; + QList realitems; foreach (const QString &s, items) realitems.append(s); @@ -149,23 +164,22 @@ void tst_QHash::qhash_qt4() } } -void tst_QHash::javaString() +template void tst_QHash::hashing_template() { + // just the hashing function QFETCH(QStringList, items); - QHash hash; - QList realitems; + QVector realitems; + realitems.reserve(items.size()); foreach (const QString &s, items) realitems.append(s); QBENCHMARK { - for (int i = 0, n = realitems.size(); i != n; ++i) { - hash[realitems.at(i)] = i; - } + for (int i = 0, n = realitems.size(); i != n; ++i) + (void)qHash(realitems.at(i)); } } - QTEST_MAIN(tst_QHash) #include "main.moc" diff --git a/tests/benchmarks/corelib/tools/qhash/main.h b/tests/benchmarks/corelib/tools/qhash/main.h index bd3f0db12d..86a1a3d09b 100644 --- a/tests/benchmarks/corelib/tools/qhash/main.h +++ b/tests/benchmarks/corelib/tools/qhash/main.h @@ -51,6 +51,16 @@ QT_BEGIN_NAMESPACE uint qHash(const Qt4String &); QT_END_NAMESPACE +struct Qt50String : QString +{ + Qt50String() {} + Qt50String(const QString &s) : QString(s) {} +}; + +QT_BEGIN_NAMESPACE +uint qHash(const Qt50String &, uint seed = 0); +QT_END_NAMESPACE + struct JavaString : QString { diff --git a/tests/benchmarks/corelib/tools/qhash/outofline.cpp b/tests/benchmarks/corelib/tools/qhash/outofline.cpp index 9ccfc11224..3a2278503d 100644 --- a/tests/benchmarks/corelib/tools/qhash/outofline.cpp +++ b/tests/benchmarks/corelib/tools/qhash/outofline.cpp @@ -57,6 +57,16 @@ uint qHash(const Qt4String &str) return h; } +uint qHash(const Qt50String &key, uint seed) +{ + const QChar *p = key.unicode(); + int len = key.size(); + uint h = seed; + for (int i = 0; i < len; ++i) + h = 31 * h + p[i].unicode(); + return h; +} + // The Java's hashing algorithm for strings is a variation of D. J. Bernstein // hashing algorithm appeared here http://cr.yp.to/cdb/cdb.txt // and informally known as DJB33XX - DJB's 33 Times Xor.