Как поместить мою структурную переменную в кэши ЦП, чтобы исключить время доступа к основной памяти?Опции - PullRequest
8 голосов
/ 31 марта 2011

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

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

Вот мой пример:

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

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

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

Я думаю, что некоторые умные коды могут сократить затраченное время, до 10-100 раз.Пожалуйста, покажите мне путь.

-------------------------------------------------------------------------

Добавлено (2011-04-01)

Деймон ~ спасибо за ваш комментарий!

После прочтения вашего комментария я проанализировалмой код снова, и нашел несколько вещей, которые я пропустил.Следующий код, который я прикрепил, является сокращенной версией моего исходного кода.

Чтобы точно измерить время выполнения каждой операции (в исходном коде есть несколько различных типов операций), я вставил код измерения времени, используяclock_gettime() функция.Я подумал, что если я измерим время выполнения каждой операции и накоплю их, можно избежать дополнительных затрат по основному циклу.

В исходном коде код измерения времени был скрыт макро-функцией, поэтому я полностью забылоб этом.

Время выполнения этого кода составляет почти 6 секунд.Но если я избавлюсь от функции измерения времени в главном цикле, она станет 0,1 секунды.

Поскольку функция clock_gettime() поддерживает очень высокую точность (до 1 наносекунды), выполняемую на основе независимойпоток, а также он требует очень большой структуры, я думаю, что функция вызвала кеширование основной области памяти, где выполняются последовательные вставки.

Еще раз спасибо за ваш комментарий.Для дальнейшего улучшения, любое предложение будет очень полезно для оптимизации моего кода.

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


typedef struct t_ptr {
    uint32 isleaf :1, isNextLeaf :1, ptr :30;
    t_ptr(void) {
        isleaf = false;
        isNextLeaf = false;
        ptr = NIL;
    }
} PTR;

typedef struct t_key {
    uint32 op :1, key :31;
    t_key(void) {
        op = OP_INS;
        key = 0;
    }
} KEY;

typedef struct t_key_pair {
    KEY key;
    PTR ptr;
    t_key_pair() {
    }

    t_key_pair(KEY k, PTR p) {
        key = k;
        ptr = p;
    }
} KeyPair;

typedef struct t_op {
    KeyPair keyPair;
    uint seq;
    t_op() {
        seq = 0;
    }
} OP;

#define MAX_OP_LEN 4000000
typedef struct t_opq {
    OP ops[MAX_OP_LEN];
    int freeOffset;
    int globalSeq;
    bool queueOp(register KeyPair keyPair);
} OpQueue;

bool OpQueue::queueOp(register KeyPair keyPair) {
    bool isFull = false;
    if (freeOffset == (int) (MAX_OP_LEN - 1)) {
        isFull = true;
    }
    ops[freeOffset].keyPair = keyPair;
    ops[freeOffset].seq = globalSeq++;
    freeOffset++;
}

OpQueue opQueue;
#include <sys/time.h>
int main() {
    struct timespec startTime, endTime, totalTime;
    for(int i = 0; i < 4000000; i++) {
        clock_gettime(CLOCK_REALTIME, &startTime);
        opQueue.queueOp(KeyPair());
        clock_gettime(CLOCK_REALTIME, &endTime);
        totalTime.tv_sec += (endTime.tv_sec - startTime.tv_sec);
        totalTime.tv_nsec += (endTime.tv_nsec - startTime.tv_nsec);
    }
    printf("\n elapsed time: %ld", totalTime.tv_sec * 1000000LL + totalTime.tv_nsec / 1000L);
}

Ответы [ 2 ]

3 голосов
/ 04 апреля 2014

ВЫ не помещаете структуру в любой кеш. Процессор делает это автоматически для вас. Процессор еще умнее; если вы получите доступ к последовательной памяти, она начнет помещать вещи из памяти в кэш до того, как вы их прочитаете.

И действительно, должен быть здравый смысл, что для такого простого кода, как этот, время, которое вы тратите на измерение, в десять раз больше, чем время на выполнение кода (по-видимому, 60 раз в вашем случае).

Поскольку вы очень доверяете clock_gettime (): я предлагаю вам вызвать его пять раз подряд и сохранить результаты, а затем распечатать различия. Есть разрешение, точность, и сколько времени нужно, чтобы вернуть текущее время, которое чертовски долго.

2 голосов
/ 28 июня 2012

Мне не удалось форсировать кеширование, но вы можете принудительно отключить кеширование памяти. Если у вас есть большие другие структуры данных, вы можете исключить их, чтобы они не загрязняли ваши кэши. Это можно сделать, указав PAGE_NOCACHE для функций Windows VirutalAllocXXX.

http://msdn.microsoft.com/en-us/library/windows/desktop/aa366786(v=vs.85).aspx

...