diff options
| author | Tejun Heo <tj@kernel.org> | 2013-02-27 20:05:08 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-02-27 22:10:21 -0500 |
| commit | 0ffc2a9c8072969253a20821c2c733a2cbb4c7c7 (patch) | |
| tree | ff6a9d270d4f0fa5c770837c6d9e5d5aac2637a7 /include/linux | |
| parent | 54616283c2948812a44240858ced610e7cacbde1 (diff) | |
idr: implement lookup hint
While idr lookup isn't a particularly heavy operation, it still is too
substantial to use in hot paths without worrying about the performance
implications. With recent changes, each idr_layer covers 256 slots
which should be enough to cover most use cases with single idr_layer
making lookup hint very attractive.
This patch adds idr->hint which points to the idr_layer which
allocated an ID most recently and the fast path lookup becomes
if (look up target's prefix matches that of the hinted layer)
return hint->ary[ID's offset in the leaf layer];
which can be inlined.
idr->hint is set to the leaf node on idr_fill_slot() and cleared from
free_layer().
[andriy.shevchenko@linux.intel.com: always do slow path when hint is uninitialized]
Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Cc: Sasha Levin <sasha.levin@oracle.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'include/linux')
| -rw-r--r-- | include/linux/idr.h | 25 |
1 files changed, 24 insertions, 1 deletions
diff --git a/include/linux/idr.h b/include/linux/idr.h index 7b1c5c6f9a06..a6f38b5c34e4 100644 --- a/include/linux/idr.h +++ b/include/linux/idr.h | |||
| @@ -37,6 +37,7 @@ struct idr_layer { | |||
| 37 | }; | 37 | }; |
| 38 | 38 | ||
| 39 | struct idr { | 39 | struct idr { |
| 40 | struct idr_layer __rcu *hint; /* the last layer allocated from */ | ||
| 40 | struct idr_layer __rcu *top; | 41 | struct idr_layer __rcu *top; |
| 41 | struct idr_layer *id_free; | 42 | struct idr_layer *id_free; |
| 42 | int layers; /* only valid w/o concurrent changes */ | 43 | int layers; /* only valid w/o concurrent changes */ |
| @@ -71,7 +72,7 @@ struct idr { | |||
| 71 | * This is what we export. | 72 | * This is what we export. |
| 72 | */ | 73 | */ |
| 73 | 74 | ||
| 74 | void *idr_find(struct idr *idp, int id); | 75 | void *idr_find_slowpath(struct idr *idp, int id); |
| 75 | int idr_pre_get(struct idr *idp, gfp_t gfp_mask); | 76 | int idr_pre_get(struct idr *idp, gfp_t gfp_mask); |
| 76 | int idr_get_new_above(struct idr *idp, void *ptr, int starting_id, int *id); | 77 | int idr_get_new_above(struct idr *idp, void *ptr, int starting_id, int *id); |
| 77 | void idr_preload(gfp_t gfp_mask); | 78 | void idr_preload(gfp_t gfp_mask); |
| @@ -97,6 +98,28 @@ static inline void idr_preload_end(void) | |||
| 97 | } | 98 | } |
| 98 | 99 | ||
| 99 | /** | 100 | /** |
| 101 | * idr_find - return pointer for given id | ||
| 102 | * @idp: idr handle | ||
| 103 | * @id: lookup key | ||
| 104 | * | ||
| 105 | * Return the pointer given the id it has been registered with. A %NULL | ||
| 106 | * return indicates that @id is not valid or you passed %NULL in | ||
| 107 | * idr_get_new(). | ||
| 108 | * | ||
| 109 | * This function can be called under rcu_read_lock(), given that the leaf | ||
| 110 | * pointers lifetimes are correctly managed. | ||
| 111 | */ | ||
| 112 | static inline void *idr_find(struct idr *idr, int id) | ||
| 113 | { | ||
| 114 | struct idr_layer *hint = rcu_dereference_raw(idr->hint); | ||
| 115 | |||
| 116 | if (hint && (id & ~IDR_MASK) == hint->prefix) | ||
| 117 | return rcu_dereference_raw(hint->ary[id & IDR_MASK]); | ||
| 118 | |||
| 119 | return idr_find_slowpath(idr, id); | ||
| 120 | } | ||
| 121 | |||
| 122 | /** | ||
| 100 | * idr_get_new - allocate new idr entry | 123 | * idr_get_new - allocate new idr entry |
| 101 | * @idp: idr handle | 124 | * @idp: idr handle |
| 102 | * @ptr: pointer you want associated with the id | 125 | * @ptr: pointer you want associated with the id |
