Здравствуйие! Я хочу пройти курс Введение в принципы функционирования и применения современных мультиядерных архитектур (на примере Intel Xeon Phi), в презентации самостоятельной работы №1 указаны логин и пароль для доступ на кластер и выполнения самостоятельных работ, но войти по такой паре логин-пароль не получается. Как предполагается выполнение самосоятельных работ в этом курсе? |
Самостоятельная работа 4: Оптимизация расчетов на примере задачи вычисления справедливой цены опциона Европейского типа
Версия 8. Оптимизация работы с кэш-памятью
В коде функций GetOptionPricesVX() мы работаем с 4-мя массивами (pT, pK, PS0, pC). При этом 3 из них используются только для чтения, а один (pC) для записи. Обратим внимание на тот факт, что значения, которые мы записываем в длинный массив pC, в цикле никак не используются. Таким образом, их кэширование вряд ли имеет смысл (массив pC относится к nontemporal data). Для записи напрямую в память, минуя кэш, результатов вычислений, идентифицированных нами как nontemporal data, предназначены так называемые streaming stores, использование которых приводит к уменьшению накладных расходов. В данном конкретном примере мы видим, что цикл имеет огромное число итераций, в нем выполняется сравнительно мало арифметических операций относительно операций с памятью, на Xeon Phi одновременно работают сотни потоков. Совокупность этих факторов приводит к тому, что мы прокачиваем через шину объем данных, сравнимый, а то и превосходящий ее пропускную способность. Использование streaming stores для массива pC позволит нам сэкономить по одной операции чтения, нужной для поддержания системы кэш-памяти в согласованном состоянии, на каждой итерации. Проверим этот факт.
__declspec(noinline) void GetOptionPricesV8(float *pT, float *pK, float *pS0, float *pC) { int i; float d1, d2, erf1, erf2, invf; float sig2 = sig * sig; #pragma simd #pragma vector nontemporal #pragma omp parallel for private(invf, d1, d2, erf1, erf2) for (i = 0; i < N; i++) { invf = invsqrtf(sig2 * pT[i]); d1 = (logf(pS0[i] / pK[i]) + (r + sig2 * 0.5f) * pT[i]) * invf; d2 = (logf(pS0[i] / pK[i]) + (r - sig2 * 0.5f) * pT[i]) * invf; erf1 = 0.5f + 0.5f * erff(d1 * invsqrt2); erf2 = 0.5f + 0.5f * erff(d2 * invsqrt2); pC[i] = pS0[i] * erf1 - pK[i] * expf((-1.0f) * r * pT[i]) * erf2; } }
Добавьте в массив указателей GetOptionPrices новую функцию.
tGetOptionPrices GetOptionPrices[9] = { GetOptionPricesV0, GetOptionPricesV1, GetOptionPricesV2, GetOptionPricesV3, GetOptionPricesV4, GetOptionPricesV5, GetOptionPricesV6, GetOptionPricesV7, GetOptionPricesV8 };
Соберите программу и проведите эксперименты. На описанной ранее инфраструктуре авторы получили следующие времена.
N | 60 000 000 | 120 000 000 | 180 000 000 | 240 000 000 |
Версия V8 | 0,009 | 0,018 | 0,027 | 0,035 |
S(V6.3/V8) | 46,878 | 47,505 | 47,610 | 47,832 |
N | 60 000 000 | 120 000 000 | 180 000 000 | 240 000 000 |
Версия V8 | 0,007 | 0,013 | 0,019 | 0,026 |
S(V6.3/V8) | 63,873 | 65,048 | 65,426 | 65,887 |
N | 60 000 000 | 120 000 000 | 180 000 000 | 240 000 000 |
Версия V8 | 0,007 | 0,013 | 0,019 | 0,026 |
S(V6.3/V8) | 63,222 | 64,768 | 65,379 | 65,420 |
Как видно из табл. 9.17-9.19, времена работы версии 8 по сравнению с версией 7.1 ухудшились на 60 ядрах и улучшились на 120 и 240. Ускорение на 120 и 240 потоках также выросло.
Наконец, для сравнения приведем результаты работы версии 8 на центральном процессоре (16 ядер) и сопроцессоре (120 ядер).
N | 60 000 000 | 120 000 000 | 180 000 000 | 240 000 000 |
Xeon | 0,030 | 0,061 | 0,090 | 0,116 |
Xeon Phi | 0,007 | 0,013 | 0,019 | 0,026 |
Как видно из таблицы 9.20, время работы параллельной версии с прогревом на сопроцессоре примерно в 4,6 раза лучше, чем на центральном процессоре.
Также отметим, что применения прагмы vector nontemporal почти не ускоряет код на центральном процессоре (сравните времена версий 7.1 и 8), что вполне объяснимо – используется всего 16 потоков, шина не перегружается.
Дополнительные задания
- Ответить на вопросы в тексте.
- Выяснить, какой способ организации данных в данной задаче более эффективен.
- Изменить реализацию так, чтобы она производила одновременное вычисление опционов типа Call и Put. Провести эксперименты с разными версиями кода, проверить влияние техник оптимизации на время работы последовательной и параллельной версий для Xeon и Xeon Phi, привести выкладки, подтверждающие факт перегрузки шины на Xeon Phi при использовании значительного числа потоков.
- Провести эксперименты на Xeon Phi с разным числом потоков. Выяснить, какое число потоков является оптимальным.