Наукове програмне забезпечення не так сильно відрізняється від іншого програмного забезпечення, наскільки знати, для чого потрібна настройка.
Я використовую метод - випадкова пауза . Ось кілька прискорень, які він знайшов для мене:
Якщо велика частина часу витрачається на такі функції, як, log
і exp
я можу побачити, які аргументи для цих функцій є функцією точок, з яких вони викликаються. Часто їх називають неодноразово одним і тим же аргументом. Якщо це так, запам'ятовування створює величезний коефіцієнт швидкості.
Якщо я використовую BLAS або LAPACK, я можу виявити, що велика частина часу витрачається на підпрограми на копіювання масивів, множення матриць, перетворення холеського тощо.
Звичайна процедура копіювання масивів існує не для швидкості, вона для зручності. Ви можете виявити, що існує менш зручний, але швидший спосіб зробити це.
Рутини для множення або перетворення матриць або прийняття холеського перетворення, як правило, містять символьні аргументи, що визначають параметри, такі як "U" або "L" для верхнього або нижнього трикутника. Знову ж таки, вони є для зручності. Що я знайшов, так як мої матриці були не дуже великими, підпрограми витрачали більше половини свого часу на виклик підпрограми для порівняння символів, щоб просто розшифрувати параметри. Написання спеціальних версій найдорожчих математичних процедур дало значну швидкість.
Якщо я можу просто розгорнути останнє: рутинне множення матриць DGEMM викликає LSAME для декодування його аргументів символів. Дивлячись на інклюзивний відсотковий час (єдину статистику, на яку варто звернути увагу), профілі, які вважаються "хорошими", могли б показати DGEMM, використовуючи якийсь відсоток загального часу, наприклад, 80%, а LSAME використовуючи деякий відсоток загального часу, як 50%. Дивлячись на колишнього, ви б спокусилися сказати: "ну це має бути сильно оптимізовано, тому я не можу з цим зробити". Дивлячись на останнє, ви б спокусилися сказати: "А? Що це все? Це просто маленька рутина. Цей профілер повинен помилятися!"
Це не помиляється, це просто не сказати тобі, що потрібно знати. Що випадкове пауза показує, що DGEMM знаходиться на 80% зразків стека, а LSAME - на 50%. (Для виявлення цього вам не потрібно багато зразків. 10, як правило, безліч.) Більше того, на багатьох із цих зразків DGEMM перебуває у виклику LSAME з декількох різних рядків коду.
Отже, тепер ви знаєте, чому обидві процедури займають так багато часу. Ви також знаєте, звідки у вашому коді вони дзвонять, щоб провести весь цей час. Ось чому я використовую випадкову паузу і переймаюсь з жовтяним оглядом профілярів, незалежно від того, наскільки вони добре зроблені. Їм більше цікаво отримати вимірювання, ніж розповісти, що відбувається.
Неважко припустити, що методи математичної бібліотеки були оптимізовані до n-го ступеня, але насправді вони були оптимізовані для використання у широкому діапазоні цілей. Вам потрібно побачити, що відбувається насправді , а не те, що легко припустити.
ДОДАТО: Отже, щоб відповісти на два ваші останні запитання:
Які найважливіші речі спробувати спершу?
Візьміть 10-20 зразків стеків, і не просто їх підсумовуйте, розумійте, що кожен з них говорить. Зробіть це першим, останнім та між ними. (Немає "спробувати", молодий Скайуокер.)
Як дізнатись, скільки я можу отримати?
xβ(s+1,(n−s)+1)sn1/(1−x)n=10s=5x
xx
Як я вже зазначав вам раніше, ви можете повторювати всю процедуру, поки не зможете більше, а коефіцієнт швидкісних скорочень може бути досить великим.
(s+1)/(n+2)=3/22=13.6%.) Нижня крива на наступному графіку - це її розподіл:
Поміркуйте, якщо ми взяли цілих 40 зразків (більше, ніж я коли-небудь мав за один раз) і побачили лише проблему на двох з них. Орієнтовна вартість (режим) цієї проблеми становить 5%, як показано на більш високій кривій.
Що таке "помилковий позитив"? Адже якщо ви вирішите проблему, ви зрозумієте такий менший виграш, ніж очікувалося, ви пошкодуєте, що її виправили. Криві показують (якщо проблема "мала"), що, хоча коефіцієнт підсилення може бути меншим, ніж частка зразків, що його показують, в середньому він буде більшим.
Існує куди більш серйозний ризик - "помилковий негатив". Це коли є проблема, але вона не знайдена. (Сприяє цьому "упередженість підтвердження", коли відсутність доказів трактується як доказ відсутності.)
Що ви отримуєте з профайлер (хороший один) це ви отримаєте набагато більше точне вимірювання (таким чином , менше ймовірність помилкових спрацьовувань), за рахунок набагато менш точної інформації про те , що проблема на насправді є (так менше шансів знайти його і отримати будь-який виграш). Це обмежує загальну швидкість, яку можна досягти.
Я б закликав користувачів профілів повідомляти про фактори прискорення, які вони реально отримують на практиці.
Є ще один момент, який потрібно зробити ще раз. Питання Педро про помилкові позитиви.
Він зауважив, що можуть виникнути труднощі при переході до невеликих проблем у високооптимізованому коді. (Для мене невелика проблема, яка становить 5% або менше всього часу.)
Оскільки цілком можливо побудувати програму, яка є абсолютно оптимальною, за винятком 5%, цей пункт можна вирішити лише емпірично, як у цій відповіді . Для узагальнення з емпіричного досвіду це виглядає так:
Програма, як написано, зазвичай містить кілька можливостей для оптимізації. (Ми можемо їх назвати "проблемами", але вони часто є абсолютно хорошим кодом, просто здатні до значного вдосконалення.) Ця діаграма ілюструє штучну програму, яка займає деякий проміжок часу (скажімо, 100), і містить проблеми A, B, C, ... що, знайшовши та виправити, економить 30%, 21% тощо від початкових 100-х.
Зауважте, що проблема F коштує 5% від початкового часу, тому її "мало" і її важко знайти без 40 і більше зразків.
Однак перші 10 зразків легко знаходять проблему А. ** Коли це буде виправлено, програма займає лише 70-і, для прискорення 100/70 = 1,43x. Це не тільки робить програму швидшою, але збільшує, за цим співвідношенням, відсотки, взяті за інші проблеми. Наприклад, проблема B спочатку займала 21-е, що становило 21% від загальної кількості, але після вилучення А, В займає 21-е з 70-х, або 30%, тому його легше знайти, коли весь процес повторюється.
Коли процес повторювались п’ять разів, тепер час виконання становить 16,8s, з яких проблема F - 30%, а не 5%, тому 10 зразків знаходять це легко.
Тож у цьому справа. Емпірично програми містять низку проблем, що мають розподіл розмірів, і будь-яка проблема, знайдена та виправлена, полегшує пошук решти. Для цього неможливо пропустити жодну з проблем, оскільки, якщо вони є, вони сидять там, вимагаючи часу, обмежуючи загальну швидкість, і не в змозі збільшити решту проблем.
Ось чому дуже важливо знайти проблеми, які ховаються .
Якщо проблеми від A до F виявлені та усунені, швидкість дорівнює 100 / 11,8 = 8,5x. Якщо один із них пропущений, наприклад D, то прискорення становить лише 100 / (11,8 + 10,3) = 4,5х.
Ось ціна, сплачена за хибні негативи.
Отже, коли профайлер каже, що "тут, здається, немає жодної суттєвої проблеми" (тобто хороший кодер, це практично оптимальний код), можливо, це правильно, а може, і ні. ( Неправдивий мінус .) Ви точно не знаєте, чи є проблеми з виправленням, для більшої швидкості, якщо ви не спробуєте інший метод профілювання та не виявите, що існують. На мій досвід, метод профілювання не потребує великої кількості зразків, узагальнених, а невеликої кількості зразків, де кожен зразок розуміється досить ґрунтовно, щоб визнати будь-яку можливість для оптимізації.
2/0.3=6.671 - pbinom(1, numberOfSamples, sizeOfProblem)
1 - pbinom(1, 20, 0.3) = 0.9923627
xβ(s+1,(n−s)+1)nsy1/(1−x)xyy−1Розподіл BetaPrime Я моделював це за допомогою 2 мільйонів зразків, дотримуючись такої поведінки:
distribution of speedup
ratio y
s, n 5%-ile 95%-ile mean
2, 2 1.58 59.30 32.36
2, 3 1.33 10.25 4.00
2, 4 1.23 5.28 2.50
2, 5 1.18 3.69 2.00
2,10 1.09 1.89 1.37
2,20 1.04 1.37 1.17
2,40 1.02 1.17 1.08
3, 3 1.90 78.34 42.94
3, 4 1.52 13.10 5.00
3, 5 1.37 6.53 3.00
3,10 1.16 2.29 1.57
3,20 1.07 1.49 1.24
3,40 1.04 1.22 1.11
4, 4 2.22 98.02 52.36
4, 5 1.72 15.95 6.00
4,10 1.25 2.86 1.83
4,20 1.11 1.62 1.31
4,40 1.05 1.26 1.14
5, 5 2.54 117.27 64.29
5,10 1.37 3.69 2.20
5,20 1.15 1.78 1.40
5,40 1.07 1.31 1.17
(n+1)/(n−s)s=ny
Це графік розподілу коефіцієнтів прискорення та їх засобів для 2 звернень із 5, 4, 3 та 2 зразків. Наприклад, якщо взяти 3 зразки, і 2 з них є пошкодженнями проблеми, і цю проблему можна усунути, середній коефіцієнт прискорення буде 4 рази. Якщо два звернення спостерігаються лише у двох зразках, середня швидкість не визначена - концептуально, тому що програми з нескінченними циклами існують з ненульовою ймовірністю!