1
0
mirror of https://github.com/systemd/systemd.git synced 2024-10-27 18:55:40 +03:00

Merge pull request #21531 from keszybz/log2-tables

Optimize log2 tables
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2021-11-29 13:58:49 +01:00 committed by GitHub
commit 4b658ff651
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 189 additions and 115 deletions

View File

@ -345,6 +345,7 @@ possible_common_cc_flags = [
'-Werror=incompatible-pointer-types',
'-Werror=int-conversion',
'-Werror=overflow',
'-Werror=override-init',
'-Werror=return-type',
'-Werror=shift-count-overflow',
'-Werror=shift-overflow=2',

View File

@ -336,7 +336,7 @@ int drop_privileges(uid_t uid, gid_t gid, uint64_t keep_capabilities) {
/* Now upgrade the permitted caps we still kept to effective caps */
if (keep_capabilities != 0) {
cap_value_t bits[u64log2(keep_capabilities) + 1];
cap_value_t bits[log2u64(keep_capabilities) + 1];
_cleanup_cap_free_ cap_t d = NULL;
unsigned i, j = 0;

View File

@ -22,11 +22,20 @@ void in_initrd_force(bool value);
int on_ac_power(void);
static inline unsigned u64log2(uint64_t n) {
/* Note: log2(0) == log2(1) == 0 here and below. */
#define CONST_LOG2ULL(x) ((x) > 1 ? (unsigned) __builtin_clzll(x) ^ 63U : 0)
#define NONCONST_LOG2ULL(x) ({ \
unsigned long long _x = (x); \
_x > 1 ? (unsigned) __builtin_clzll(_x) ^ 63U : 0; \
})
#define LOG2ULL(x) __builtin_choose_expr(__builtin_constant_p(x), CONST_LOG2ULL(x), NONCONST_LOG2ULL(x))
static inline unsigned log2u64(uint64_t x) {
#if __SIZEOF_LONG_LONG__ == 8
return (n > 1) ? (unsigned) __builtin_clzll(n) ^ 63U : 0;
return LOG2ULL(x);
#else
#error "Wut?"
# error "Wut?"
#endif
}
@ -34,26 +43,27 @@ static inline unsigned u32ctz(uint32_t n) {
#if __SIZEOF_INT__ == 4
return n != 0 ? __builtin_ctz(n) : 32;
#else
#error "Wut?"
# error "Wut?"
#endif
}
static inline unsigned log2i(int x) {
assert(x > 0);
#define CONST_LOG2U(x) ((x) > 1 ? __SIZEOF_INT__ * 8 - __builtin_clz(x) - 1 : 0)
#define NONCONST_LOG2U(x) ({ \
unsigned _x = (x); \
_x > 1 ? __SIZEOF_INT__ * 8 - __builtin_clz(_x) - 1 : 0; \
})
#define LOG2U(x) __builtin_choose_expr(__builtin_constant_p(x), CONST_LOG2U(x), NONCONST_LOG2U(x))
return __SIZEOF_INT__ * 8 - __builtin_clz(x) - 1;
static inline unsigned log2i(int x) {
return LOG2U(x);
}
static inline unsigned log2u(unsigned x) {
assert(x > 0);
return sizeof(unsigned) * 8 - __builtin_clz(x) - 1;
return LOG2U(x);
}
static inline unsigned log2u_round_up(unsigned x) {
assert(x > 0);
if (x == 1)
if (x <= 1)
return 0;
return log2u(x - 1) + 1;

View File

@ -162,7 +162,7 @@ static unsigned burst_modulate(unsigned burst, uint64_t available) {
/* Modulates the burst rate a bit with the amount of available
* disk space */
k = u64log2(available);
k = log2u64(available);
/* 1MB */
if (k <= 20)

View File

@ -4218,7 +4218,7 @@ _public_ int sd_event_run(sd_event *e, uint64_t timeout) {
this_run = now(CLOCK_MONOTONIC);
l = u64log2(this_run - e->last_run_usec);
l = log2u64(this_run - e->last_run_usec);
assert(l < ELEMENTSOF(e->delays));
e->delays[l]++;

View File

@ -284,6 +284,12 @@ tests += [
[],
network_includes],
[['src/network/test-networkd-util.c'],
[libnetworkd_core,
libsystemd_network],
[],
network_includes],
[['src/network/test-network.c'],
[libnetworkd_core,
libsystemd_network],

View File

@ -26,33 +26,30 @@
int address_flags_to_string_alloc(uint32_t flags, int family, char **ret) {
_cleanup_free_ char *str = NULL;
static const struct {
uint32_t flag;
const char *name;
} map[] = {
{ IFA_F_SECONDARY, "secondary" }, /* This is also called "temporary" for ipv6. */
{ IFA_F_NODAD, "nodad" },
{ IFA_F_OPTIMISTIC, "optimistic" },
{ IFA_F_DADFAILED, "dadfailed" },
{ IFA_F_HOMEADDRESS, "home-address" },
{ IFA_F_DEPRECATED, "deprecated" },
{ IFA_F_TENTATIVE, "tentative" },
{ IFA_F_PERMANENT, "permanent" },
{ IFA_F_MANAGETEMPADDR, "manage-temporary-address" },
{ IFA_F_NOPREFIXROUTE, "no-prefixroute" },
{ IFA_F_MCAUTOJOIN, "auto-join" },
{ IFA_F_STABLE_PRIVACY, "stable-privacy" },
static const char* map[] = {
[LOG2U(IFA_F_SECONDARY)] = "secondary", /* This is also called "temporary" for ipv6. */
[LOG2U(IFA_F_NODAD)] = "nodad",
[LOG2U(IFA_F_OPTIMISTIC)] = "optimistic",
[LOG2U(IFA_F_DADFAILED)] = "dadfailed",
[LOG2U(IFA_F_HOMEADDRESS)] = "home-address",
[LOG2U(IFA_F_DEPRECATED)] = "deprecated",
[LOG2U(IFA_F_TENTATIVE)] = "tentative",
[LOG2U(IFA_F_PERMANENT)] = "permanent",
[LOG2U(IFA_F_MANAGETEMPADDR)] = "manage-temporary-address",
[LOG2U(IFA_F_NOPREFIXROUTE)] = "no-prefixroute",
[LOG2U(IFA_F_MCAUTOJOIN)] = "auto-join",
[LOG2U(IFA_F_STABLE_PRIVACY)] = "stable-privacy",
};
assert(IN_SET(family, AF_INET, AF_INET6));
assert(ret);
for (size_t i = 0; i < ELEMENTSOF(map); i++)
if (flags & map[i].flag &&
!strextend_with_separator(
&str, ",",
map[i].flag == IFA_F_SECONDARY && family == AF_INET6 ? "temporary" : map[i].name))
return -ENOMEM;
if (FLAGS_SET(flags, 1 << i) && map[i])
if (!strextend_with_separator(
&str, ",",
family == AF_INET6 && (1 << i) == IFA_F_SECONDARY ? "temporary" : map[i]))
return -ENOMEM;
*ret = TAKE_PTR(str);
return 0;

View File

@ -2660,50 +2660,47 @@ int link_call_getlink(Link *link, link_netlink_message_handler_t callback) {
}
static const char* const link_state_table[_LINK_STATE_MAX] = {
[LINK_STATE_PENDING] = "pending",
[LINK_STATE_PENDING] = "pending",
[LINK_STATE_INITIALIZED] = "initialized",
[LINK_STATE_CONFIGURING] = "configuring",
[LINK_STATE_CONFIGURED] = "configured",
[LINK_STATE_UNMANAGED] = "unmanaged",
[LINK_STATE_FAILED] = "failed",
[LINK_STATE_LINGER] = "linger",
[LINK_STATE_CONFIGURED] = "configured",
[LINK_STATE_UNMANAGED] = "unmanaged",
[LINK_STATE_FAILED] = "failed",
[LINK_STATE_LINGER] = "linger",
};
DEFINE_STRING_TABLE_LOOKUP(link_state, LinkState);
int link_flags_to_string_alloc(uint32_t flags, char **ret) {
_cleanup_free_ char *str = NULL;
static const struct {
uint32_t flag;
const char *name;
} map[] = {
{ IFF_UP, "up" }, /* interface is up. */
{ IFF_BROADCAST, "broadcast" }, /* broadcast address valid.*/
{ IFF_DEBUG, "debug" }, /* turn on debugging. */
{ IFF_LOOPBACK, "loopback" }, /* interface is a loopback net. */
{ IFF_POINTOPOINT, "point-to-point" }, /* interface has p-p link. */
{ IFF_NOTRAILERS, "no-trailers" }, /* avoid use of trailers. */
{ IFF_RUNNING, "running" }, /* interface RFC2863 OPER_UP. */
{ IFF_NOARP, "no-arp" }, /* no ARP protocol. */
{ IFF_PROMISC, "promiscuous" }, /* receive all packets. */
{ IFF_ALLMULTI, "all-multicast" }, /* receive all multicast packets. */
{ IFF_MASTER, "master" }, /* master of a load balancer. */
{ IFF_SLAVE, "slave" }, /* slave of a load balancer. */
{ IFF_MULTICAST, "multicast" }, /* supports multicast.*/
{ IFF_PORTSEL, "portsel" }, /* can set media type. */
{ IFF_AUTOMEDIA, "auto-media" }, /* auto media select active. */
{ IFF_DYNAMIC, "dynamic" }, /* dialup device with changing addresses. */
{ IFF_LOWER_UP, "lower-up" }, /* driver signals L1 up. */
{ IFF_DORMANT, "dormant" }, /* driver signals dormant. */
{ IFF_ECHO, "echo" }, /* echo sent packets. */
static const char* map[] = {
[LOG2U(IFF_UP)] = "up", /* interface is up. */
[LOG2U(IFF_BROADCAST)] = "broadcast", /* broadcast address valid.*/
[LOG2U(IFF_DEBUG)] = "debug", /* turn on debugging. */
[LOG2U(IFF_LOOPBACK)] = "loopback", /* interface is a loopback net. */
[LOG2U(IFF_POINTOPOINT)] = "point-to-point", /* interface has p-p link. */
[LOG2U(IFF_NOTRAILERS)] = "no-trailers", /* avoid use of trailers. */
[LOG2U(IFF_RUNNING)] = "running", /* interface RFC2863 OPER_UP. */
[LOG2U(IFF_NOARP)] = "no-arp", /* no ARP protocol. */
[LOG2U(IFF_PROMISC)] = "promiscuous", /* receive all packets. */
[LOG2U(IFF_ALLMULTI)] = "all-multicast", /* receive all multicast packets. */
[LOG2U(IFF_MASTER)] = "master", /* master of a load balancer. */
[LOG2U(IFF_SLAVE)] = "slave", /* slave of a load balancer. */
[LOG2U(IFF_MULTICAST)] = "multicast", /* supports multicast.*/
[LOG2U(IFF_PORTSEL)] = "portsel", /* can set media type. */
[LOG2U(IFF_AUTOMEDIA)] = "auto-media", /* auto media select active. */
[LOG2U(IFF_DYNAMIC)] = "dynamic", /* dialup device with changing addresses. */
[LOG2U(IFF_LOWER_UP)] = "lower-up", /* driver signals L1 up. */
[LOG2U(IFF_DORMANT)] = "dormant", /* driver signals dormant. */
[LOG2U(IFF_ECHO)] = "echo", /* echo sent packets. */
};
assert(ret);
for (size_t i = 0; i < ELEMENTSOF(map); i++)
if (flags & map[i].flag &&
!strextend_with_separator(&str, ",", map[i].name))
return -ENOMEM;
if (FLAGS_SET(flags, 1 << i) && map[i])
if (!strextend_with_separator(&str, ",", map[i]))
return -ENOMEM;
*ret = TAKE_PTR(str);
return 0;

View File

@ -221,25 +221,22 @@ DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(route_protocol_full, int, UINT8_MAX);
int route_flags_to_string_alloc(uint32_t flags, char **ret) {
_cleanup_free_ char *str = NULL;
static const struct {
uint32_t flag;
const char *name;
} map[] = {
{ RTNH_F_DEAD, "dead" }, /* Nexthop is dead (used by multipath) */
{ RTNH_F_PERVASIVE, "pervasive" }, /* Do recursive gateway lookup */
{ RTNH_F_ONLINK, "onlink" }, /* Gateway is forced on link */
{ RTNH_F_OFFLOAD, "offload" }, /* Nexthop is offloaded */
{ RTNH_F_LINKDOWN, "linkdown" }, /* carrier-down on nexthop */
{ RTNH_F_UNRESOLVED, "unresolved" }, /* The entry is unresolved (ipmr) */
{ RTNH_F_TRAP, "trap" }, /* Nexthop is trapping packets */
static const char* map[] = {
[LOG2U(RTNH_F_DEAD)] = "dead", /* Nexthop is dead (used by multipath) */
[LOG2U(RTNH_F_PERVASIVE)] = "pervasive", /* Do recursive gateway lookup */
[LOG2U(RTNH_F_ONLINK)] = "onlink" , /* Gateway is forced on link */
[LOG2U(RTNH_F_OFFLOAD)] = "offload", /* Nexthop is offloaded */
[LOG2U(RTNH_F_LINKDOWN)] = "linkdown", /* carrier-down on nexthop */
[LOG2U(RTNH_F_UNRESOLVED)] = "unresolved", /* The entry is unresolved (ipmr) */
[LOG2U(RTNH_F_TRAP)] = "trap", /* Nexthop is trapping packets */
};
assert(ret);
for (size_t i = 0; i < ELEMENTSOF(map); i++)
if (flags & map[i].flag &&
!strextend_with_separator(&str, ",", map[i].name))
return -ENOMEM;
if (FLAGS_SET(flags, 1 << i) && map[i])
if (!strextend_with_separator(&str, ",", map[i]))
return -ENOMEM;
*ret = TAKE_PTR(str);
return 0;

View File

@ -24,25 +24,25 @@ static const char * const network_config_source_table[_NETWORK_CONFIG_SOURCE_MAX
DEFINE_STRING_TABLE_LOOKUP_TO_STRING(network_config_source, NetworkConfigSource);
int network_config_state_to_string_alloc(NetworkConfigState s, char **ret) {
static const struct {
NetworkConfigState state;
const char *str;
} map[] = {
{ .state = NETWORK_CONFIG_STATE_PROBING, .str = "probing", },
{ .state = NETWORK_CONFIG_STATE_REQUESTING, .str = "requesting", },
{ .state = NETWORK_CONFIG_STATE_CONFIGURING, .str = "configuring", },
{ .state = NETWORK_CONFIG_STATE_CONFIGURED, .str = "configured", },
{ .state = NETWORK_CONFIG_STATE_MARKED, .str = "marked", },
{ .state = NETWORK_CONFIG_STATE_REMOVING, .str = "removing", },
static const char* states[] = {
[LOG2U(NETWORK_CONFIG_STATE_PROBING)] = "probing",
[LOG2U(NETWORK_CONFIG_STATE_REQUESTING)] = "requesting",
[LOG2U(NETWORK_CONFIG_STATE_CONFIGURING)] = "configuring",
[LOG2U(NETWORK_CONFIG_STATE_CONFIGURED)] = "configured",
[LOG2U(NETWORK_CONFIG_STATE_MARKED)] = "marked",
[LOG2U(NETWORK_CONFIG_STATE_REMOVING)] = "removing",
};
_cleanup_free_ char *buf = NULL;
assert(ret);
for (size_t i = 0; i < ELEMENTSOF(map); i++)
if (FLAGS_SET(s, map[i].state) &&
!strextend_with_separator(&buf, ",", map[i].str))
return -ENOMEM;
for (size_t i = 0; i < ELEMENTSOF(states); i++)
if (FLAGS_SET(s, 1 << i)) {
assert(states[i]);
if (!strextend_with_separator(&buf, ",", states[i]))
return -ENOMEM;
}
*ret = TAKE_PTR(buf);
return 0;

View File

@ -0,0 +1,19 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "networkd-util.h"
#include "tests.h"
TEST(network_config_state_to_string_alloc) {
for (unsigned i = 1; i <= NETWORK_CONFIG_STATE_REMOVING; i <<= 1) {
_cleanup_free_ char *x;
assert_se(network_config_state_to_string_alloc(i, &x) == 0);
log_debug("%u → %s", i, x);
}
_cleanup_free_ char *x;
assert_se(network_config_state_to_string_alloc(~0u, &x) == 0);
log_debug("%u → %s", ~0u, x);
};
DEFINE_TEST_MAIN(LOG_DEBUG);

View File

@ -17,14 +17,72 @@
#include "tests.h"
#include "util.h"
TEST(u64log2) {
assert_se(u64log2(0) == 0);
assert_se(u64log2(8) == 3);
assert_se(u64log2(9) == 3);
assert_se(u64log2(15) == 3);
assert_se(u64log2(16) == 4);
assert_se(u64log2(1024*1024) == 20);
assert_se(u64log2(1024*1024+5) == 20);
TEST(LOG2ULL) {
assert_se(LOG2ULL(0) == 0);
assert_se(LOG2ULL(1) == 0);
assert_se(LOG2ULL(8) == 3);
assert_se(LOG2ULL(9) == 3);
assert_se(LOG2ULL(15) == 3);
assert_se(LOG2ULL(16) == 4);
assert_se(LOG2ULL(1024*1024) == 20);
assert_se(LOG2ULL(1024*1024+5) == 20);
}
TEST(CONST_LOG2ULL) {
assert_se(CONST_LOG2ULL(0) == 0);
assert_se(CONST_LOG2ULL(1) == 0);
assert_se(CONST_LOG2ULL(8) == 3);
assert_se(CONST_LOG2ULL(9) == 3);
assert_se(CONST_LOG2ULL(15) == 3);
assert_se(CONST_LOG2ULL(16) == 4);
assert_se(CONST_LOG2ULL(1024*1024) == 20);
assert_se(CONST_LOG2ULL(1024*1024+5) == 20);
}
TEST(NONCONST_LOG2ULL) {
assert_se(NONCONST_LOG2ULL(0) == 0);
assert_se(NONCONST_LOG2ULL(1) == 0);
assert_se(NONCONST_LOG2ULL(8) == 3);
assert_se(NONCONST_LOG2ULL(9) == 3);
assert_se(NONCONST_LOG2ULL(15) == 3);
assert_se(NONCONST_LOG2ULL(16) == 4);
assert_se(NONCONST_LOG2ULL(1024*1024) == 20);
assert_se(NONCONST_LOG2ULL(1024*1024+5) == 20);
}
TEST(log2u64) {
assert_se(log2u64(0) == 0);
assert_se(log2u64(1) == 0);
assert_se(log2u64(8) == 3);
assert_se(log2u64(9) == 3);
assert_se(log2u64(15) == 3);
assert_se(log2u64(16) == 4);
assert_se(log2u64(1024*1024) == 20);
assert_se(log2u64(1024*1024+5) == 20);
}
TEST(log2u) {
assert_se(log2u(0) == 0);
assert_se(log2u(1) == 0);
assert_se(log2u(2) == 1);
assert_se(log2u(3) == 1);
assert_se(log2u(4) == 2);
assert_se(log2u(32) == 5);
assert_se(log2u(33) == 5);
assert_se(log2u(63) == 5);
assert_se(log2u(INT_MAX) == sizeof(int)*8-2);
}
TEST(log2i) {
assert_se(log2i(0) == 0);
assert_se(log2i(1) == 0);
assert_se(log2i(2) == 1);
assert_se(log2i(3) == 1);
assert_se(log2i(4) == 2);
assert_se(log2i(32) == 5);
assert_se(log2i(33) == 5);
assert_se(log2i(63) == 5);
assert_se(log2i(INT_MAX) == sizeof(int)*8-2);
}
TEST(protect_errno) {
@ -58,17 +116,6 @@ TEST(unprotect_errno) {
assert_se(errno == 4711);
}
TEST(log2i) {
assert_se(log2i(1) == 0);
assert_se(log2i(2) == 1);
assert_se(log2i(3) == 1);
assert_se(log2i(4) == 2);
assert_se(log2i(32) == 5);
assert_se(log2i(33) == 5);
assert_se(log2i(63) == 5);
assert_se(log2i(INT_MAX) == sizeof(int)*8-2);
}
TEST(eqzero) {
const uint32_t zeros[] = {0, 0, 0};
const uint32_t ones[] = {1, 1};