On Fri Mar 7, 2025 at 7:36 AM CET, Alexei Starovoitov wrote: > On Wed, Mar 5, 2025 at 6:33 AM <arthur@xxxxxxxxxxxxxxx> wrote: > > > > +struct __trait_hdr { > > + /* Values are stored ordered by key, immediately after the header. > > + * > > + * The size of each value set is stored in the header as two bits: > > + * - 00: Not set. > > + * - 01: 2 bytes. > > + * - 10: 4 bytes. > > + * - 11: 8 bytes. > > ... > > > + * - hweight(low) + hweight(high)<<1 is offset. > > the comment doesn't match the code > > > + */ > > + u64 high; > > + u64 low; > > ... > > > +static __always_inline int __trait_total_length(struct __trait_hdr h) > > +{ > > + return (hweight64(h.low) << 1) + (hweight64(h.high) << 2) > > + // For size 8, we only get 4+2=6. Add another 2 in. > > + + (hweight64(h.high & h.low) << 1); > > +} > > This is really cool idea, but 2 byte size doesn't feel that useful. > How about: > - 00: Not set. > - 01: 4 bytes. > - 10: 8 bytes. > - 11: 16 bytes. > > 4 byte may be useful for ipv4, 16 for ipv6, and 8 is just a good number. > And compute the same way with 3 popcount with extra +1 to shifts. I chose the sizes arbitrarily, happy to change them. 16 is also useful for UUIDs, for tracing. Size 0 could store bools / flags. Keys could be set without a value, and users could check if the key is set or not. That replaces single bits of the mark today, for example a "route locally" key. That only leaves one other size, maybe 4 for smaller values? If we want more sizes, we could also: - Add another u64 word to the header, so we have 3 bits per key. It uses more room, and we need more popcnts, but most modern x86 CPUs can do 3 popcnts in parallel so it could be ok. - Let users set consecutive keys to one big value. Instead of supporting size 16, we let them set two 8 byte KVs in one trait_set() call and provide a 16 byte value. Eg: trait_set_batch(u64 key_from, u64_key_to, size, ...); It's easy to implement, but it makes the API more complicated.