From: Pekka Enberg <hidden> Date: 2005-04-23 11:27:45
Hi,
On 4/23/05, Rik van Riel [off-list ref] wrote:
Note that this code could use an actual hash function.
How about this? It computes hash for the two longs and combines them by
addition and multiplication as suggested by [Bloch01].
Signed-off-by: Pekka Enberg <redacted>
---
include/linux/hash.h | 13 ++++++++++++-
mm/nonresident.c | 11 ++++++++---
2 files changed, 20 insertions(+), 4 deletions(-)
Index: 2.6/include/linux/hash.h
===================================================================
@@ -23,7 +23,7 @@#error Define GOLDEN_RATIO_PRIME for your wordsize.#endif-staticinlineunsignedlonghash_long(unsignedlongval,unsignedintbits)+staticinlineunsignedlonghash_long_mul(unsignedlongval){unsignedlonghash=val;
@@ -46,6 +46,17 @@/* On some cpus multiply is faster, on others gcc will do shifts */hash*=GOLDEN_RATIO_PRIME;#endif+returnhash;+}++staticinlineunsignedlonghash_ptr_mul(void*ptr)+{+returnhash_long_mul((unsignedlong)ptr);+}++staticinlineunsignedlonghash_long(unsignedlongval,unsignedintbits)+{+unsignedlonghash=hash_long_mul(val);/* High bits are more random, so use them. */returnhash>>(BITS_PER_LONG-bits);
@@ -51,11 +51,16 @@/* The non-resident page hash table. */staticstructnr_bucket*nr_hashtable;-/* Wanted: a real hash function for 2 longs. */structnr_bucket*nr_hash(void*mapping,unsignedlongoffset_and_gen){+unsignedlonghash;unsignedlongbucket;-bucket=((unsignedlong)mapping+offset_and_gen)%nr_buckets;++hash=17;+hash=37*hash+hash_ptr_mul(mapping);+hash=37*hash+hash_long_mul(offset_and_gen);+bucket=hash%nr_buckets;+returnnr_hashtable+bucket;}--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"aart@kvack.org"> aart@kvack.org </a>
From: Rik van Riel <hidden> Date: 2005-04-23 11:32:22
On Sat, 23 Apr 2005, Pekka Enberg wrote:
On 4/23/05, Rik van Riel [off-list ref] wrote:
quoted
Note that this code could use an actual hash function.
How about this? It computes hash for the two longs and combines them by
addition and multiplication as suggested by [Bloch01].
I've thought about it, but ...
quoted hunk
@@ -23,7 +23,7 @@ #error Define GOLDEN_RATIO_PRIME for your wordsize. #endif
... include/linux/hash.c appears to only work right for
32 bit words, not 64 bit ones ...
--
"Debugging is twice as hard as writing the code in the first place.
Therefore, if you write the code as cleverly as possible, you are,
by definition, not smart enough to debug it." - Brian W. Kernighan
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"aart@kvack.org"> aart@kvack.org </a>
From: Rik van Riel <hidden> Date: 2005-04-23 17:14:39
On Sat, 23 Apr 2005, Pekka Enberg wrote:
How about this? It computes hash for the two longs and combines them by
addition and multiplication as suggested by [Bloch01].
Signed-off-by: Pekka Enberg <redacted>
Looks good to me, here's a new version of the patch.
The next part of my cunning plan is to get rid of the object
generation number, and use a cryptographic hash of (offset,
mapping->host->i_ino, mapping->host->i_sb). That way there's
only a small chance of false positives - assuming a perfect
hash, one false positive every 256MB of data, or 2^16 pages.
Unless there are filesystems that immediately reassign the same
inode number when creating a file after one got deleted - not
sure about that...
Anyway, here is the current code:
Signed-off-by: Rik van Riel <redacted>
include/linux/hash.h | 13 +++-
include/linux/nonresident.h | 12 +++
mm/Makefile | 3
mm/nonresident.c | 137 ++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 163 insertions(+), 2 deletions(-)
@@ -23,7 +23,7 @@#error Define GOLDEN_RATIO_PRIME for your wordsize.#endif-staticinlineunsignedlonghash_long(unsignedlongval,unsignedintbits)+staticinlineunsignedlonghash_long_mul(unsignedlongval){unsignedlonghash=val;
@@ -46,6 +46,17 @@ static inline unsigned long hash_long(un/* On some cpus multiply is faster, on others gcc will do shifts */hash*=GOLDEN_RATIO_PRIME;#endif+returnhash;+}++staticinlineunsignedlonghash_ptr_mul(void*ptr)+{+returnhash_long_mul((unsignedlong)ptr);+}++staticinlineunsignedlonghash_long(unsignedlongval,unsignedintbits)+{+unsignedlonghash=hash_long_mul(val);/* High bits are more random, so use them. */returnhash>>(BITS_PER_LONG-bits);---linux-2.6.11/mm/nonresident.c.nonres2005-04-2217:19:13.000000000-0400+++linux-2.6.11/mm/nonresident.c2005-04-2313:09:03.000000000-0400
@@ -0,0 +1,137 @@+/*+*mm/nonresident.c+*(C)2004,2005RedHat,Inc+*WrittenbyRikvanRiel<riel@redhat.com>+*ReleasedundertheGPL,seethefileCOPYINGfordetails.+*+*Keepstrackofwhetheranon-residentpagewasrecentlyevicted+*andshouldbeimmediatelypromotedtotheactivelist.Thisalso+*helpsautomaticallytunetheinactivetarget.+*+*Thepageoutcodestoresarecentlyevictedpageinthiscache+*bycallingremember_page(mapping/mm,offset/vaddr,generation)+*andcanlookitupinthecachebycallingrecently_evicted()+*withthesamearguments.+*+*Notethatthereisnowaytoinvalidatepagesaftereg.truncate+*orexit,weletthepagesfalloutofthenon-residentsetthrough+*normalreplacement.+*/+#include<linux/mm.h>+#include<linux/cache.h>+#include<linux/spinlock.h>+#include<linux/bootmem.h>+#include<linux/hash.h>+#include<linux/nonresident.h>++staticunsignedlongnr_buckets;++/*+*Wefoldtheobjectgenerationnumberintotheoffsetfield,since+*thatonehasthemost"free"bitsona32bitsystem.+*/+#define NR_GEN_SHIFT (BITS_PER_LONG * 7 / 8)+#define NR_OFFSET_MASK ((1 << NR_GEN_SHIFT) - 1)+#define make_nr_oag(x,y) (((x) & NR_OFFSET_MASK) + ((y) << NR_GEN_SHIFT))++structnr_page{+void*mapping;+unsignedlongoffset_and_gen;+};++/* Number of non-resident pages per hash bucket */+#define NUM_NR ((L1_CACHE_BYTES - sizeof(spinlock_t))/sizeof(struct nr_page))++structnr_bucket+{+spinlock_tlock;+structnr_pagepages[NUM_NR];+}____cacheline_aligned;++/* The non-resident page hash table. */+staticstructnr_bucket*nr_hashtable;++structnr_bucket*nr_hash(void*mapping,unsignedlongoffset_and_gen)+{+unsignedlongbucket;+unsignedlonghash;++hash=17;+hash=37*hash+hash_ptr_mul(mapping);+hash=37*hash+hash_long_mul(offset_and_gen);+bucket=hash%nr_buckets;++returnnr_hashtable+bucket;+}++staticintnr_same(structnr_page*first,structnr_page*second)+{+/* Chances are this nr_page belongs to a different mapping ... */+if(first->mapping!=second->mapping)+return0;++/* ... but if it matches the mapping, it's probably the same page. */+if(likely(first->offset_and_gen==second->offset_and_gen))+return1;++return0;+}++intrecently_evicted(void*mapping,unsignedlongoffset,unsignedlonggen)+{+unsignedlongoffset_and_gen=make_nr_oag(offset,gen);+structnr_bucket*nr_bucket=nr_hash(mapping,offset_and_gen);+structnr_pagewanted;+intstate=-1;+inti;++wanted.offset_and_gen=offset_and_gen;+wanted.mapping=mapping;++spin_lock(&nr_bucket->lock);+for(i=0;i<NUM_NR;i++){+structnr_page*found=&nr_bucket->pages[i];+if(nr_same(found,&wanted)){+found->mapping=NULL;+state=1;+break;+}+}+spin_unlock(&nr_bucket->lock);++returnstate;+}++intremember_page(void*mapping,unsignedlongoffset,unsignedlonggen)+{+unsignedlongoffset_and_gen=make_nr_oag(offset,gen);+structnr_bucket*nr_bucket=nr_hash(mapping,offset_and_gen);+structnr_page*victim;+intrecycled=0;+inti;++spin_lock(&nr_bucket->lock);+for(i=0;i<NUM_NR;i++){+victim=&nr_bucket->pages[i];+if(victim->mapping==NULL)+gotoassign;+}++/* Randomly recycle an nr_page. */+i=(offset^jiffies)%NUM_NR;+victim=&nr_bucket->pages[i];+recycled=1;++assign:+victim->mapping=mapping;+victim->offset_and_gen=offset_and_gen;+spin_unlock(&nr_bucket->lock);+returnrecycled;+}++/* We should probably remember 2/3 of nr_physpages in non-resident pages */+void__initinit_nonresident(unsignedlongmempages)+{+nr_buckets=mempages/NUM_NR;+nr_hashtable=alloc_bootmem(nr_buckets*sizeof(structnr_bucket));+}---linux-2.6.11/mm/Makefile.nonres2005-04-2217:19:49.000000000-0400+++linux-2.6.11/mm/Makefile2005-04-2211:25:36.000000000-0400
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"aart@kvack.org"> aart@kvack.org </a>
From: Rik van Riel <hidden> Date: 2005-04-23 18:58:53
On Sat, 23 Apr 2005, Rik van Riel wrote:
The next part of my cunning plan is to get rid of the object
generation number,
Here's the change, incremental to the previous patch. This should
simplify things for the caller and work with both the swap cache
and filesystem backed inodes - assuming filesystems are smart about
recycling inode numbers, otherwise I may need to use another field
too ...
Signed-off-by: Rik van Riel <redacted>
@@ -51,19 +43,31 @@ struct nr_bucket/* The non-resident page hash table. */staticstructnr_bucket*nr_hashtable;-structnr_bucket*nr_hash(void*mapping,unsignedlongoffset_and_gen)+structnr_bucket*nr_hash(void*mapping,unsignedlongoffset){unsignedlongbucket;unsignedlonghash;-hash=17;-hash=37*hash+hash_ptr_mul(mapping);-hash=37*hash+hash_long_mul(offset_and_gen);+hash=hash_ptr_mul(mapping);+hash=37*hash+hash_long_mul(offset);bucket=hash%nr_buckets;returnnr_hashtable+bucket;}+staticunsignedlongnr_cookie(structaddress_space*mapping,unsignedlongoffset)+{+unsignedlongcookie=offset;++if(mapping->host){+cookie=hash_mul_long(offset);+cookie=37*cookie+hash_ptr_mul(mapping->host->i_ino);+cookie=37*cookie+hash_ptr_mul(mapping->host->i_sb);+}++returncookie;+}+staticintnr_same(structnr_page*first,structnr_page*second){/* Chances are this nr_page belongs to a different mapping ... */
@@ -77,10 +81,10 @@ static int nr_same(struct nr_page * firsreturn0;}-intrecently_evicted(void*mapping,unsignedlongoffset,unsignedlonggen)+intrecently_evicted(structaddress_space*mapping,unsignedlongoffset){-unsignedlongoffset_and_gen=make_nr_oag(offset,gen);-structnr_bucket*nr_bucket=nr_hash(mapping,offset_and_gen);+unsignedlongoffset_and_gen=nr_cookie(mapping,offset);+structnr_bucket*nr_bucket=nr_hash(mapping,offset);structnr_pagewanted;intstate=-1;inti;
@@ -102,10 +106,10 @@ int recently_evicted(void * mapping, unsreturnstate;}-intremember_page(void*mapping,unsignedlongoffset,unsignedlonggen)+intremember_page(structaddress_space*mapping,unsignedlongoffset){-unsignedlongoffset_and_gen=make_nr_oag(offset,gen);-structnr_bucket*nr_bucket=nr_hash(mapping,offset_and_gen);+unsignedlongoffset_and_gen=nr_cookie(mapping,offset);+structnr_bucket*nr_bucket=nr_hash(mapping,offset);structnr_page*victim;intrecycled=0;inti;--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"aart@kvack.org"> aart@kvack.org </a>