Skip to content

include: util: Add generic function to count bits set in a value #87943

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

Thalley
Copy link
Contributor

@Thalley Thalley commented Apr 1, 2025

Adds a generic function that will count the number of bits set in a value.

It uses POPCOUNT (e.g. __builtin_popcount for GCC) if available,
or else it will use Brian Kernighan’s Algorithm to count bits.

POPCOUNT will likely always support unsigned ints, but the function
was implemented to use it with uint8_t for the sake of simplicity
and compatibility with Brian Kernighan’s Algorithm.

A generic solution was chosen rather than a macro/function per
type (e.g. uint8_t, uint16_t, etc.) as that is easier to maintain
and also supports array types (e.g. counting the number of bits
in 128 or 256 octet arrays).

fixes #87718

* @param value The value to count number of bits set of
* @param len The number of octets in @p value
*/
static inline size_t zephyr_count_bits(const void *value, size_t len)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tough, this could be just sys_count_bits() use the well-known sys_ prefix and be aligned with existing utils, for unknown reasons some people prefer to use the zephyr_ prefix. But zephyr_ is not really better, because it is also used by many other software projects, and it does not minimize the likelihood of collisions. Instead, we should use UUID version 5 as a prefix, like 7f756fa7_4e84_529e_b406_276069b9bcd0_.

