Live data from Hacker News

Feel the cache size: a definitive experiment

melikyan.blogspot.com

21–30 of 33 posts

Re: Feel the cache size: a definitive experiment

#21
post #15

Earlier quoted context omitted.

Not sure I understand your question, but all kinds of juggling with pointers is I think idiomatic in C.

Since not every one got it: in C, the difference between two pointers of type (T *) is the difference in (byte) addresses divided by sizeof(T). In other words, pointer subtraction gives an index (of integral type ptrdiff_t, which should be 64bit if pointers are). For all p2 and p1 pointing to the same type, p2==p1[p2-p1].

[deleted]

Re: Feel the cache size: a definitive experiment

#22
post #15

Earlier quoted context omitted.

Not sure I understand your question, but all kinds of juggling with pointers is I think idiomatic in C.

Since not every one got it: in C, the difference between two pointers of type (T *) is the difference in (byte) addresses divided by sizeof(T). In other words, pointer subtraction gives an index (of integral type ptrdiff_t, which should be 64bit if pointers are). For all p2 and p1 pointing to the same type, p2==p1[p2-p1].

Not exactly. The standard only defines pointer subtraction between two pointers that point into the same array object. That's not what's going on here. If he had written

    ((func_table+max) - (func_table+0))
then yes you would just get max. The difference is that (func_table[max] - func_table[0]) is actually

    (*(func_table+max) - *(func_table+0))
which is subtraction of two arbitrary function pointers. It's not covered by the standard. In this case GCC is just subtracting the two addresses, with no division. His results (and mine above) bear this out. If you compile with -pedantic you'll actually get a warning about it.

Re: Feel the cache size: a definitive experiment

#23

This article is not really about the memory cache hierarchy. It's an excuse to show off the author's exciting new algorithm for computing the value of the integer "max": (func_table[max] - func_table[0]).

You idiot! What you wrote would have been true only if the expression were &func_table[max] - &func_table[0]. However, you make a good point: the difference between two pointers is in multiples of the pointed-to size. It's not 11 bytes per function, but rather 11 * sizeof(pointer to function type) - probably 11 * 4 = 44 bytes. (the author is lucky that the functions are indeed laid out consecutively in memory) When y…

Yeah, that's what I was getting at.

Re: Feel the cache size: a definitive experiment

#24
post #15
post #13

Earlier quoted context omitted.

Right. What I meant was that (func_table[max] - func_table[0]) is equivalent to (in the example assembly given) max * 11. When I asked if there was more idiomatic way to do this, I meant more idiomatic than the original code, not actually using (max*11) in the code.

Not sure I understand your question, but all kinds of juggling with pointers is I think idiomatic in C.

Yeah, I thought the top comment was saying that the way the author did it wasn't idiomatic, in which case I was wondering what is.

Re: Feel the cache size: a definitive experiment

#25
Isn't this 'definitive experiment' just showing that code which doesn't take advantage of locality of reference is bound to be really slow if it is larger than the cache size?

I mean, he's just executing trivial code from random locations in memory - not a typical access pattern at all. Because of this, the experiment exaggerates the effect of code size on performance. For example, if you had a 1 million line program that didn't loop, it's performance would not degrade nearly as much as his results imply.

Re: Feel the cache size: a definitive experiment

#26

Isn't this 'definitive experiment' just showing that code which doesn't take advantage of locality of reference is bound to be really slow if it is larger than the cache size? I mean, he's just executing trivial code from random locations in memory - not a typical access pattern at all. Because of this, the experiment exaggerates the effect of code size on performance. For example, if you had a 1 million line program…

Exactly. This experiment shows pretty much the opposite of what it aims to prove. It shows that code bloat is completely irrelevant as long as locality is taken into account in performance critical parts of the code.

The "valuable" lession we can learn from this is this: Never access a million random memory locations in your innermost loop :-)

Re: Feel the cache size: a definitive experiment

#27
The massive difference in random access speeds in comparison to sequential speeds is the thing that changed in the last 15 years. The gap between memory clock speed and CPU clock speed has been increasing for all this time, whereas prior to that they were often similar.

The impact is that random access has suffered and cache has become vital in coping with the majority of those seemingly random jumps. Algorithms like quicksort benefit from locality of reference and hence better utilise the cache than algorithms that theorectically do less work.

Its interesting to see it jump like this, but its not indicative of large programs so much as it is indicative of what happens when you randomly access memory and effectively nullify your cache and your memorys DDR properties. Thankfully most programs don't in practice do this, if they did the programs would run about as well as they did in the mid 90's on an original Pentium.

Re: Feel the cache size: a definitive experiment

#28
post #23

Earlier quoted context omitted.

You idiot! What you wrote would have been true only if the expression were &func_table[max] - &func_table[0]. However, you make a good point: the difference between two pointers is in multiples of the pointed-to size. It's not 11 bytes per function, but rather 11 * sizeof(pointer to function type) - probably 11 * 4 = 44 bytes. (the author is lucky that the functions are indeed laid out consecutively in memory) When y…

Yeah, that's what I was getting at.

I would have gone on being Wrong on the Internet forever had nobody replied. Thanks for catching my buggy thought :)

Re: Feel the cache size: a definitive experiment

#29
post #22

Earlier quoted context omitted.

Since not every one got it: in C, the difference between two pointers of type (T *) is the difference in (byte) addresses divided by sizeof(T). In other words, pointer subtraction gives an index (of integral type ptrdiff_t, which should be 64bit if pointers are). For all p2 and p1 pointing to the same type, p2==p1[p2-p1].

Not exactly. The standard only defines pointer subtraction between two pointers that point into the same array object. That's not what's going on here. If he had written ((func_table+max) - (func_table+0)) then yes you would just get max. The difference is that (func_table[max] - func_table[0]) is actually (*(func_table+max) - *(func_table+0)) which is subtraction of two arbitrary function pointers. It's not covered…

I'd noticed that I misread the original code and replied to my top-level post.

But that's an interesting point about the standard - perhaps it's intended to allow a smaller sizeof(ptrdiff_t) than sizeof(void *), where no contiguous allocation would be allowed such that you the larger type.

Re: Feel the cache size: a definitive experiment

#30

Isn't this 'definitive experiment' just showing that code which doesn't take advantage of locality of reference is bound to be really slow if it is larger than the cache size? I mean, he's just executing trivial code from random locations in memory - not a typical access pattern at all. Because of this, the experiment exaggerates the effect of code size on performance. For example, if you had a 1 million line program…

The experiment does exaggarate the impact indeed, but I think there are real-world examples that are pretty close to it. For one thing, some bloated virtual machines. Let the effect of optimization of your VM be 20%, not 15 times, then 20% would be a huge gain you might struggle for if this is the runtime environment for your language.
Post reply on HN