Шаблон класса для использования кеш-памяти в C ++ - PullRequest
3 голосов
/ 18 января 2011

(чтобы предоставить информацию, необходимую для понимания моего вопроса, достаточно много, но он уже сжат)

Я пытаюсь реализовать шаблон класса для распределения и доступа к кэшу данных.Это работает очень хорошо, однако попытка реализовать поддержку массивов является проблемой.

Семантически код должен обеспечивать это отображение в памяти для одного элемента, подобного этому:

cache_aligned<element_type>* my_el = 
          new(cache_line_size) cache_aligned<element_type>();
| element | buffer |

access (пока) выглядит так:

*my_el; // returns cache_aligned<element_type>
**my_el; //returns element_type
*my_el->member_of_element();

ОДНАКО для массива, я хотел бы иметь это:

 cache_aligned<element_type>* my_el_array = 
         new(cache_line_size)  cache_aligned<element_type()[N];
 | element 0 | buffer | element 1 | buffer | ... | element (N-1) | buffer |

Пока у меня есть следующий код

template <typename T>
class cache_aligned {
    private:
        T instance;
    public:
        cache_aligned()
        {}
        cache_aligned(const T& other)
        :instance(other.instance)
        {}
        static void* operator new (size_t size, uint c_line_size) {
             return c_a_malloc(size, c_line_size);
        }
        static void* operator new[] (size_t size, uint c_line_size) {
             int num_el = (size - sizeof(cache_aligned<T>*) 
                              / sizeof(cache_aligned<T>);
             return c_a_array(sizeof(cache_aligned<T>), num_el, c_line_size);
        }
        static void operator delete (void* ptr) {
             free_c_a(ptr);
        }
        T* operator-> () {
             return &instance;
        }
        T& operator * () {
             return instance;
        }
};

функции cache_aligned_malloc

void* c_a_array(uint size, ulong num_el, uint c_line_size) {
    void* mem = malloc((size + c_line_size) * num_el + sizeof(void*));
    void** ptr = (void**)((long)mem + sizeof(void*));
    ptr[-1] = mem;
    return ptr;
}

void free_c_a(void ptr) {
    free(((void**)ptr)[-1]);
}

Проблема здесь, доступ к данным должен работать следующим образом:

my_el_array[i]; // returns cache_aligned<element_type>
*(my_el_array[i]); // returns element_type
my_el_array[i]->member_of_element();

Мои идеи для ее решения:

(1) что-то похожее на это, чтобы перегрузить оператор sizeof:

static size_t operator sizeof () {
   return sizeof(cache_aligned<T>) + c_line_size;
}

-> невозможно, так как перегрузка оператора sizeof недопустима

(2) что-то вроде этого,перегрузить оператор [] для типа указателя:

static T& operator [] (uint index, cache_aligned<T>* ptr) {
    return ptr + ((sizeof(cache_aligned<T>) + c_line_size) * index);
}

-> невозможно в C ++, в любом случае

(3) полностью тривиальное решение

template <typename T> cache_aligned {
    private:
          T instance;
          bool buffer[CACHE_LINE_SIZE]; 
          // CACHE_LINE_SIZE defined as macro
    public:
          // trivial operators and methods ;)
};

-> Я не знаю, насколько это надежно, на самом деле я использую gcc-4.5.1 в Linux ...

(4) Replдействующий экземпляр T;по T * instance_ptr;в шаблоне класса и используя оператор [] для вычисления положения элемента, например:

|указатель на экземпляр |----> |элемент 0 |буфер |... |элемент (N-1) |buffer |

это не предполагаемая семантика, так как экземпляр шаблона класса становится узким местом при вычислении адреса элементов.

Спасибо за чтение!Я не знаю, как сократить проблему.Было бы здорово, если бы вы могли помочь!Любой обходной путь очень помог бы.

Я знаю, что выравнивание - это расширение в C ++ 0x.Однако в gcc он еще не доступен.

Greetz, sema

1 Ответ

1 голос
/ 18 января 2011

Когда c_line_size является интегральной постоянной времени компиляции, тогда, конечно, лучше дополнить cache_aligned массивом char в зависимости от размера T.

Вы также можете проверить, умещаются ли 2 T-ов на одну строку кэша, и соответственно снизить требования к выравниванию.

Не ожидайте чудес от такой оптимизации. Я думаю, что в 2 раза лучшая производительность для некоторых алгоритмов - это предел, который вы можете выжать, избегая разбиения строк кэша.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...