Нижегородский государственный университет им. Н.И.Лобачевского
Опубликован: 02.06.2014 | Доступ: свободный | Студентов: 183 / 28 | Длительность: 04:58:00
Специальности: Программист, Системный архитектор
Самостоятельная работа 2: Оптимизация вычислительно трудоемкого программного модуля для архитектуры Intel Xeon Phi. Линейные сортировки
Модификация сортировки LSD
Внесём изменения в метод exectute класса Placer5Читатель может самостоятельно оценить вклад каждого из внесённых изменений во время работы программы. :
- Избавимся от повторного вычисления значений inpUC[i<<3] .
- Выполним разворачивание цикла на две итерации – это уменьшит ко-личество операций сравнения и снизит зависимость между итерациями.
- Выполним упреждающую загрузку данных в кэш-память с помощью функции _mm_prefetch. Значение _MM_HINT_T0 означает, что данные надо загрузить в ближайший кэш к ядру L1 (а т.к. архитектура кэша инклюзивная, то и в L2).
task* execute() { unsigned char *inpUC=(unsigned char *)inp + byteNum; int end = size - size%2; int end_prefetch = end-8; _mm_prefetch((const char*)&(out[counter[inpUC[(0)<<3]]]), _MM_HINT_T0); _mm_prefetch((const char*)&(out[counter[inpUC[(1)<<3]]]), _MM_HINT_T0); for(int i=0; i<end_prefetch; i+=2) { int next = i+1; _mm_prefetch( (const char*)&(out[counter[inpUC[(i+8)<<3]]]), _MM_HINT_T0); _mm_prefetch( (const char*)&(out[counter[inpUC[(i+9)<<3]]]), _MM_HINT_T0); int &c1=counter[inpUC[i<<3]]; int &c2=counter[inpUC[next<<3]]; out[c1++]=inp[i]; out[c2++]=inp[next]; } for(int i=end_prefetch; i<end; i+=2) { int &c1=counter[inpUC[i<<3]]; int &c2=counter[inpUC[(i+1)<<3]]; out[c1++]=inp[i]; out[c2++]=inp[i+1]; } for(int i=end; i<size; i++) { int &c=counter[inpUC[i<<3]]; out[c++]=inp[i]; } return NULL; }
Внесём изменения в функцию exectute класса LSDParallelSorter, чтобы выделять память под масси-вы объектов один раз.
task* execute() { int *counters = new int[256 * nThreads]; int byteNum = 0; Counter **ctr1 = new Counter*[nThreads-1]; Placer **pl1 = new Placer*[nThreads-1]; Counter **ctr2 = new Counter*[nThreads-1]; Placer **pl2 = new Placer*[nThreads-1]; int s = size / nThreads; for(;byteNum<8;byteNum+=2) { for(int i=0; i<nThreads-1; i++) { ctr1[i] = new (allocate_child()) Counter(mas + i*s, s, byteNum, counters + 256 * i); ctr2[i] = new (allocate_child()) Counter(tmp + i*s, s, byteNum+1, counters + 256 * i); pl1[i] = new (allocate_child()) Placer(mas + i*s, tmp, s, byteNum, counters + 256 * i); pl2[i] = new (allocate_child()) Placer(tmp + i*s, mas, s, byteNum+1, counters + 256 * i); } Counter &ctrLast1 = *new (allocate_child()) Counter(mas + s * (nThreads-1), size - s * (nThreads-1) , byteNum, counters + 256 * (nThreads-1)); Counter &ctrLast2 = *new (allocate_child()) Counter(tmp + s * (nThreads-1), size - s * (nThreads-1) , byteNum+1, counters + 256 * (nThreads-1)); Placer &plLast1 = *new (allocate_child()) Placer(mas + s * (nThreads-1),tmp, size - s * (nThreads-1), byteNum, counters + 256 * (nThreads-1)); Placer &plLast2 = *new (allocate_child()) Placer(tmp + s * (nThreads-1),mas, size - s * (nThreads-1), byteNum+1, counters + 256 * (nThreads-1)); set_ref_count(nThreads+1); for(int i=0; i<nThreads-1; i++) spawn(*(ctr1[i])); spawn_and_wait_for_all(ctrLast1); int sm = 0; for(int j=0; j<256; j++) { for(int i=0; i<nThreads; i++) { int b=counters[j + i * 256]; counters[j + i * 256]=sm; sm+=b; } } set_ref_count(nThreads+1); for(int i=0; i<nThreads-1; i++) spawn(*(pl1[i])); spawn_and_wait_for_all(plLast1); set_ref_count(nThreads+1); for(int i=0; i<nThreads-1; i++) spawn(*(ctr2[i])); spawn_and_wait_for_all(ctrLast2); sm = 0; for(int j=0; j<256; j++) { for(int i=0; i<nThreads; i++) { int b=counters[j + i * 256]; counters[j + i * 256]=sm; sm+=b; } } set_ref_count(nThreads+1); for(int i=0; i<nThreads-1; i++) spawn(*(pl2[i])); spawn_and_wait_for_all(plLast2); } delete[] pl1; delete[] pl2; delete[] ctr1; delete[] ctr2; delete[] counters; return NULL; }
Сравним время работы модифицированной версии и базовой на хосте ( рис. 4.25) и сопроцессоре ( рис. 4.26, рис. 4.27) при сортировке 100 миллионов эле-ментов.
увеличить изображение
Рис. 4.25. Сравнение параллельных реализаций LSD на хосте при сор-тировки 100 миллионов элементов