Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
конспект_укр.docx
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
1.07 Mб
Скачать

Приклад реалізації класу Log.

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.IO;

namespace Test

{

public static class ClassReportLog // класс для создания log файлов

{

public static List<string> logText = new List<string>();

public static string fileNameLog = @"ReportLog\SRLog.txt";

private static void addMessageToLog(DateTime inCurrentDate, string inFunctionName, string inMessage)

{

logText.Add(inCurrentDate.ToString() + " " + inFunctionName + " "+ inMessage);

}

public static void createLogFile(string inPath = @"ReportLog\")

{

fileNameLog =inPath + "SRLog_d"+Convert.ToString(DateTime.Now.Day)+"m"+Convert.ToString(DateTime.Now.Month)+".txt";

if (!File.Exists(fileNameLog))

{

StreamWriter file = new StreamWriter(fileNameLog);

file.Close();

}

}

private static void writeMessage(string inFunctionName, string inMessage)

{

addMessageToLog( DateTime.Now, inFunctionName, inMessage);

StreamWriter file = new StreamWriter(File.Open(fileNameLog, FileMode.Append));

file.WriteLine(DateTime.Now.ToString() + " " + inFunctionName + " " + inMessage);

file.Close();

}

public static void info(string inFunctionName, string inMessage, int isModeLog = 0, bool isIgnoreLogMode = false)

{

if(isIgnoreLogMode) { writeMessage(inFunctionName, inMessage); }

else if(isModeLog >= 2) { writeMessage(inFunctionName, inMessage);}

}

public static void error(string inFunctionName, string inMessage, int isModelog = 0, bool isIgnoreLogMode = false)

{

if(isIgnoreLogMode) { writeMessage(inFunctionName, inMessage); }

else if((isModelog >= 0)) { writeMessage(inFunctionName, inMessage);}

}

public static void warning(string inFunctionName, string inMessage, int isModelog = 0, bool isIgnoreLogMode = false)

{

if(isIgnoreLogMode) { writeMessage(inFunctionName, inMessage); }

else if(isModelog >= 1) { writeMessage(inFunctionName, inMessage);}

}

}

}

Розробка програмного продукту з двома потоками

Створити програму з двома потоками. У першому потоці виконувати обчислення за будь якою математичною функцією від значення х. Значення х повинно постійно змінюватися, приймати як позитивні, так і від’ємні значення. У другому потоці виводити на форму анімаційне зображення «Wait.gif». Запуск програми на виконання розрахунків повинно здійснюватися при натисненні на кнопку «Старт». Перерівання роботи повинно здійснюватися при натисканні на кнопку «Стоп». Поновлення роботи – при натислення на кнопку «Старт».

Визначення крапок контролю програмного продукту.

Додати у проект клас Log. У програмі викликати методи класу для вионання кожно кроку виконання програми. Переглянути створений класом Log файл.

Лекція №5

Тема: Профілювання та оптимізація програмних продуктів.

Мета: Придбати знання з виконання технологічних процесів по профілювання та оптимізації програмних продуктів.

Перелік питань, що розглядаються на лекції:

  1. Призначення та функції профілювання.

  2. Профілювальник.

  3. Мета й завдання профілюваьника.

  4. Загальна година виконання.

  5. Питомна година виконання.

  6. Інформація про пенальті.

