Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When and why would I want to use i8 instead of i32?

Tags:

integer

rust

I think the default size in rust is 32 bits, signed, when assigning a variable to an integer value.

Provided I'm dealing with a value that fits in 16 bits (e.g 15000) or even 8 bits (e.g 120), why would I want to NOT still just use the default?

I'd probably be saving some memory - but is this worth the consideration? And is there any speed advantage? What else, if anything?

like image 596
Daniel Avatar asked Oct 22 '25 23:10

Daniel


2 Answers

TL;DR: For Performance.

Quickly

Performance is a complex topic, in general, so which type to choose will vary wildly between usecases.

In general, though, there are two major reasons to choose smaller data-types:

  • Better cache utilization.
  • SIMD.

Better cache utilization

Modern CPUs have gotten faster, and RAM did not follow. Long are the days where the frequency of the RAM was equal to that of the CPU.

This is where caches come in: L1, L2, and L3 on a typical desktop CPU. The problem is that physical limits are at play, which themselves limit the size of those caches. A typical L1 cache is 32KB instructions / 32KB data, with 64 bytes cache lines.

32KB data is:

  • 8K i32.
  • 16K i16.
  • 32K i8.

Tighter data-packing can therefore be used to:

  • Fit more data in L1 (or L2, L3, ...).
  • Fit the data in less cache lines.

In short, tighter packing enables better cache utilization.

SIMD

One of the latest hash-table design in Abseil's Swiss Table.

Abseil's Swiss Table main trick is creating groups of 16 elements, and having a 16 bytes header for each group which contains a 1-byte (u8) hash residual for each element of the group.

A single SIMD instruction (SSE2 is 16-bytes wide) allows looking up for the hash residual across all 16 elements, and identifying which elements match!

This is a general theme in SIMD, the instructions have very limited operands:

  • SSE is 16 bytes (128 bits),
  • AVX is 32 bytes (256 bits),
  • AVX-512 is 64 bytes (512 bits).

With SIMD instructions, dividing the size of the element by 2 immediately means processing 2x as many elements in a single instruction, thereby speeding algorithms up to 2x.

like image 114
Matthieu M. Avatar answered Oct 24 '25 14:10

Matthieu M.


In cases such as an embedded system, a data transfer protocol or anything else where the net storage and transfer of data is a main concern, using i8 and i16 and such others is a really good idea. Also, the compiler rearranges struct fields to make the struct more compact, which it can do more efficiently when the fields are smaller.

But for the general case, so whenever as you say, you have values that always fit in 16 or 8 bits... I'm not sure there's a clear-cut answer. I would say that the speed at least would end up being architecture-dependent.

User trentcl has just linked to this post over at the Discourse forums, which I think illustrates many points of view regarding the general case.

like image 33
felix91gr Avatar answered Oct 24 '25 15:10

felix91gr