2013-10-15 2 views
0

Я смущен расчетами CGMA. Я знаю, что CGMA = # операций/# выборки памяти. Во-первых, когда x = g_A[idx], следует ли считать операцию записи x или игнорировать ее, потому что она хранится в регистре? Аналогично, в z = (x*y) + (y/x) + (y-x); следует считать считанные значения x и y как память читает при расчете CGMA? Наконец, следует ли считать все операции в функции Kernel (эти пять строк)?Расчет CGMA в CUDA

__global__ void PerformSomeOperations(int* g_A,int* g_B,int* g_C, int Size) 
{ 
    const int idx = threadIdx.x + (blockIdx.x*blockDim.x); 
    if(idx < Size) 
    { 
     int x = g_A[idx]; 
     int y = g_B[idx]; 
     int z = 0; 
     z = (x*y) + (y/x) + (y-x); 
     g_C[idx] = z; 
    } 
} 
+1

считывает и записывает в регистры, не считая GMA. 2 читается из 'g_A' и' g_B' count. Запись в 'g_C' подсчитывается. Чтобы правильно вычислить арифметические вычисления, вам нужно будет посмотреть код SASS, или вы можете просто оценить исходный код или код PTX. Вы должны считать все арифметические операции, в том числе относящиеся к 'idx' –

+0

Выполняет ли оператор' <'как операцию? – Shibli

+0

Да.Любая арифметика, выполняемая в ядре, подсчитывает (например, арифметику вычисления не очевидного адреса). –

ответ

1

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

Лучший способ рассчитать коэффициент - это запустить вашу программу в профилировщике CUDA и использовать счетчики производительности для доступа к памяти и операций с плавающей запятой. Согласно определению, которое я нашел, ваше ядро ​​имеет CGMA равным нулю, потому что оно выполняет целочисленную арифметику, а не с плавающей запятой. Если вы измените определение, то x = g_A[idx] - это одна операция чтения и операции записи. Это связано с тем, что файл регистров не хранится в глобальной памяти («G» в CGMA). Глобальной памяти не читается в z = (x*y) + (y/x) + (y-x);, поэтому считайте это как 5 операций. Если все потоки выполняются с idx < Size, то у вас есть 3 глобальных доступа к памяти и 8 операций. Обратите внимание, однако, что в CUDA производительность доступа к глобальной памяти зависит от того, объединены ли они. Многие совместные обращения к памяти могут работать намного быстрее, чем несколько несовместимых. Таким образом, CGMA не обязательно дает точную картину потенциала производительности вашего ядра.

Ссылки:

http://www.greatlakesconsortium.org/events/GPUMulticore/Chapter4-CudaMemoryModel.pdf

http://cs.nyu.edu/courses/spring12/CSCI-GA.3033-012/lecture6.pdf

2

разобранном код, соответствующий вашему ядру (составитель для compute_20,sm_20) следующая

/*0000*/  MOV R1, c[0x1][0x100];      
/*0008*/  S2R R0, SR_CTAID.X;       
/*0010*/  S2R R2, SR_TID.X;        
/*0018*/  IMAD R0, R0, c[0x0][0x8], R2;    
/*0020*/  ISETP.GE.AND P0, PT, R0, c[0x0][0x2c], PT; 
/*0028*/ @P0 EXIT ;          
/*0030*/  SHL R0, R0, 0x2;       
/*0038*/  IADD R2, R0, c[0x0][0x20];     
/*0040*/  IADD R3, R0, c[0x0][0x24];     
/*0048*/  IADD R0, R0, c[0x0][0x28];     
/*0050*/  LD R2, [R2];        R2 = x = g_A[idx] 
/*0058*/  LD R3, [R3];        R3 = y = g_B[idx] 
/*0060*/  I2I.S32.S32 R5, |R2|;      
/*0068*/  I2F.F32.U32.RP R4, R5;      R4 = (float)x 
/*0070*/  MUFU.RCP R4, R4;       R4 = 1/R4 
/*0078*/  IADD32I R4, R4, 0xffffffe;     
/*0080*/  F2I.FTZ.U32.F32.TRUNC R4, R4;    
/*0088*/  IMUL.U32.U32 R6, R5, R4;     R6 = x * (1/y) 
/*0090*/  I2I.S32.S32 R7, -R6;      
/*0098*/  I2I.S32.S32 R6, |R3|;      
/*00a0*/  IMAD.U32.U32.HI R7, R4, R7, R4;    
/*00a8*/  IMUL.U32.U32.HI R4, R7, R6;    
/*00b0*/  LOP.XOR R7, R3, R2;       
/*00b8*/  IMAD.U32.U32 R6, -R5, R4, R6;    
/*00c0*/  ISETP.GE.AND P1, PT, R7, RZ, PT;   
/*00c8*/  ISETP.LE.U32.AND P0, PT, R5, R6, PT;  
/*00d0*/ @P0 ISUB R6, R6, R5;       
/*00d8*/ @P0 IADD R4, R4, 0x1;       
/*00e0*/  ISETP.GE.U32.AND P0, PT, R6, R5, PT;  
/*00e8*/  LOP.PASS_B R6, RZ, ~R2;      
/*00f0*/  ISUB R5, R3, R2;       
/*00f8*/ @P0 IADD R4, R4, 0x1;       
/*0100*/ @!P1 I2I.S32.S32 R4, -R4;      
/*0108*/  ICMP.EQ R4, R6, R4, R2;      
/*0110*/  IADD R4, R5, R4;       
/*0118*/  IMAD R2, R3, R2, R4;      
/*0120*/  ST [R0], R2;        
/*0128*/  EXIT ;          

Из приведенного выше кода, Есть после операций с плавающей запятой

I2F.F32.U32.RP R4, R5;      Integer to Float conversion 
MUFU.RCP R4, R4;       Multifunction Floating Point Operation (Reciprocal) 
F2I.FTZ.U32.F32.TRUNC R4, R4;    Float to Integer conversion 

Эти операции, как представляется, связаны с (x/y), который является делением между двумя целыми числами, но требует преобразования в плавающую точку. Я действительно не знаю, учитываются ли преобразования как операции с плавающей запятой или нет. Я не вижу никакой другой операции с плавающей запятой в коде.

Глобальные операции с памятью являются следующие 3

LD R2, [R2];        
LD R3, [R3];        
ST [R0], R2;        

Я бы сказал, что CGMA = 3/3 = 1 для вашего случая (считая преобразования int2float и float2int, как операции с плавающей точкой).

+0

С какой архитектурой вы скомпилировали? Интересно, что у него нет целочисленного оборудования. –

+1

@RogerDahl Fermi: 'compute_20, sm_20'. – JackOLantern

Смежные вопросы