2016-09-10 4 views
-1
void loop(int loops) 
    { 
     while (loops-- > 0) 
     asm volatile ("" : : : "memory") 
    } 
  1. Я знаю, что asm volatile ("" : : : "memory") предотвращает инструкцию компилятора переназначения. Но здесь я не вижу, что может быть переупорядочено и почему это может быть проблематичным с точки зрения параллелизма. (Принимаю во внимание возможные прерывания). Итак, почему существует барьер?Busy петли и барьер

  2. И, во-вторых, связанная проблема. Предположим, что у нас есть 10000000 строк кода (см. Ниже). Как мы знаем, CPU может изменить порядок StoreLoad.

    mov [eax], $ 2; nop; nop; ...; nop; mov ebx, [ecx];

Насколько глубоко ЦП способен предсказать, что есть возможность применить StoreLoad?

Тот же вопрос может быть применен к компилятору, но это касается различного переназначения (не только StoreLoad и не только операций с памятью)

+1

1) Возможно, в качестве побочного эффекта он не позволяет оптимизатору отказаться от «ненужной» модификации «петель» в противном случае. –

+0

Что произойдет, если вы выберете его и скомпилируете с помощью функции -O3? Как код отличается от барьера на месте? –

+0

Я вижу. Поэтому вы предполагаете, что существует барьер, потому что, в противном случае, он будет удален компилятором? Как насчет вопроса? Возможно, я не очень хорошо объяснил, что я имел в виду? – Gilgamesz

ответ

2

TL: DR: Проблема здесь заключается в том, что вы только думаете о это как std::atomic_thread_fence(std::memory_order_seq_cst), но это не единственное, что делают заявления GNU C volatile asm.


Да, очевидно, что существует барьер, создающий неприятный цикл задержки ожидания ожидания. Помните, что волатильный оператор asm нельзя переупорядочить с помощью каких-либо других операторов C, а не только операций с памятью.

Godbolt

void loop_nomemclobber(int loops) { 
    do {  // loop rearranged for simpler asm 
    asm volatile ("" : : : /* "memory" */); 
    } while (--loops > 0); 
} 

loop_nomemclobber: 
.L3: 
    sub  edi, 1 
    test edi, edi 
    jg  .L3 
    ret 

Мы до сих пор получить петлю, даже не заставляя всех достижимых памяти быть уточненный и рассматриваться как затирается. Таким образом, аргумент asm volatile делает это не имеет ничего общего с клеем "memory".

int loops является локальным с автоматическим хранением. Компилятор может доказать, что ничто (включая оператор asm) не имеет никакого способа определить, где оно может быть в памяти, поэтому оно не должно быть в памяти вообще.


Как глубоко ли процессор в состоянии предсказать, что есть шанс применить StoreLoad?

ЦП не ищет возможности изменить порядок памяти без причины! Переупорядочение происходит естественным образом (если не предотвращено с помощью MFENCE), потому что ЦП должен хранить буферные хранилища, пока не станет уверенным, что они не являются спекулятивными, а также хранилищами с кэшем. Таким образом, он помещает магазины в буфер хранилища, и в конечном итоге они фиксируют кеш.

Внутри процессора нет немного демона, говорящего «ага, вот еще один шанс сделать вещи сложными для Гильгамеза, может быть, я на самом деле обману его на этот раз с этим переупорядочением!"


Существует реальный вопрос здесь, и это , как далеко друг от друга две команды должны быть (по времени или по количеству insns, или число промежуточных нагрузок/магазинов) до того, как конкретный микроархитектуры Безразлично» t иметь достаточные ресурсы не по порядку для этого магазина, чтобы когда-либо буферизоваться до этой загрузки.

Я не знаю, но поскольку переупорядочение StoreStore не разрешено, хранилище кэш-миссий, критическая строка кэша не может сидеть там, ожидая получения доступа к линии кэша, пока выполняются миллионы других инструкций. Если ни одна из этих инструкций не была магазином.

Я не знаю ответа, но я считаю правдоподобным, что теоретически теоретически можно было бы запаздывать на миллионы циклов в Intel Haswell, возможно, ограничиваясь только алгоритмами справедливости аппаратных арбитражных механизмов, которые обрабатывают случай, когда несколько ядер бороться за доступ к одной и той же строке кэша.

Я забыл, что я читал о том, работает ли это современное оборудование Intel, или нет, но я думаю, что, возможно, магазин может уйти из ядра внешнего порядка, но все еще не привязан к кэшу L1. Вместо этого, это только в очереди магазина как магазин, который определенно произойдет. Это позволит магазинам кэширования избежать блокировки ввода новых инструкций в ROB. (Нагрузки должны исследовать буфер хранилища, чтобы сохранить правильное выполнение в одном ядре, но для этого не требуется, чтобы магазины также отслеживались ROB).

+1

Весь оператор asm мог быть упрощен до 'asm (" ");' –

+2

@MichaelPetch: о, ха-ха. Да, потому что 'asm()' без выходов неявно нестабильно. –

+2

«Даже без этого компилятор должен предположить, что оператор volm volatile может читать любые глобальные переменные» На самом деле это не так. Доступ к (энергонезависимым) глобалам из расширенного asm gcc (без явного указания их как входов) является небезопасным. До gcc v7.x это тоже не было безопасно в базовом asm. Тем не менее, в этом конкретном случае это работает так, поскольку использование asm обычно отключает встраивание, а функция вызывает неявно скрытую память. –