代码之家  ›  专栏  ›  技术社区  ›  Bartzilla

CUDA内核在两个不同的gpu上抛出不同的结果(GeForce 8600mgt vs Quadro FX 770M)

  •  4
  • Bartzilla  · 技术社区  · 14 年前

    我一直在研究一个AES-CUDA应用程序,我有一个在GPU上执行ECB加密的内核。为了确保并行运行时算法的逻辑不被修改,我发送一个由NIST提供的已知输入测试向量,然后从主机代码将输出与由NIST提供的已知测试向量输出进行比较,并使用断言。 我已经在我的NVIDIA GPU上运行了这个测试,它是一个8600米燃气轮机。这是在Windows7下运行的,驱动程序版本是3.0。在这种情况下,一切工作都很完美,断言成功。

    现在,当应用程序在Quadro FX 770M上运行时,启动相同的应用程序,发送相同的测试向量,但得到的结果不正确,断言失败!!. 它在Linux上运行,驱动程序版本相同 内核由256个线程执行。在内核中使用256个元素的算术预计算查找表。这些表最初加载在全局内存中,256个线程中有1个线程在加载查找表的1个元素时启动内核colaborate,并将该元素移动到共享内存中的新查找表中,从而减少访问延迟。

    最初,我考虑过由于gpu之间的时钟速度差异而导致的同步问题。因此,可能是线程使用的值仍然没有加载到共享内存中,或者以某种方式使用的值仍然没有被处理,使得输出 把事情搞砸,最后弄错了。

    在这里,已知的测试向量被声明,因此基本上它们被发送到AES_set_encrption,AES_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);
    }
    

    在这里,setup函数负责分配内存、调用内核并将结果发送回hos。请注意,在发送回主机之前,我已经进行了同步,因此在这一点上,所有工作都应该完成,这使我认为问题出在内核中。。

    __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 GPU时的输出,它工作正常:

    AES 256位密钥

    NIST测试向量:

    原告文本:6bc1bee22e409f96e93d7e117393172a

    密钥:603deb1015ca71be2b73aef0857d7781

    密文:f3eed1bdb5d2a03c64b5a7e3db181f8

    GPU加密:f3eed1bdb5d2a03c64b5a7e3db181f8

    测试状态:通过

    当我使用Quadro FX 770米时失败了!!

    AES 256位密钥 NIST测试向量:

    原告文本:6bc1bee22e409f96e93d7e117393172a

    密钥:603deb1015ca71be2b73aef0857d7781

    密文:f3eed1bdb5d2a03c64b5a7e3db181f8

    GPU加密:c837204eb4c1063ed79c77946893b0

    泛型assert memcmp(out,testCipherText,16)==0引发错误

    测试状态:失败

    为什么两个gpu即使处理相同的内核也会计算不同的结果呢??? 我将感谢任何提示或故障排除您可以给我或任何步骤,以解决这个问题

    提前谢谢!!

    1 回复  |  直到 14 年前
        1
  •  1
  •   jmilloy Amir    14 年前

    免责声明:我对AES加密一无所知。

    你用双精度吗?您可能已经意识到了,但是为了确定-我相信您使用的两张卡都是计算能力1.1,它不支持双精度。也许卡片或平台以不同的方式转换成单一的精度。。。?有人知道吗?事实上,IEEE的浮点偏差有很好的规定,所以我很惊讶。