Кеш-пам'ять процесора. Рівні та принципи функціонування
Одним з важливих факторів, що підвищують продуктивність процесора, є наявність кеш-пам'яті, а точніше її обсяг, швидкість доступу та розподіл за рівнями.
Вже досить давно майже всі процесори оснащуються цим типом пам'яті, що вкотре доводить корисність її наявності. У цій статті, ми поговоримо про структуру, рівні та практичне призначення кеш-пам'яті, як про дуже важливу характеристику процесора.
Що таке кеш-пам'ять та її структура
Кеш-пам'ять – це надшвидка пам'ять, що використовується процесором, для тимчасового зберігання даних, які найчастіше використовуються. Ось так, коротко, можна описати цей тип пам'яті.
Кеш-пам'ять побудована на тригерах, які у свою чергу складаються з транзисторів. Група транзисторів займає набагато більше місця, ніж ті ж конденсатори, з яких складається оперативна пам'ять. Це тягне у себе безліч труднощів у виробництві, і навіть обмеження обсягах. Саме тому кеш пам'ять є дуже дорогою пам'яттю, при цьому володіючи незначними обсягами. Але з такої структури випливає головна перевага такої пам'яті – швидкість. Так як тригери не потребують регенерації, а час затримки вентиля, на яких вони зібрані, невелика, то час перемикання тригера з одного стану до іншого відбувається дуже швидко. Це дозволяє кеш-пам'яті працювати на таких же частотах, що і сучасні процесори.
Також важливим фактором є розміщення кеш-пам'яті. Розміщена вона на самому кристалі процесора, що значно зменшує час доступу до неї.Раніше, кеш пам'ять деяких рівнів, розміщувалася поза кристала процесора, на спеціальній мікросхемі SRAM десь на просторах материнської плати. Зараз, практично у всіх процесорів, кеш-пам'ять розміщена на кристалі процесора.
Навіщо потрібна кеш-пам'ять процесора?
Як згадувалося, головне призначення кеш-пам'яті – це зберігання даних, які часто використовуються процесором. Кеш є буфером, в який завантажуються дані, і, незважаючи на його невеликий об'єм, (близько 4-16 Мбайт) у сучасних процесорах, він дає значний приріст продуктивності у будь-яких додатках.
Щоб краще зрозуміти необхідність кеш-пам'яті, давайте уявімо організацію пам'яті комп'ютера у вигляді офісу. Оперативна пам'ять буде шафою з папками, до яких періодично звертається бухгалтер, щоб витягти великі блоки даних (тобто папки). А стіл буде кеш-пам'яттю.
Існують такі елементи, які розміщені на столі бухгалтера, до яких він звертається протягом години по кілька разів. Наприклад, це можуть бути номери телефонів, приклади документів. Дані види інформації знаходяться прямо на столі, що, у свою чергу, збільшує швидкість доступу до них.
Так само, дані можуть додатися з великих блоків даних (папок), на стіл, для швидкого використання, наприклад, будь-який документ. Коли цей документ стає не потрібним, його поміщають назад у шафу (в оперативну пам'ять), тим самим очищаючи стіл (кеш-пам'ять) та звільняючи цей стіл для нових документів, які будуть використовуватись у наступний відрізок часу.
Також і з кеш-пам'яттю, якщо є якісь дані, до яких найімовірніше буде повторне звернення, то ці дані з оперативної пам'яті підвантажуються в кеш-пам'ять. Дуже часто, це відбувається зі спільним завантаженням тих даних, які найімовірніше будуть використовуватися після поточних даних. Тобто тут є наявність припущень про те, що ж буде використано «після». Ось такі складні принципи функціонування.
Рівні кеш-пам'яті процесора
Сучасні процесори, оснащені кешем, який складається, найчастіше з 2-ух або 3-х рівнів. Звичайно ж, бувають і винятки, але найчастіше це саме так.
Загалом можуть бути такі рівні: L1 (перший рівень), L2 (другий рівень), L3 (третій рівень). Тепер трохи докладніше щодо кожного з них:
Кеш першого рівня (L1) – найбільш швидкий рівень кеш-пам'яті, який працює безпосередньо з ядром процесора, завдяки цій щільній взаємодії, даний рівень має найменший час доступу та працює на частотах близьких процесору. Буфер між процесором і кеш-пам'яттю другого рівня.
Ми розглядатимемо обсяги на процесорі високого рівня продуктивності Intel Core i7-3770K. Цей процесор оснащений 4х32 Кб кеш-пам'яті першого рівня 4 x 32 КБ = 128 Кб. (На кожне ядро по 32 КБ)
Кеш другого рівня (L2) – другий рівень масштабніший, ніж перший, але в результаті, має менші «швидкісні характеристики». Відповідно, служить буфером між рівнем L1 та L3. Якщо знову звернутися до нашого прикладу Core i7-3770 K, то тут обсяг кеш-пам'яті L2 становить 4х256 Кб = 1 Мб.
Кеш третього рівня (L3) – третій рівень, знову ж таки, повільніший, ніж два попередні.Але все одно він набагато швидший, ніж оперативна пам'ять. Об'єм кешу L3 в i7-3770K становить 8 Мбайт. Якщо два попередні рівні поділяються на кожне ядро, цей рівень є загальним для всього процесора. Показник досить солідний, але не надхмарний. Так як, наприклад, у процесорів Extreme-серії на кшталт i7-3960X, він дорівнює 15Мб, а в деяких нових процесорів Xeon, понад 20.
Кеш пам'ять процесора – наскільки важлива вона
Кеш пам'ять (Cache)- масив надшвидкої оперативної пам'яті, що є буфером між контролером системної пам'яті та процесором. У цьому буфері зберігаються блоки даних, з якими центральний процесор працює в даний момент, тим самим значно зменшується кількість звернень до повільної системної пам'яті. Тим самим помітно зростає загальна продуктивність процесора.
Розрізняють кеш пам'ять 1-, 2- та 3-го рівнів (маркуються L1, L2 і L3).
Кеш пам'ять першого рівня (L1) - Найшвидший, але за обсягом менший, ніж у інших. З ним працює ядро процесора. Вона має найменшу латентність (час доступу).
Кеш пам'ять другого рівня (L2) - Об'єм цієї пам'яті значно більше, ніж L1.
Кеш пам'ять третього рівня (L3) – з більшим обсягом, але повільніша, ніж L2.
У традиційному варіанті існувало два рівні кеш-пам'яті - перший і другий рівень. Третій рівень по організації відрізняється від L2. Якщо дані не оброблялися або процесор повинен обробити термінові дані, для звільнення L2 дані переміщуються в кеш пам'ять 3-го рівня. L3 більше за розміром, однак, і повільніше, ніж L2 (шина між L2 і L3 більш вузька, ніж шина між L1 і L2), але все ж таки його швидкість, набагато вища швидкість оперативної пам'яті.
У кеш пам'ять другого рівня спочатку передаються всі дані, для обробки центральним процесором, дані частково декодуються і переходять далі в ядро.
У L2 з даних будуються ланцюжок інструкцій, а L1 «дзеркально» будуються внутрішні команди процесора, які враховують особливості процесора, регістри тощо. Число внутрішніх команд центрального процесора не дуже багато тому величина кеша 1-го рівня не має великого значення (у сучасних процесорах L1 може бути з 64 Кб, 128Кб на кожне з ядер). На відміну від L1, L2 для процесора має велике значення, саме тому процесори з максимальним обсягом кеша 2-го рівня демонструють високу продуктивність.
В організації структури пам'яті процесорів AMD та Intel існують відмінності. Наприклад, процесори AMD чітко розділені між ядрами кеш пам'яті, і маркуються відповідно - 512х2 (Athlon 5200 і нижче) або 1024х2 (у Athlon 5200 та вище). А у процесорів Intel Core2Duo кеш строго не поділений, а значить для кожного з ядер можна використовувати необхідну кількість пам'яті, це добре підходить для систем, що не підтримують багатоядерність. Якщо використовувати всі ядра, кеш пам'ять поділяється на кожне ядер динамічно, залежно від навантаження кожного з ядер.
Java та сучасний процесор, Частина 1: Пам'ять та ієрархія кешу
Уявімо, що у нас є масив, що містить 67 000 цілих елементів. Над цим масивом виконуються два цикли, як показано в Лістинге 1. Обидва ці цикли просто множать елементи масиву на три. Однак якщо перший цикл змінює кожен елемент, другий цикл змінює тільки кожен 16-й елемент.Наскільки швидше працюватиме другий цикл порівняно з першим? Спробуйте вгадати: у 16 разів швидше?
Лістинг 1. Який цикл відпрацює швидше?
private static final int ARRAY_SIZE = 64*1024*1024; public int[] array = новий int[ARRAY_SIZE]; for (int i = 0, n = array.length; i < n; i + +) < array [i] * = 3; >for (int i = 0, n = array.length; i
Можливо, відповідь на це питання виявиться для вас несподіваною - при виконанні коду на звичайному ноутбуці обидва цикли займають приблизно однаковий час. На малюнку 1 показані результати вимірювань на трьох комп'ютерах, і, як бачите, різниця незначна. Другий цикл виконує лише невелику частину роботи, тому що це можливо, що перший цикл працює з тією ж швидкістю?
Малюнок 1. Порівняння продуктивності двох циклів на трьох різних комп'ютерах.
Щоб зрозуміти причину такої поведінки, нам потрібно розібратися, як працюють процесор та система пам'яті. На найнижчому рівні сучасні комп'ютери можуть демонструвати фокуси схожі на квантову механіку, яка, здавалося б, суперечить повсякденному досвіду. Але іноді квантова механіка помітно впливає на реальний світ. І тонкощі влаштування процесів на апаратному рівні теж іноді мають помітний (і з першого погляду не очевидний) вплив на програми. У цій статті ми розглянемо роботу сучасних комп'ютерів на найнижчому рівні, приділивши особливу увагу тому, що може вплинути на продуктивність.
Інструкції, процесори, пам'ять та кеш
Якщо ми спробуємо уявити собі, як виконуються цикли в Лістингу 1, то перше, що спадає нам на думку, це ситуація, коли масив зберігається в оперативній пам'яті, а процесор зчитує елемент за елементом, множить кожен елемент на три і записує результат назад, Як показано на малюнку 2. Така інтерпретація може допомогти нам зрозуміти принцип роботи циклів, але це не зовсім те, що насправді відбувається всередині комп'ютера.
На малюнку 3 показаний графік відносного підвищення продуктивності процесорів та пам'яті за останні десятиліття. Продуктивність пам'яті постійно зростала протягом усього цього періоду, але це зростання не йде в жодні порівняння з підвищенням швидкості процесора, особливо в 1990-і роки. В останні роки швидкість простих процесорів досягла стелі, але не варто дурити! Шкала на Малюнку 3 є логарифмічною. Незважаючи на те, що може здатися, що продуктивність пам'яті наздоганяє процесори, розрив все ще величезний.
Малюнок 3. Відносне підвищення швидкості процесорів та пам'яті за останні три десятиліття (логарифмічна шкала)
Насправді, якби комп'ютер працював саме так, як показано на Малюнку 2, він був би вкрай неефективним, оскільки надшвидкий процесор більшу частину часу чекав би, поки набагато повільніша оперативна пам'ять видасть йому наступний елемент.
Щоб обійти це вузьке місце, розробники процесорів додали шар кеш-пам'яті між процесором та основною пам'яттю. Кеш-пам'ять є набагато швидшим модулем пам'яті, метою якого є скорочення розриву в продуктивності. На малюнку 4 представлена ця вдосконалена модель процесора та системи пам'яті.
Зазвичай програми звертаються до тих самих даних і коду кілька разів протягом короткого періоду часу (тимчасова локальність), а доступ до пам'яті часто обмежується невеликими фрагментами (просторова локальність). Це означає, що якщо завантажити в кеш всі дані, то велика ймовірність того, що вони знову знадобляться трохи пізніше. Оскільки наступного разу, коли вам знадобляться ці дані, вони, можливо, все ще будуть у кеші, продуктивність ваших програм значно зростає.
Але тепер виникає закономірне питання: якщо між процесором та оперативною пам'яттю можна вставити швидшу пам'ять, то чому не можна зробити швидшою всю пам'ять комп'ютера? На це є дві серйозні причини:
- Оперативна пам'ять набагато більше кеш-пам'яті, і банально потрібно більше часу, щоб знайти потрібну адресу в межах 16 Гбайт (типовий розмір оперативної пам'яті на момент написання статті), ніж якщо ми шукали потрібну адресу в межах 8 Кбайт (типовий розмір кеш-пам'яті) першого рівня [L1]).
- Електронні компоненти кеш-пам'яті набагато більш вимогливі з точки зору тепловиділення та займаної площі, ніж ті, що використовуються в оперативній пам'яті. Тепло і простір є лімітуючими чинниками розробки сучасних мікросхем зокрема, і розробки сучасних комп'ютерів загалом.
Для отримання вигоди з просторової локальності кеш-пам'ять працює не з окремими байтами, а з рядками кеш-пам'яті. Кеш-рядок (або кеш-лінія) - це суміжна частина пам'яті, зазвичай 64 байти.
Якщо брати до уваги кеш-рядки, те, що відбувається при ітерації великих циклів з Лістингу 1, можна побачити на рис.Процесор завантажує повний рядок в кеш з оперативної пам'яті і модифікує елементи в кеші безпосередньо. Перший цикл модифікує всі елементи в кеш-рядку, а другий - тільки один елемент (з 16 цілих чисел завдовжки 4 байти кожне).
Обмежуючим чинником за такої організації роботи є завантаження рядків у кеш, тому кількість операцій, що виконуються над кожним рядком кешу, практично не має значення. Це пояснює, чому продуктивність обох циклів приблизно однакова.
Малюнок 5. Додавання кеш-рядків у функціональні діаграми показує, чому два цикли виконуються майже за те саме час.
Підрахунок кількості інструкцій для оцінки продуктивності алгоритму є корисною апроксимацією, оскільки цей метод простий і зазвичай дає нам гарне уявлення. Але, як видно з наведеного вище прикладу, необхідно враховувати, що це лише приблизна оцінка. Насправді ж час виконання окремих інструкцій сильно варіюється, і покладатися лише з їх кількість не можна.
Розмір даних та кеші L1, L2 та L3
Чи впливає структура даних на продуктивність під час виконання? Щоб відповісти на це питання, спробуємо провести невеликий експеримент із використанням коду з Лістингу 2. Візьміть другий цикл із коду першого прикладу та запустіть його кілька разів. Однак цього разу змініть розмір масиву та виміряйте середній час виконання однієї ітерації циклу.
Мета цього експерименту — запустити тривіальний алгоритм структури даних, розмір якої ми можемо контролювати. Цей експеримент повинен показати залежність між розміром масиву та часом, необхідним модифікації одного елемента.
Лістинг 2.Тест дозволяє побачити, як зміна розміру структури даних може вплинути на продуктивність під час виконання програми.
private static final int ARRAY_CONTENT = 777; @Param() public int size; public int[] array; public int counter; public int mask; @Setup(Level.Iteration) public void setUp() < final int elements = size / 4; final int indexes = elements/16; mask = indexes – 1; array = new int[elements]; Arrays.fill(array, ARRAY_CONTENT); counter = 0; for (int i = 0; i < indexes; i++) < seqIndex[i] = 16 * i; >> @Benchmark public void benchLoop()
Перш ніж подивитися на реальні результати, давайте трохи поміркуємо про те, що ми очікуємо побачити. Доступ до одного елемента масиву відбувається за певний (константний) проміжок часу, що записується у вигляді O(1) згідно з нотацією великого О. Отже, внутрішня частина циклу також має виконуватися за константний час. Таким чином, для досить великих масивів ми досягнемо верхньої межі цього показника, який буде константним. Але що відбувається до досягнення верхнього кордону? Чи завжди час виконання буде однаковим?
На малюнку 6 показана залежність між розміром масиву та часом доступу до елемента. Як бачите, між цими величинами існує залежність. Так, поодинока модифікація виконується швидше, якщо масив невеликий. Але не все так просто. Отримана крива нагадує ступінчасту функцію. Час доступу залишається одним і тим самим, доки розмір масиву не перевищить певний поріг, а потім він перескакує на новий рівень, де і залишається таким же до досягнення наступного порога.
Чому взагалі існує така залежність і звідки беруться ці щаблі? Ми зможемо відповісти на це питання, якщо згадаємо різні типи кеш-пам'яті в сучасному процесорі.
Малюнок 6. Залежність між часом доступу до елемента та розміром масиву.
Кеш-пам'ять, як правило, не є єдиним блоком, а складається з кількох ієрархічних рівнів з різними розмірами та часом доступу. Як показано на малюнку 7, кеш L1 є найменшим і найшвидшим. L2 більше та значно повільніше. L3 ще більше і повільніше, але все одно набагато швидше за основну пам'ять.
Малюнок 7. Ієрархія кеш-пам'яті: від процесора до L1, L2, L3 та оперативної пам'яті.
Наскільки великі розриви у продуктивності між різними рівнями кеш-пам'яті? Щоб пояснити це у більш доступній для розуміння формі, мій колишній колега Річард Томпсон (Richard Thompson) вигадав “пивну ієрархію”. Уявіть собі, що ви сидите перед телевізором, дивіться гру улюбленої спортивної команди і вам хочеться випити пива.
- Кеш L1 – це пляшка пива у вашій руці. Час доступу до неї практично миттєво (< 1 нс), але її обсяг, якщо можна так сказати, вкрай обмежений (наприклад, 32 КБ на моєму комп'ютері).
- Кеш L2 – це холодильник поряд з диваном. Час доступу досі досить мало (7 нс), але обсяг значно більший (256 КБ, що еквівалентно 8 пляшкам пива).
- Кеш L3 – це холодильник на кухні. Час доступу вже помітно більший (25 нс), але об'єм настільки великий, що аналогія починає розсипатися (8 МБ, що еквівалентно 256 пляшкам пива).
- Оперативна пам'ять - це магазин на розі.Час доступу до нього величезний (100 нс), але пива там вистачить, напевно, на все ваше життя (16 Гбайт, що еквівалентно більш ніж півмільйона пляшок пива).
Дивлячись на ці цифри, стає цілком очевидно, чому обидва цикли у вихідному прикладі зайняли однаковий час, адже не має значення скільки ковтків пива ви вип'єте, якщо за кожною пляшкою доведеться бігти в магазин на розі.
А тепер повернімося до графіка на Малюнку 6. Кожне плато на графіку відповідає одному з рівнів в ієрархії кеш-пам'яті. Поки масив міститься в кеші L1 і L2 час доступу дуже мало. Але як тільки масив стає занадто великим і його доводиться зчитувати з кешу L3 час доступу помітно збільшується. І те саме відбувається, коли масив не міститься в кеш L3 і його доводиться читати з оперативної пам'яті. Якщо придивитися, то на графіку можна розглянути невеликий перескок між кешами L1 та L2.
Розмір має значення. Незважаючи на те, що пам'ять зараз дешевша, ніж будь-коли, намагайтеся не розбазарювати її. Чим менший обсяг даних, займаний тією чи іншою структурою, тим вища ймовірність того, що вона поміститься в кеш, що, у свою чергу, може призвести до помітного підвищення продуктивності.
Схеми доступу до даних та інструмент perf
Розмір даних впливає продуктивність. А чи впливає на продуктивність порядок (схема) доступу до даних? Щоб знайти відповідь на це питання, нам потрібно трохи змінити попередній експеримент. Тепер замість того щоб просто пробігати масивом по порядку, ми створимо другий масив, в якому зберігатиметься порядок доступу. Спочатку ми виконаємо послідовний доступ до масиву, як і раніше, а потім довільний, і заміряємо різницю.Код обох експериментів наведено у Лістингу 3.
Лістинг 3. Різний порядок доступу даних.
public int[] rndIndex; @Setup(Level.Iteration) public void setUp() < … rndIndex = new int[indexes]; final Listlist = новий ArrayList<>(indexes); for (int i=0; i Collections.shuffle(list); for (int i=0; i >
Якщо ми проведемо цей експеримент із масивами різної довжини і на основі результатів побудуємо графік, то у нас вийдуть дві криві, як показано на малюнку 8. І ось ми знову бачимо вже знайому картину зі сходинками. Обидві криві демонструють однаковий час доступу на двох нижніх рівнях, які відповідають кешам L1 та L2.
Але на третьому рівні продуктивність схеми послідовного доступу помітно вища. На четвертому рівні спостерігається істотна різниця. Чому порядок доступу не має особливого впливу на малі масиви і так відчутний на великих?
Малюнок 8. Продуктивність при послідовному та випадковому доступі до елементів.
Розібратися, що відбувається всередині комп'ютера, нам допоможе профільувальник Linux – інструмент perf, який збирає та відображає події, що генеруються процесором та системою пам'яттю під час виконання програми. Спосіб роботи з perf у командному рядку нагадує роботу з git. Викликати perf можна за допомогою команди, яку ви хочете виконати, наприклад:
Отримати список усіх команд можна за допомогою команди perf-help. Щоб отримати довідку щодо конкретної команди, можна виконати таке:
Але найбільш важливою командою є stat , яка дозволяє perf запустити іншу програму та відстежує апаратні події під час її виконання, наприклад:
perf stat [ARGS] PROGRAM
Ця команда, введена без жодних аргументів, запустить програму PROGRAM, і відстежуватиме деякі спільні події до завершення роботи програми, після чого виведе статистику. На малюнку 9 ви можете бачити типовий висновок:
За допомогою опції -e можна вказати які саме події повинні відстежуватися. Щоб переглянути список подтримуваних подій, запустіть команду perf list .
Java зазвичай не потрібно відстежувати всю програму повністю, оскільки це передбачає підключення віртуальної машини, just-in-time (JIT) компіляції і т.д. На щастя, perf можна підключитися до запущеного процесу за допомогою опції -p. Необхідно вказати програму, яка виконуватиметься – вимір закінчиться, як тільки ця програма завершиться. Щоб задати тривалість тесту, можна використовувати команду sleep.
Спочатку виміряємо обидва цикли, використовуючи стандартні налаштування perf. Це дасть нам гарне уявлення про швидкодію. На малюнку 10 ми бачимо цікаві результати:
Кількість тактів простою (stalled front-end/back-end cycles) суттєво відрізняється в обох прогонах. Такт простою означає, що процесор простоює в очікуванні чогось. Однією з найімовірніших причин front-end тактів простою є "непопадання" в кеш (cache miss - відсутність затребуваних даних у кеші), в результаті якого процесор очікує надходження даних з оперативної пам'яті або повільнішого кешу. Для підтвердження цього припущення можна знову запустити perf, але цього разу спеціально для вимірювання навантаження на кеш та відсотки промахів. Результат можна побачити на Рисунку 11:
Малюнок 11. Тест perf, що замірює завантаження з кеш-пам'яті та відсоток непопадань.
Співвідношення між успішними завантаженнями та промахами сильно різниться.При послідовному зверненні до масиву всього лише близько 6% всіх завантажень пам'яті призводять до непотраплення в кеш. доводиться завантажувати все з оперативної пам'яті. Але чому при послідовному зверненні до масиву промахів майже немає?
Час, необхідний для завантаження даних з основної пам'яті в ієрархію кешу, часто є основним вузьким місцем. ви змінюєте елементи рядка кешу, спеціальний механізм префетчером, завантажує в кеш наступний рядок. вже будуть доступні у кеші.
Малюнок 12. Префетчер завантажує інформацію з оперативної пам'яті у рядок кешу.
Він може правильно вгадати наступну комірку пам'яті тільки в тому випадку, якщо, наприклад, завантаження пам'яті відбувається за стандартною послідовною схемою:
- У першому випадку, коли ви проходили масив послідовно, вгадати наступну комірку пам'яті було легко, і префетчер міг пом'якшити значну частину втрат продуктивності, попередньо вибравши наступну комірку пам'яті.
- Але при випадковому зверненні до масиву правильно вгадати наступну комірку пам'яті було неможливо, і алгоритму доводилося чекати, поки дані завантажаться з оперативної пам'яті, проте мінусів у префетчингу немає.
Схема доступу істотно впливає на продуктивність алгоритму, але можливості використання цього знання в Java обмежені. Ви практично не маєте контролю над розташуванням даних у пам'яті.
Використання інструментів мікробенчмаркінгу
Мікробенчмаркінг - це ще один цінний інструмент, що дозволяє отримати більш глибоке уявлення про ваші програми. Ймовірно, найважливіше правило мікробенчмаркінгу - завжди використовувати інструмент, який допомагає уникнути багатьох "підводних каменів", таких як недостатнє прогрівання віртуальної машини, усунення мертвого коду та розгортання циклів.
Java Microbenchmark Harness (JMH) є, мабуть, найкращим із існуючих на сьогоднішній день. JMH - це Java-інструмент для створення, запуску та аналізу мікробенчмарків, написаних на Java та інших мовах, орієнтованих на JVM.
Тести, написані під JMH, аналогічні JUnit тестам. Код, який ви хочете перевірити, повинен знаходитися в одному методі і повинен бути анотований @ Benchmark. Тест можна конфігурувати за допомогою інструкцій на рівні класу. На Малюнку 13 показані найважливіші інструкції та їх значення. Вам слід трохи поекспериментувати із цим інструментом, щоб зрозуміти, як він працює.
Малюнок 13. Важливі інструкції для Java Microbenchmark Harness
Висновок
Найчастіше процеси на апаратному рівні не мають істотного впливу на програми, але не завжди. Тому мати хоча б приблизне уявлення про те, що відбувається на апаратному рівні, дуже корисне.
У цій статті йшлося про пам'ять і, зокрема, про ієрархію кешу. У другій частині цього циклу я розкрию тему виконання інструкцій, зокрема, ми поговоримо про хибний поділ і помилкові передбачення умовних розгалужень.
Додаткові матеріали на тему
Нещодавно вчені відкрили, що на світі бувають неуважні розробники, які роблять навпаки. Вчені вигадали, що таким розробникам потрібно давати не корисні, а шкідливі поради. Вони все зроблять навпаки, і вийде якраз правильно.
Запрошуємо всіх бажаючих розробників на відкритий урок сьогодні о 20:00, на якому розберемо шкідливі поради щодо створення коду. Після заняття ви точно знатимете, як НЕ треба писати код, щоб успішно проходити співбесіди та працювати в команді на проектах. Це безкоштовне заняття проходитиме в рамках курсу «Поглиблене вивчення мови Java». Записатися можна за посиланням.