source: trunk/CrypPlugins/KeySearcher/ExternalClient/Cryptool.cpp @ 2230

Last change on this file since 2230 was 2230, checked in by schwittmann, 11 years ago

Improved performance of ExternalClient

File size: 9.4 KB
Line 
1#include <cstdio>
2#include <cstdlib>
3#include <iostream>
4#include <SDKFile.hpp>
5#include <SDKCommon.hpp>
6#include <SDKApplication.hpp>
7
8#ifdef _OPENMP
9#include <omp.h>
10#else
11#warning No OpenMP support. Expect performance impacts.
12#endif
13
14#define __NO_STD_VECTOR
15#define __NO_STD_STRING
16
17#include "Cryptool.h"
18
19Cryptool::Cryptool()
20{
21    cl_int err;
22
23    kernel = 0;
24
25    // Platform info
26    cl::vector<cl::Platform> platforms;
27    std::cout<<"HelloCL!\nGetting Platform Information\n";
28    err = cl::Platform::get(&platforms);
29    if(err != CL_SUCCESS)
30    {
31        std::cerr << "Platform::get() failed (" << err << ")" << std::endl;
32        throw std::exception();
33    }
34    if (platforms.size() == 0)
35    {
36        std::cerr << "No platforms available!" << std::endl;
37        throw std::exception();
38    }
39
40    cl::vector<cl::Platform>::iterator i;
41    if(platforms.size() > 0)
42    {
43        for(i = platforms.begin(); i != platforms.end(); ++i)
44        {
45            if(!strcmp((*i).getInfo<CL_PLATFORM_VENDOR>(&err).c_str(), "Advanced Micro Devices, Inc."))
46            {
47                break;
48            }
49        }
50    }
51    if(err != CL_SUCCESS)
52    {
53        std::cerr << "Platform::getInfo() failed (" << err << ")" << std::endl;
54        throw std::exception();
55    }
56
57    /*
58     * If we could find our platform, use it. Otherwise pass a NULL and get whatever the
59     * implementation thinks we should be using.
60     */
61
62    cl_context_properties cps[3] = { CL_CONTEXT_PLATFORM, (cl_context_properties)(*i)(), 0 };
63
64    std::cout<<"Creating a context AMD platform\n";
65    context = new cl::Context(CL_DEVICE_TYPE_CPU, cps, NULL, NULL, &err);
66    if (err != CL_SUCCESS) {
67        std::cerr << "Context::Context() failed (" << err << ")\n";
68        throw std::exception();
69    }
70
71    std::cout<<"Getting device info\n";
72    devices = context->getInfo<CL_CONTEXT_DEVICES>();
73    if (err != CL_SUCCESS) {
74        std::cerr << "Context::getInfo() failed (" << err << ")\n";
75        throw std::exception();
76    }
77    if (devices.size() == 0) {
78        std::cerr << "No device available\n";
79        throw std::exception();
80    }
81
82    for(uint32_t i=0; i< devices.size(); ++i)
83    {
84        std::string out;
85        devices[i].getInfo(CL_DEVICE_NAME, &out);
86        printf("name: %s\n", out.c_str());
87        devices[i].getInfo(CL_DEVICE_VENDOR, &out);
88        printf("vendor: %s\n", out.c_str());
89        devices[i].getInfo(CL_DEVICE_OPENCL_C_VERSION, &out);
90        printf("version c: %s\n", out.c_str());
91    }
92
93    // results
94    costs = cl::Buffer(*context, CL_MEM_WRITE_ONLY, sizeof(float)*subbatch, NULL, &err);
95
96    if(err != CL_SUCCESS)
97    {
98        std::cerr << "Failed allocate to costsbuffer(" << err << ")\n";
99        throw new std::exception();
100    }
101   
102    localCosts = new float[subbatch];
103}
104
105void Cryptool::buildKernel(const Job& j)
106{
107    if (j.Src == "")
108    {
109        if (kernel != 0)
110            return;
111        else
112        {
113            std::cout << "Source transmission failure!" << std::endl;
114            throw new std::exception();
115        }
116    }
117
118    cl_int err;
119
120    std::cout<<"compiling CL source\n";
121    cl::Program::Sources sources(1, std::make_pair(j.Src.c_str(), j.Src.length()));
122
123    cl::Program program = cl::Program(*context, sources, &err);
124    if (err != CL_SUCCESS) {
125        std::cerr << "Program::Program() failed (" << err << ")\n";
126        throw new std::exception();
127    }
128
129    err = program.build(devices);
130    if (err != CL_SUCCESS) {
131
132        if(err == CL_BUILD_PROGRAM_FAILURE)
133        {
134            cl::string str = program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(devices[0]);
135
136            std::cout << " \n\t\t\tBUILD LOG\n";
137            std::cout << " ************************************************\n";
138                        std::cout << str.c_str() << std::endl;
139            std::cout << " ************************************************\n";
140        }
141
142        std::cerr << "Program::build() failed (" << err << ")\n";
143        throw new std::exception();
144    }
145
146    if (kernel != 0)
147        delete kernel;
148
149    kernel = new cl::Kernel(program, "bruteforceKernel", &err);
150    if (err != CL_SUCCESS) {
151        std::cerr << "Kernel::Kernel() failed (" << err << ")\n";
152        throw new std::exception();
153    }
154}
155
156JobResult Cryptool::doOpenCLJob(const Job& j)
157{
158    cl_int err;
159
160    buildKernel(j);
161
162    cl::CommandQueue queue(*context, devices[0], 0, &err);
163    if (err != CL_SUCCESS) {
164        std::cerr << "CommandQueue::CommandQueue() failed (" << err << ")\n";
165        throw new std::exception();
166    }
167
168    // key
169    cl::Buffer keybuffer = cl::Buffer(*context, CL_MEM_READ_ONLY, j.KeySize*sizeof(float), NULL, &err);
170    if(err != CL_SUCCESS)
171    {
172        std::cerr << "Failed to allocate keybuffer(" << err << ")\n";
173        throw new std::exception();
174    }
175
176    err = queue.enqueueWriteBuffer(keybuffer, 1, 0, j.KeySize*sizeof(float), j.Key);
177    if(err != CL_SUCCESS)
178    {
179        std::cerr << "Failed write to keybuffer(" << err << ")\n";
180        throw new std::exception();
181    }
182
183    this->compareLargerThan = j.LargerThen;
184    this->resultSize = j.ResultSize;
185    res.ResultList.resize(j.ResultSize);
186    initTop(res.ResultList, j.LargerThen);
187
188    //execute:
189    std::cout<<"Running CL program with " << j.Size << " calculations!\n";
190    enqueueKernel(queue, j.Size, keybuffer, costs, j);
191
192    std::cout<<"Done!\n";
193
194    return res;
195}
196
197void Cryptool::enqueueSubbatch(cl::CommandQueue& queue, cl::Buffer& keybuffer, cl::Buffer& costs, int add, int length, const Job& j)
198{
199        cl_int err;
200
201        err = kernel->setArg(0, keybuffer);
202        if (err != CL_SUCCESS) {
203                std::cerr << "Kernel::setArg() failed (" << err << ")\n";
204                throw new std::exception();
205        }
206
207        err = kernel->setArg(1, costs);
208        if (err != CL_SUCCESS) {
209                std::cerr << "Kernel::setArg() failed (" << err << ")\n";
210                throw new std::exception();
211        }
212
213        err = kernel->setArg(2, add);
214        if (err != CL_SUCCESS) {
215                std::cerr << "Kernel::setArg() failed (" << err << ")\n";
216                throw new std::exception();
217        }
218
219        err = queue.enqueueNDRangeKernel(*kernel, cl::NullRange, cl::NDRange(256, 256, 256), cl::NullRange);
220
221        if (err != CL_SUCCESS) {
222                std::cerr << "CommandQueue::enqueueNDRangeKernel()" \
223                    " failed (" << err << ")\n";
224                throw new std::exception();
225        }
226
227        err = queue.finish();
228        if (err != CL_SUCCESS) {
229                std::cerr << "Event::wait() failed (" << err << ")\n";
230                throw new std::exception();
231        }
232
233        queue.enqueueReadBuffer(costs, 1, 0, sizeof(float)*length, localCosts);
234        err = queue.finish();
235        if (err != CL_SUCCESS) {
236                std::cerr << "Event::wait() failed (" << err << ")\n";
237                throw new std::exception();
238        }
239#ifdef _OPENMP
240#pragma omp parallel
241    {
242        std::list<std::pair<float, int> > localtop;
243        int eachChunk = length/omp_get_num_threads();
244        int from = omp_get_thread_num()*eachChunk;
245        int to = from + eachChunk;
246        if(omp_get_thread_num() == omp_get_num_threads()-1)
247        {
248            to = length;
249        }
250        for(int i=from; i<to; ++i)
251        {
252            std::list<std::pair<float, int> >::iterator it = isInTop(localtop, localCosts[i], j.LargerThen);
253            if (it != localtop.end() || it == localtop.begin())
254                pushInTop(localtop, it, localCosts[i], i+add);
255        }
256        // merge it
257#pragma omp critical
258        {
259            std::list<std::pair<float, int> >::iterator itr;
260            for(itr = localtop.begin(); itr != localtop.end(); ++itr)
261            {
262                std::list<std::pair<float, int> >::iterator posInGlobalList = isInTop(res.ResultList, itr->first, j.LargerThen);
263                if (posInGlobalList != res.ResultList.end())
264                    pushInTop(res.ResultList, posInGlobalList, itr->first, itr->second);
265            }
266        }
267    }
268#else
269        //check results:
270        for(int i=0; i<length; ++i)
271        {
272                //std::cout << localCosts[i] << std::endl;
273                std::list<std::pair<float, int> >::iterator it = isInTop(res.ResultList, localCosts[i], j.LargerThen);
274                if (it != res.ResultList.end())
275                        pushInTop(res.ResultList, it, localCosts[i], i+add);
276        }
277#endif
278}
279
280void Cryptool::enqueueKernel(cl::CommandQueue& queue, int size, cl::Buffer& keybuffer, cl::Buffer& costs, const Job& j)
281{
282    for (int i = 0; i < (size/subbatch); i++)
283    {
284        enqueueSubbatch(queue, keybuffer, costs, i*subbatch, subbatch, j);
285    }
286
287    int remain = (size%subbatch);
288    if (remain != 0)
289    {
290        enqueueSubbatch(queue, keybuffer, costs, size-remain, remain, j);
291    }
292}
293
294void Cryptool::pushInTop(std::list<std::pair<float, int> >& top, std::list<std::pair<float, int> >::iterator it, float val, int k) {
295        top.insert(it, std::pair<float, int>(val, k));
296    if(top.size() > this->resultSize)
297        top.pop_back();
298}
299
300std::list<std::pair<float, int> >::iterator Cryptool::isInTop(std::list<std::pair<float, int> >& top, float val, bool LargerThen) {
301    if (top.size() == 0)
302        return top.begin();
303
304        if (LargerThen)
305        {
306                if(top.size() > 0 && val <= top.rbegin()->first)
307                        return top.end();
308                for (std::list<std::pair<float, int> >::iterator k = top.begin(); k != top.end(); k++)
309                        if (val > k->first)
310                                return k;
311        }
312        else
313        {
314                if(top.size() > 0 && val >= top.rbegin()->first)
315                        return top.end();
316                for (std::list<std::pair<float, int> >::iterator k = top.begin(); k != top.end(); k++)
317                        if (val < k->first)
318                                return k;
319        }
320
321        return top.end();
322}
323
324void Cryptool::initTop(std::list<std::pair<float, int> >& top, bool LargerThen) {
325        for (std::list<std::pair<float, int> >::iterator k = top.begin(); k != top.end(); k++)
326        {
327            if (LargerThen)
328                k->first = -1000000.0;
329            else
330                k->first = 1000000.0;
331        }
332}
Note: See TracBrowser for help on using the repository browser.