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/idr.h | |
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/idr.h')
-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 |