linux内核哈希(Hash)函数

本文介绍了Linux内核中使用的多种哈希算法实现,包括基于Golden Ratio Prime的哈希函数、用于不同场景如文件系统、块设备等的特定哈希算法。文章详细解释了这些算法如何提高系统的效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

No. 0

[include/linux/hash.h]

#ifndef _LINUX_HASH_H
#define _LINUX_HASH_H
/* Fast hashing routine for ints,  longs and pointers.
   (C) 2002 William Lee Irwin III, IBM */

/*
 * Knuth recommends primes in approximately golden ratio to the maximum
 * integer representable by a machine word for multiplicative hashing.
 * Chuck Lever verified the effectiveness of this technique:
 * http://www.citi.umich.edu/techreports/reports/citi-tr-00-1.pdf
 *
 * These primes are chosen to be bit-sparse, that is operations on
 * them can use shifts and additions instead of multiplications for
 * machines where multiplications are slow.
 */

#include <asm/types.h>

/* 2^31 + 2^29 - 2^25 + 2^22 - 2^19 - 2^16 + 1 */
#define GOLDEN_RATIO_PRIME_32 0x9e370001UL
/*  2^63 + 2^61 - 2^57 + 2^54 - 2^51 - 2^18 + 1 */
#define GOLDEN_RATIO_PRIME_64 0x9e37fffffffc0001UL

#if BITS_PER_LONG == 32
#define GOLDEN_RATIO_PRIME GOLDEN_RATIO_PRIME_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_PRIME_64
#else
#error Wordsize not 32 or 64
#endif

static inline u64 hash_64(u64 val, unsigned int bits)
{
    u64 hash = val;

    /*  Sigh, gcc can't optimise this alone like it does for 32 bits. */
    u64 n = hash;
    n <<= 18;
    hash -= n;
    n <<= 33;
    hash -= n;
    n <<= 3;
    hash += n;
    n <<= 3;
    hash -= n;
    n <<= 4;
    hash += n;
    n <<= 2;
    hash += n;

    /* High bits are more random, so use them. */
    return hash >> (64 - bits);
}

static inline u32 hash_32(u32 val, unsigned int bits)
{
    /* On some cpus multiply is faster, on others gcc will do shifts */
    u32 hash = val * GOLDEN_RATIO_PRIME_32;

    /* High bits are more random, so use them. */
    return hash >> (32 - bits);
}

static inline unsigned long hash_ptr(void *ptr, unsigned int bits)
{
    return hash_long((unsigned long)ptr, bits);
}
#endif /* _LINUX_HASH_H */

No. 1

[/arch/ia64/kernel/unwind.c]

static inline unw_hash_index_t
hash (unsigned long ip)
{
#define hashmagic   0x9e3779b97f4a7c16UL    /* based on (sqrt(5)/2-1)*2^64 */

    return (ip >> 4)*hashmagic >> (64 - UNW_LOG_HASH_SIZE);
#undef hashmagic
}

#define UNW_LOG_CACHE_SIZE  7   /* each unw_script is ~256 bytes in size */
#define UNW_CACHE_SIZE      (1 << UNW_LOG_CACHE_SIZE)

#define UNW_LOG_HASH_SIZE   (UNW_LOG_CACHE_SIZE + 1)
#define UNW_HASH_SIZE       (1 << UNW_LOG_HASH_SIZE)

No. 2

[/fs/block_dev.c]

#define MINORBITS   20
#define MINORMASK   ((1U << MINORBITS) - 1)

#define MAJOR(dev)  ((unsigned int) ((dev) >> MINORBITS))
#define MINOR(dev)  ((unsigned int) ((dev) & MINORMASK))

/*
 * Most likely _very_ bad one - but then it's hardly critical for small
 * /dev and can be fixed when somebody will need really large one.
 * Keep in mind that it will be fed through icache hash function too.
 */
static inline unsigned long hash(dev_t dev)
{
    return MAJOR(dev)+MINOR(dev);
}

No. 3

static inline unsigned long hash(struct super_block *sb, unsigned long hashval)
{
    unsigned long tmp;

    tmp = (hashval * (unsigned long)sb) ^ (GOLDEN_RATIO_PRIME + hashval) /
            L1_CACHE_BYTES;
    tmp = tmp ^ ((tmp ^ GOLDEN_RATIO_PRIME) >> I_HASHBITS);
    return tmp & I_HASHMASK;
}

/*
 * Knuth recommends primes in approximately golden ratio to the maximum
 * integer representable by a machine word for multiplicative hashing.
 * Chuck Lever verified the effectiveness of this technique:
 * http://www.citi.umich.edu/techreports/reports/citi-tr-00-1.pdf
 *
 * These primes are chosen to be bit-sparse, that is operations on
 * them can use shifts and additions instead of multiplications for
 * machines where multiplications are slow.
 */
