Skip to content

Commit 2c57a0e

Browse files
YuryNorovtorvalds
authored andcommitted
lib: find_*_bit reimplementation
This patchset does rework to find_bit function family to achieve better performance, and decrease size of text. All rework is done in patch 1. Patches 2 and 3 are about code moving and renaming. It was boot-tested on x86_64 and MIPS (big-endian) machines. Performance tests were ran on userspace with code like this: /* addr[] is filled from /dev/urandom */ start = clock(); while (ret < nbits) ret = find_next_bit(addr, nbits, ret + 1); end = clock(); printf("%ld\t", (unsigned long) end - start); On Intel(R) Core(TM) i7-3770 CPU @ 3.40GHz measurements are: (for find_next_bit, nbits is 8M, for find_first_bit - 80K) find_next_bit: find_first_bit: new current new current 26932 43151 14777 14925 26947 43182 14521 15423 26507 43824 15053 14705 27329 43759 14473 14777 26895 43367 14847 15023 26990 43693 15103 15163 26775 43299 15067 15232 27282 42752 14544 15121 27504 43088 14644 14858 26761 43856 14699 15193 26692 43075 14781 14681 27137 42969 14451 15061 ... ... find_next_bit performance gain is 35-40%; find_first_bit - no measurable difference. On ARM machine, there is arch-specific implementation for find_bit. Thanks a lot to George Spelvin and Rasmus Villemoes for hints and helpful discussions. This patch (of 3): New implementations takes less space in source file (see diffstat) and in object. For me it's 710 vs 453 bytes of text. It also shows better performance. find_last_bit description fixed due to obvious typo. [akpm@linux-foundation.org: include linux/bitmap.h, per Rasmus] Signed-off-by: Yury Norov <yury.norov@gmail.com> Reviewed-by: Rasmus Villemoes <linux@rasmusvillemoes.dk> Reviewed-by: George Spelvin <linux@horizon.com> Cc: Alexey Klimov <klimov.linux@gmail.com> Cc: David S. Miller <davem@davemloft.net> Cc: Daniel Borkmann <dborkman@redhat.com> Cc: Hannes Frederic Sowa <hannes@stressinduktion.org> Cc: Lai Jiangshan <laijs@cn.fujitsu.com> Cc: Mark Salter <msalter@redhat.com> Cc: AKASHI Takahiro <takahiro.akashi@linaro.org> Cc: Thomas Graf <tgraf@suug.ch> Cc: Valentin Rothberg <valentinrothberg@gmail.com> Cc: Chris Wilson <chris@chris-wilson.co.uk> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent 396ada6 commit 2c57a0e

File tree

3 files changed

+91
-216
lines changed

3 files changed

+91
-216
lines changed

include/linux/bitops.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -218,9 +218,9 @@ static inline unsigned long __ffs64(u64 word)
218218
/**
219219
* find_last_bit - find the last set bit in a memory region
220220
* @addr: The address to start the search at
221-
* @size: The maximum size to search
221+
* @size: The number of bits to search
222222
*
223-
* Returns the bit number of the first set bit, or size.
223+
* Returns the bit number of the last set bit, or size.
224224
*/
225225
extern unsigned long find_last_bit(const unsigned long *addr,
226226
unsigned long size);

lib/find_last_bit.c

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,44 +4,36 @@
44
* Written by Rusty Russell <rusty@rustcorp.com.au>
55
* (Inspired by David Howell's find_next_bit implementation)
66
*
7+
* Rewritten by Yury Norov <yury.norov@gmail.com> to decrease
8+
* size and improve performance, 2015.
9+
*
710
* This program is free software; you can redistribute it and/or
811
* modify it under the terms of the GNU General Public License
912
* as published by the Free Software Foundation; either version
1013
* 2 of the License, or (at your option) any later version.
1114
*/
1215

1316
#include <linux/bitops.h>
17+
#include <linux/bitmap.h>
1418
#include <linux/export.h>
15-
#include <asm/types.h>
16-
#include <asm/byteorder.h>
19+
#include <linux/kernel.h>
1720

1821
#ifndef find_last_bit
1922

2023
unsigned long find_last_bit(const unsigned long *addr, unsigned long size)
2124
{
22-
unsigned long words;
23-
unsigned long tmp;
24-
25-
/* Start at final word. */
26-
words = size / BITS_PER_LONG;
25+
if (size) {
26+
unsigned long val = BITMAP_LAST_WORD_MASK(size);
27+
unsigned long idx = (size-1) / BITS_PER_LONG;
2728

28-
/* Partial final word? */
29-
if (size & (BITS_PER_LONG-1)) {
30-
tmp = (addr[words] & (~0UL >> (BITS_PER_LONG
31-
- (size & (BITS_PER_LONG-1)))));
32-
if (tmp)
33-
goto found;
34-
}
29+
do {
30+
val &= addr[idx];
31+
if (val)
32+
return idx * BITS_PER_LONG + __fls(val);
3533

36-
while (words) {
37-
tmp = addr[--words];
38-
if (tmp) {
39-
found:
40-
return words * BITS_PER_LONG + __fls(tmp);
41-
}
34+
val = ~0ul;
35+
} while (idx--);
4236
}
43-
44-
/* Not found */
4537
return size;
4638
}
4739
EXPORT_SYMBOL(find_last_bit);

0 commit comments

Comments
 (0)