  7. Проблеми профілювання.

Відповідно до правила "10/90", десять відсотків коду "з'їдають" дев'яносто відсотків продуктивності системи. Якщо година, витрачений на виконання кожної машинної інструкції, зобразити графічно в порядку зростання їхнього лінійного адресі, на отриманій діаграмі мі виявимо кілька височенних піків, що піднімаються над практично порожньою рівниною, засіяної безліччю низеньких горбків, ці самі піки — і є "гарячі" крапки.

Чому "температура" різних ділянок програми настільки неоднакова? Причина в тім, що переважлива більшість обчислювальних алгоритмів чи так інакше зводяться до циклів, — тобто  багаторазовим повторенням одного фрагмента коду, причому найчастіше циклі обробляються не послідовно, а утворять більш-менш глибокі ієрархії. У результаті, велику частину всього години виконання, програма проводити в циклах з найбільшим рівнем вкладення, і саме їхня оптимізація дає найкращий приріст продуктивності!

Громіздкі й гальмові, алі рідко викликувані функції оптимізувати немає ні якого сенсу, — це практично не збільшить швидкодії додатка (ну хіба що тільки в тому випадку, якщо смороду зовсім вуж будуть "криво" написані).

Коли ж алгоритм програми простий, а її вихідний текст вільно вміщається в сотню-іншу рядків, те "гарячі" крапки неважко виявити й візуальним переглядом лістингу. Алі зі збільшенням обсягу коду це стає вусі складніше й складніше. У програмі, що складається з тисяч складно взаємодіючих один з одним функцій (частина з яких це функції зовнішніх бібліотек і API — Application Programming Interface, інтерфейс прикладного програмування — операційної системи) далеко не так очевидно: яка ж саме з їх найбільшою мірою відповідальна за низьку продуктивність додатка. Природний вихід — вдатися до допомоги спеціалізованих програмних засобів.

Профіліровщик (так саме називаний "профайлером") — основний інструмент оптимізатора програм. Оптимізація "у сліпу" рідко дає гарний результат. Згадайте прислів'я "самий повільний верблюд визначає швидкість каравану"? Програмний код поводитися повністю відповідає цьому, і продуктивність додатка визначається самою вузькою його ділянкою. Буває, що винуватницею виявляється одна-єдина машинна інструкція (наприклад, інструкція розподілу, що багаторазово виконується в глибоко вкладеному циклі). Програміст, затративши воістину титанічні зусилля на поліпшення іншого коду, виявиться пребагато здивований, що продуктивність додатка чи навряд зросла відсотків на десять-п'ятнадцять.

Правило номер один: ліквідація не самих "гарячих" крапок програми, практично не збільшує її швидкодії. Дійсно, скільки не підганяй іншого позад верблюда — від цього караван швидше йти не буде (випадок, коли передостанньої верблюд гальмує останнього — це вже тема іншої розмови, що вимагає глибоких знань техніки профілювання, а тому й не розглянута в поданому матеріалі).

Мета й завдання профілювання

Основна позначка профілювання — досліджувати характер поводження додатка у всіх його крапках. Під "крапкою" залежно від ступеня деталізації може матися на увазі як окрема машинна команда, так ціла конструкція мови високого рівня (наприклад: функція, цикл або одна-єдиний рядок вихідного тексту).

Більшість сучасних профіліровщиків підтримують наступний набір базових операцій:

  • визначення загального години виконання кожної крапки програми (total [spots] timing);

  • визначення питомого години виконання кожної крапки програми ([spots] timing);

  • визначення заподій й/або джерела конфліктів і пенальті (penalty information);

  • визначення кількості викликів тої або іншої крапки програми ([spots] count);

