центральний процесор- (англ. "central processing unit", CPU - центральний процесорний пристрій) - мікросхема, призначена для обробки програмного коду і визначає основні функції комп'ютера, що стосуються обробки інформації. Процесор виконує логічні та арифметичні операції, керує обчислювальними процесами та займається координацією роботи пристроїв системи.

Центральний процесор є чіп, який розташований на материнській платі або встановлюється в неї.

Розглянемо основні характеристики мікропроцесора.

Ядро- це основна складова центрального процесора, яка визначає більшість параметрів процесора, наприклад, таких як тип сокету, діапазон робочих частот і частоту роботи внутрішньої шини передачі даних (FSB).

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

Кількість ядер - кількість ядер у ЦПУ. Збільшення кількості ядер ЦПУ підвищує його продуктивність.

Об'єм КЕШ – пам'яті першого рівня (кеш L1)

Кеш L1 - це високошвидкісна пам'ять обсягом від 8 до 128 Кб, у якому копіюються дані з оперативної пам'яті. Блок кеш-пам'яті розміщується на ядрі процесора. Завдяки тому, що обробка даних у кеш-пам'яті відбувається швидше, ніж даних з оперативної пам'яті, зберігання КЕШ основних команд дозволяє збільшити продуктивність ЦПУ. Для багатоядерних процесорів обсяг КЕШ-пам'яті L1 вказується на одне ядра.

Об'єм кеш-пам'яті другого рівня (кеш L2)

Кеш L2 – це високошвидкісна пам'ять, призначена для тих же цілей, що і кеш-пам'ять першого рівня, проте вона має більший обсяг – від 128 до 12288 Кб. Для вирішення ресурсомістких завдань призначені процесори з великим обсягом кеш-пам'яті другого рівня. Багатоядерні ЦПУ характеризуються сумарним обсягом кеш L2.

Об'єм кеш-пам'яті третього рівня (кеш L3)знаходиться в діапазоні від 0 до 16 384 Кб.

Інтегрована кеш-пам'ять третього рівня та системна шина утворюють разом високошвидкісний канал для обміну даними із системною пам'яттю. Пам'яттю кеш L3 комплектують переважно лише процесори, призначені для комплектації комп'ютера - сервера. Кеш L3 мають такі лінійки процесорів, як Itanium 2, Intel Pentium 4 Extreme Edition, Xeon DP та ін.

Сокет- Роз'єм для встановлення мікропроцесора на материнську плату. Тип сокету визначається виробником процесора та кількістю ніжок. Різним ЦПУ відповідають різні типи сокетів.

Тактова частотапроцесора (МГц) - кількість операцій (тактів), які процесор виконує за секунду. Чим вище цей показник, тим продуктивніший процесор. Але слід пам'ятати, що це справедливо лише для ЦПУ одного виробника, оскільки крім тактової частоти на продуктивність мікропроцесора впливають такі параметри: об'єм кеш L2, частота кеш L3 та ін. Частота процесора пропорційна FSB (частоті шини).

Частота шини(Front Side Bus – FSB) – це тактова частота, з якою здійснюється обмін даними між системною шиною та процесором.

Шина даних- це сукупність сигнальних ліній, призначених обмінюватись даними процесора з внутрішніми пристроями комп'ютера.

Тепловиділення(англ. TDP – thermal design power) – параметр, що визначає яку потужність необхідно відводити системі охолодження для забезпечення нормального функціонування процесора. Значення цього параметра в діапазоні від 10 до 165 Вт. Здійснювати порівняння величини тепловиділення коректно тільки для процесорів одного виробника, тому кожен виробник по-різному визначає тепловиділення.

Підтримка Virtualization Technology
За допомогою функції Virtualization Technology стало можливим завантажувати кілька операційних систем одночасно на одному комп'ютері.

Підтримка технології AMD64/EM64T
Завдяки цій технології мікропроцесори з 64-бітною архітектурою здатні працювати з 32-бітними та 64-бітними додатками однаково ефективно. Лінійки процесорів з 64-бітною архітектурою: AMD Athlon 64, AMD Opteron, Core 2 Duo, Intel Xeon 64 та інші. ЦПУ, що підтримують 64-бітну адресацію, здатні працювати з оперативною пам'яттю об'ємом більше 4 Гб, що недоступно для 32-бітових процесорів. Реліз 64-бітових розширень в ЦПУ лінійки AMD називається AMD64, а для Intel - EM64T.

Максимальна робоча температура (від 54.8 до 105 C) - це максимальне значення допустимої температури процесора, за якої можлива нормальна його робота. Робоча температура ЦПУ залежить від його завантаженості та якості охолодження. При низькій завантаженості та нормальному тепловідведенні температура процесора становить 25-40 °C, а при високій завантаженості - до 60-70 °C. Процесорам з високою робочою температурою необхідні системи охолодження, що забезпечують ефективне тепловідведення.

Напруга на ядрі - показник, що визначає напруга на ядрі процесора, необхідне процесору для роботи. Напруга на ядрі коливається в діапазоні від 0,65 до 165 Вт.

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

Ряд моделей центральних процесорів (ЦП) мають власний кеш, щоб мінімізувати доступ до оперативної пам'яті (ОЗУ), яка повільніше, ніж регістри. Кеш-пам'ять може давати значний виграш у продуктивності, якщо тактова частота ОЗУ значно менше тактової частоти ЦП. Тактова частота для кеш-пам'яті зазвичай набагато менше частоти ЦП.