Suggested change
static inline size_t zephyr_count_bits(const void *value, size_t len)
static inline size_t 7f756fa7_4e84_529e_b406_276069b9bcd0_count_bits(const void *const value, const size_t len)
{

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get your point, and I don't really have a strong preference myself. I went with zephyr_ as that seemed like the least controversial output from #64627

but zephyr_ is not really better, because it is also used by many other software projects

Can you share some of these projects so we can consider them properly?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead, we should use UUID version 5 as a prefix, like 7f756fa7_4e84_529e_b406_276069b9bcd0_.

The C language prohibits starting identifiers with a number 🫣

Copy link
Contributor

@jfischer-no jfischer-no Apr 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can use 30a23962-5d6b-4c76-87aa-cc799d50a6a7 and with "Zephyr RTOS" as namespace, which results in c496e475_323e_5ca0_8fa1_39f91557c0e0.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you share some of these projects so we can consider them properly?

There are some cloud and cryptobro projects. Just search for zephyr.

@Thalley Thalley marked this pull request as ready for review April 1, 2025 12:11
@github-actions github-actions bot added area: Testsuite Testsuite Release Notes To be mentioned in the release notes platform: Microchip SAM Microchip SAM Platform (formerly Atmel SAM) area: ADC Analog-to-Digital Converter (ADC) area: Bluetooth Audio labels Apr 1, 2025
@github-actions github-actions bot added area: Kernel area: Samples Samples area: Base OS Base OS Library (lib/os) labels Apr 1, 2025
@Thalley Thalley requested a review from Copilot April 4, 2025 18:30
Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot reviewed 8 out of 9 changed files in this pull request and generated 1 comment.

Files not reviewed (1)
  • doc/releases/release-notes-4.2.rst: Language not supported

@Thalley Thalley force-pushed the zephyr_count_bits branch from a052223 to b659ec7 Compare April 4, 2025 18:51
@Thalley Thalley requested a review from Copilot April 4, 2025 18:51
Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot reviewed 8 out of 9 changed files in this pull request and generated no comments.

Files not reviewed (1)
  • doc/releases/release-notes-4.2.rst: Language not supported

@Thalley Thalley force-pushed the zephyr_count_bits branch from b659ec7 to 70ca373 Compare April 4, 2025 20:46
Comment on lines 797 to 834
#ifdef POPCOUNT
for (; i < len / sizeof(unsigned int); i++) {
unsigned int val = ((unsigned int *)value)[i];

cnt += POPCOUNT(val);
}
i *= sizeof(unsigned int); /* convert to a uint8_t index for the remainder (if any) */
#endif
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

POPCOUNT works very well for unsigned int types for both GCC and Clang. There are additional POPCOUNT functions for other sizes, but not sure if they provide any meaningful optimizations.

It is, however (from my benchmark tests) very important to provide a unsigned int to GCC; there was a factor of more than 10000 in terms of speed on whether I provided a unsigned int or a uint8_t to POPCOUNT, so this version is the fastest I've been able to produce which handles any size, but being extremely fast if POPCOUNT has been defined.

@Thalley Thalley requested a review from Copilot April 4, 2025 20:50
Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot reviewed 8 out of 9 changed files in this pull request and generated no comments.

Files not reviewed (1)
  • doc/releases/release-notes-4.2.rst: Language not supported

@Thalley Thalley force-pushed the zephyr_count_bits branch from 70ca373 to 70e017c Compare April 22, 2025 08:40
@Thalley
Copy link
Contributor Author

Thalley commented Apr 22, 2025

Rebased to fix merge conflicts

@Thalley
Copy link
Contributor Author

Thalley commented May 1, 2025

Also worth mentioning that C23 comes with a stdc_count_ones* set of functions for this purpose too, which seems to be an alternative to POPCOUNT at least

@Thalley Thalley force-pushed the zephyr_count_bits branch from 70e017c to 070c3c7 Compare May 5, 2025 11:02
@pdgendt
Copy link
Contributor

pdgendt commented May 5, 2025

Based on the Arch meeting discussions, and the past vote to keep "area" prefixes, I think sys_count_bits would be preferred now?

@Thalley
Copy link
Contributor Author

Thalley commented May 5, 2025

Based on the Arch meeting discussions, and the past vote to keep "area" prefixes, I think sys_count_bits would be preferred now?

Maybe - The last minutes didn't specify any conclusion, and I'd prefer waiting to update this PR until we reach a consensus to avoid having to update this PR multiple times

@Thalley Thalley force-pushed the zephyr_count_bits branch 3 times, most recently from 93a2909 to 87cac90 Compare May 19, 2025 09:21
@Thalley Thalley force-pushed the zephyr_count_bits branch from 87cac90 to 3f94320 Compare June 16, 2025 11:36
Thalley and others added 4 commits July 1, 2025 14:20
Adds a generic function that will count the number of bits set in
a value.

It uses POPCOUNT (e.g. __builtin_popcount for GCC) if available,
or else it will use Brian Kernighan’s Algorithm to count bits.

POPCOUNT will likely always support unsigned ints, but the function
was implemented to use it with uint8_t for the sake of simplicity
and compatibility with Brian Kernighan’s Algorithm.

A generic solution was chosen rather than a macro/function per
type (e.g. uint8_t, uint16_t, etc.) as that is easier to maintain
and also supports array types (e.g. counting the number of bits
in 128 or 256 octet arrays).

Signed-off-by: Emil Gydesen <emil.gydesen@nordicsemi.no>
Instead of re-implementing or assuming that POPCOUNT is available
we now use the generic function from Zephyr.

Signed-off-by: Emil Gydesen <emil.gydesen@nordicsemi.no>
Adopt new zephyr_count_bits helper from util.h and avoid
having conflicting definition

Signed-off-by: Benjamin Cabé <benjamin@zephyrproject.org>
Signed-off-by: Emil Gydesen <emil.gydesen@nordicsemi.no>
Adopt new zephyr_count_bits helper from util.h and avoid
having conflicting definition

Signed-off-by: Benjamin Cabé <benjamin@zephyrproject.org>
Signed-off-by: Emil Gydesen <emil.gydesen@nordicsemi.no>
@Thalley Thalley force-pushed the zephyr_count_bits branch from 3f94320 to 9f23d9f Compare July 1, 2025 12:20
Copy link
Contributor

@andyross andyross left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hate to be That Guy in a patch that has clearly been through the bike shed too many times already, but there're a ton of whitespace-only changes in that first patch obscuring what is actually a very simple semantic change. Can you split those out?

Copy link

sonarqubecloud bot commented Jul 1, 2025

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: ADC Analog-to-Digital Converter (ADC) area: Base OS Base OS Library (lib/os) area: Bluetooth Audio area: Bluetooth area: Kernel area: Samples Samples area: Testsuite Testsuite platform: Microchip SAM Microchip SAM Platform (formerly Atmel SAM) Release Notes To be mentioned in the release notes
Projects
Status: In Review
Development

Successfully merging this pull request may close these issues.

Update POPCOUNT macro to be type-flexible
7 participants