【发布时间】:2014-09-23 23:01:47
【问题描述】:
#include <iostream>
#include <stdint.h>
using namespace std;
struct UIContainer {
uint16_t x, y; //Position on the screen
uint16_t h, w; //Height and width of the UIContainer
uint16_t color; //Color, rgba such as 0xFF000000 & color is red, 0x00FF0000 is green, 0x0000FF00 is blue, 0x000000FF is alpha
uint16_t ID; //Unique ID of the ui container
}; //16 bytes big
void drawUI(UIContainer _container, SDL_Renderer* _renderer) {
SDL_Rect rect {.x = _container.x, .y = _container.y, .h = _container.h, .w = _container.w }
uint8_t r = color & 0xFF000000;
uint8_t g = color & 0x00FF0000;
uint8_t b = color & 0x0000FF00;
uint8_t a = color & 0x000000FF;
SDL_SetRenderDrawColor(_renderer, r, g, b, a);
SDL_RenderFillRect(_renderer, &rect);
}
int main()
{
UIContainer UIContainers[1024]; //16 * 1024 is 16384 bytes = 16 kilobytes
SDL_Renderer* renderer; //Pretend it is initialized
//Draw all the UI
int i = 0;
for(i; i < 1024; ++i) {
drawUI(_container, renderer);
}
return 0;
}
我决定尝试了解数据本地化以及如何提高缓存的利用率。假设 L1 缓存为 64 KB,我假设 UIContainer 的整个数组将被加载到缓存中是正确的,因为 16KB 小于 64KB?如果缓存行是 128 字节,那将是每行 8 个 UIContainer 块?
据我了解,当某些内容当前不在缓存中时,会发生缓存未命中。这也适用于缓存行吗?例如,我在容器 [3] 上操作,然后我想跳到容器 [100],这会导致缓存未命中,因为它必须跳到容器 [100] 所在的任何缓存行?
最后,假设我将 UIContainer 的所有内部部分提取到它们自己的单独数组中,因此代码现在看起来像:
#include <iostream>
#include <stdint.h>
using namespace std;
struct location {
uint16_t x, y; //Position on the screen
}; //4 bytes
struct size {
uint16_t h, w; //Height and width of the UIContainer
}; //4 bytes
struct color {
uint32_t color; //Color, rgba such as 0xFF000000 & color is red, 0x00FF0000 is green, 0x0000FF00 is blue, 0x000000FF is alpha
} //4 bytes
struct UIContainer {
uint32_t ID; //Unique ID of the ui container
}; //4 bytes
void drawUI(location l, size s, color c, SDL_Renderer* _renderer) {
SDL_Rect rect {.x = l.x, .y = l.y, .h = s.h, .w = s.w }
uint8_t r = c & 0xFF000000;
uint8_t g = c & 0x00FF0000;
uint8_t b = c & 0x0000FF00;
uint8_t a = c & 0x000000FF;
SDL_SetRenderDrawColor(_renderer, r, g, b, a);
SDL_RenderFillRect(_renderer, &rect);
}
int main()
{
UIContainer UIContainers[1024]; //4 * 1024 is 4048 bytes = 4 kilobytes
location _location[1024]; //4 KB
size _size[1024]; //4KB
color _color[1024]; //4KB
//////////////////////////////////////// 16 KB Total
SDL_Renderer* renderer; //Pretend it is initialized
//Draw all the UI
int i = 0;
for(i; i < 1024; ++i) {
drawUI(_location[i], _size[i], _color[i], renderer);
}
return 0;
}
这会导致缓存未命中吗?我认为不会,因为 _location[]、_size[] 和 _color[] 都在缓存中,并且被线性访问?还是我错过了什么?
【问题讨论】:
-
你在实现编译器吗?如果不是,您可能不应该在意,只要数据是连续排列的,直到您通过测量证明存在问题。
-
“你可能不关心”实际上是最糟糕的建议,尤其是当“我决定尝试了解数据本地化以及如何提高缓存的利用率。”
-
缓存行为并非完全可预测且极其复杂。您可能需要查看what every programmer needs to know about memory 以了解其工作原理。
-
好吧,直到您看到(通过测量)某些代码对于您的特定用例来说太慢了,优化您的特定代码是浪费时间。缓存利用率本身是一个非常复杂的领域(就像所有指令级优化一样),它不(或不应该)依赖于除了连续/非连续数据布局之外的“高级”代码。如果您确实实现了编译器,那么您必须关心,如果没有,编译器应该(并且如果体面的话)会关心您。这实际上与您的特定代码无关,而是与应如何将特定 C++ 语法转换为程序集有关。
-
@Baum 这是一个糟糕的建议。如果你关心高性能,你真的需要在你的算法中考虑缓存行为。假设我要实现软件光栅化器,我知道(无需测量)我应该使用混合纹理布局而不是线性,以获得更好的缓存一致性和性能。编译器不会提高算法的缓存一致性。