Рівні кешу

Кеш центрального процесора поділено на кілька рівнів. В універсальному процесорі в даний час число рівнів може досягати 3. Кеш-пам'ять рівня N+1 зазвичай більше за розміром і повільніше швидкості доступу і передачі даних, ніж кеш-пам'ять рівня N.

Найшвидшою пам'яттю є кеш першого рівня - L1-cache. По суті вона є невід'ємною частиною процесора, оскільки розташована на одному з ним кристалі і входить до складу функціональних блоків. У сучасних процесорах зазвичай кеш L1 розділений на два кеші, кеш команд (інструкцій) та кеш даних (Гарвардська архітектура). Більшість процесорів без кешу L1 не можуть функціонувати. L1 кеш працює на частоті процесора, і, у випадку, звернення до нього може проводитися кожен такт. Найчастіше можна виконувати кілька операцій читання/запису одночасно. Латентність доступу зазвичай дорівнює 2×4 тактам ядра. Обсяг зазвичай невеликий - трохи більше 384 Кбайт.

Другим за швидкодією є L2-cache - кеш другого рівня, зазвичай він розташований на кристалі, як і L1. У старих процесорах – набір мікросхем на системній платі. Об'єм L2 кешу від 128 Кбайт до 1×12 Мбайт. У сучасних багатоядерних процесорах кеш другого рівня, перебуваючи тому ж кристалі, є пам'яттю роздільного користування -- за загального обсягу кешу в nM Мбайт на кожне ядро ​​посідає nM/nC Мбайта, де nC кількість ядер процесора. Зазвичай латентність кешу L2, розташованого на кристалі ядра, становить від 8 до 20 тактів ядра.

Кеш третього рівня найменш швидкодіючий, але він може бути дуже великого розміру - більше 24 Мбайт. L3 кеш повільніший за попередні кеші, але все одно значно швидше, ніж оперативна пам'ять. У багатопроцесорних системах знаходиться у загальному користуванні та призначений для синхронізації даних різних L2.

Іноді існує і 4 рівень кешу, зазвичай він розташований в окремій мікросхемі. Застосування кешу 4 рівня виправдане лише для високопродуктивних серверів та мейнфреймів.

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

Що таке кеш-процесора?

Кеш – це частина пам'яті, яка забезпечує максимальну швидкість доступу та прискорює швидкість обчислення. Він зберігає у собі частини даних, які процесор запитує найчастіше, отже процесору немає необхідності постійно звертатися до пам'яті системи.

Як ви знаєте, це частина обладнання комп'ютера, яка характеризується найбільш повільними швидкостями обміну даними. Якщо процесору знадобиться якась інформація, він відправляється за нею до оперативної пам'яті по однойменній шині. Отримавши від процесора запит, та починає копатися у своїх анналах у пошуках потрібних процесору даних. Після отримання ОЗУ пересилає їх у процесор за тією ж шині пам'яті. Таке коло для обміну даними завжди було довгим. Тому виробники і вирішили, що можна було б дозволити процесору зберігати дані десь поблизу. Принцип роботи кешу ґрунтується на простій ідеї.

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

Навіщо потрібен кеш процесору?

А тепер уявіть, що бібліотекареві набридло постійно носитися туди-сюди з книгами, які постійно у неї вимагають рік у рік, день у день. Він обзавівся великою тумбою, де зберігає книги, що найбільш часто запитуються, і підручники. Решта, що належить, звичайно, так і продовжує зберігатися на колишніх полицях. Але ці завжди під рукою. Скільки ж часу він заощадив цією тумбою і собі, і іншим. Це кеш.

Значить, кеш вміє зберігати лише необхідні дані?

Так. Але він може більше. Наприклад, вже зберігаючи в собі часто необхідні дані, він здатний оцінити (за допомогою процесора) ситуацію і зажадати інформацію, яка ось-ось знадобиться. Так, клієнт відео прокату, який зажадав фільм "Міцний горішок" з першою частиною, швидше за все, попросить другу. А ось вона! Також і з кешем процесора. Звертаючись до ОЗУ та зберігаючи певні дані, він витягує і дані із сусідніх осередків пам'яті. Такі шматки даних отримали назву рядок кешу.

Що таке дворівневий кеш?

Сучасний процесор має два рівні. Відповідно, перший та другий. Позначаються літерою L від англійської Level. Перший – L1 – швидший, але за обсягом невеликий. Другий - L2 - трохи більше, але повільніше, але швидше, ніж оперативна пам'ять. Кеш першого рівня ділиться на кеш інструкцій та кеш даних. Кеш інструкцій зберігає у собі тих їх набір, які необхідні процесору для розрахунків. Тоді як у кеші даних зберігаються величини чи значення, необхідних поточного обчислення. А кеш другого рівня використовується для підвантаження даних із оперативної пам'яті комп'ютера. Принцип роботи рівнів кешу можна пояснити за допомогою прикладу шкільної бібліотеки. Так, заповнивши куплену тумбу, бібліотекар розуміє, що її не вистачає на книги, заради яких постійно доводиться бігати по залі. Але список таких книг остаточно оформлений, і потрібно купити ту саму тумбу. Першу він викидати не став - шкода - і просто купив другу. І тепер, у міру заповнюваності першої, бібліотекар починає заповнювати другу, яка входить у справу, коли перша заповнена, але потрібні книжки до неї не помістилися. З рівнями кешу те саме. І в міру розвитку мікропроцесорної техніки рівні кешу процесора зростають у своїх обсягах.