  • визначення ступеня покриття програми ([spots] covering).

Загальна година виконання

Відомості про годину, що додаток витрачає на виконання кожної крапки програми, дозволяють виявити його найбільше "гарячі" ділянки. Правда, отут необхідно зробити одне уточнення. Безпосередній вимір покаже, що, принаймні, 99,99% усього години виконання програма проводити усередині функції main, алі адже очевидно, що "гарячої" є аж ніяк не сама main, а викликувані нею функції! Щоб не викликати в програмістів здивування, профіліровщики звичайно віднімають година, витрачений на виконання дочірніх функцій, із загального години виконання кожної функції програми.

Розглянемо, наприклад, результат профілювання деякого додатка профіліровщиком profile.exe, що входити в комплект поставки компілятора Microsoft Visual C++.

Лістинг 1.1. Приклад профілювання додатка програмою profile.exe

Func Func+Child Hit

Time % Time % Count Function

350,192 95,9 360,982 98,9 10000 _do_pswd (pswd_x.obj)

5,700 1,6 5,700 1,6 10000 _CalculateCRC (pswd_x.obj)

5,090 1,4 10,790 3,0 10000 _CheckCRC (pswd_x.obj)

2,841 0,8 363,824 99,6 1 _gen_pswd (pswd_x.obj)

1,226 0,3 365,148 100,0 1 _main (pswd_x.obj)

0,098 0,0 0,098 0,0 1 _print_dot (pswd_x.obj)

У середньому стовпчику (Func+Child Time) приводитися повний година виконання кожної функції, левова частина якого належить функції main (ну цього й випливало очікувати), за нею з мінімальним відривом треба gen_pswd зі своїми 99,6%, далі йде do_pswd — 98,9% і, сильно відстаючи від її, десь там на відшибі плететься CheckCRC, відтягаючи на собі всього лише 3,0%. А функцією CalculateCRC, з її боязким показником 1,6%, на перший погляд можна й зовсім зневажити! Отже, зважаючи на всі, мі маємо три "гарячих" крапки: main, gen_pswd і do_pswd.

Діаграма, що ілюструє загальний година виконання кожної з функцій. На перший погляд, отут три "гарячих" крапки, але насправді це не так

Втім, функцію main можна відкинути відразу. Вона, зрозуміла праворуч, ні в чому не "винувата". Залишаються функції gen_pswd і do_pswd. Якби це були абсолютно незалежні функції, те "гарячих" крапок було б і впрямь дві, алі в нашім випадку це не так. І, якщо з повного години виконання функції gen_pswd, відняти година виконання її дочірньої функції do_pswd в "матері" завтратитися всього лише…0,7%..... Так! Менше відсотка години виконання!

Звернемося до крайнього лівого стовпчика (лістинг 1.1) таблиці профилировщика (Funct Time), щоб підтвердити наші припущення. Дійсно, у програмі присутня всього лише одна "гаряча" крапка — do_pswd, і тільки її оптимізація здатна істотно збільшити швидкодію додатка.

Діаграма, що ілюструє чистий година роботи кожної з функцій (тобто з відрахуванням години дочірніх функцій). Як видно, у програмі є одна, алі надзвичайно "гаряча" крапка

Добрі, будемо вважати, що найбільше "гаряча" функція визначена й тепер мі палко бажаємо її оптимізувати. А для цього варто б довідатися картину розподілу "температури" усередині самої функції. На жаль, профіліровщик profile.exe (і інші подібні йому) не зможе нічим нам допомогти, оскільки його розв'язна здатність обмежується саме функціями.

Але, на наше щастя існують і більше розвинуті профіліровщики, що впевнено розрізняють окремі рядки й навіть машинні команди! До таким профилировщикам зокрема ставитися VTune від Intel. Давайте завантажимо його й заглянемо усередину функції do_pswd

Лістинг 1.2. Карта розподілу "температури" усередині функції do_pswd, отримана за допомогою профіліровщика VTune

Line

Clock ticks

Source

temperature

105

729

while((++pswd[p])>'z'){e

106

14

pswd[p] = '!';

107

1

y = y | y << 8;

108

2

x -= k;

109

k = k << 8;

110

3

k += 0x59;

111

2

p++;

112

1

}

Від тепер зовсім інша праворуч — відразу видно, що доцільно оптимізувати, а що й без того працює відмінно. "Гарячі" крапки головним чином зосереджені навколо конструкції pswd[p], — вона дуже повільно виконується. Чому? Вихідний текст не дає безпосередньої відповіді на поставлене питання й тому зовсім не ясно: що конкретно варто зробити для зниження "температури" "гарячих" крапок.

Доводити спускатися на рівень "голих" машинних команд (благо профіліровщик VTune це дозволяє). Від, наприклад, у що компілятор перетворив необразливий на вид оператор присвоєння pswd[p] = '!'

Лістинг 1.3. Дослідження температури машинних команд усередині конструкції pswd[p] = '!'

Line

Instructions

Cycles

Count

temperature

107

mov edx,DWORD PTR [ebp+0ch]

143

11

107

завантажити в регістр EDX покажчик pswd

107

add edx, DWORD PTR [ ebp-4]

22

11

107

скласти EDX зі змінної p

107

mov BYTE PTR [edx], 021h

33

11

107

по отриманому зсуві записати значення 0х21 ('!')

В одному рядку вихідного тексту відбувається цілих три звертання до пам'яті! Спочатку покажчик pswd завантажується в регістр EDX, потім він підсумується зі змінної p, що так саме розташована в пам'яті, і лише потім по розрахованому зсуві на згадку благополучно записується константа '!' (021h).

Проте, однаково залишається не ясно, чому завантаження покажчика pswd займає стільки години? Може бути, хтось постійно витісняє покажчик pswd з кэша, змушуючи процесор звертатися до повільної оперативної пам'яті? Так і є! Програма працює з великою кількістю змінних, що свідомо не вміщаються в кеш іншого рівня.

Питомна година виконання

Якщо година виконання деякої крапки програми не постійно, а варіюється в тихнув або інших межах (наприклад, залежно від роду оброблюваних даних), те трактування результатів профілювання стає неоднозначної, а сам результат — ненадійним. Для більше достовірного аналізу потрібно: а) визначити чи дійсно в програмі присутні подібні "плаваючі" крапки й, якщо так, ті: б) визначити година їхнього виконання в кращому, гіршому й середньому випадках.

