7

I read in the book "Game Engine Architecture" by Jason Gregory that:

"It’s possible to access data items that are narrower than the width of a machine’s data bus, but it’s typically more costly than accessing items whose widths match that of the data bus. For example, when reading a 16-bit value on a 64-bit machine, a full 64 bits worth of data must still be read from memory. The desired 16-bit field then has to be masked off and possibly shifted into place within the destination register."

So, if I just use long long (64 bit integers), will my code be faster than if I use less bits integers (short, int)? If so, why still using shorts and ints if we can get larger values (when needed) and faster code with just long longs?

7
  • Does this answer your question? Is micro-optimisation important when coding?
    – gnat
    Jun 6, 2020 at 18:25
  • 4
    @gnat no, it doesn't.
    – user360409
    Jun 6, 2020 at 18:28
  • 4
    It depends on the specific CPU. Accessing smaller or misaligned data is slower on some chips but not on other chips.
    – cwallach
    Jun 6, 2020 at 18:57
  • Your question is too theoretical to get a single answer because you are not applying the information that you read to a specific situation. As it says, accessing items with different width is "typically" more costly, but as others have commented, it depends. You are likely getting these down votes because your question is too general.
    – Jason K.
    Jun 9, 2020 at 0:01
  • 3
    If you're writing C, just use an appropriate fixed width integer type like uint_fast32_t (the fastest unsigned int with at least 32 bits), instead of less clear types like long. Let the compiler do the difficult work of figuring out the very best representation.
    – amon
    Jun 17, 2020 at 19:44

5 Answers 5

9

In practice, it's not going to matter most of the time.

  1. It won't matter in most programs.
  2. For some programs where it might potentially matter, it might still not matter because there's no significant, measurable performance difference.
  3. For those programs where there is a measurable performance difference, it might still not matter because the program performs adequately anyway.

And so, in order for this to matter, there must be:

  1. A performance difference,
  2. That can be measured,
  3. Where that measurable performance difference materially impacts your application.

"Materially" means that:

  1. The measured performance difference is significant enough to cause one of your performance requirements to fail, and
  2. Using the higher-performing technique, either alone or in concert with other improvement techniques, causes the performance requirement to succeed, as measured by your performance tests.

In short, measure. Profile your code using both techniques, and then use those measurements to determine what to do. It's the only way to be sure.


Incidentally, this is the reason many programming languages use a 32 bit signed integer as the default numeric type. It's usually the best compromise for speed, flexibility, storage space and numeric resolution.

7
  • C and C++ use 32 bit int because otherwise there is no 32 bit type available (char = 8 bit, short = 16 bit or you have no 16 bit type, int must be 32 bit or you have no 32 bit type). Swift on 64 bit devices has Int = 64 bit, but also has Int8, Int16, Int32 and Int64 so the problem that C has is avoided.
    – gnasher729
    Jun 6, 2020 at 18:53
  • 4
    @gnasher729 C and C++ have had integer types of guaranteed width for decades now (stdint.h from C99, which has int32_t)
    – gntskn
    Jun 16, 2020 at 3:14
  • Gntskn They are not guaranteed to be available. And if int > 32 bit then the compiler has a problem.
    – gnasher729
    Jun 23, 2020 at 18:08
  • 1
    @gnasher729 what stops a compiler providing int32_t alongside a 64 bit int?
    – Caleth
    Jun 24, 2020 at 8:15
  • Just ran a .NET6/C# test on my Ryzen 3800XT. It does 500 million empty loops in a second, when using an int (32 bit) as the iteration variable. It does 1 billion empty loops in a second, when I use a long (64 bit).
    – Jay
    Nov 17, 2021 at 18:24
9

Robert Harvey's answer is fully correct, but since you mentioned Game Engine Architecture, I think it is worth to add a few words to the case where speed actually could matter.

The described effect of "more CPU work" when "reading a 16-bit value on a 64-bit machine" is something which on some CPUs may occur, and on other's not. But when all what happens in a bottleneck section of a program is 32 bit integer arithmetic, then replacing 32 bit variables blindly by 64 bit variables will seldom speed up a program. Quite the opposite, this introduces the risk of making a program exhaust the CPU caches or the available RAM earlier, which can easily result in slowing it down.

In my experience, for gaining a noteable speed by more bits, one needs to utilize the extra bits actively. This can be achieved, for example,

  • by using adapted algorithms (like memory copying with 64 bits)

  • by using certain SIMD instructions which make use of the broader data bus.

I have never seen any noteable performance gain in a real world program by replacing 32 bit int data type by a 64 bit long long without changing anything else.

3

So, if I just use long long (64 bit integers), will my code be faster than if I use less bits integers

Not automatically no. Robert has already covered the most of it. But there was one thing I thougtht was worth mentioning. If you save four 16 bit integers in one 64 bit integer, you will of course have a bit overhead separating them. But the code can become much more cache friendly, which can impact performance to a quite large degree in some cases.

I once had an array of one million 32 bit ints and I treated them as Boolean variables. But when I changed so that each individual bit was a Boolean, then the array could be just 1/32 of the original size, which made the code MUCH faster.

It is correct that using the native word size may require less cpu instructions to do what you want, but this is not certain. The cpu may contain special instructions to deal with word fractions. But even if it really yields less cpu instructions, it still don't automatically transform into better performance.

3
  • "It is correct that using the native word size will require less cpu instructions to do what you want. " -- also note that x86-64 has native instructions for handling 8-bit, 16-bit and 32-bit values, as well as 64-bit. There should be no performance penalty for using those, as long as you ensure all data is correctly aligned. This is especially true if you perform the same operation on large numbers of them, because then SSE (or similar) instructions can be used to workon themin parallel.
    – occipita
    Jun 15, 2020 at 22:52
  • @occipita True. Maybe I'll add a point about that, but we'll see. I think may main point with my post is still about the cache.
    – klutt
    Jun 15, 2020 at 23:49
  • @occipita fixed
    – klutt
    Jun 17, 2020 at 19:07
0

How many integers are we talking about? 1, 10, or 10 million?

For significant amounts of data cache usage is important. If 20,000 16 bit ints fit into L1 cache, and 20,000 64 bit ints don’t, then 16 bit will be a lot faster. If you look at individual variables, the opposite is true. The native size will be fastest. And there can be a huge difference with SIMD processors: if you have 256 bit registers you will handle sixteen 16-bit values in one instruction as fast as four 64-bit values.

0

Addressing a specific part of your quote:

For example, when reading a 16-bit value on a 64-bit machine, a full 64 bits worth of data must still be read from memory. The desired 16-bit field then has to be masked off and possibly shifted into place within the destination register.

This is true for some architectures, but not all of them. Particularly, the x86-64 architecture has instructions for working directly with 16-bit values, so doing so on that architecture will not require mask and shift operations. Futhermore, while 64 bits[1] will still be fetched from memory, if subsequent instructions need to use the data in the other 48 bits they will be able to do so without needing to access main memory again due to the processor's cache. For this architecture specifically, therefore, this advice is wrong.

[1]: or, more likely, 128 bits, as this is the width of the cache on most modern processors

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.