Кеш продовжуватиме рости?

Навряд чи. Гонитва за частотою процесора теж тривала недовго, і виробники знайшли інші шляхи збільшення потужності. Також із кешем. Говорячи конкретно, обсяг і кількість рівнів нескінченно роздмухувати не можна. Кеш не повинен перетворюватися на ще одну планку оперативної пам'яті з повільною швидкістю доступу до неї або перетворювати розміри процесора до рівня половини материнської плати. Адже швидкість доступу до даних – це насамперед енергоспоживання та витрата продуктивності самого процесора. Також стали частішати промахи кешу (на противагу попаданню кешу), коли процесор звертається до кешованої пам'яті за даними, яких там не виявляється. Дані в кеші постійно оновлюються, використовуючи різні алгоритми, щоб посилити ймовірність попадання кешу.

Майже всі розробники знають, що кеш процесора - це така маленька, але швидка пам'ять, в якій зберігаються дані з нещодавно відвіданих областей пам'яті - коротке визначення і досить точне. Тим не менш, знання «нудних» подробиць щодо механізмів роботи кешу необхідне для розуміння факторів, що впливають на продуктивність коду.

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

Habracut - - -

Приклад 1: доступ до пам'яті та продуктивність

Як ви думаєте, наскільки другий цикл швидше за перший?
int arr = new int;

// перший
for (int i = 0; i< arr.Length; i++) arr[i] *= 3;

// другий
for (int i = 0; i< arr.Length; i += 16) arr[i] *= 3;


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

Розгадка проста – доступ до пам'яті. Швидкість роботи цих циклів насамперед визначається швидкістю роботи підсистеми пам'яті, а чи не швидкістю цілочисленного множення. Як ми побачимо в наступному прикладі, кількість звернень до оперативної пам'яті однакова і в першому та другому випадку.

Приклад 2: вплив рядків кешу

Копнем глибше - спробуємо інші значення кроку, не тільки 1 і 16:
for (int i = 0; i< arr.Length; i += K /* шаг */ ) arr[i] *= 3;

Ось час роботи цього циклу для різних значень кроку K:

Зверніть увагу, що при значеннях кроку від 1 до 16 час роботи практично не змінюється. Але при значеннях більше 16, час роботи зменшується приблизно вдвічі щоразу, коли ми збільшуємо крок у два рази. Не означає, що цикл якимось магічним чином починає працювати швидше, просто кількість ітерацій у своїй так само зменшується. Ключовий момент – однаковий час роботи при значеннях кроку від 1 до 16.

Причина цього в тому, що сучасні процесори здійснюють доступ до пам'яті не побайтно, а невеликими блоками, які називають рядками кешу. Зазвичай розмір рядка становить 64 байти. Коли ви читаєте якесь значення з пам'яті, в кеш потрапляє щонайменше один рядок кеша. Подальший доступ до якогось значення з цього рядка відбувається дуже швидко.

Через те, що 16 значень типу int займають 64 байти, цикли з кроками від 1 до 16 звертаються до однакової кількості рядків кешу, точніше, до всіх рядків кешу масиву. При кроці 32 звернення відбувається до кожного другого рядка, при кроці 64, до кожного четвертого.

Розуміння цього дуже важливе для деяких способів оптимізації. Від місця розташування даних у пам'яті залежить кількість звернень до неї. Наприклад, через невирівняні дані може знадобитися два звернення до оперативної пам'яті, замість одного. Як ми з'ясували вище, швидкість роботи при цьому буде вдвічі нижчою.

Приклад 3: розміри кешів першого та другого рівня (L1 та L2)

Сучасні процесори, як правило, мають два або три рівні кешів, зазвичай їх називають L1, L2 та L3. Щоб дізнатися розміри кешів різних рівнів, можна скористатися утилітою CoreInfo або функцією Windows API GetLogicalProcessorInfo . Обидва способи також надають інформацію про розмір рядка кешу для кожного рівня.

На моїй машині CoreInfo повідомляє про кеші даних L1 об'ємом по 32 Кбайт, кеші інструкцій L1 об'ємом по 32 Кбайт і кеші даних L2 об'ємом по 4 Мбайт. Кожне ядро ​​має свої персональні кеші L1, кеші L2 спільні для кожної пари ядер:

Logical Processor to Cache Map: *--- Data Cache 0, Level 1, 32 KB, Assoc 8, LineSize 64 *--- Instruction Cache 0, Level 1, 32 KB, Assoc 8, LineSize 64 -*-- Data Cache 1, Level 1, 32 KB, Assoc 8, LineSize 64 -*-- Instruction Cache 1, Level 1, 32 KB, Assoc 8, LineSize 64 **-- Unified Cache 0, Level 2, 4 MB, Assoc 16, LineSize 64 --*- Data Cache 2, Level 1, 32 KB, Assoc 8, LineSize 64 --*- Instruction Cache 2, Level 1, 32 KB, Assoc 8, LineSize 64 ---* Data Cache 3, Level 1, 32 KB, Assoc 8, LineSize 64 ---* Instruction Cache 3, Level 1, 32 KB, Assoc 8, LineSize 64 --** Unified Cache 1, Level 2, 4 MB, Assoc 16, LineSize 64
Перевіримо цю інформацію експериментально. Для цього пройдемося по нашому масиву інкрементуючи кожне 16-е значення - простий спосіб змінити дані в кожному рядку кешу. При досягненні кінця повертаємося до початку. Перевіримо різні розміри масиву, ми повинні побачити падіння продуктивності, коли масив перестає поміщатися в кеші різних рівнів.