Далеко не всі профіліровщики мають здатність визначати питомий година виконання машинних команд (інша назва розтактовка). На щастя, профіліровщик VTune це вміє! Звернемося до сгенерованого їм протоколу динамічного аналізу. Бути може, він допоможе нам дозволити загадку "неповороткості" завантаження покажчика pswd?

Лістинг 1.4. Питомий година виконання машинних команд усередині профилируемого фрагмента програми

Line

Instructions

Dyn-Retirement

Cycles

107 pswd[p] = '!';

107

mov edx, DWORD PTR [ebp+0ch]

13

107;

завантажити в регістр EDX покажчик pswd

107

add edx,DWORD PTR [ ebp-4]

2

107;

^ скласти регістр EDX зі змінної p

107

mov BYTE PTR [edx], 021h

3

107;

записати в *(pswd+p) значення '!'

109 y = y | y << 8;

109

mov eax,DWORD PTR [ ebp-28]

2

109;

завантажити в регістр EAX змінну y

109

shl eax, 08h

1

109;

зрушити EAX на 8 позицій уліво

109

mov ecx, DWORD PTR [ ebp-28]

(0,7.3,80)

109;

завантажити в регістр ECX змінну y

109

or ecx, eax

1

109;

ECX = ECX | EAX (tmp = y | y)

109

mov DWORD PTR [ ebp-28], ecx

1

109;

записати отриманий результат в y

110 x -= k;

110

mov edx, DWORD PTR [ ebp-24]

0

110;

завантажити в регістр EDX змінну x

110

sub edx, DWORD PTR [ ebp-36]

1

110;

відняти з регістра EDX змінну k

110

mov DWORD PTR [ ebp-24], edx

1

110;

записати отриманий результат в x

Ну, від знову, — всі команди, як команди, а завантаження покажчика pswd відбувається цілих тринадцять тактів, у тої година як інші вільно укладаються в один-два тактів, а деякі й зовсім займають нулів, маючи змогу завершитися одночасно з попередніми інструкціями.

