Ядра CUDA дают разные результаты на 2 разных графических процессорах (GeForce 8600M GT против Quadro FX 770M) - PullRequest
4 голосов
/ 20 октября 2010

Я работал над приложением AES CUDA, и у меня есть ядро, которое выполняет шифрование ECB на GPU. Чтобы гарантировать, что логика алгоритма не изменяется при параллельной работе, я отправляю известный входной тестовый вектор, предоставленный NIST, а затем из кода хоста сравниваю выходной сигнал с известным тестовым вектором, предоставленным NIST, с assert. Я провел этот тест на моем графическом процессоре NVIDIA, который является 8600M GT. Это работает под Windows 7 и версия драйвера 3.0. В этом сценарии все работает идеально, и утверждение успешно.

Теперь, когда приложение запущено на Quadro FX 770M. Запускается одно и то же приложение, отправляются те же тестовые векторы, но полученный результат неверен и утверждение не выполняется !!. Это работает на Linux с той же версией драйвера Ядра выполнены 256 потоками. В ядрах и для пропуска арифметики используются предварительно вычисленные таблицы поиска из 256 элементов. Эти таблицы изначально загружаются в глобальную память, 1 поток из 256 потоков запускает колоборат ядра при загрузке 1 элемента таблицы поиска и перемещает элемент в новую таблицу поиска в разделяемой памяти, поэтому задержка доступа уменьшается.

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

Здесь объявлены известные тестовые векторы, поэтому в основном они отправляются в AES_set_encrption, который отвечает за настройку ядра

void test_vectors ()
{ 

  unsigned char testPlainText[]  = {0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a}; 
     unsigned char testKeyText[] =  {0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77,0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4};
     unsigned char testCipherText[] = {0xf3, 0xee, 0xd1, 0xbd, 0xb5, 0xd2, 0xa0, 0x3c, 0x06, 0x4b, 0x5a, 0x7e, 0x3d, 0xb1, 0x81, 0xf8};

 unsigned char out[16] = {0x0};
     //AES Encryption
AES_set_encrption( testPlainText, out, 16, (u32*)testKeyText);

 //Display encrypted data
 printf("\n  GPU Encryption: "); 
 for (int i = 0; i < AES_BLOCK_SIZE; i++)
         printf("%x", out[i]);

 //Assert that the encrypted output is the same as the NIST testCipherText vector 
 assert (memcmp (out, testCipherText, 16) == 0);
}

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

__host__ double AES_set_encrption (... *input_data,...*output_data, .. input_length, ... ckey )

 //Allocate memory in the device and copy the input buffer from the host to the GPU
  CUDA_SAFE_CALL( cudaMalloc( (void **) &d_input_data,input_length ) ); 
  CUDA_SAFE_CALL( cudaMemcpy( (void*)d_input_data, (void*)input_data, input_length, cudaMemcpyHostToDevice ) ); 

     dim3 dimGrid(1);
     dim3 dimBlock(THREAD_X,THREAD_Y); // THREAD_X = 4 & THREAD_Y = 64
  AES_encrypt<<<dimGrid,dimBlock>>>(d_input_data);

     cudaThreadSynchronize();

     //Copy the data processed by the GPU back to the host 
  cudaMemcpy(output_data, d_input_data, input_length, cudaMemcpyDeviceToHost);

  //Free CUDA resources
  CUDA_SAFE_CALL( cudaFree(d_input_data) );
}

И, наконец, в ядре у меня есть набор раундов AES. Так как я думал, что проблема с синхронизацией была тогда внутри ядра, я установил __syncthreads (); после каждого раунда или вычислительной операции, чтобы убедиться, что все потоки движутся одновременно, поэтому никакие вычисленные значения не могут быть оценены. Но все же это не решило проблему.

Вот вывод при использовании графического процессора 8600M GT, который работает нормально:

AES 256-битный ключ

Тестовые векторы NIST:

PlaintText: 6bc1bee22e409f96e93d7e117393172a

Ключ: 603deb1015ca71be2b73aef0857d7781

CipherText: f3eed1bdb5d2a03c64b5a7e3db181f8

Шифрование графического процессора: f3eed1bdb5d2a03c64b5a7e3db181f8

Состояние теста: Пройдено

А вот когда я использую Quadro FX 770M и выходит из строя !!

AES 256-битный ключ Тестовые векторы NIST:

PlaintText: 6bc1bee22e409f96e93d7e117393172a

Ключ: 603deb1015ca71be2b73aef0857d7781

CipherText: f3eed1bdb5d2a03c64b5a7e3db181f8

Шифрование графического процессора: c837204eb4c1063ed79c77946893b0

Универсальный assert memcmp (out, testCipherText, 16) == 0 выдал ошибку

Состояние теста: Не удалось

В чем может быть причина того, что 2 графических процессора вычисляют разные результаты, даже если они обрабатывают одно и то же ядро ​​??? Я буду признателен за любую подсказку или устранение неполадок, которые вы можете дать мне, или за любой шаг, чтобы решить эту проблему

Заранее спасибо !!

1 Ответ

1 голос
/ 22 октября 2010

отказ от ответственности: я ничего не знаю о шифровании AES.

Вы используете двойную точность?Вы, вероятно, знаете, но просто чтобы быть уверенным - я считаю, что обе карты, которые вы используете, имеют вычислительную емкость 1.1, которая не поддерживает двойную точность.Возможно, карты или платформы по-разному конвертируются в одну точность ...?Кто-нибудь знает?По правде говоря, отклонения IEEE с плавающей запятой хорошо определены, поэтому я был бы удивлен.

...