Код такий:

int steps = 64*1024*1024; // кількість ітерацій
int lengthMod = arr.Length - 1; // розмір масиву - ступінь двійки

for (int i = 0; i< steps; i++)
{
// x & lengthMod = x % arr.Length, бо ступеня двійки
arr [(i * 16) & lengthMod] ++;
}


Результати тестів:

На моїй машині помітні падіння продуктивності після 32 Кбайт та 4 Мбайт – це і є розміри кешів L1 та L2.

Приклад 4: паралелізм інструкцій

Тепер погляньмо на дещо інше. На вашу думку, який із цих двох циклів виконається швидше?
int steps = 256*1024*1024;
int a = new int;

// перший
for (int i = 0; i< steps; i++) { a++; a++; }

// другий
for (int i = 0; i< steps; i++) { a++; a++; }


Виявляється, другий цикл виконується майже вдвічі швидше принаймні на всіх протестованих мною машинах. Чому? Тому що команди усередині циклів мають різні залежності за даними. Команди першого мають наступний ланцюжок залежностей:

У другому циклі залежності такі:

Функціональні частини сучасних процесорів здатні виконувати певну кількість деяких операцій одночасно, зазвичай, невелике число. Наприклад, можливий паралельний доступ до даних з кешу L1 за двома адресами, так само можливе одночасне виконання двох простих арифметичних команд. У першому циклі процесор неспроможна задіяти ці можливості, а може у другому.

Приклад 5: асоціативність кешу

Одне з ключових питань, на яке необхідно дати відповідь при проектуванні кешу - чи можуть дані з певної області пам'яті зберігатися в будь-яких осередках кешу або лише в деяких із них. Три можливі рішення:
  1. Кеш прямого відображення, дані кожного рядка кешу в оперативній пам'яті зберігаються лише в одному заздалегідь визначеному осередку кешу. Найпростіший спосіб обчислення відображення: індекс_рядка_в_пам'яті % кількість_осередків_кешу. Два рядки, відображені на один і той же осередок, не можуть знаходитися в кеші одночасно.
  2. N-вхідний частково-асоціативний кеш, кожен рядок може зберігатися в N різних осередках кешу. Наприклад, у 16-входовому кеші рядок може зберігатися в одному з 16-ти осередків складових групу. Зазвичай рядки з рівними молодшими бітами індексів поділяють одну групу.
  3. Повністю асоціативний кеш, будь-який рядок може бути збережено в будь-яку комірку кешу. Рішення еквівалентне хеш-таблиці за своєю поведінкою.
Кеші прямого відображення схильні до конфліктів, наприклад, коли два рядки змагаються за один осередок, по черзі витісняючи один одного з кеша, ефективність дуже низька. З іншого боку, повністю асоціативні кеші, хоч і позбавлені цього недоліку, дуже складні та дорогі у реалізації. Частково-асоціативні кеші – типовий компроміс між складністю реалізації та ефективністю.

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

Так як кеш L2 має 65536 осередків (4 * 2 20 / 64) і кожна група складається з 16 осередків, всього ми маємо 4096 груп. Таким чином, молодші 12 біт індексу рядка визначають до якої групи відноситься цей рядок (2 12 = 4 096). У результаті рядки з адресами кратними 262 144 (4 096 * 64) поділяють ту саму групу з 16-ти осередків і змагаються за місце в ній.

Щоб ефекти асоціативності проявили себе, нам необхідно постійно звертатися до великої кількості рядків із однієї групи, наприклад, використовуючи наступний код:

public static long UpdateEveryKthByte(byte arr, int K)
{
const int rep = 1024*1024; // кількість ітерацій

Stopwatch sw = Stopwatch.StartNew();

int p = 0;
for (int i = 0; i< rep; i++)
{
arr[p]++;

P + = K; if (p> = arr.Length) p = 0;
}

Sw.Stop();
return sw.ElapsedMilliseconds;
}


Метод інкрементує кожен K-ий елемент масиву. Після досягнення кінця, починаємо заново. Після досить великої кількості ітерацій (220), зупиняємося. Я зробив прогони для різних розмірів масиву та значень кроку K. Результати (синій – великий час роботи, білий – маленький):

Синім областям відповідають ті випадки, коли при постійній зміні даних кеш не вміє вмістити всі необхідні дані одночасно. Яскравий синій колір говорить про час роботи близько 80 мс, майже білий – 10 мс.

