mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-28 20:02:17 +00:00
![Isabella Basso](/assets/img/avatar_default.png)
Patch series "test_hash.c: refactor into KUnit", v3. We refactored the lib/test_hash.c file into KUnit as part of the student group LKCAMP [1] introductory hackathon for kernel development. This test was pointed to our group by Daniel Latypov [2], so its full conversion into a pure KUnit test was our goal in this patch series, but we ran into many problems relating to it not being split as unit tests, which complicated matters a bit, as the reasoning behind the original tests is quite cryptic for those unfamiliar with hash implementations. Some interesting developments we'd like to highlight are: - In patch 1/5 we noticed that there was an unused define directive that could be removed. - In patch 4/5 we noticed how stringhash and hash tests are all under the lib/test_hash.c file, which might cause some confusion, and we also broke those kernel config entries up. Overall KUnit developments have been made in the other patches in this series: In patches 2/5, 3/5 and 5/5 we refactored the lib/test_hash.c file so as to make it more compatible with the KUnit style, whilst preserving the original idea of the maintainer who designed it (i.e. George Spelvin), which might be undesirable for unit tests, but we assume it is enough for a first patch. This patch (of 5): Currently, there exist hash_32() and __hash_32() functions, which were introduced in a patch [1] targeting architecture specific optimizations. These functions can be overridden on a per-architecture basis to achieve such optimizations. They must set their corresponding define directive (HAVE_ARCH_HASH_32 and HAVE_ARCH__HASH_32, respectively) so that header files can deal with these overrides properly. As the supported 32-bit architectures that have their own hash function implementation (i.e. m68k, Microblaze, H8/300, pa-risc) have only been making use of the (more general) __hash_32() function (which only lacks a right shift operation when compared to the hash_32() function), remove the define directive corresponding to the arch-specific hash_32() implementation. [1] https://lore.kernel.org/lkml/20160525073311.5600.qmail@ns.sciencehorizons.net/ [akpm@linux-foundation.org: hash_32_generic() becomes hash_32()] Link: https://lkml.kernel.org/r/20211208183711.390454-1-isabbasso@riseup.net Link: https://lkml.kernel.org/r/20211208183711.390454-2-isabbasso@riseup.net Reviewed-by: David Gow <davidgow@google.com> Tested-by: David Gow <davidgow@google.com> Co-developed-by: Augusto Durães Camargo <augusto.duraes33@gmail.com> Signed-off-by: Augusto Durães Camargo <augusto.duraes33@gmail.com> Co-developed-by: Enzo Ferreira <ferreiraenzoa@gmail.com> Signed-off-by: Enzo Ferreira <ferreiraenzoa@gmail.com> Signed-off-by: Isabella Basso <isabbasso@riseup.net> Cc: Geert Uytterhoeven <geert@linux-m68k.org> Cc: Brendan Higgins <brendanhiggins@google.com> Cc: Daniel Latypov <dlatypov@google.com> Cc: Shuah Khan <skhan@linuxfoundation.org> Cc: Rodrigo Siqueira <rodrigosiqueiramelo@gmail.com> Cc: kernel test robot <lkp@intel.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
101 lines
2.9 KiB
C
101 lines
2.9 KiB
C
#ifndef _LINUX_HASH_H
|
|
#define _LINUX_HASH_H
|
|
/* Fast hashing routine for ints, longs and pointers.
|
|
(C) 2002 Nadia Yvette Chambers, IBM */
|
|
|
|
#include <asm/types.h>
|
|
#include <linux/compiler.h>
|
|
|
|
/*
|
|
* The "GOLDEN_RATIO_PRIME" is used in ifs/btrfs/brtfs_inode.h and
|
|
* fs/inode.c. It's not actually prime any more (the previous primes
|
|
* were actively bad for hashing), but the name remains.
|
|
*/
|
|
#if BITS_PER_LONG == 32
|
|
#define GOLDEN_RATIO_PRIME GOLDEN_RATIO_32
|
|
#define hash_long(val, bits) hash_32(val, bits)
|
|
#elif BITS_PER_LONG == 64
|
|
#define hash_long(val, bits) hash_64(val, bits)
|
|
#define GOLDEN_RATIO_PRIME GOLDEN_RATIO_64
|
|
#else
|
|
#error Wordsize not 32 or 64
|
|
#endif
|
|
|
|
/*
|
|
* This hash multiplies the input by a large odd number and takes the
|
|
* high bits. Since multiplication propagates changes to the most
|
|
* significant end only, it is essential that the high bits of the
|
|
* product be used for the hash value.
|
|
*
|
|
* Chuck Lever verified the effectiveness of this technique:
|
|
* http://www.citi.umich.edu/techreports/reports/citi-tr-00-1.pdf
|
|
*
|
|
* Although a random odd number will do, it turns out that the golden
|
|
* ratio phi = (sqrt(5)-1)/2, or its negative, has particularly nice
|
|
* properties. (See Knuth vol 3, section 6.4, exercise 9.)
|
|
*
|
|
* These are the negative, (1 - phi) = phi**2 = (3 - sqrt(5))/2,
|
|
* which is very slightly easier to multiply by and makes no
|
|
* difference to the hash distribution.
|
|
*/
|
|
#define GOLDEN_RATIO_32 0x61C88647
|
|
#define GOLDEN_RATIO_64 0x61C8864680B583EBull
|
|
|
|
#ifdef CONFIG_HAVE_ARCH_HASH
|
|
/* This header may use the GOLDEN_RATIO_xx constants */
|
|
#include <asm/hash.h>
|
|
#endif
|
|
|
|
/*
|
|
* The _generic versions exist only so lib/test_hash.c can compare
|
|
* the arch-optimized versions with the generic.
|
|
*
|
|
* Note that if you change these, any <asm/hash.h> that aren't updated
|
|
* to match need to have their HAVE_ARCH_* define values updated so the
|
|
* self-test will not false-positive.
|
|
*/
|
|
#ifndef HAVE_ARCH__HASH_32
|
|
#define __hash_32 __hash_32_generic
|
|
#endif
|
|
static inline u32 __hash_32_generic(u32 val)
|
|
{
|
|
return val * GOLDEN_RATIO_32;
|
|
}
|
|
|
|
static inline u32 hash_32(u32 val, unsigned int bits)
|
|
{
|
|
/* High bits are more random, so use them. */
|
|
return __hash_32(val) >> (32 - bits);
|
|
}
|
|
|
|
#ifndef HAVE_ARCH_HASH_64
|
|
#define hash_64 hash_64_generic
|
|
#endif
|
|
static __always_inline u32 hash_64_generic(u64 val, unsigned int bits)
|
|
{
|
|
#if BITS_PER_LONG == 64
|
|
/* 64x64-bit multiply is efficient on all 64-bit processors */
|
|
return val * GOLDEN_RATIO_64 >> (64 - bits);
|
|
#else
|
|
/* Hash 64 bits using only 32x32-bit multiply. */
|
|
return hash_32((u32)val ^ __hash_32(val >> 32), bits);
|
|
#endif
|
|
}
|
|
|
|
static inline u32 hash_ptr(const void *ptr, unsigned int bits)
|
|
{
|
|
return hash_long((unsigned long)ptr, bits);
|
|
}
|
|
|
|
/* This really should be called fold32_ptr; it does no hashing to speak of. */
|
|
static inline u32 hash32_ptr(const void *ptr)
|
|
{
|
|
unsigned long val = (unsigned long)ptr;
|
|
|
|
#if BITS_PER_LONG == 64
|
|
val ^= (val >> 32);
|
|
#endif
|
|
return (u32)val;
|
|
}
|
|
|
|
#endif /* _LINUX_HASH_H */
|