Add bit_count to the bitstring(3) api
Add a bit_count function, which efficiently counts the number of bits set in a bitstring. sys/sys/bitstring.h tests/sys/sys/bitstring_test.c share/man/man3/bitstring.3 Add bit_alloc sys/kern/subr_unit.c Use bit_count instead of a naive counting loop in check_unrhdr, used when INVARIANTS are enabled. The userland test runs about 6x faster in a generic build, or 8.5x faster when built for Nehalem, which has the POPCNT instruction. sys/sys/param.h Bump __FreeBSD_version due to the addition of bit_alloc UPDATING Add a note about the ABI incompatibility of the bitstring(3) changes, as suggested by lidl. Suggested by: gibbs Reviewed by: gibbs, ngie MFC after: 9 days X-MFC-With: 299090, 300538 Relnotes: yes Sponsored by: Spectra Logic Corp Differential Revision: https://reviews.freebsd.org/D6255
This commit is contained in:
parent
fc13dfc8e2
commit
1b82e02f4d
6
UPDATING
6
UPDATING
@ -31,6 +31,12 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 11.x IS SLOW:
|
||||
disable the most expensive debugging functionality run
|
||||
"ln -s 'abort:false,junk:false' /etc/malloc.conf".)
|
||||
|
||||
20160523:
|
||||
The bitstring(3) API has been updated with new functionality and
|
||||
improved performance. But it is binary-incompatible with the old API.
|
||||
Objects built with the new headers may not be linked against objects
|
||||
built with the old headers.
|
||||
|
||||
20160520:
|
||||
The brk and sbrk functions have been removed from libc on arm64.
|
||||
Binutils from ports has been updated to not link to these
|
||||
|
@ -27,7 +27,7 @@
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" Copyright (c) 2014 Spectra Logic Corporation
|
||||
.\" Copyright (c) 2014,2016 Spectra Logic Corporation
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
@ -58,12 +58,13 @@
|
||||
.\" @(#)bitstring.3 8.1 (Berkeley) 7/19/93
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd May 4, 2016
|
||||
.Dd May 23, 2016
|
||||
.Dt BITSTRING 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm bit_alloc ,
|
||||
.Nm bit_clear ,
|
||||
.Nm bit_count ,
|
||||
.Nm bit_decl ,
|
||||
.Nm bit_ffc ,
|
||||
.Nm bit_ffs ,
|
||||
@ -84,6 +85,8 @@
|
||||
.Ft void
|
||||
.Fn bit_clear "bitstr_t *name" "int bit"
|
||||
.Ft void
|
||||
.Fn bit_count "bitstr_t *name" "int count" "int nbits" "int *value"
|
||||
.Ft void
|
||||
.Fn bit_ffc "bitstr_t *name" "int nbits" "int *value"
|
||||
.Ft void
|
||||
.Fn bit_ffs "bitstr_t *name" "int nbits" "int *value"
|
||||
@ -225,6 +228,17 @@ the location referenced by
|
||||
.Fa value
|
||||
is set to \-1.
|
||||
.Pp
|
||||
The
|
||||
.Fn bit_count
|
||||
function stores in the location referenced by
|
||||
.Fa value
|
||||
the number of bits set in the array of
|
||||
.Fa nbits
|
||||
bits referenced by
|
||||
.Fa name ,
|
||||
at or after the zero-based bit index
|
||||
.Fa start .
|
||||
.Pp
|
||||
The arguments in bit string macros are evaluated only once and may safely
|
||||
have side effects.
|
||||
.Sh EXAMPLES
|
||||
|
@ -224,7 +224,8 @@ check_unrhdr(struct unrhdr *uh, int line)
|
||||
{
|
||||
struct unr *up;
|
||||
struct unrb *ub;
|
||||
u_int x, y, z, w;
|
||||
int w;
|
||||
u_int y, z;
|
||||
|
||||
y = uh->first;
|
||||
z = 0;
|
||||
@ -237,9 +238,7 @@ check_unrhdr(struct unrhdr *uh, int line)
|
||||
up->len, NBITS, line));
|
||||
z++;
|
||||
w = 0;
|
||||
for (x = 0; x < up->len; x++)
|
||||
if (bit_test(ub->map, x))
|
||||
w++;
|
||||
bit_count(ub->map, 0, up->len, &w);
|
||||
y += w;
|
||||
} else if (up->ptr != NULL)
|
||||
y += up->len;
|
||||
|
@ -65,6 +65,7 @@
|
||||
#ifdef _KERNEL
|
||||
#include <sys/libkern.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
typedef unsigned long bitstr_t;
|
||||
@ -202,7 +203,7 @@ bit_ffs_at(bitstr_t *_bitstr, int _start, int _nbits, int *_result)
|
||||
_test &= _bit_make_mask(_start, _BITSTR_BITS - 1);
|
||||
while (_test == 0 && _curbitstr < _stopbitstr)
|
||||
_test = *(++_curbitstr);
|
||||
|
||||
|
||||
_offset = ffsl(_test);
|
||||
_value = ((_curbitstr - _bitstr) * _BITSTR_BITS) + _offset - 1;
|
||||
if (_offset == 0 || _value >= _nbits)
|
||||
@ -231,7 +232,7 @@ bit_ffc_at(bitstr_t *_bitstr, int _start, int _nbits, int *_result)
|
||||
_test |= _bit_make_mask(0, _start - 1);
|
||||
while (_test == _BITSTR_MASK && _curbitstr < _stopbitstr)
|
||||
_test = *(++_curbitstr);
|
||||
|
||||
|
||||
_offset = ffsl(~_test);
|
||||
_value = ((_curbitstr - _bitstr) * _BITSTR_BITS) + _offset - 1;
|
||||
if (_offset == 0 || _value >= _nbits)
|
||||
@ -256,4 +257,40 @@ bit_ffc(bitstr_t *_bitstr, int _nbits, int *_result)
|
||||
bit_ffc_at(_bitstr, /*start*/0, _nbits, _result);
|
||||
}
|
||||
|
||||
/* Count the number of bits set in a bitstr of size _nbits at or after _start */
|
||||
static inline void
|
||||
bit_count(bitstr_t *_bitstr, int _start, int _nbits, int *_result)
|
||||
{
|
||||
bitstr_t *_curbitstr, mask;
|
||||
int _value = 0, curbitstr_len;
|
||||
|
||||
if (_start >= _nbits)
|
||||
goto out;
|
||||
|
||||
_curbitstr = _bitstr + _bit_idx(_start);
|
||||
_nbits -= _BITSTR_BITS * _bit_idx(_start);
|
||||
_start -= _BITSTR_BITS * _bit_idx(_start);
|
||||
|
||||
if (_start > 0) {
|
||||
curbitstr_len = (int)_BITSTR_BITS < _nbits ?
|
||||
(int)_BITSTR_BITS : _nbits;
|
||||
mask = _bit_make_mask(_start, _bit_offset(curbitstr_len - 1));
|
||||
_value += __bitcountl(*_curbitstr & mask);
|
||||
_curbitstr++;
|
||||
_nbits -= _BITSTR_BITS;
|
||||
}
|
||||
while (_nbits >= (int)_BITSTR_BITS) {
|
||||
_value += __bitcountl(*_curbitstr);
|
||||
_curbitstr++;
|
||||
_nbits -= _BITSTR_BITS;
|
||||
}
|
||||
if (_nbits > 0) {
|
||||
mask = _bit_make_mask(0, _bit_offset(_nbits - 1));
|
||||
_value += __bitcountl(*_curbitstr & mask);
|
||||
}
|
||||
|
||||
out:
|
||||
*_result = _value;
|
||||
}
|
||||
|
||||
#endif /* _SYS_BITSTRING_H_ */
|
||||
|
@ -58,7 +58,7 @@
|
||||
* in the range 5 to 9.
|
||||
*/
|
||||
#undef __FreeBSD_version
|
||||
#define __FreeBSD_version 1100111 /* Master, propagated to newvers */
|
||||
#define __FreeBSD_version 1100112 /* Master, propagated to newvers */
|
||||
|
||||
/*
|
||||
* __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD,
|
||||
|
@ -342,6 +342,67 @@ BITSTRING_TC_DEFINE(bit_nset)
|
||||
}
|
||||
}
|
||||
|
||||
BITSTRING_TC_DEFINE(bit_count)
|
||||
/* bitstr_t *bitstr, int nbits, const char *memloc */
|
||||
{
|
||||
int result, s, e, expected;
|
||||
|
||||
/* Empty bitstr */
|
||||
memset(bitstr, 0, bitstr_size(nbits));
|
||||
bit_count(bitstr, 0, nbits, &result);
|
||||
ATF_CHECK_MSG(0 == result,
|
||||
"bit_count_%d_%s_%s: Failed with result %d",
|
||||
nbits, "clear", memloc, result);
|
||||
|
||||
/* Full bitstr */
|
||||
memset(bitstr, 0xFF, bitstr_size(nbits));
|
||||
bit_count(bitstr, 0, nbits, &result);
|
||||
ATF_CHECK_MSG(nbits == result,
|
||||
"bit_count_%d_%s_%s: Failed with result %d",
|
||||
nbits, "set", memloc, result);
|
||||
|
||||
/* Invalid _start value */
|
||||
memset(bitstr, 0xFF, bitstr_size(nbits));
|
||||
bit_count(bitstr, nbits, nbits, &result);
|
||||
ATF_CHECK_MSG(0 == result,
|
||||
"bit_count_%d_%s_%s: Failed with result %d",
|
||||
nbits, "invalid_start", memloc, result);
|
||||
|
||||
/* Alternating bitstr, starts with 0 */
|
||||
memset(bitstr, 0xAA, bitstr_size(nbits));
|
||||
bit_count(bitstr, 0, nbits, &result);
|
||||
ATF_CHECK_MSG(nbits / 2 == result,
|
||||
"bit_count_%d_%s_%d_%s: Failed with result %d",
|
||||
nbits, "alternating", 0, memloc, result);
|
||||
|
||||
/* Alternating bitstr, starts with 1 */
|
||||
memset(bitstr, 0x55, bitstr_size(nbits));
|
||||
bit_count(bitstr, 0, nbits, &result);
|
||||
ATF_CHECK_MSG((nbits + 1) / 2 == result,
|
||||
"bit_count_%d_%s_%d_%s: Failed with result %d",
|
||||
nbits, "alternating", 1, memloc, result);
|
||||
|
||||
/* Varying start location */
|
||||
memset(bitstr, 0xAA, bitstr_size(nbits));
|
||||
for (s = 0; s < nbits; s++) {
|
||||
expected = s % 2 == 0 ? (nbits - s) / 2 : (nbits - s + 1) / 2;
|
||||
bit_count(bitstr, s, nbits, &result);
|
||||
ATF_CHECK_MSG(expected == result,
|
||||
"bit_count_%d_%s_%d_%s: Failed with result %d",
|
||||
nbits, "vary_start", s, memloc, result);
|
||||
}
|
||||
|
||||
/* Varying end location */
|
||||
memset(bitstr, 0xAA, bitstr_size(nbits));
|
||||
for (e = 0; e < nbits; e++) {
|
||||
bit_count(bitstr, 0, e, &result);
|
||||
ATF_CHECK_MSG(e / 2 == result,
|
||||
"bit_count_%d_%s_%d_%s: Failed with result %d",
|
||||
nbits, "vary_end", e, memloc, result);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ATF_TP_ADD_TCS(tp)
|
||||
{
|
||||
|
||||
@ -354,6 +415,7 @@ ATF_TP_ADD_TCS(tp)
|
||||
BITSTRING_TC_ADD(tp, bit_ffc_at);
|
||||
BITSTRING_TC_ADD(tp, bit_nclear);
|
||||
BITSTRING_TC_ADD(tp, bit_nset);
|
||||
BITSTRING_TC_ADD(tp, bit_count);
|
||||
|
||||
return (atf_no_error());
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user