Jogamp
implemented isReleased()
[jocl-demos.git] / src / com / jogamp / opencl / demos / radixsort / RadixSort.java
1 /*
2  * 20:38 Sunday, February 28 2010
3  */
4
5 package com.jogamp.opencl.demos.radixsort;
6
7 import com.jogamp.opencl.CLBuffer;
8 import com.jogamp.opencl.CLCommandQueue;
9 import com.jogamp.opencl.CLContext;
10 import com.jogamp.opencl.CLKernel;
11 import com.jogamp.opencl.CLProgram;
12 import com.jogamp.opencl.CLResource;
13 import java.io.IOException;
14 import java.nio.IntBuffer;
15
16 import static com.jogamp.opencl.CLMemory.Mem.*;
17 import static com.jogamp.opencl.CLProgram.*;
18 import static com.jogamp.opencl.CLProgram.CompilerOptions.*;
19
20 /**
21  *
22  * @author Michael Bien
23  */
24 public class RadixSort implements CLResource {
25
26     private static final int NUM_BANKS = 16;
27     private static final int WARP_SIZE = 32;
28     private static final int bitStep   = 4;
29
30     private final int CTA_SIZE;
31
32     private final CLKernel ckRadixSortBlocksKeysOnly;
33     private final CLKernel ckFindRadixOffsets;
34     private final CLKernel ckScanNaive;
35     private final CLKernel ckReorderDataKeysOnly;
36
37     private final CLBuffer<?> tempKeys;
38     private final CLBuffer<?> mCounters;
39     private final CLBuffer<?> mCountersSum;
40     private final CLBuffer<?> mBlockOffsets;
41
42     private final CLCommandQueue queue;
43     private final Scan scan;
44     private final CLProgram program;
45
46     public RadixSort(CLCommandQueue queue, int maxElements, int CTA_SIZE) throws IOException {
47
48         this.CTA_SIZE = CTA_SIZE;
49         scan = new Scan(queue, maxElements / 2 / CTA_SIZE * 16);
50
51         int numBlocks = ((maxElements % (CTA_SIZE * 4)) == 0)
52                 ? (maxElements / (CTA_SIZE * 4)) : (maxElements / (CTA_SIZE * 4) + 1);
53
54         this.queue = queue;
55
56         CLContext context  = queue.getContext();
57         this.tempKeys      = context.createBuffer(4 * maxElements,           READ_WRITE);
58         this.mCounters     = context.createBuffer(4 * WARP_SIZE * numBlocks, READ_WRITE);
59         this.mCountersSum  = context.createBuffer(4 * WARP_SIZE * numBlocks, READ_WRITE);
60         this.mBlockOffsets = context.createBuffer(4 * WARP_SIZE * numBlocks, READ_WRITE);
61
62         program = context.createProgram(getClass().getResourceAsStream("RadixSort.cl"))
63                          .build(ENABLE_MAD, define("WARP_SIZE", WARP_SIZE));
64
65 //        out.println(program.getBuildLog());
66
67         ckRadixSortBlocksKeysOnly  = program.createCLKernel("radixSortBlocksKeysOnly");
68         ckFindRadixOffsets         = program.createCLKernel("findRadixOffsets");
69         ckScanNaive                = program.createCLKernel("scanNaive");
70         ckReorderDataKeysOnly      = program.createCLKernel("reorderDataKeysOnly");
71
72     }
73
74     void sort(CLBuffer<IntBuffer> d_keys, int numElements, int keyBits) {
75         radixSortKeysOnly(d_keys, numElements, keyBits);
76     }
77
78     //----------------------------------------------------------------------------
79     // Main key-only radix sort function.  Sorts in place in the keys and values
80     // arrays, but uses the other device arrays as temporary storage.  All pointer
81     // parameters are device pointers.  Uses cudppScan() for the prefix sum of
82     // radix counters.
83     //----------------------------------------------------------------------------
84     void radixSortKeysOnly(CLBuffer<IntBuffer> keys, int numElements, int keyBits) {
85         int i = 0;
86         while (keyBits > i * bitStep) {
87             radixSortStepKeysOnly(keys, bitStep, i * bitStep, numElements);
88             i++;
89         }
90     }
91
92     //----------------------------------------------------------------------------
93     // Perform one step of the radix sort.  Sorts by nbits key bits per step,
94     // starting at startbit.
95     //----------------------------------------------------------------------------
96     void radixSortStepKeysOnly(CLBuffer<IntBuffer> keys, int nbits, int startbit, int numElements) {
97
98         // Four step algorithms from Satish, Harris & Garland
99         radixSortBlocksKeysOnlyOCL(keys, nbits, startbit, numElements);
100
101         findRadixOffsetsOCL(startbit, numElements);
102
103         scan.scanExclusiveLarge(mCountersSum, mCounters, 1, numElements / 2 / CTA_SIZE * 16);
104
105         reorderDataKeysOnlyOCL(keys, startbit, numElements);
106     }
107
108     //----------------------------------------------------------------------------
109     // Wrapper for the kernels of the four steps
110     //----------------------------------------------------------------------------
111     void radixSortBlocksKeysOnlyOCL(CLBuffer<IntBuffer> keys, int nbits, int startbit, int numElements) {
112
113         int totalBlocks = numElements / 4 / CTA_SIZE;
114         int globalWorkSize = CTA_SIZE * totalBlocks;
115         int localWorkSize = CTA_SIZE;
116
117         ckRadixSortBlocksKeysOnly.putArg(keys).putArg(tempKeys).putArg(nbits).putArg(startbit)
118                                  .putArg(numElements).putArg(totalBlocks).putNullArg(4 * CTA_SIZE * 4)
119                                  .rewind();
120
121         queue.put1DRangeKernel(ckRadixSortBlocksKeysOnly, 0, globalWorkSize, localWorkSize);
122     }
123
124     void findRadixOffsetsOCL(int startbit, int numElements) {
125
126         int totalBlocks = numElements / 2 / CTA_SIZE;
127         int globalWorkSize = CTA_SIZE * totalBlocks;
128         int localWorkSize = CTA_SIZE;
129
130         ckFindRadixOffsets.putArg(tempKeys).putArg(mCounters).putArg(mBlockOffsets)
131                           .putArg(startbit).putArg(numElements).putArg(totalBlocks).putNullArg(2 * CTA_SIZE * 4)
132                           .rewind();
133
134         queue.put1DRangeKernel(ckFindRadixOffsets, 0, globalWorkSize, localWorkSize);
135     }
136
137     void scanNaiveOCL(int numElements) {
138         
139         int nHist = numElements / 2 / CTA_SIZE * 16;
140         int globalWorkSize = nHist;
141         int localWorkSize = nHist;
142         int extra_space = nHist / NUM_BANKS;
143         int shared_mem_size = 4 * (nHist + extra_space);
144
145         ckScanNaive.putArg(mCountersSum).putArg(mCounters).putArg(nHist).putNullArg(2 * shared_mem_size).rewind();
146
147         queue.put1DRangeKernel(ckScanNaive, 0, globalWorkSize, localWorkSize);
148     }
149
150     void reorderDataKeysOnlyOCL(CLBuffer<IntBuffer> keys, int startbit, int numElements) {
151
152         int totalBlocks = numElements / 2 / CTA_SIZE;
153         int globalWorkSize = CTA_SIZE * totalBlocks;
154         int localWorkSize = CTA_SIZE;
155
156         ckReorderDataKeysOnly.putArg(keys).putArg(tempKeys).putArg(mBlockOffsets).putArg(mCountersSum).putArg(mCounters)
157                              .putArg(startbit).putArg(numElements).putArg(totalBlocks).putNullArg(2 * CTA_SIZE * 4).rewind();
158
159         queue.put1DRangeKernel(ckReorderDataKeysOnly, 0, globalWorkSize, localWorkSize);
160     }
161
162     public void release() {
163
164         scan.release();
165
166         //program & kernels
167         program.release();
168
169         //buffers
170         tempKeys.release();
171         mCounters.release();
172         mCountersSum.release();
173         mBlockOffsets.release();
174     }
175
176     @Override
177     public boolean isReleased() {
178         return scan.isReleased();
179     }
180
181     public void close() {
182         release();
183     }
184
185
186
187 }
http://JogAmp.org git info: FAQ, tutorial and man pages.