Linux核心中hash函式的實現

2021-08-27 10:41:55 字數 1908 閱讀 8967

linux核心中通過pid查詢程序描述符(task_struct)時,用到了hash表。下面介紹一下這一部分核心中hash函式的實現。

核心用pid_hashfn巨集把pid轉換為表索引(kernel/pid.c):

#define pid_hashfn(nr, ns)  \

hash_long((unsigned long)nr + (unsigned long)ns, pidhash_shift)

其中hash_long在中定義如下:

/* 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)

static inline u32 hash_32(u32 val, unsigned int bits)

static inline unsigned long hash_ptr(const void *ptr, unsigned int bits)

#endif /* _linux_hash_h */

上面的函式很有趣,我們來仔細看一下。

首先,hash的方式是,讓key乘以乙個大數,於是結果溢位,就把留在32/64位變數中的值作為hash值,又由於雜湊表的索引長度有限,我們就取這hash值的高幾為作為索引值,之所以取高幾位,是因為高位的數更具有隨機性,能夠減少所謂「衝突」。什麼是衝突呢?從上面的演算法來看,key和hash值並不是一一對應的。有可能兩個key算出來得到同乙個hash值,這就稱為「衝突」。

那麼,乘以的這個大數應該是多少呢?從上面的**來看,32位系統中這個數是0x9e370001ul,64位系統中這個數是0x9e37fffffffc0001ul。這個數是怎麼得到的呢?

「knuth建議,要得到滿意的結果,對於32位機器,2^32做**分割,這個大樹是最接近**分割點的素數,0x9e370001ul就是接近 2^32*(sqrt(5)-1)/2 的乙個素數,且這個數可以很方便地通過加運算和位移運算得到,因為它等於2^31 + 2^29 - 2^25 + 2^22 - 2^19 - 2^16 + 1。對於64位系統,這個數是0x9e37fffffffc0001ul,同樣有2^63 + 2^61 - 2^57 + 2^54 - 2^51 - 2^18 + 1。」

從程式中可以看到,對於32位系統計算hash值是直接用的乘法,因為gcc在編譯時會自動優化演算法。而對於64位系統,gcc似乎沒有類似的優化,所以用的是位移運算和加運算來計算。首先n=hash, 然後n左移18位,hash-=n,這樣hash = hash * (1 - 2^18),下一項是-2^51,而n之前已經左移過18位了,所以只需要再左移33位,於是有n <<= 33,依次類推,最終算出了hash值。

Linux核心中的cmpxchg函式

前幾天,為了這個函式花了好多時間,由於參考的資料有誤,一直都沒有看明白,直到google之後,總算搞明白了,因此寫出來大家分享一下。在linux核心中,提供了比較並交換的函式cmpxchg,在include asm i386 cmpxchg.h中,函式的原型是 全選cmpxchg void ptr,...

linux核心中的typecheck函式

最近在檢視linux 時看到了乙個typecheck函式,剛開始不是很明白,具體 如下 define typecheck type,x 這是乙個巨集,它是檢查type和x的資料型別是否一樣,比如我們這樣使用 int a typecheck double,a 巨集展開後是乙個表示式 typeof關鍵字...

linux核心中的延遲函式

linux核心提供3個函式分別進行納秒,微妙和毫秒延時 void ndelay unsigned long nsecs void udelay unsigned long usecs void mdelay unsigned long msecs 這3個函式的延時原理是忙等待,也就是說在延時的過程中...