Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Opencl, sum of integer vector elements

Problem:

In Opencl 1.2, there is no built-in function like

long sum_int4_elements_into_long(int4 v);

What I've tried:

So I'm using the code below (prefetched inner part of an unrolled loop)

// acc is long
int4 tmp=arr[i+7];
acc+=tmp.x+tmp.y+tmp.z+tmp.w;
tmp=arr[i+6];
acc+=tmp.x+tmp.y+tmp.z+tmp.w;
tmp=arr[i+5];
acc+=tmp.x+tmp.y+tmp.z+tmp.w;
tmp=arr[i+4];"
acc+=tmp.x+tmp.y+tmp.z+tmp.w;
tmp=arr[i+3];
acc+=tmp.x+tmp.y+tmp.z+tmp.w;
tmp=arr[i+2];
acc+=tmp.x+tmp.y+tmp.z+tmp.w;
tmp=arr[i+1];
acc+=tmp.x+tmp.y+tmp.z+tmp.w;
tmp=arr[i];
acc+=tmp.x+tmp.y+tmp.z+tmp.w;       

to sum(reduction) all elements of an integer array (int4 arr) into a single long variable with a speed-up of only +%20 to +%30 compared to serial code. If it could enable SSE or AVX, it would be much faster.

also tried:

using pure integer accumulator speeds the summing operation up by 3x but integer overflows so I can only use a long variable. Then I tried using a long4 and long2 variable as

   // acc is a long4, arr is an int4 array
   acc+=convert_long4(arr[...]) 

  //  acc is a long2, arr is an int2 array
   acc+=convert_long2(arr[...])   

but it failed and locked the computer(checked indexing and limits, there is no problem) so there must be a problem with longn to intn under the hardware instruction mappings with AMD CPU.

Clarification:

There must be some equivalent SIMD(SSE or AVX) assembly instruction of AMD and INTEL for

        32 bit integers in a 128-bit SSE register
         |       |       |      |        
  acc+=tmp.x + tmp.y + tmp.z + tmp.w
   ^    
   | 
  64-bit register 

but somehow opencl doesnt have mapping to this or I did not pack C99 instructions well enough so cl-compiler couldnt use SSE/AVX instructions.

The closest built-in float version is

 acc=dot(v,(float4)(1,1,1,1));

but I need an integer version of this, because fp needs Kahan's Summation Correction which needs extra time.

Edit:

Im not sure if int+int+int+int will have a proper long result or just have an overflowed int into a long.

Opencl version: 1.2 running on CPU (Java ----> Jocl)

CPU: AMD fx-8150

OS:64 bit windows 10

Driver: latest one by amd.

Date: 23.09.2015

For comparison:

16M 32-bit integers, FX8150 @ 3300MHz (using 6 cores out of 8)

Serial code on java 1.8_25 takes 16.5 ms on average.

IntStream of Java-1.8 takes 13.5 ms on average (X.reduce(0, Integer::sum))

Parallel code in this question takes 12.5 ms on average (using single workgroup)

Parallel code in this question takes 5.8 ms on average (using four workgroups)

Parallel but overflowing non-long version takes 5ms. (hitting memory bandwidth)

mfa's answer:

 acc=dot(v,(double4)(1,1,1,1));

takes 13.5 ms on average but float version takes 12.2 ms on average.

Im not sure if a float can keep its precision always to add 1.0 (or even 0.0) to a very big fp number.

like image 848
huseyin tugrul buyukisik Avatar asked Aug 10 '26 19:08

huseyin tugrul buyukisik


1 Answers

What is the speed of doing reductions? Maybe is not so bad after all.

long4 lv = (long4)v;
long2 t = lv.xy + lv.zw;
acc += t.x + t.y;

Also, if what you really want is to reduce multiple items, not a single int4. Then sum them in long4 space and then reduce the last one only.

long4 sums = long4(0);
sums += convert_long4(arr[0]);
sums += convert_long4(arr[1]);
sums += convert_long4(arr[2]);
...
sums += convert_long4(arr[N-1]);
sums += convert_long4(arr[N]);
long2 t = sums.xy + sums.zw;
long res = t.x + t.y;

NOTE: If this is the only operation you are doing memory bottlenecks are likely to be the main problem here. So measuring the kernel execution time is going to give a highly biased result.

like image 57
DarkZeros Avatar answered Aug 13 '26 13:08

DarkZeros



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!