diff --git a/builds/posix/prefix.linux b/builds/posix/prefix.linux index dad8cb6cc1..56d1529570 100644 --- a/builds/posix/prefix.linux +++ b/builds/posix/prefix.linux @@ -25,3 +25,8 @@ WARN_FLAGS=-Wall -Wno-switch -Wno-parentheses -Wno-unknown-pragmas -Wno-unused-v PROD_FLAGS=$(COMMON_FLAGS) $(OPTIMIZE_FLAGS) #DEV_FLAGS=-DUSE_VALGRIND -p $(COMMON_FLAGS) $(WARN_FLAGS) DEV_FLAGS=-p $(COMMON_FLAGS) $(WARN_FLAGS) + +# This file must be compiled with SSE4.2 support +%/CRC32C.o: COMMON_FLAGS += -msse4 + +CXXFLAGS := $(CXXFLAGS) -std=c++11 diff --git a/builds/posix/prefix.linux_amd64 b/builds/posix/prefix.linux_amd64 index 11d49a0694..394286f334 100644 --- a/builds/posix/prefix.linux_amd64 +++ b/builds/posix/prefix.linux_amd64 @@ -25,3 +25,8 @@ WARN_FLAGS=-Wall -Wno-switch -Wno-parentheses -Wno-unknown-pragmas -Wno-unused-v PROD_FLAGS=$(COMMON_FLAGS) $(OPTIMIZE_FLAGS) #DEV_FLAGS=-DUSE_VALGRIND $(COMMON_FLAGS) $(WARN_FLAGS) -fmax-errors=8 DEV_FLAGS=$(COMMON_FLAGS) $(WARN_FLAGS) -fmax-errors=8 + +# This file must be compiled with SSE4.2 support +%/CRC32C.o: COMMON_FLAGS += -msse4 + +CXXFLAGS := $(CXXFLAGS) -std=c++11 diff --git a/builds/win32/msvc10/common.vcxproj b/builds/win32/msvc10/common.vcxproj index c19b233b22..2ce220268e 100644 --- a/builds/win32/msvc10/common.vcxproj +++ b/builds/win32/msvc10/common.vcxproj @@ -30,6 +30,7 @@ + @@ -49,6 +50,16 @@ + + true + true + true + true + ProgramDatabase + ProgramDatabase + ProgramDatabase + ProgramDatabase + diff --git a/builds/win32/msvc10/common.vcxproj.filters b/builds/win32/msvc10/common.vcxproj.filters index 3b1dc2fbc1..871ca48d2f 100644 --- a/builds/win32/msvc10/common.vcxproj.filters +++ b/builds/win32/msvc10/common.vcxproj.filters @@ -210,6 +210,12 @@ common + + classes + + + classes + diff --git a/builds/win32/msvc12/common.vcxproj b/builds/win32/msvc12/common.vcxproj index d425513d3e..cd1e2084a5 100644 --- a/builds/win32/msvc12/common.vcxproj +++ b/builds/win32/msvc12/common.vcxproj @@ -30,6 +30,7 @@ + @@ -49,6 +50,12 @@ + + true + StreamingSIMDExtensions2 + true + StreamingSIMDExtensions2 + diff --git a/builds/win32/msvc12/common.vcxproj.filters b/builds/win32/msvc12/common.vcxproj.filters index 3b1dc2fbc1..fb87986102 100644 --- a/builds/win32/msvc12/common.vcxproj.filters +++ b/builds/win32/msvc12/common.vcxproj.filters @@ -210,6 +210,12 @@ common + + classes + + + common + diff --git a/src/common/CRC32C.cpp b/src/common/CRC32C.cpp new file mode 100644 index 0000000000..9630b4ab7a --- /dev/null +++ b/src/common/CRC32C.cpp @@ -0,0 +1,68 @@ +/* + * PROGRAM: Common Library + * MODULE: CRC32C.cpp + * DESCRIPTION: Hardware-accelerated hash calculation + * + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl. + * + * Software distributed under the License is distributed AS IS, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. + * See the License for the specific language governing rights + * and limitations under the License. + * + * The Original Code was created by Dmitry Sibiryakov + * for the Firebird Open Source RDBMS project. + * + * Copyright (c) 2015 Dmitry Sibiryakov + * and all contributors signed below. + * + * All Rights Reserved. + * Contributor(s): ______________________________________. + * + */ + +#include "firebird.h" + +// Can be used only on x86 architectures +// WARNING: With GCC must be compiled separately with -msse4.2 flag +#if defined(_M_IX86) || defined(_M_X64) || defined(__x86_64__) || defined(__i386__) + +#include + +unsigned int CRC32C(unsigned int length, const unsigned char* value) +{ + unsigned int hash_value = 0; + + if (length == 1) + return _mm_crc32_u8(hash_value, *value); + + if (length == 2) + return _mm_crc32_u16(hash_value, *(unsigned short*) value); + + while (length >= 4) + { + hash_value = _mm_crc32_u32(hash_value, *(unsigned int*) value); + value += 4; + length -= 4; + } + + if (length >= 2) + { + hash_value = _mm_crc32_u16(hash_value, *(unsigned short*) value); + value += 2; + length -= 2; + } + + if (length) + { + hash_value = _mm_crc32_u8(hash_value, *value); + } + + return hash_value; +} + +#endif // architecture check diff --git a/src/common/classes/Hash.cpp b/src/common/classes/Hash.cpp new file mode 100644 index 0000000000..6614708889 --- /dev/null +++ b/src/common/classes/Hash.cpp @@ -0,0 +1,113 @@ +/* + * PROGRAM: Common Library + * MODULE: Hash.cpp + * DESCRIPTION: Hash of data + * + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl. + * + * The Original Code was created by Dmitry Sibiryakov + * for the Firebird Open Source RDBMS project. + * + * Copyright (c) 2015 Dmitry Sibiryakov + * and all contributors signed below. + * + * All Rights Reserved. + * Contributor(s): ______________________________________. + * + */ + +#include "firebird.h" +#include "../common/classes/Hash.h" + +#if defined(_M_IX86) || defined(_M_X64) || defined(__x86_64__) || defined(__i386__) +#ifdef _MSC_VER +#include +#else +#include +#endif +#endif + +using namespace Firebird; + +unsigned int CRC32C(unsigned int length, const unsigned char* value); + +namespace +{ + typedef unsigned int (*hash_func_t)(unsigned int length, const UCHAR* value); + + unsigned int basicHash(unsigned int length, const UCHAR* value) + { + unsigned int hash_value = 0; + + UCHAR* p; + const UCHAR* q = value; + + while (length >= 4) + { + p = (UCHAR*) &hash_value; + p[0] += q[0]; + p[1] += q[1]; + p[2] += q[2]; + p[3] += q[3]; + length -= 4; + q += 4; + } + + p = (UCHAR*) &hash_value; + + if (length >= 2) + { + p[0] += q[0]; + p[1] += q[1]; + length -= 2; + } + + if (length) + { + q += 2; + *p += *q; + } + + return hash_value; + } + +#if defined(_M_IX86) || defined(_M_X64) || defined(__x86_64__) || defined(__i386__) + + bool SSE4_2Supported() + { +#ifdef _MSC_VER + const int bit_SSE4_2 = 1 << 20; + // MS VC has its own definition of __cpuid + int flags[4]; + __cpuid(flags, 1); + return (flags[2] & bit_SSE4_2) != 0; +#else +#if defined(__clang__) && !defined(bit_SSE4_2) + const int bit_SSE4_2 = bit_SSE42; +#endif + + // GCC - its own + unsigned int eax,ebx,ecx,edx; + __cpuid(1, eax, ebx, ecx, edx); + return (ecx & bit_SSE4_2) != 0; +#endif + } + + hash_func_t internalHash = SSE4_2Supported() ? CRC32C : basicHash; + +#else // architecture check + + hash_func_t internalHash = basicHash; + +#endif // architecture check + +} + +unsigned int InternalHash::hash(unsigned int length, const UCHAR* value) +{ + return internalHash(length, value); +} diff --git a/src/common/classes/Hash.h b/src/common/classes/Hash.h index 307270a129..39aaa5b46f 100644 --- a/src/common/classes/Hash.h +++ b/src/common/classes/Hash.h @@ -41,7 +41,7 @@ namespace Firebird size_t sum = 0; size_t val; - const char* data = static_cast(value); + const UCHAR* data = static_cast(value); while (length >= sizeof(size_t)) { @@ -72,7 +72,6 @@ namespace Firebird { return hash(&value, sizeof value, hashSize); } - }; const FB_SIZE_T DEFAULT_HASH_SIZE = 97; // largest prime number < 100 @@ -82,7 +81,7 @@ namespace Firebird typename K = C, // default key typename KeyOfValue = DefaultKeyValue, // default keygen typename F = DefaultHash > // hash function definition - class Hash + class HashTable { public: // This class is supposed to be used as a BASE class for class to be hashed @@ -156,22 +155,22 @@ namespace Firebird }; // class Entry private: - Hash(const Hash&); // not implemented + HashTable(const HashTable&); // not implemented public: - explicit Hash(MemoryPool&) + explicit HashTable(MemoryPool&) : duplicates(false) { clean(); } - Hash() + HashTable() : duplicates(false) { clean(); } - ~Hash() + ~HashTable() { // by default we let hash entries be cleaned by someone else cleanup(NULL); @@ -255,7 +254,7 @@ namespace Firebird private: // disable use of default operator= - Hash& operator= (const Hash&); + HashTable& operator= (const HashTable&); void clean() { @@ -266,7 +265,7 @@ namespace Firebird class iterator { private: - const Hash* hash; + const HashTable* hash; FB_SIZE_T elem; Entry* current; @@ -286,7 +285,7 @@ namespace Firebird } public: - explicit iterator(const Hash& h) + explicit iterator(const HashTable& h) : hash(&h), elem(0), current(hash->data[elem]) { next(); @@ -329,7 +328,18 @@ namespace Firebird return !(*this == h); } }; // class iterator - }; // class Hash + }; // class HashTable + + class InternalHash + { + public: + static unsigned int hash(unsigned int length, const UCHAR* value); + + static unsigned int hash(unsigned int length, const UCHAR* value, unsigned int hashSize) + { + return hash(length, value) % hashSize; + } + }; } // namespace Firebird diff --git a/src/common/db_alias.cpp b/src/common/db_alias.cpp index 8b9f629f52..b25628c4d8 100644 --- a/src/common/db_alias.cpp +++ b/src/common/db_alias.cpp @@ -183,7 +183,7 @@ namespace struct DbName; #ifdef HAVE_ID_BY_NAME struct Id; - typedef Hash, BinHash > IdHash; + typedef HashTable, BinHash > IdHash; struct Id : public IdHash::Entry { @@ -206,7 +206,7 @@ namespace }; #endif - typedef Hash, PathHash > DbHash; + typedef HashTable, PathHash > DbHash; struct DbName : public DbHash::Entry { DbName(MemoryPool& p, const PathName& db) @@ -234,7 +234,7 @@ namespace }; struct AliasName; - typedef Hash, PathHash > AliasHash; + typedef HashTable, PathHash > AliasHash; struct AliasName : public AliasHash::Entry { diff --git a/src/jrd/Mapping.cpp b/src/jrd/Mapping.cpp index 6015f2f244..c1bcf0e790 100644 --- a/src/jrd/Mapping.cpp +++ b/src/jrd/Mapping.cpp @@ -146,7 +146,7 @@ private: }; class Map; -typedef Hash, Map> MapHash; +typedef HashTable, Map> MapHash; class Map : public MapHash::Entry, public GlobalStorage { diff --git a/src/jrd/dfw.epp b/src/jrd/dfw.epp index b6ef980e67..43a4fd25b7 100644 --- a/src/jrd/dfw.epp +++ b/src/jrd/dfw.epp @@ -150,7 +150,7 @@ using namespace Firebird; namespace Jrd { -typedef Hash< +typedef HashTable< DeferredWork, DEFAULT_HASH_SIZE, DeferredWork, @@ -308,7 +308,7 @@ public: class DfwSavePoint; -typedef Hash< +typedef HashTable< DfwSavePoint, DEFAULT_HASH_SIZE, SavNumber, diff --git a/src/jrd/lck.cpp b/src/jrd/lck.cpp index 7b366d368f..931e8a871d 100644 --- a/src/jrd/lck.cpp +++ b/src/jrd/lck.cpp @@ -28,6 +28,7 @@ #include "firebird.h" #include +#include "../common/classes/Hash.h" #include "../jrd/jrd.h" #include "../jrd/lck.h" #include "gen/iberror.h" @@ -59,7 +60,6 @@ static void bug_lck(const TEXT*); static bool compatible(const Lock*, const Lock*, USHORT); static void enqueue(thread_db*, CheckStatusWrapper*, Lock*, USHORT, SSHORT); static int external_ast(void*); -static USHORT hash_func(const UCHAR*, USHORT); static void hash_allocate(Lock*); static Lock* hash_get_lock(Lock*, USHORT*, Lock***); static void hash_insert_lock(Lock*); @@ -977,38 +977,6 @@ static int external_ast(void* lock_void) } - -static USHORT hash_func(const UCHAR* value, USHORT length) -{ -/************************************** - * - * h a s h - * - ************************************** - * - * Functional description - * Provide a repeatable hash value based - * on the passed key. - * - **************************************/ - - // Hash the value, preserving its distribution as much as possible - - ULONG hash_value = 0; - UCHAR* p = 0; - const UCHAR* q = value; - - for (USHORT l = 0; l < length; l++) - { - if (!(l & 3)) - p = (UCHAR*) &hash_value; - *p++ += *q++; - } - - return (USHORT) (hash_value % LOCK_HASH_SIZE); -} - - static void hash_allocate(Lock* lock) { /************************************** @@ -1059,7 +1027,8 @@ static Lock* hash_get_lock(Lock* lock, USHORT* hash_slot, Lock*** prior) if (!att->att_compatibility_table) hash_allocate(lock); - const USHORT hash_value = hash_func(lock->getKeyString(), lock->lck_length); + const USHORT hash_value = + (USHORT) InternalHash::hash(lock->lck_length, lock->getKeyString(), LOCK_HASH_SIZE); if (hash_slot) *hash_slot = hash_value; diff --git a/src/jrd/recsrc/HashJoin.cpp b/src/jrd/recsrc/HashJoin.cpp index 702fb7dbca..4e2bd4646b 100644 --- a/src/jrd/recsrc/HashJoin.cpp +++ b/src/jrd/recsrc/HashJoin.cpp @@ -21,6 +21,7 @@ */ #include "firebird.h" +#include "../common/classes/Hash.h" #include "../jrd/jrd.h" #include "../jrd/btr.h" #include "../jrd/req.h" @@ -249,7 +250,7 @@ class HashJoin::HashTable : public PermanentStorage }; public: - HashTable(MemoryPool& pool, size_t streamCount, size_t tableSize = HASH_SIZE) + HashTable(MemoryPool& pool, size_t streamCount, unsigned int tableSize = HASH_SIZE) : PermanentStorage(pool), m_streamCount(streamCount), m_tableSize(tableSize), m_slot(0) { @@ -265,28 +266,12 @@ public: delete[] m_collisions; } - size_t hash(ULONG length, const UCHAR* buffer) const - { - ULONG hash_value = 0; - - UCHAR* p = NULL; - const UCHAR* q = buffer; - for (size_t l = 0; l < length; l++) - { - if (!(l & 3)) - p = (UCHAR*) &hash_value; - - *p++ += *q++; - } - - return (hash_value % m_tableSize); - } - void put(size_t stream, ULONG keyLength, const KeyBuffer* keyBuffer, ULONG offset, ULONG position) { - const size_t slot = hash(keyLength, keyBuffer->begin() + offset); + const unsigned int slot = + InternalHash::hash(keyLength, keyBuffer->begin() + offset, m_tableSize); fb_assert(stream < m_streamCount); fb_assert(slot < m_tableSize); @@ -304,7 +289,7 @@ public: bool setup(ULONG length, const UCHAR* data) { - const size_t slot = hash(length, data); + const unsigned int slot = InternalHash::hash(length, data, m_tableSize); for (size_t i = 0; i < m_streamCount; i++) { @@ -350,7 +335,7 @@ public: private: const size_t m_streamCount; - const size_t m_tableSize; + const unsigned int m_tableSize; CollisionList** m_collisions; size_t m_slot; }; diff --git a/src/lock/lock.cpp b/src/lock/lock.cpp index f750363d5b..89eb4c5179 100644 --- a/src/lock/lock.cpp +++ b/src/lock/lock.cpp @@ -51,6 +51,7 @@ #include "../common/isc_s_proto.h" #include "../common/config/config.h" #include "../common/classes/array.h" +#include "../common/classes/Hash.h" #include "../common/classes/semaphore.h" #include "../common/classes/init.h" #include "../common/classes/timestamp.h" @@ -2087,7 +2088,6 @@ void LockManager::debug_delay(ULONG lineno) } #endif - lbl* LockManager::find_lock(USHORT series, const UCHAR* value, USHORT length, @@ -2107,23 +2107,11 @@ lbl* LockManager::find_lock(USHORT series, * **************************************/ - // Hash the value preserving its distribution as much as possible - - ULONG hash_value = 0; - { // scope - UCHAR* p = NULL; // silence uninitialized warning - const UCHAR* q = value; - for (USHORT l = 0; l < length; l++) - { - if (!(l & 3)) - p = (UCHAR*) &hash_value; - *p++ += *q++; - } - } // scope - // See if the lock already exists - const USHORT hash_slot = *slot = (USHORT) (hash_value % m_sharedMemory->getHeader()->lhb_hash_slots); + const USHORT hash_slot = *slot = + (USHORT) InternalHash::hash(length, value, m_sharedMemory->getHeader()->lhb_hash_slots); + ASSERT_ACQUIRED; srq* const hash_header = &m_sharedMemory->getHeader()->lhb_hash[hash_slot];