. Как влияет кеш на многопоточные приложения / Хабр

Как влияет кеш на многопоточные приложения / Хабр

Собрание интересных и полезных материалов по множеству направлений — без ограничений в темах.

Позвонить: +7 (384) 445-09-33

Как влияет кеш на многопоточные приложения

Так сложилось, узким местом во многих компьютерах является интерфейс оперативная память — процессор. Связано это со значительным временем формирования запроса в память и с тем что частота работы памяти ниже частоты процессора. В общем случае на время получения данных из памяти исполнение программы останавливается. Для улучшения ситуации используется специализированная высокоскоростная память – кеш.

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

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

У меня возник вопрос насколько все может быть плохо. Кроме того, интересно было посмотреть как влияет длина данных.

Эксперимент. Для проверки были написаны 2 многопоточных программы на С++ для двух случаев пересечения рабочих областей:

Рабочих нитей – 2, каждая, меняя свои слова, проходит весь массив и, достигнув границы, возвращается к началу и так далее. Каждая из нитей делает по 100 000 000 изменений.

UPD Спасибо mikhanoid за выявленную опечатку в названии CPU. Для тестирования использовалась рабочая станция HP xw4600, CPU Core 2 Quad (Q9300), OS Linux Slamd64 12.1, ядро 2.6.24.5, компилятор gcc 4.2.3. В итоге получалась 64-х битная программа, следовательно любая арифметическая операция для слов длиной 1,4 и 8 байт выполнялась за 1 такт.

Время исполнения измерялось командой time(1), и усреднялось по 5-и экспериментам.

Сначала была написана программа, которая просто инкрементирует слово и кладет его обратно, но оказалось что в случае массива на стеке оптимизация -O2 творит что-то непотребное. Поэтому была написана вторая программа, которая делает с данными что-то более сложное.

Результаты. UPD: Thnx за замечание mt_ и Google Charts за api графиков. Результат в графической форме. Желающие посмотреть цифры, могут промотать дальше.

По оси Y реальное время исполнения программы в секундах. По оси X разрядность слова (парами).

Программа 2 + оптимизация -O2.

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

А вот зависимость от длины слова как-то мало заметна.

UPD Попытка перенести в блог Совершенный код, мне кажется что это самое правильное место.

Результаты в табличной форме. Результаты представлены в секундах.

Программа 1 (общая память). Длина слова 64 32 8 Реальное время 1,297 1,532 0,846 Время польз. режима 2,461 3,049 1,664

Программа 1 (стек) Длина слова 64 32 8 Реальное время 0,453 0,431 0,441 Время польз. режима 0,851 0,842 0,866

Программа 2 (общая память). Длина слова 64 32 8 Реальное время 9,191 9,033 8,921 Время польз. режима 18,365 18,039 17,824

Программа 2 (стек) Длина слова 64 32 8 Реальное время с 8,432 8,412 8,808 Время польз. Режима с 16,843 16,796 17,548

Программа 2 + оптимизация -O2 (общая память). Длина слова 64 32 8 Реальное время 4,247 4,380 3,473 Время польз. режима 8,415 8,960 6,781

Программа 2 + оптимизация -O2 (стек) Длина слова 64 32 8 Реальное время 3,282 3,718 3,308 Время польз. режима 6,550 7,384 5,565

Исходный код.

Программа 1.

#include <stdio.h> #include <stdlib.h>

#define TBYTES 1024 // #define TOTAL 2 // определяет тип слова u_int8_t u_int32_t u_int64_t #define MTYPE u_int8_t // #define MAXAR TBYTES/ sizeof (MTYPE) #define DOIT 100000000

pthread_mutex_t mux = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond = PTHREAD_COND_INITIALIZER; int workers = 2;

// Определяет используется ли общая память //#define SHARED 1

void * runner( void * args) // pthread_mutex_lock(&mux); -- workers; pthread_mutex_unlock(&mux); pthread_cond_broadcast(&cond); // return 0; >;

int main() ; // * This source code was highlighted with Source Code Highlighter .

Программа 2.

#include <stdio.h> #include <stdlib.h>

#define TBYTES 1024 // #define TOTAL 2 // определяет тип слова u_int8_t u_int32_t u_int64_t #define MTYPE u_int64_t // #define MAXAR TBYTES/ sizeof (MTYPE) //#define DOIT 100000000 * (sizeof(u_int64_t) / sizeof(MTYPE)) #define DOIT 100000000

pthread_mutex_t mux = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond = PTHREAD_COND_INITIALIZER; int workers = 2;

template<typename RTYPE, int TLEN> RTYPE scramble(u_int16_t *seed, RTYPE a) 1) &0x1); mask = mask & 0x1; *seed = (mask << 15) | (*seed >> 1); // a = a ^ ((RTYPE)mask << d); > // return a; >;

// Определяет используется ли общая память //#define SHARED 1

void * runner( void * args) (&seed, data); #else data = array1[index]; array1[index] = scramble<MTYPE, 8* sizeof (MTYPE)>(&seed, data); #endif // index += TOTAL; > // pthread_mutex_lock(&mux); -- workers; pthread_mutex_unlock(&mux); pthread_cond_broadcast(&cond); // return 0; >;

int main() ; // * This source code was highlighted with Source Code Highlighter .

📎📎📎📎📎📎📎📎📎📎

Цель проекта

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

Категории материалов

События и факты

Краткие сводки по темам, вызывающим наибольший интерес среди пользователей.

Общая информация

Тексты на повседневные, бытовые, региональные и популярные темы.

Подборки

Собранные по схожести темы статьи и материалы разного характера.

Архивные разделы

Доступ к ранее опубликованным материалам и тематическим блокам.

Контакты

📍 г. Кемерово, ул. Полезная, д. 21, офис 410

☎ +7 (384) 445-09-33

📧 info@site.ru

🕓 Приём писем: ежедневно, 08:00 – 22:00

Отказ от ответственности

Контент, размещённый на сайте, поступает из общедоступных источников и обрабатывается автоматически. Администрация не участвует в создании и проверке опубликованных материалов.

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

Сайт не зарегистрирован как СМИ и не несёт ответственности за точность информации.

Размер шрифта: