Бар’єри та порядок виконання

У випадку, коли необхідно мати справу з синхронізацією між різними процесорами або різними апаратними пристроями, іноді виникає вимога, щоб читання памяті (load) або запис в память (Save) виконувалися в тому ж порядку, як це зазначено в початковому програмному коді При роботі з апаратними пристроями часто необхідно, щоб деяка зазначена операція читання була виконана перед іншими операціями читання або запису На додаток до цього, на

симетричною багатопроцесорної системі може виявитися необхідним, щоб операції запису виконувалися строго в тому порядку, як це зазначено в початковому програмному коді (зазвичай для того, щоб гарантувати, що послідовні операції читання отримують дані в тому ж порядку) Ці проблеми ускладнюються тим, що як компілятор, так і процесор можуть міняти порядок операцій читання і запісі6 для підвищення продуктивності На щастя, всі процесори, які мають пріоритет над порядок операцій читання або запису надають машинні інструкції, які вимагають виконання операцій читання-запису памяті в зазначеному порядку Також існує можливість дати інструкцію компілятору, що не можна змінювати порядок виконання операцій при переході через певну точку програми Ці інструкції називаються барєрами (barrier)

Розглянемо наступний код

а = 1

Ь = 2

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

Хоча в попередньому прикладі і може бути змінений порядок виконання, ні процесор, ні компілятор ніколи не будуть змінювати порядок виконання наступного коду, де змінні а і b є глобальними

а = 1

b = а

Це відбувається тому, що в останньому випадку чітко видно залежність між змінними a і b Проте ні компілятор, ні процесор не мають жодної інформації про код, який виконується в інших контекстах Часто важливо, щоб результати запису в память бачилися в потрібному порядку іншим кодом, який виконується за межами нашої досяжності Така ситуація часто має місце при роботі з апаратними пристроями, а також виникає на багатопроцесорних машинах

Функція rmb () дозволяє встановити барєр читання памяті (read memory barrier) Вона гарантує, що ніякі операції читання памяті, які виконуються перед викликом функції rmb (), що не будуть переставлені місцями з операціями, які виконуються після цього виклику Іншими словами, всі операції читання, які вказані до цього виклику, будуть виконані перед цим викликом, а всі операції читання, які вказані після цього виклику ніколи не виконуватимуться перед ним

6 Процесор и Intel х86 ніколи не переважають т порядо до операци ї записи, Те виконую т запис завжди в зазначеному порядку Проте інші процесор и можуть нести себе і по-іншому,

Функція wmb () дозволяє встановити барєр записи памяті (write barrier) Вона працює так само, як і функція rmb (), але не з операціями читання, а з операціями запису – гарантується, що операції записи, які знаходяться по різні сторони барєру, ніколи не будуть переставлені місцями один з одним

Функція rnb () дозволяє створити барєр на читання і запис Ніякі операції читання і запису, які вказані по різні сторони виклику функції rab {), що не будуть переставлені місцями один з одним Ця функція надається користувачеві, так як існує машинна інструкція (часто та ж інструкція, що використовується викликом rmb ()), яка дозволяє встановити барєр на читання і запис

Варіант функції rmb () read_barrier_depends () забезпечує створення барєру читання, алетільки для тих операцій читання, від яких залежать наступні, за ними операції читанняГарантується, що всі операції читання, які вказані перед барєром виконаються перед тими операціями читання, які знаходяться після барєру і залежать від операцій читання, що йдуть перед барєром Все зрозуміло Загалом, ця функція дозволяє створити барєр читання, так само як і функція rmb (), але цей барєр буде встановлений тільки для деяких операцій читання – тих, які залежать один від одного

Для деяких апаратних платформ функція read_barrier_depend s () виконується значно швидше, ніж функція rmb (), так як для цих платформ функція read_barrier_depend s () просто не потрібна і замість неї виконується інструкція nоор (немає операції)

Розглянемо приклад використання функцій mb () і rmb () Первинне значення змінної а дорівнює 1, а змінної b дорівнює 2 –

Потік 1 Потік 2

а = 3

mb()

b=4                         c=b rmb() d=a

Без використання барєрів памяті для деяких процесорів можлива ситуація, в якій після виконання цих фрагментів коду змінної з присвоїться нове, значення змінної b, тоді як змінної d присвоїться старе значення змінної а Наприклад, змінна з може стати рівною 4 (що ми і хочемо), а змінна d може залишитися рівною 1 (чого ми не хочемо) Використання функції mb () дозволяє гарантувати, що змінні a і b записуються в зазначеному порядку, а функція rmb () гарантує, що читання змінних b і а буде виконано в зазначеному порядку

Така зміна порядку виконання операцій може виникнути через те, що сучасні процесори обробляють і передають на виконання інструкції в зміненому порядку для того, щоб оптимізувати використання конвеєрів Це може призвести до того, що інструкції читання змінних b і а виконаються не в тому порядку Функції rmb () і wmb () відповідають інструкціям, які змушують процесор виконати всі незакінчені операції читання і запису перед тим, як продовжити роботу далі

Розглянемо простий приклад випадку, коли можна використовувати функцію read_ barrier_depend s () замість функції rmb () У цьому прикладі спочатку змінна а дорівнює 1, b 2, а p & b

Потік 1 Потік 2

а = 3

mb()

p = & а pp = р read_barrier_depends () b = * pp

Знову без використання барєрів памяті зявляється можливість того, що змінної b буде привласнено значення * рр до того, як змінної рр буде присвоєно значення змінної р Функція read_barrier_depend s () забезпечує достатній барєр, так як зчитування значення * рр залежить від зчитування змінної р Тут також буде досить використовувати функцію rmb (), але оскільки операції читання залежні між собою, то можна використовувати потенційно більш швидку функцію read_barrier_depend s () Зауважимо, що в обох випадках потрібно використовувати функцію mb () для того, щоб гарантувати необхідний порядок виконання операцій читання-запису в потоці 1

Макроси smp_rmb (), smp_wmb (), smp_mb () і smpread_barrier_depend s () дозволяють виконати корисну оптимізацію Для SMP-ядра вони визначені як звичайні барєри памяті, а для ядра, розрахованого на однопроцесорних машину, – тільки як барєр компілятора Ці SMP-варіанти барєрів можна використовувати, коли обмеження на порядок виконання операцій є специфічними для SMP-систем

Функція barrie r () запобігає можливість оптимізації компілятором операцій зчитування і запису даних, якщо ці операції знаходяться по різні сторони від виклику даної функції (тобто забороняє зміна порядку операцій) Компілятор не змінює порядок операцій запису і зчитування у випадках, коли це може вплинути на правильність виконання коду, написаного на мові С, або на існуючі залежності між даними Однак у компілятора немає інформації про події, які можуть статися поза поточного контексту Наприклад, компілятор не може мати інформацію про переривання, в контексті яких може виконуватися зчитування даних, які в даний момент записуються Наприклад, з цієї причини може виявитися необхідним гарантувати, що операція запису виконається перед операцією зчитування Зазначені раніше барєри памяті працюють і як барєри компілятора, але барєр компілятора значно швидше, ніж барєр памяті (практично не впливає на продуктивність) Використання барєру компілятора на практиці є опціональним, так як він просто запобігає можливість того, що компілятор щось змінить

У табл 910 наведено повний список функцій установки барєрів памяті і компілятора, які доступні для різних апаратних платформ, підтримуваних ядром Linux

Слід зауважити, що ефекти установки барєрів можуть бути різними для різних апаратних платформ Наприклад, якщо машина не змінює порядок операцій запису (як у випадку набору мікросхем Intel x86), то функція wmb () не виконує ніяких дій Можна використовувати відповідний барєр памяті для самої поганої ситуації (тобто для процесора з найгіршим порядком виконання), і ваш код буде скомпільовано оптимально для вашої апаратної платформи

Таблиця 910 Засоби установки барєрів компілятора і памяті

Барєр Опис

rmb()

read_barrier_depends()

wtnb() mb() smp_rmb()

smp_read_barrier_depends()

srap_wmb() smp_mb() barrier()

Запобігає зміна порядку виконання операцій читання даних з памяті при переході через барєр

Запобігає зміна порядку виконання операцій читання даних з памяті при переході через барєр, але тільки для операцій читання, які залежні один від одного

Запобігає зміна порядку виконання операцій запису даних в память при переході через барєр

Запобігає зміна порядку виконання операцій читання і запису даних при переході через барєр

Для SMP-ядер еквівалентно функції rmb (), а для ядер, розрахованих на однопроцесорні машини, еквівалентно функції barrier ()

Для SMP-ядер еквівалентно функції read_barrier_depends () а для ядер, розрахованих на однопроцесорні машини, еквівалентно функції barrier ()

Для SMP-ядер еквівалентно функції wmb (), а для ядер, розрахованих на однопроцесорні машини, еквівалентно функції barrier ()

Для SMP-ядер еквівалентно функції mb (), а для ядер, розрахованих на однопроцесорні машини, еквівалентно функції barrier ()

Запобігає оптимізації компілятора з читання і запису даних при переході через барєр

Джерело: Лав, Роберт Розробка ядра Linux, 2-е видання : Пер з англ – М: ТОВ «ІД Вільямс »2006 – 448 с : Ил – Парал тит англ

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*