За винятком команди, що завантажує вміст змінної y у регістр ECX, година виконання всіх інших команд строго постійно й не міняється година від години. Наша ж "підопічна" залежно від ще не з'ясованих обставин, може виконуватися навіть вісімдесят тактів, що на годину робить її самою "гарячою" крапкою даного фрагмента програми. Вісімдесят тактів — це взагалі повне свавілля! І пускай средній годину її виконання становить усього лише сім тактів, а мінімальне — і зовсім нуль, мі не заспокоїмося поки не з'ясуємо: на що й при яких саме обставинах іде така кількість тактів?

Інформація про пенальті

Уже сам факт існування "гарячої" крапки говорити про ті, що в програмі щось неправильно. Добрі, якщо це чисто алгоритмічна помилка, що видно неозброєним оком (наприклад, найбільш вузьким місцем додатка виявилося використання бульбашкового методу сортування). Гірше, якщо процесорний година зникає буквально на порожнім місці без усяких видимих на ті причин. Ще гірше, якщо "розкрадання" тактів відбуваються не систематично, а відбуваються при строго певнім стіканні якихось невідомих нам обставин.

Повернемося до попереднього питання: чому покажчик pswd завантажується так довго? І при яких саме обставинах завантаження змінної "підскакує" зі своїх звичайних семи до вісімдесятьох тактів? Зважаючи на всі, процесору щось не сподобалося й він обклав ці дві машинні команди "штрафом" (penalty), на годину пригальмувавши їхнє виконання. Чи можемо мі довідатися, коли й за який "провину" це відбулося? Не прибігаючи до повної емуляції процесора — чи навряд (хоча сучасні процесори x86 з деякими обмеженнями дозволяють одержати цю інформацію й так).

Гранди комп'ютерної індустрії — Intel і AMD уже давно випустили власні профіліровщики, що містять повноцінні емулятори процесорів, що випускаються ними,, ці програми дозволяють візуалізувать нюанси виконання кожної машинної інструкції.

Просто клацніть по рядку mov ecx, DWORD PTR [ ebp-28] і профіліровщик VTune видасть всю, наявну в нього інформацію (лістинг 1.5).

Лістинг 1.5. Висновок програми VTune додаткової інформації про виконання інструкції

decoder minimum clocks = 1 ; МІНІМАЛЬНИЙ ГОДИНА ДЕКОДУВАННЯ – 1 ТАКТ

Decoder Average Clocks = 8.7 ; Ефективний година декодування – 8,7 тактів

Decoder Maximum Clocks = 86 ; Максимальний година декодування – 86 тактів

 

Retirement Minimum Clocks = 0, ; МІНІМАЛЬНИЙ ГОДИНА ЗАВЕРШЕННЯ – 0 ТАКТІВ

Retirement Average Clocks = 7.3 ; Ефективний година завершення – 7,3 такти

Retirement Maximum Clocks = 80 ; Максимальний година завершення – 80 тактів

  total cycles = 80 (00,65%) ; УСЬОГО ЧАСУ ВИКОНАННЯ – 80 ТАКТІВ

 micro-ops for this instruction = 1 ; КІЛ-У МІКРООПЕРАЦІЙ В ІНСТРУКЦІЇ – 1

 The instruction had to wait 0 cycles for it's sources to be ready

("ІНСТРУКЦІЯ ЧЕКАЛА 0 ТАКТІВ ПОКИ ПІДГОТОВЛЯЛИСЯ ЇЇ ОПЕРАНДЫ, Т.Е. ПОПРОСТУ ВОНА ЇХ НЕ ЧЕКАЛА ЗОВСІМ")

 Dynamic Penalty: IC_miss

The instruction was not in the instruction cache, so the processor loads the instruction from the L2 cache or main memory.

("ІНСТРУКЦІЯ БУЛА ВІДСУТНЯ В КОДОВОМУ КЕШ, І ПРОЦЕСОР БУВ ЗМУШЕНИЙ ЗАВАНТАЖУВАТИ ЇЇ З КЕШ ІНШОГО РІВНЯ АБО ОСНОВНОЇ ОПЕРАТИВНОЇ ПАМ'ЯТІ")