Розберемося із синіми областями:

  1. Чому з'являються вертикальні лінії?Вертикальні лінії відповідають значенням кроку, при яких здійснюється доступ до занадто великого числа рядків (більше 16-ти) з однієї групи. Для таких значень 16-вхідний кеш моєї машини не може вмістити всі необхідні дані.

    Деякі з поганих значень кроку - ступеня двійки: 256 і 512. Наприклад розглянемо крок 512 і масив 8 Мбайт. При цьому кроці, в масиві є 32 ділянки (8*220/262144), які ведуть боротьбу один з одним за осередки в 512 групах кешу (262144/512). Ділянки 32, а осередків у кеші під кожну групу лише 16, тому місця на всіх не вистачає.

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

  2. Чому вертикальні лінії обриваються на кордоні 4 Мбайт?При розмірі масиву в 4 Мбайт або менше, 16-вхідний кеш поводиться так само, як і повністю асоціативний, тобто може вмістити всі дані масиву без конфліктів. Є трохи більше 16-ти областей провідних боротьбу одну групу кешу (262 144 * 16 = 4 * 2 20 = 4 Мбайт).
  3. Чому зліва нагорі знаходиться великий синій трикутник?Тому що при невеликому етапі і великому масиві кеш не в змозі вмістити всі необхідні дані. Ступінь асоціативності кеша відіграє тут другорядну роль, обмеження пов'язані з обсягом кешу L2.

    Наприклад, при розмірі масиву в 16 Мбайт і кроці 128, ми звертаємося до кожного 128 байта, таким чином, модифікуючи кожен другий рядок кешу масиву. Щоб зберегти кожен другий рядок у кеші, необхідний його об'єм 8 Мбайт, але на моїй машині є лише 4 Мбайт.

    Навіть якби кеш був повністю асоціативним, це не дозволило б зберегти в ньому 8 Мбайт даних. Зауважте, що у вже розглянутому прикладі з кроком 512 та розміром масиву 8 Мбайт, нам необхідний лише 1 Мбайт кешу, щоб зберегти всі необхідні дані, але це неможливо зробити через недостатню асоціативність кешу.

  4. Чому ліва сторона трикутника поступово набирає своєї інтенсивності?Максимум інтенсивності посідає значення кроку 64 байти, що дорівнює розміру рядка кеша. Як ми побачили в першому і в другому прикладі, послідовний доступ до одного і того ж рядка практично нічого не вартий. Скажімо, при кроці 16 байт, ми маємо чотири звернення до пам'яті за ціною одного.

    Так як кількість ітерацій дорівнює в нашому тесті за будь-якого значення кроку, то більш дешевий крок в результаті дає менший час роботи.

Виявлені ефекти зберігаються при великих значеннях параметрів:

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

Приклад 6: хибний поділ кешу

На багатоядерних машинах можна зіткнутися з іншою проблемою – узгодження кешів. Ядра процесора мають частково чи повністю роздільні кеші. На моїй машині кеші L1 роздільні (як і зазвичай), так само є два кеші L2, спільні для кожної пари ядер. Деталі можуть відрізнятися, але загалом сучасні багатоядерні процесори мають багаторівневі ієрархічні кеші. Причому найшвидші, але й найменші кеші належать індивідуальним ядрам.

Коли одне з ядер модифікує значення у своєму кеші, інші ядра більше неможливо використовувати старе значення. Значення в кешах інших ядер має бути оновлено. Більше того, має бути оновлена повністю весь рядок кешу, тому що кеші оперують даними на рівні рядків.

Продемонструємо цю проблему на наступному коді:

private static int s_counter = new int;

private void UpdateCounter(int position)
{
for (int j = 0; j< 100000000; j++)
{
s_counter = s_counter + 3;
}
}


Якщо на своїй чотириядерній машині я викличу цей метод із параметрами 0, 1, 2, 3 одночасно з чотирьох потоків, то час роботи становитиме 4.3 секунди. Але якщо я викликаю метод із параметрами 16, 32, 48, 64, то час роботи становитиме лише 0.28 секунд.

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

Приклад 7: складність заліза

Навіть тепер, коли принципи роботи кешів для вас не секрет, залізо, як і раніше, дасть вам сюрпризи. Процесори відрізняються один від одного методами оптимізації, евристиками та іншими тонкощами реалізації.

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

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

Ось інший приклад дивних примх заліза:

private static int A, B, C, D, E, F, G;

private static void Weirdness()
{
for (int i = 0; i< 200000000; i++)
{
<какой-то код>
}
}


Якщо замість<какой-то код>підставити три різні варіанти, можна отримати такі результати:

