Чому мій масштабування множинної матриці-вектор не масштабується?


15

Вибачте за довгий пост, але я хотів включити все, що, на мою думку, було актуальним.

Що я хочу

Я реалізую паралельну версію методів підпростору Крилова для щільних матриць. В основному GMRES, QMR та CG. Я зрозумів (після профілювання), що мій режим DGEMV був жалюгідним. Тому я вирішив сконцентруватися на цьому, виділивши його. Я спробував запустити його на 12-ядерній машині, але наведені нижче результати призначені для 4-ядерного ноутбука Intel i3. Різниці в тренді мало.

Мій KMP_AFFINITY=VERBOSEвихід доступний тут .

Я виписав невеликий код:

size_N = 15000
A = randomly_generated_dense_matrix(size_N,size_N); %Condition Number is not bad
b = randomly_generated_dense_vector(size_N);
for it=1:n_times %n_times I kept at 50 
 x = Matrix_Vector_Multi(A,b);
end

Я вважаю, що це імітує поведінку CG за 50 ітерацій.

Що я спробував:

Переклад

Я спочатку писав код у Фортран. Я переклав це на C, MATLAB та Python (Numpy). Само собою зрозуміло, що MATLAB і Python були жахливими. Дивно, але для вищезгаданих значень C виявився кращим за FORTRAN на секунду-дві. Послідовно.

Профілювання

Я профілював свій код для запуску, і він працював протягом 46.075декількох секунд. Це було коли було встановлено MKL_DYNAMICFALSE і були використані всі ядра. Якщо я використовував MKL_DYNAMIC як істинний, тільки (приблизно) половина кількості ядер використовувалася в будь-який момент часу. Ось кілька деталей:

Address Line    Assembly                CPU Time

0x5cb51c        mulpd %xmm9, %xmm14     36.591s

Здається, найбільш трудомісткий процес:

Call Stack                          LAX16_N4_Loop_M16gas_1
CPU Time by Utilization             157.926s
CPU Time:Total by Utilization       94.1%
Overhead Time                       0us
Overhead Time:Total                 0.0%    
Module                              libmkl_mc3.so   

Ось кілька фотографій:введіть тут опис зображення введіть тут опис зображення

Висновки:

Я справжній початківець у профілюванні, але розумію, що швидкість все ще не є хорошою. Послідовний (1 Core) код закінчується за 53 секунди. Це швидкість, що перевищує 1,1!

Справжнє запитання: Що мені зробити, щоб покращити швидкість?

Те, що, на мою думку, може допомогти, але я не можу бути впевнений:

  • Реалізація Pthreads
  • Реалізація MPI (ScaLapack)
  • Ручна настройка (не знаю як. Будь ласка, рекомендуйте ресурс, якщо ви запропонуєте це)

Якщо комусь потрібно більше (особливо щодо пам’яті) деталей, будь ласка, дайте мені знати, що мені слід запускати та як. Я ніколи раніше не пам'ятався з профілем пам'яті.

Відповіді:


20

Ваша матриця розміром 15 000 х 15 000, тому в матриці у вас є елементи 225 М. Це забезпечує приблизно 2 Гб пам'яті. Це набагато більше, ніж розмір кешу вашого процесора, тому його потрібно завантажувати повністю з основної пам’яті при кожному множенні матриці, роблячи приблизно 100 ГБ передачі даних, плюс те, що потрібно для джерела та призначення векторів.

Максимальна пропускна здатність i3 становить приблизно 21 ГБ / с на основі специфікацій Intel, але якщо ви оглянетеся в Інтернеті, ви побачите, що щонайменше половина цього дійсно доступна в реальності. Таким чином, ви принаймні очікуєте, що ваш показник триватиме 10 секунд, а фактичний показник 45 секунд не так далеко від цієї позначки.

У той же час ви також робите кілька мільярдів плаваючої крапки, що множиться та додається. Враховуючи, скажімо, 10 тактових циклів для комбінації та тактову частоту 3 ГГц, ви вийдете за ~ 30 секунд. Звичайно, вони можуть працювати одночасно зі спекулятивними навантаженнями на пам'ять, якщо кеш-пам'ять розумна.

Загалом, я б сказав, що ви не надто далеко від позначки. Що б ви очікували?


Чи не існує способу отримати принаймні прискорення 2-3?
Запит

@Nunoxic - можливо, ви захочете орієнтувати продуктивність пам’яті у вашій системі за допомогою такого інструменту, як SiSoftware Sandra. Аналіз Вольфгангса для мене виглядає помітним, якщо ваша програма обмежена пропускною здатністю пам’яті, паралелізація взагалі мало допоможе. Також перегляньте будь-які можливі варіанти економії енергії, вони можуть зменшити продуктивність пам'яті. Крім того, розгляньте можливість заміни пам’яті більш високою якістю пам’яті, наприклад, менша затримка CAS може призвести до великої зміни у вашій стіні.
Марк Бут

4

Як ви робите множення матричного вектора? Подвійний контур вручну? Або дзвінки в BLAS? Якщо ви використовуєте MKL, я настійно рекомендую використовувати підпрограми BLAS в потоковій версії.

З цікавості ви також можете скомпілювати власну налаштовану версію ATLAS і подивитися, як це відбувається з вашою проблемою.

Оновлення

Після обговорення в коментарях нижче, виявляється, що ваш Intel Core i3-330M має лише два "справжніх" ядра. Два відсутні сердечники імітуються гіперточенням . Оскільки в гіперточених ядрах спільна шина пам'яті і одиниці з плаваючою комою поділяються, ви не отримаєте жодного прискорення, якщо будь-яке з двох є обмежуючим фактором. Насправді, використання чотирьох ядер, ймовірно, навіть сповільнить справи.

Які результати ви отримуєте на "лише" двох ядрах?


Я спробував ATLA, GoTo та Netlib BLAS. Всі слабкіші за MKL за продуктивністю. Це очікується чи я роблю щось не так? Я склав ATLAS, як згадувалося в посібнику. Крім того, я вставив мій (точно) код тут . Його дзвінок у BLL MKL.
Запит

Добре, а для масштабування ви впевнені, що у вашому базовому випадку код працює лише на одному процесорі? Наприклад, якщо ви його орієнтуєте, чи гістограма використання процесора показує лише одне ядро?
Педро

Так. Гістограма CPU показує 1 ядро.
Запит

Знову з цікавості, що ви отримуєте за два-три ядра? Чи справді ваша машина має чотири фізичні ядра, або лише два ядра з гіперточенням ?
Педро

Як я це дізнаюся? Я включив свій KMP_AFFINITY до основного.
Запит

0

У мене складається враження, що впорядкування основних рядків є оптимальним для цієї проблеми стосовно часу доступу до пам’яті, використання кеш-ліній та пропусків TLB. Я думаю, що ваша версія FORTRAN замість цього використовувала головне стовпчикове замовлення, що могло б пояснити, чому воно стабільно повільніше, ніж версія C.

б

Ви також можете перевірити швидкість, якщо просто підсумувати всі елементи матриці в одному циклі замість множення матричного вектора. (Можливо, ви захочете розкрутити цикл фактором 4, оскільки неасоціативність додавання може перешкодити компілятору робити цю оптимізацію для вас.)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.