CUDA Global Barrier - работает на Кеплера, а не на Ферми

Следующий глобальный барьер работает на Kepler K10, а не на Fermi GTX580:

__global__ void cudaKernel (float* ref1, float* ref2, int* lock, int time, int dim) {
  int gid  = blockIdx.x * blockDim.x + threadIdx.x;
  int lid  = threadIdx.x;                          
  int numT = blockDim.x * gridDim.x;               
  int numP = int (dim / numT);                     
  int numB = gridDim.x;

  for (int t = 0; t < time; ++t) {
    // compute @ time t
    for (int i = 0; i < numP; ++i) {
      int idx  = gid + i * numT;
      if (idx > 0 && idx < dim - 1)
        ref2 [idx]  = 0.333f * ((ref1 [idx - 1] + ref1 [idx]) + ref1 [idx + 1]);
    }

    // global sync
    if (lid == 0){
      atomicSub (lock, 1);
      while (atomicCAS(lock, 0, 0) != 0);
    }
    __syncthreads();

    // copy-back @ time t
    for (int i = 0; i < numP; ++i) {
      int idx  = gid + i * numT;
      if (idx > 0 && idx < dim - 1)
        ref1 [idx]  = ref2 [idx];
    }

    // global sync
    if (lid == 0){
      atomicAdd (lock, 1);
      while (atomicCAS(lock, numB, numB) != numB);
    }
    __syncthreads();
  }
}

Итак, просмотрев выходные данные, отправленные обратно в ЦП, я заметил, что один поток (1-й или последний) выходит за пределы барьера и возобновляет выполнение раньше, чем другие. Я использую CUDA 5.0. количество блоков также всегда меньше, чем количество SM (в моем наборе прогонов).

Есть идеи, почему один и тот же код не работает на двух архитектурах? Что нового в Kepler, который помогает этой глобальной синхронизации?

1 ответ

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

Ни у Кеплера, ни у Ферми есть кэши L1, которые связаны друг с другом. То, что вы обнаружили (хотя это не связано с самим вашим барьерным кодом), - это то, что поведение кэша L1 отличается у Кеплера и Ферми.

В частности, кеш Kepler L1 не работает при глобальных нагрузках, как описано в приведенной выше ссылке, и поэтому поведение кеширования обрабатывается на уровне L2, который является общесистемным, и, следовательно, согласованным. Когда Kepler SMX считывает свои глобальные данные, он получает согласованные значения от L2.

С другой стороны, в Fermi есть кэши L1, которые также участвуют в глобальных нагрузках (по умолчанию - хотя такое поведение можно отключить), а кэши L1, как описано в приведенной выше ссылке, уникальны для каждого SM Fermi и не согласованы с L1 кеширует в других SM. Когда SM Fermi читает свои глобальные данные, он получает значения от L1, которые могут быть не согласованы с другими кэшами L1 в других SM.

В этом заключается разница в "когерентности", которую вы видите, в данных, которыми вы манипулируете до и после барьера.

Как я уже упоминал, я считаю, что сам барьерный код, вероятно, работает одинаково на обоих устройствах.

Другие вопросы по тегам