Occurances = 1 ; Таке траплялося 1 раз

Dynamic Penalty: L2instr_miss

The instruction was not in the L2 cache, so the processor loads the instruction from main memory.

("ІНСТРУКЦІЯ БУЛА ВІДСУТНЯ В КЕШ ІНШОГО РІВНЯ Й ПРОЦЕСОР БУВ ЗМУШЕНИЙ ЗАВАНТАЖУВАТИ ЇЇ З ОСНОВНОЇ ОПЕРАТИВНОЇ ПАМ'ЯТІ")

Occurances = 1 ; Таке траплялося 1 раз

Dynamic Penalty: Store_addr_unknown

The load instruction stalls due to the address calculation of the previous store instruction.

(" ІНСТРУКЦІЯ, ЩОЗАВАНТАЖУЄ, ПРОСТОЮВАЛА З ТІЄЇ ЗАПОДІЙ, ЩО АДРЕСИ ДЖЕРЕЛА РОЗРАХОВУВАВСЯ ПОПЕРЕДНЬОЮ ІНСТРУКЦІЄЮ ЗАПИСУ")

Occurances = 10 ; Таке траплялося 10 разів

Так, здається, наше розслідування перетворюється в самого справжнього детектива. Якщо прикласти до отриманого результату навіть самий скромний арифметичний апарат, вийде повна нісенітниця й повна розбіжність "дебіту із кредитом". Аналізуйте самостійно. Повний година виконання інструкції — 80 тактів, причому, відомо, що вона виконувалася 11 разів (див. у лістингу 1.3 колонкові count звіту профіліровщика). А найгірший година виконання інструкції склало…80тактів! А найгірший година декодування й зовсім — 86! Тобто, гірший година декодування інструкції перевищує загальний година її виконання й при цьому в десяти ітераціях вона ще може простоювати як мінімум один такт за кожну ітерацію через зайнятість блоку розрахунку адреса.

Причина такої невідповідності полягає у відносності самого поняття години. Ви думаєте година відносно тільки в Эйнштейна? Аж ніяк! У конвеєрних процесорах (зокрема процесорах Pentium і AMD K6/Athlon) поняття "години виконання інструкції" взагалі не існує в принципі. У силу того, що кілька інструкцій можуть виконуватися паралельно, просте алгебраїчне підсумовування години їхнього виконання дасть значно більший результат, ніж виконання займає в дійсності.

Добрі, залишимо розбирання з відносністю до більше пізніх часів, а поки оборотний увага на тої факт, що в силу відсутності нашої інструкції в кеш (вона саме перебуває на границі двох кэш-лінійок) і необхідності, що випливає звідси, завантажувати її з основної пам'яті, у першій ітерації циклу вона виконується значно повільніше, ніж у всіх наступних. Звідси, властиво, і беруться ці горезвісні вісімдесят тактів.

При великій кількості ітерацій (а при "живому" виконанні програми воно й впрямь велико) годиною початкового завантаження можна й зневажити, алі…Стоп! Адже профіліровщик виконав тіло даного циклу всього 11 разів, у результаті чого середній година виконання цієї інструкції склало 7,3 тактів, що зовсім не відповідає реальній дійсності!

Виявляється, це зовсім не "гаряча" крапка! І отут зробленого німа чого оптимізувати. Якщо мі збільшимо кількість прогонів профіліровщика хоча б у чотири рази, середній година виконання нашої інструкції понизитися до 1,8 тактів і вона виявиться одним із самих "холодних" місць програми! Точніше — це взагалі абсолютний нуль, оскільки ефективний година виконання даної інструкції — нуль тактів (тобто  вона завершується одночасно з попередньою машинною командою). Словом, мі "промахнулися" по повній програмі.

Звідси правило: перш ніж приступати до оптимізації, переконаєтеся, що кількість прогонів програми досить велика для маскування накладних витрат первісного завантаження.