Інкрементування полів A, B, C, D займає більше часу, ніж інкрементування полів A, C, E, G. Що ще дивніше, інкрементування полів A та C займає більше часу, ніж полів A, C і E, G. Не знаю точно які причини цього, але можливо вони пов'язані з банками пам'яті ( так-так, із звичайними трилітровими ощадними банками пам'яті, а не те, що ви подумали). Тих, хто має міркування щодо цього, прошу висловлюватися в коментарях.

У мене на машині вищеописаного не спостерігається, проте іноді бувають аномально погані результати - швидше за все, планувальник завдань вносить свої «корективи».

З цього прикладу можна винести наступний урок: дуже складно цілком передбачити поведінку заліза. Так, можна, можливопередбачити багато, але необхідно постійно підтверджувати свої передбачення за допомогою вимірів та тестування.

Висновок

Сподіваюся, що все розглянуте допомогло зрозуміти пристрій кешів процесорів. Тепер ви можете використовувати отримані знання практично для оптимізації свого коду.

Першим процесором, який вироблявся з кешем L2, став Pentium Pro у 1995 році. Він мав 256 або 512 кбайт кешу другого рівня на кристалі, що давало істотну перевагу над звичайними процесорами Pentium, чий кеш розташовувався на материнській платі. З появою Pentium II у модулі Slot 1 виділена кеш-пам'ять "оселилася" поруч із процесором. Але лише у другого покоління Pentium III для Socket 370 кеш-пам'ять перейшла на кристал процесора. Так триває і донині, але є процесори з невеликою кількістю кешу, а є з більшим. Чи варто витрачати гроші на модель із великим кешем? У минулому додаткова кеш-пам'ять не завжди відчутно впливала на продуктивність.

Хоча завжди можна знайти різниці між двома процесорами з різними розмірами кешу, для економії коштів цілком можна було купувати процесори з меншим кешем. Але жоден процесор до появи Core 2 Duo був доступний з трьома різними варіантами кеша.

Pentium 4 у своєму першому поколінні (Willamette, 180 нм) оснащувався 256 кбайт кешу, а успішнішому другому поколінні (Northwood, 130 нм) - вже 512 кбайт кешу. Тоді дешеві процесори Celeron з меншим кешем вироблялися тих самих обчислювальних ядрах. Celeron відносяться до першого покоління продуктів з однією технологічною базою для high-end та дешевих моделей, що відрізняються лише доступним розміром кешу та частотами FSB/ядра. Пізніше було додано і різниця у функціях, щоб помітніше розділити сегменти ринку.

З випуском 90-нм ядра Prescott обсяг кешу L2 виріс до 1 Мбайт, і цей процесор став основою лінійки настільних процесорів Intel до появи 2-Мбайт 65-нм Cedar Mill. Intel навіть використовувала два таких ядра для створення процесорів Pentium D 900 другого покоління. Втім, більш швидкі тактові частоти та більший обсяг кешу навіть тоді не означали дуже багато. Сьогодні ситуація змінилася: краща продуктивність Core 2 Duo (Conroe, 65 нм) та менше енергоспоживання чимало завдячують розміру кешу.

AMD дуже стримано ставилася до збільшення обсягу кешу. Швидше за все це пов'язано з площею кристала (бюджетом транзисторів), оскільки кількість 65-нм процесорів не може задовольнити попит на ринку, а у менш вигідних 90-нм моделей це питання стоїть ще гостріше. У Intel, з іншого боку, є перевага у вигляді виробництва всіх масових процесорів по 65-нм техпроцесу, та й ємність кешу L2 ще зростатиме. Наприклад, наступне покоління Core 2 на 45-нм ядрі Penryn оснащуватиметься до 6 Мбайт кешу L2. Чи можна розглядати це як маркетинговий крок, чи збільшення ємності L2 справді дасть приріст продуктивності? Давайте подивимося.

Великий кеш L2: маркетинг чи зростання продуктивності?

Кеші процесора грають цілком певну роль: вони зменшують кількість звернень до пам'яті, буферизуючи дані, що часто використовуються. Сьогодні ємність ОЗУ становить від 512 Мбайт до 4 Гбайт, а об'єм кешу – від 256 кбайт до 8 Мбайт, залежно від моделі. Втім, навіть невеликого обсягу кешу в 256 або 512 кбайт достатньо, щоб забезпечити високу продуктивність, яку сьогодні сприймають само собою зрозумілою.

Існують різні способи організації ієрархії кешу. У більшості сучасних комп'ютерів встановлені процесори з невеликим кешем першого рівня (L1, до 128 Кбайт), який зазвичай поділяється на кеш даних та кеш інструкцій. Кеш L2 більшого розміру зазвичай використовується для зберігання даних, він є загальним для двох процесорних ядер Core 2 Duo, хоча Athlon 64 X2 або Pentium D мають окремі кеші на ядро. Кеш L2 може працювати ексклюзивно або інклюзивно, тобто він може або зберігати копію вмісту L1 кешу, або ні. AMD незабаром представить процесори з третім рівнем кешу, який буде загальним для чотирьох ядер у процесорах AMD Phenom. Те саме очікується і для архітектури Nehalem, яку Intel представить у 2008 році на заміну поточним Core 2.

Кеш L1 завжди був у складі процесора, але спочатку кеш L2 встановлювався на материнські плати, як було у випадку багатьох комп'ютерів 486DX та Pentium. Для кеш-пам'яті першого рівня використовувалися прості чіпи статичної пам'яті (SRAM, Static RAM). Вони незабаром були замінені на конвеєрний пакетний кеш (pipelined burst cache) у процесорів Pentium, поки не з'явилася можливість встановлювати кеш на кристал. Pentium Pro на 150 – 200 МГц став першим процесором, що містить 256 кбайт кеш-пам'яті L2 на кристалі, побивши рекорд за розміром керамічної упаковки для настільних ПК та робочих станцій. Pentium III для Socket 370, що працює на частотах від 500 МГц до 1,13 ГГц, став першим процесором з 256 кбайт кеш-пам'яті на кристалі L2, що давало перевагу зниження затримок, оскільки кеш працює на частоті CPU.

Вбудований кеш L2 дав суттєвий приріст продуктивності практично у будь-яких додатках. Збільшення продуктивності виявилося настільки суттєвим, що поява інтегрованого кеша L2 можна назвати найважливішим фактором продуктивності процесорів x86. Відключення кешу L2 зменшить продуктивність сильніше, ніж відключення другого ядра у двоядерного процесора.

Однак кеш-пам'ять впливає не лише на продуктивність. Вона стала потужним інструментом, що дозволяє створювати різні моделі процесорів для low-end, масового та high-end сегментів, оскільки виробник може гнучко відбирати процесори з відбраковування та тактових частот. Якщо кристалі немає дефектів, можна включити весь кеш L2, та й частоти виходять високі. Якщо ж бажаних тактових частот досягти не вдасться, кристал може стати моделлю початкового рівня в high-end лінійці, наприклад, Core 2 Duo 6000 з 4 Мбайт кешу і низькими частотами. Якщо дефекти присутні в кеші L2, то виробник має можливість відключити його частину і створити модель початкового рівня з меншим об'ємом кешу, наприклад, Core 2 Duo E4000 з 2 Мбайт кешу L2 або навіть Pentium Dual Core лише з 1 Мбайт кешу. Все це справді так, але питання полягає в наступному: наскільки різниця в обсязі кешу впливає на продуктивність?

Варіанти Core 2 Duo

Intel випустила ринок великий асортимент настільних процесорів. Сьогодні ще можна знайти Pentium 4 та Pentium D, але більшість моделей побудовано на мікро-архітектурі Core. Ми не рекомендуємо брати процесори Pentium 4 або Pentium D, хоча їх частоти тактові до 3,8 ГГц можуть виглядати привабливо. Але будь-який процесор Core 2 на частоті 2,2 ГГц і вище може перемогти навіть найшвидші моделі Pentium D (власне, як і Athlon 64 X2), оскільки Core 2 дає набагато кращу продуктивність на такт .

Завдяки меншим тактовим частотам процесори Core 2 ефективніші з енергоспоживання. Якщо топові моделі Pentium D 800 "з'їдають" до 130 Вт, лише Core 2 Extreme з чотирма ядрами долає поріг 100 Вт. Усі двоядерні процесори споживають не більше 65 Вт. Крім того, енергоспоживання в режимі бездіяльності процесорів Core 2 Duo ще нижче, оскільки робоча частота в режимі бездіяльності менша (максимум 1,2 ГГц для Core 2 Duo/Quad проти 2,8 ГГц Pentium D/4). На зниження енергоспоживання вплинув покращений дизайн транзисторів із зменшеними струмами витоку.

Сьогодні доступні моделі E та X. Моделі E призначені для масового ринку, а X відносяться до класу Extreme Edition. Q позначає чотири ядра, які Intel створює, розміщуючи два двоядерні кристали в одній фізичній упаковці. Процесори E6000 оснащені 4 Мбайт кешу L2, якщо їх модельний номер вищий за E6400 або закінчується на 20 (наприклад, E6320). Моделі, що закінчуються на 00 (наприклад, E6600), працюють з FSB 266 МГц (FSB1066), а моделі, що закінчуються на 50 (E6750), працюють з FSB 333 МГц (FSB1333). Остання вимагає чіпсету P35 або X38 і дає трохи більшу продуктивність. E4000 працює з FSB 200 МГц (FSB800) і має лише 2 Мбайт кешу L2. Версії з 1 Мбайт кешу продаються як Pentium Dual Core E2140, E2160 та E2180 з частотами від 1,6 до 2,0 ГГц. Крім назви та деяких функцій, які Intel відключає у дешевих процесорів, згадані моделі Pentium Dual Cores ідентичні Core 2 Duo.

Характеристики процесорів Core 2 Duo
Номер 65-нм процесора Кеш Тактова частота FSB Технологія віртуалізації Технологія Trusted Execution
E6850 4 Мбайт L2 3 ГГц 333 МГц X X
E6750 4 Мбайт L2 2,66 ГГц 333 МГц X X
E6700 4 Мбайт L2 2,66 ГГц 266 МГц X
E6600 4 Мбайт L2 2,40 ГГц 266 МГц X
E6550 4 Мбайт L2 2,33 ГГц 333 МГц X X
E6540 4 Мбайт L2 2,33 ГГц 333 МГц X
E6420 4 Мбайт L2 2,13 ГГц 266 МГц X
E6400 2 Мбайт L2 2,13 ГГц 266 МГц X
E6320 4 Мбайт L2 1,86 ГГц 266 МГц X
E6300 2 Мбайт L2 1,86 ГГц 266 МГц X
E4600 2 Мбайт L2 2,40 ГГц 200 МГц
E4500 2 Мбайт L2 2,20 ГГц 200 МГц
E4400 2 Мбайт L2 2 ГГц 200 МГц
E4300 2 Мбайт L2 1,80 ГГц 200 МГц


Платформа
CPU I Intel Pentium Dual Core E2160 (65 нм; 1800 МГц, 1 Мбайт кешу L2) на частоті 2,4 ГГц (266 МГц x9)
CPU II Intel Core 2 Duo E4400 (65 нм; 2000 МГц, 2 Мбайт кешу L2) на частоті 2,4 ГГц (266 МГц x9)
CPU III Intel Core 2 Duo X6800 (65 нм; 3000 МГц, 4 Мбайт кешу L2) на частоті 2,4 ГГц (266 МГц x9)
Материнська плата ASUS Blitz Formula, Rev: 1.0
Чіпсет: Intel P35, BIOS 1101
Пам'ять Corsair CM2X1024-888C4D, 2x 1024 Мбайт DDR2-800 (CL 4-4-4-12 2T)
Жорсткий диск Western Digital Raptor WD1500ADFD, 150 Гбайт, 10 000 об/хв, кеш 16 Мбайт, SATA/150
DVD-ROM Samsung SH-S183
Відеокарта Zotac GeForce 8800 GTS, GPU: GeForce 8800 GTS (500 МГц), пам'ять: 320 Мбайт GDDR3 (1600 МГц)
Звукова карта Вбудована
Блок живлення Enermax EG565P-VE, ATX 2.01, 510 Вт
Системне ПЗ та драйвери
ОС Windows XP Professional 5.10.2600, Service Pack 2
Версія DirectX 9.0c (4.09.0000.0904)
Драйвери платформи Intel Version 8.3.1013
Графічний драйвер nVidia Forceware 162.18

Тести та налаштування

3D-ігри
Call Of Duty 2 Version: 1.3 Retail
Video Mode: 1280x960
Anti Aliasing: off
Graphics Card: medium
Timedemo demo2
Prey Version: 1.3
Video Mode: 1280x1024
Video Quality: game default
Vsync = off
Benchmark: THG-Demo
Quake 4 Version: 1.2 (Dual-Core Patch)
Video Mode: 1280x1024
Video Quality: high
THG Timedemo waste.map
timedemo demo8.demo 1 (1 = load textures)
Аудіо
Lame MP3 Version 3.98 Beta 5
Аудіо CD "Термінатор II SE", 53 min
wave to mp3
160 kbps
Відео
TMPEG 3.0 Express Version: 3.0.4.24 (no Audio)
fist 5 Minutes DVD Terminator 2 SE (704x576) 16:9
Multithreading by rendering
DivX 6.7 Version: 6.6 (4 Logical CPUs)
Profile: High Definition Profile
1-pass, 3000 kbit/s
Encoding mode: Insane Quality
Оптимальний multithreading
no Audio
XviD 1.1.3 Version: 1.1.3
Target quantizer: 1.00
Mainconcept H.264 v2 Version 2.1
260 MB MPEG-2 source (1920x1080) 16:9
Код: H.264
Mode: NTSC
Audio: AAC
Profile: High
Stream: Program
Програми
WinRAR Version 3.70
(303 MB, 47 Files, 2 Folders)
Compression = Best
Dictionary = 4096 kB
Autodesk 3D Studio Max Version: 8.0
Characters "Dragon_Charater_rig"
rendering HTDV 1920x1080
Cinebench Version: R10
1 CPU, x CPU run
PCMark05 Pro Version: 1.2.0
CPU та Memory Tests
Windows Media Player 10.00.00.3646
Windows Media Encoder 9.00.00.2980




Висновок

Якщо обсяг кеш-пам'яті обмежено впливає такі синтетичні тести, як PCMark05, то різниця у продуктивності більшості реальних додатків виявилася дуже істотною. Спочатку це здається дивним, оскільки досвід каже, що саме синтетичні тести дають найвідчутнішу різницю у продуктивності, яка мало відбивається на реальних додатках.

Відповідь проста: розмір кешу дуже важливий для сучасних процесорів з мікроархітектурою Core 2 Duo. Ми використовували 4-Мбайт Core 2 Extreme X6800, 2-Мбайт Core 2 Duo E4400 та Pentium Dual Core E2160, який є процесором Core 2 Duo з кешем L2 всього 1 Мбайт. Всі процесори працювали на однаковій системній шині 266 МГц і з множником 9x, щоб частота становила 2400 МГц. Єдина різниця полягає у розмірі кешу, оскільки всі сучасні двоядерні процесори, за винятком старого Pentium D, виготовляються з однакових кристалів. Чим стане ядро, Core 2 Extreme Edition чи Pentium Dual Core, визначається виходом придатних кристалів (дефектами) чи попитом ринку.

Якщо ви порівняєте результати 3D-шутерів Prey і Quake 4, що є типовими ігровими програмами, різниця у продуктивності між 1 і 4 Мбайт становить приблизно один крок за частотою. Те саме стосується тестів кодування відео для кодеків DivX 6.6 і XviD 1.1.2, а також архіватора WinRAR 3.7. Однак, такі інтенсивно навантажувальні CPU програми, як 3DStudio Max 8, Lame MP3 Encoder або H.264 Encoder V2 від MainConcept не надто сильно виграють від збільшення розміру кешу.

Втім, підхід Intel, а саме використання всього доступного бюджету транзисторів, який збільшився при переході з 65-нм техпроцесу на 45-нм, має для мікро-архітектури Core 2 Duo певну значимість. Кеш L2 у цих процесорів працює дуже ефективно, особливо якщо врахувати, що він загальний для двох ядер. Тому кеш нівелює вплив різних частот пам'яті та запобігає "вузькому місцем" у вигляді FSB. І робить він це чудово, оскільки тести наочно показують, що продуктивність процесора з одним мегабайтом кеш-пам'яті невисока.

З цієї точки зору збільшення розміру кешу L2 з 4 Мбайт до максимум 6 Мбайт у майбутніх 45-нм двоядерних процесорів Penryn (лінійка Core 2 Duo E8000) має сенс. Зменшення техпроцесу з 65 до 45 нм дозволяє Intel збільшити бюджет транзисторів, і завдяки збільшенню обсягу кешу ми знову отримаємо зростання продуктивності. Втім, Intel отримає вигоду через різні варіанти процесорів з 6, 4, 2 або навіть 1 Мбайт кешу L2. Завдяки кільком варіантам Intel може використовувати більше кристалів з пластини, незважаючи на наявність випадкових дефектів, які в іншому випадку призводили б до попадання кристала в кошик для сміття. Великий розмір кешу, як бачимо, важливий як для продуктивності, а й у прибутку Intel.