RFO имеет значение для операций атомарного добавления и блокировки кэширования на процессорах Intel? - PullRequest
0 голосов
/ 08 октября 2018

Я пытаюсь понять природу атомарной операции добавления.Итак, я выполняю следующий код на машине Broadwell.

int main(int argc, char ** argv){
    int nThreads = -1;
    float shareFrac = -1;
    uint64_t nIter = -1;

    ParseArg(argc, argv, nThreads, shareFrac, nIter);

    atomic<uint64_t> justToAvoidCompilerOptimization;

    #pragma omp parallel num_threads(nThreads)
    {
        int me = omp_get_thread_num();
        atomic<uint64_t> *tsData = &trueSharingData.data[0];
        atomic<uint64_t> *privateData = &(new SharedData_t())->data[0];
        for(uint64_t i = 0 ; i < nIter; i++) {
            // Use RDTSC as a proxy random number generator
            unsigned long lo, hi;
                asm volatile( "rdtsc" : "=a" (lo), "=d" (hi) ); 
                int rNum  = (lo % 54121) % 100; // mod by a prime.
            // if the random number is < shareFrac, perform a shared memory operation
            if (rNum < shareFrac) {
                *tsData += rNum2;
            } else {
                *privateData += rNum;
            }
        }       
        justToAvoidCompilerOptimization += *tsData;     
        justToAvoidCompilerOptimization += *privateData;        
    }


    return justToAvoidCompilerOptimization.load() ^ justToAvoidCompilerOptimization.load();
}

В этом коде в основном каждый поток выполняет операцию атомарного добавления nIter число раз, при этом nIter является счетчиком циклов.В каждой итерации цикла операция атомарного добавления может выполняться либо в расположении общей памяти, либо в локальной переменной потока.

Доля счетчика отключений цикла, затрачиваемая на выполнение операций атомарного добавления в расположении общей памяти, определяетсяпараметр shareFrac.Например, если shareFrac равно 0,3, а nIter равно 1000, то ожидается, что атомарное добавление будет выполнено в общей памяти примерно 300 раз.


Итак, я выполнил небольшой эксперимент, в которомЯ запускал этот простой код несколько раз с увеличением значения shareFrac.Для каждого прогона я подсчитывал вхождения событий L2_RQSTS.RFO_MISS с помощью perf.Я также сравниваю значения, указанные в perf, с ожидаемыми значениями.Ожидаемый счет просто nthreads * nIter * shareFrac.

Результаты следующие.

nThreads = 2, nIter = 100 миллионов
nThreads = 2, nIter = 100 millions

nThreads = 8, nIter = 100 миллионов
nThreads = 8, nIter = 100 millions

Как видно на рисунках, количество промахов RFO превышает ожидаемое число в большинстве прогонов.Как это может быть возможным??Возможное объяснение состоит в том, что атомарное добавление приводит строку с RFO в надежде прочитать и затем обновить.Тем не менее, строка может быть украдена между чтением и записью, и в этом случае строка должна быть возвращена.Но, насколько мне известно, для атомарных операций в x86, кешлайн заблокирован, и, следовательно, кешлайн не должен быть украден, как только он доставлен с эксклюзивным разрешением.Или мое понимание неверно?

Чтобы исключить возможность передачи из кэша строк из-за предварительной выборки, я также исключил ч / б предварительные выборки на всех ядрах машин до получения этих результатов.

1 Ответ

0 голосов
/ 09 октября 2018

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

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

Однако сам патент описывает механизм ослаблениятребование блокировки.В частности, выполнение операции загрузки / блокировки на ранней стадии, в основном в виде простой загрузки, и предположение о том, что связанный кэш не будет «украден» во время между выполнением загрузки и фиксацией хранилища.Если такая украденная строка кэша происходит, операцию необходимо воспроизвести.По словам Intel из патента:

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

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

Это лишь небольшая выдержка, но она отражает соответствующую идею: попробуйте выполнить блокировку вспособ, который более совместим с выполнением вне очереди, если это не удается, повторите более консервативный подход.Далее в патенте объясняется, как могут работать предикторы, и проводится аналогия с предсказанием ветвлений.Основной подход заключается в простом отслеживании конфликтного поведения для каждого IP-адреса.

Это объясняет, почему дополнительные события RFO стремятся к нулю вблизи shareFrac, равного 100%: в этот момент линии сильнодостаточно утверждал, что эвристика / предиктор, который попытался бы реализовать более агрессивную реализацию блокировки, не сработала, поэтому она всегда выбирает консервативный путь.

Возможно, вы могли бы подтвердить эту теорию тестом, который обнаружил отсутствие или присутствиевыполнение заказа и показать, что когда количество запросов RFO возрастает, также происходит некоторое выполнение OoO.

...