#if BITS_PER_LONG == 32
/* 2^31 + 2^29 - 2^25 + 2^22 - 2^19 - 2^16 + 1 */
#define GOLDEN_RATIO_PRIME 0x9e370001UL
#elif BITS_PER_LONG == 64
/*  2^63 + 2^61 - 2^57 + 2^54 - 2^51 - 2^18 + 1 */
#define GOLDEN_RATIO_PRIME 0x9e37fffffffc0001UL
#else
#error Define GOLDEN_RATIO_PRIME for your wordsize.
#endif

/*
 * Inode lookup is no longer as critical as it used to be:
 * most of the lookups are going to be through the dcache.
 */
#define I_HASHBITS  i_hash_shift
#define I_HASHMASK  i_hash_mask

static unsigned int i_hash_mask;
static unsigned int i_hash_shift;

/* L1 cache line size */
#define L1_CACHE_SHIFT  (CONFIG_X86_L1_CACHE_SHIFT)
#define L1_CACHE_BYTES  (1 << L1_CACHE_SHIFT)

No. 4

/* Borrowed from buffer.c: this is a tried and tested block hash function */
static inline int hash(journal_t *journal, unsigned long block)
{
    struct jbd_revoke_table_s *table = journal->j_revoke;
    int hash_shift = table->hash_shift;

    return ((block << (hash_shift - 6)) ^
        (block >> 13) ^
        (block << (hash_shift - 12))) & (table->hash_size - 1);
}

No. 5

[/fs/namespace.c]

static int hash_mask, hash_bits;
static kmem_cache_t *mnt_cache; 

static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry)
{
    unsigned long tmp = ((unsigned long) mnt / L1_CACHE_BYTES);
    tmp += ((unsigned long) dentry / L1_CACHE_BYTES);
    tmp = tmp + (tmp >> hash_bits);
    return tmp & hash_mask;
}

No. 6

[/init/initramfs.c]

static inline int hash(int major, int minor, int ino)
{
    unsigned long tmp = ino + minor + (major << 3);
    tmp += tmp >> 5;
    return tmp & 31;
}

No. 7

[/net/tipc/name_table.c]

static int tipc_nametbl_size = 1024;        /* must be a power of 2 */

static int hash(int x)
{
    return x & (tipc_nametbl_size - 1);
}
jhash函数Linux内核中一个用于哈希表操作的散列函数,它的实现代码可以在内核源码的"include/linux/jhash.h"头文件中找到。 jhash函数的输入参数包括要哈希的数据、数据长度和一个初始化的哈希值。函数的返回值是一个32位无符号整数,表示该数据在哈希表中的位置。 jhash函数的实现使用了一些位运算和乘法运算,以及一些常量。具体实现可以参考下面的代码: ```c static inline u32 jhash(const void *key, u32 length, u32 initval) { u32 a, b, c; const u8 *k = (const u8 *)key; /* Set up the internal state */ a = b = c = 0xdeadbeef + length + initval; /* All but the last block: affect some 32 bits of (a,b,c) */ while (length > 12) { a += k[0]; a += ((u32)k[1])<<8; a += ((u32)k[2])<<16; a += ((u32)k[3])<<24; b += k[4]; b += ((u32)k[5])<<8; b += ((u32)k[6])<<16; b += ((u32)k[7])<<24; c += k[8]; c += ((u32)k[9])<<8; c += ((u32)k[10])<<16; c += ((u32)k[11])<<24; /* Mix */ a -= c; a ^= rol32(c, 4); c += b; b -= a; b ^= rol32(a, 6); a += c; c -= b; c ^= rol32(b, 8); b += a; a -= c; a ^= rol32(c, 16); c += b; b -= a; b ^= rol32(a, 19); a += c; c -= b; c ^= rol32(b, 4); b += a; k += 12; length -= 12; } /* Last block: affect all 32 bits of (c) */ switch (length) { case 12: c += ((u32)k[11])<<24; case 11: c += ((u32)k[10])<<16; case 10: c += ((u32)k[9])<<8; case 9: c += k[8]; case 8: b += ((u32)k[7])<<24; case 7: b += ((u32)k[6])<<16; case 6: b += ((u32)k[5])<<8; case 5: b += k[4]; case 4: a += ((u32)k[3])<<24; case 3: a += ((u32)k[2])<<16; case 2: a += ((u32)k[1])<<8; case 1: a += k[0]; }; /* Mix */ c ^= b; c -= rol32(b, 14); a ^= c; a -= rol32(c, 11); b ^= a; b -= rol32(a, 25); c ^= b; c -= rol32(b, 16); a ^= c; a -= rol32(c, 4); b ^= a; b -= rol32(a, 14); c ^= b; c -= rol32(b, 24); return c; } ``` 在上面的代码中,rol32是一个左旋32位的宏,实现如下: ```c #define rol32(x, n) (((x)<<(n)) | ((x)>>(32-(n)))) ``` jhash函数采用了一种叫做"Bob Jenkins' Hash"的哈希算法,它被广泛应用于Linux内核中的哈希表操作中,具有较好的散列性能和分布特性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值