Лістинг 1.6. Демонстрація коду, деякі ділянки якого аналізуються профіліровщиком відносно невелику кількість разів, що спотворює результат профілювання

while((++pswd[p])>'z') // даний цикл прогоняется профилировщиком 1.000 разів

{

pswd[p] = '!'; // дана інструкція прогоняется всього 11 разів

}

Тому, виявивши "гарячу" крапку в першу чергу переконаєтеся, що кількість її прогонів досить великий. У противному випадку отриманий результат з великим ступенем імовірності виявиться недостовірним. І отут мі плавно переходимо до обговорення підрахунку числа викликів кожної крапки програми.

Втім ні, постійте. Нам ще має бути розібратися із другою "гарячою" крапкою й напрочуд повільною швидкістю завантаження покажчика pswd. Досвідчені програмісти, імовірно, уже догадалися в чому отут праворуч.

Дійсно, — рядок pswd[p] = '!' — це перший рядок тіла циклу, що одержує керування кожні 0x59 ітерацій, що набагато перевершує "проникливість" динамічного алгоритму пророкування розгалужень, що використовується процесором для запобігання зупинки обчислювального конвеєра.

Отже, дане розгалуження завжди передвіщається помилково й виконання цієї інструкції процесору доводити починати з нуля. А процесорний конвеєр — довгий. Поки він заповнитися…Властиво, отут винувата зовсім не команда mov edx, dword ptr [ebp+0ch] — будь-яка інша команда на її місці виконувалася б настільки ж непродуктивно! "Паяльна грілка, до червона нагріває" цю крапку програми, перебуває зовсім в іншому місці!

Піднімемо курсор ледве вище, на інструкцію умовного переходу попередній цій команді, і двічі клацнемо мишкою. Профіліровщик VTune видасть наступну інформацію:

decoder minimum clocks = 0 ; МІНІМАЛЬНИЙ ГОДИНА ДЕКОДУВАННЯ – 0 ТАКТІВ

Decoder Average Clocks = 0 ; Ефективний година декодування – 0 тактів

Decoder Maximum Clocks = 4 ; Максимальний година декодування – 4 такти

retirement average clocks = 1 ; ЕФЕКТИВНИЙ ГОДИНА ЗАВЕРШЕННЯ – 1 ТАКТ

total cycles = 1011 (08,20%) ; УСЬОГО ЧАСУ ВИКОНАННЯ – 1010 ТАКТІВ (8,2%)

micro-ops for this instruction = 1 ; КІЛ-У МІКРООПЕРАЦІЙ В ІНСТРУКЦІЇ – 1

The instruction had to wait (8,11.1,113) cycles for it's sources to be ready

("ЦЯ ІНСТРУКЦІЯ ЧЕКАЛА МІНІМАЛЬНО 8, МАКСИМАЛЬНО 113, А В ОСНОВНОМУ 11,1 ТАКТІВ ПОКИ ЇЇ ОПЕРАНДЫ НЕ БУЛИ ГОТОВІ")

Dynamic Penalty: BTB_Miss_Penalty ; ШТРАФ ТИПУ btb_miss_penalty

This instruction stalls because the branch was mispredicted.

("ЦЯ ІНСТРУКЦІЯ ПРОСТОЮВАЛА ТОМУ ЩО РОЗГАЛУЖЕННЯ НЕ БУЛО ПЕРЕДВІЩЕНО")

Occurances = 13 ; Таке траплялося 13 разів

Наша гіпотеза повністю підтверджується. Це розгалуження тринадцять разів передвіщалося неправильно, про що VTune і свідчить! Постій, як тринадцять?! Адже тіло циклу виконується тільки одинадцять! Так, правильно, одинадцять. Алі адже процесор наперед цього не знав, і двічі намагався передати на нього керування, і лише потім, "побачивши", що жодне із двох пророкувань не збулося, "плюнувши і заприсяг", що ніколи-ніколи не поставити свої фішки на цю гілку.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]