mirror of https://github.com/mirror/busybox.git
libbb: add bit counting function, use where appropriate
Although "naive" counting function is not too slow and is smaller, using it on e.g. each of 1024 words of CPU mask feels wrong. function old new delta bb_popcnt_32 - 52 +52 get_prefix 323 321 -2 nproc_main 206 199 -7 d4_run_script 739 731 -8 ipcalc_main 533 507 -26 ------------------------------------------------------------------------------ (add/remove: 2/0 grow/shrink: 0/4 up/down: 52/-43) Total: 9 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>master
parent
5a68a246e7
commit
2075553a1b
|
@ -56,13 +56,10 @@ int nproc_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
|
|||
unsigned long *mask = get_malloc_cpu_affinity(0, &sz);
|
||||
sz /= sizeof(long);
|
||||
for (i = 0; i < sz; i++) {
|
||||
unsigned long m = mask[i];
|
||||
while (m) {
|
||||
if (m & 1)
|
||||
count++;
|
||||
m >>= 1;
|
||||
}
|
||||
if (mask[i] != 0) /* most mask[i] are usually 0 */
|
||||
count += bb_popcnt_long(mask[i]);
|
||||
}
|
||||
IF_FEATURE_CLEAN_UP(free(mask);)
|
||||
}
|
||||
|
||||
IF_LONG_OPTS(count -= ignore;)
|
||||
|
|
|
@ -397,6 +397,13 @@ extern int *BB_GLOBAL_CONST bb_errno;
|
|||
uint64_t bb_bswap_64(uint64_t x) FAST_FUNC;
|
||||
#endif
|
||||
|
||||
unsigned FAST_FUNC bb_popcnt_32(uint32_t m);
|
||||
#if ULONG_MAX > 0xffffffff
|
||||
unsigned FAST_FUNC bb_popcnt_long(unsigned_long m);
|
||||
#else
|
||||
#define bb_popcnt_long(m) bb_popcnt_32(m)
|
||||
#endif
|
||||
|
||||
unsigned long FAST_FUNC isqrt(unsigned long long N);
|
||||
|
||||
unsigned long long monotonic_ns(void) FAST_FUNC;
|
||||
|
|
|
@ -72,6 +72,7 @@ lib-y += perror_nomsg.o
|
|||
lib-y += perror_nomsg_and_die.o
|
||||
lib-y += pidfile.o
|
||||
lib-y += platform.o
|
||||
lib-y += popcnt.o
|
||||
lib-y += printable.o
|
||||
lib-y += printable_string.o
|
||||
lib-y += print_flags.o
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* Utility routines.
|
||||
*
|
||||
* Copyright (C) 2024 Denys Vlasenko
|
||||
*
|
||||
* Licensed under GPLv2, see file LICENSE in this source tree.
|
||||
*/
|
||||
#include "libbb.h"
|
||||
|
||||
unsigned FAST_FUNC bb_popcnt_32(uint32_t m)
|
||||
{
|
||||
/* replace each 2 bit group with the count of set bits in it */
|
||||
/* 00->00 01->01 10->01 11->10 */
|
||||
m = m - ((m >> 1) & 0x55555555);
|
||||
/* in each 4 bit group, add two 2-bit counts */
|
||||
m = (m & 0x33333333) + ((m >> 2) & 0x33333333);
|
||||
/* in each 8 bit group, add two 4-bit counts (in fact, 3-bit, 0nnn with n=0..4) */
|
||||
m = (m + (m >> 4)) & 0x0f0f0f0f;
|
||||
#if 1 /* assume 32*32->32 multiply is fast */
|
||||
m = m * 0x01010101; /* top byte = m + (m<<8) + (m<<16) + (m<<24) */
|
||||
return m >> 24;
|
||||
#else
|
||||
/* 0000aaaa0000bbbb0000cccc0000dddd */
|
||||
/* + 0000aaaa0000bbbb0000cccc */
|
||||
/* = 0000xxxx000_a+b_000xxxxx000_c+d_ (we don't care about x bits) */
|
||||
m += m >> 8; /* in each 16-bit group, lowest 5 bits is the count */
|
||||
/* 0000xxxx000_a+b_000xxxxx000_c+d_ */
|
||||
/* + 0000xxxx000_a+b_ */
|
||||
/* = 0000xxxx000xxxxx00xxxxxx00a+b+cd */
|
||||
m += m >> 16; /* in each 32-bit group, lowest 6 bits is the count */
|
||||
return m & 0x3f; /* clear x bits */
|
||||
#endif
|
||||
}
|
||||
|
||||
#if ULONG_MAX > 0xffffffff
|
||||
unsigned FAST_FUNC bb_popcnt_long(unsigned long m)
|
||||
{
|
||||
BUILD_BUG_ON(sizeof(m) != 8);
|
||||
/* 64-bit version of bb_popcnt_32 exists, but it uses 64-bit constants,
|
||||
* which are awkward to generate on assembly level on most CPUs.
|
||||
* For now, just add two 32-bit counts:
|
||||
*/
|
||||
return bb_popcnt_32((uint32_t)m) + bb_popcnt_32((uint32_t)(m >> 32));
|
||||
}
|
||||
#endif
|
|
@ -306,7 +306,6 @@ static int count_netmask_bits(const char *dotted_quad)
|
|||
// d = ~d; /* 11110000 -> 00001111 */
|
||||
|
||||
/* Shorter version */
|
||||
int result;
|
||||
struct in_addr ip;
|
||||
unsigned d;
|
||||
|
||||
|
@ -316,12 +315,7 @@ static int count_netmask_bits(const char *dotted_quad)
|
|||
d = ~d; /* 11110000 -> 00001111 */
|
||||
if (d & (d+1)) /* check that it is in 00001111 form */
|
||||
return -1; /* no it is not */
|
||||
result = 32;
|
||||
while (d) {
|
||||
d >>= 1;
|
||||
result--;
|
||||
}
|
||||
return result;
|
||||
return bb_popcnt_32(~d);
|
||||
}
|
||||
# endif
|
||||
|
||||
|
|
|
@ -71,25 +71,6 @@ static unsigned long get_netmask(unsigned long ipaddr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#if ENABLE_FEATURE_IPCALC_FANCY
|
||||
static int get_prefix(unsigned long netmask)
|
||||
{
|
||||
unsigned long msk = 0x80000000;
|
||||
int ret = 0;
|
||||
|
||||
netmask = htonl(netmask);
|
||||
while (msk) {
|
||||
if (netmask & msk)
|
||||
ret++;
|
||||
msk >>= 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
int get_prefix(unsigned long netmask);
|
||||
#endif
|
||||
|
||||
|
||||
#define NETMASK 0x01
|
||||
#define BROADCAST 0x02
|
||||
#define NETWORK 0x04
|
||||
|
@ -210,7 +191,7 @@ int ipcalc_main(int argc UNUSED_PARAM, char **argv)
|
|||
|
||||
if (ENABLE_FEATURE_IPCALC_FANCY) {
|
||||
if (opt & NETPREFIX) {
|
||||
printf("PREFIX=%i\n", get_prefix(netmask));
|
||||
printf("PREFIX=%i\n", bb_popcnt_32(netmask));
|
||||
}
|
||||
|
||||
if (opt & HOSTNAME) {
|
||||
|
|
|
@ -175,14 +175,13 @@ static void get_prefix_1(inet_prefix *dst, char *arg, int family)
|
|||
if (netmask_pfx.family == AF_INET) {
|
||||
/* fill in prefix length of dotted quad */
|
||||
uint32_t mask = ntohl(netmask_pfx.data[0]);
|
||||
uint32_t host = ~mask;
|
||||
uint32_t inv = ~mask;
|
||||
|
||||
/* a valid netmask must be 2^n - 1 */
|
||||
if (host & (host + 1))
|
||||
goto bad;
|
||||
/* a valid netmask must be 11..10..00 */
|
||||
if (inv & (inv + 1))
|
||||
goto bad; /* inv is not 00..01..11 */
|
||||
|
||||
for (plen = 0; mask; mask <<= 1)
|
||||
++plen;
|
||||
plen = bb_popcnt_32(mask);
|
||||
if (plen > dst->bitlen)
|
||||
goto bad;
|
||||
/* dst->flags |= PREFIXLEN_SPECIFIED; */
|
||||
|
|
|
@ -150,18 +150,6 @@ static int sprint_nip(char *dest, const char *pre, const uint8_t *ip)
|
|||
return sprintf(dest, "%s%u.%u.%u.%u", pre, ip[0], ip[1], ip[2], ip[3]);
|
||||
}
|
||||
|
||||
/* really simple implementation, just count the bits */
|
||||
static int mton(uint32_t mask)
|
||||
{
|
||||
int i = 0;
|
||||
mask = ntohl(mask); /* 111110000-like bit pattern */
|
||||
while (mask) {
|
||||
i++;
|
||||
mask <<= 1;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
#if ENABLE_FEATURE_UDHCPC_SANITIZEOPT
|
||||
/* Check if a given name represents a valid DNS name */
|
||||
/* See RFC1035, 2.3.1 */
|
||||
|
@ -508,7 +496,8 @@ static void fill_envp(struct dhcp_packet *packet)
|
|||
/* Generate extra envvar for DHCP_SUBNET, $mask */
|
||||
uint32_t subnet;
|
||||
move_from_unaligned32(subnet, opt_item->data);
|
||||
putenvp(xasprintf("mask=%u", mton(subnet)));
|
||||
//FIXME: we do not check that subnet has bit pattern 11..10..0
|
||||
putenvp(xasprintf("mask=%u", bb_popcnt_32(subnet)));
|
||||
}
|
||||
} else {
|
||||
unsigned ofs;
|
||||
|
|
Loading…
Reference in New Issue