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

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

ExternalClient: Display progress for each subbatch

File size: 9.8 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    lastSubbatchCompleted = clock();
104
105    // required for thousand/million separator in printf
106    setlocale(LC_ALL,"");
107}
108
109void Cryptool::buildKernel(const Job& j)
110{
111    if (j.Src == "")
112    {
113        if (kernel != 0)
114            return;
115        else
116        {
117            std::cout << "Source transmission failure!" << std::endl;
118            throw new std::exception();
119        }
120    }
121
122    cl_int err;
123
124    std::cout<<"compiling CL source\n";
125    cl::Program::Sources sources(1, std::make_pair(j.Src.c_str(), j.Src.length()));
126
127    cl::Program program = cl::Program(*context, sources, &err);
128    if (err != CL_SUCCESS) {
129        std::cerr << "Program::Program() failed (" << err << ")\n";
130        throw new std::exception();
131    }
132
133    err = program.build(devices);
134    if (err != CL_SUCCESS) {
135
136        if(err == CL_BUILD_PROGRAM_FAILURE)
137        {
138            cl::string str = program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(devices[0]);
139
140            std::cout << " \n\t\t\tBUILD LOG\n";
141            std::cout << " ************************************************\n";
142                        std::cout << str.c_str() << std::endl;
143            std::cout << " ************************************************\n";
144        }
145
146        std::cerr << "Program::build() failed (" << err << ")\n";
147        throw new std::exception();
148    }
149
150    if (kernel != 0)
151        delete kernel;
152
153    kernel = new cl::Kernel(program, "bruteforceKernel", &err);
154    if (err != CL_SUCCESS) {
155        std::cerr << "Kernel::Kernel() failed (" << err << ")\n";
156        throw new std::exception();
157    }
158}
159
160JobResult Cryptool::doOpenCLJob(const Job& j)
161{
162    cl_int err;
163
164    buildKernel(j);
165
166    cl::CommandQueue queue(*context, devices[0], 0, &err);
167    if (err != CL_SUCCESS) {
168        std::cerr << "CommandQueue::CommandQueue() failed (" << err << ")\n";
169        throw new std::exception();
170    }
171
172    // key
173    cl::Buffer keybuffer = cl::Buffer(*context, CL_MEM_READ_ONLY, j.KeySize*sizeof(float), NULL, &err);
174    if(err != CL_SUCCESS)
175    {
176        std::cerr << "Failed to allocate keybuffer(" << err << ")\n";
177        throw new std::exception();
178    }
179
180    err = queue.enqueueWriteBuffer(keybuffer, 1, 0, j.KeySize*sizeof(float), j.Key);
181    if(err != CL_SUCCESS)
182    {
183        std::cerr << "Failed write to keybuffer(" << err << ")\n";
184        throw new std::exception();
185    }
186
187    this->compareLargerThan = j.LargerThen;
188    this->resultSize = j.ResultSize;
189    res.ResultList.resize(j.ResultSize);
190    initTop(res.ResultList, j.LargerThen);
191
192    //execute:
193    std::cout<<"Running CL program with " << j.Size << " calculations!\n";
194    enqueueKernel(queue, j.Size, keybuffer, costs, j);
195
196    std::cout<<"Done!\n";
197
198    return res;
199}
200
201void Cryptool::enqueueSubbatch(cl::CommandQueue& queue, cl::Buffer& keybuffer, cl::Buffer& costs, int add, int length, const Job& j)
202{
203        cl_int err;
204
205        err = kernel->setArg(0, keybuffer);
206        if (err != CL_SUCCESS) {
207                std::cerr << "Kernel::setArg() failed (" << err << ")\n";
208                throw new std::exception();
209        }
210
211        err = kernel->setArg(1, costs);
212        if (err != CL_SUCCESS) {
213                std::cerr << "Kernel::setArg() failed (" << err << ")\n";
214                throw new std::exception();
215        }
216
217        err = kernel->setArg(2, add);
218        if (err != CL_SUCCESS) {
219                std::cerr << "Kernel::setArg() failed (" << err << ")\n";
220                throw new std::exception();
221        }
222
223        err = queue.enqueueNDRangeKernel(*kernel, cl::NullRange, cl::NDRange(256, 256, 256), cl::NullRange);
224
225        if (err != CL_SUCCESS) {
226                std::cerr << "CommandQueue::enqueueNDRangeKernel()" \
227                    " failed (" << err << ")\n";
228                throw new std::exception();
229        }
230
231        err = queue.finish();
232        if (err != CL_SUCCESS) {
233                std::cerr << "Event::wait() failed (" << err << ")\n";
234                throw new std::exception();
235        }
236
237        queue.enqueueReadBuffer(costs, 1, 0, sizeof(float)*length, localCosts);
238        err = queue.finish();
239        if (err != CL_SUCCESS) {
240                std::cerr << "Event::wait() failed (" << err << ")\n";
241                throw new std::exception();
242        }
243#ifdef _OPENMP
244#pragma omp parallel
245    {
246        std::list<std::pair<float, int> > localtop;
247        int eachChunk = length/omp_get_num_threads();
248        int from = omp_get_thread_num()*eachChunk;
249        int to = from + eachChunk;
250        if(omp_get_thread_num() == omp_get_num_threads()-1)
251        {
252            to = length;
253        }
254        for(int i=from; i<to; ++i)
255        {
256            std::list<std::pair<float, int> >::iterator it = isInTop(localtop, localCosts[i], j.LargerThen);
257            if (it != localtop.end() || it == localtop.begin())
258                pushInTop(localtop, it, localCosts[i], i+add);
259        }
260        // merge it
261#pragma omp critical
262        {
263            std::list<std::pair<float, int> >::iterator itr;
264            for(itr = localtop.begin(); itr != localtop.end(); ++itr)
265            {
266                std::list<std::pair<float, int> >::iterator posInGlobalList = isInTop(res.ResultList, itr->first, j.LargerThen);
267                if (posInGlobalList != res.ResultList.end())
268                    pushInTop(res.ResultList, posInGlobalList, itr->first, itr->second);
269            }
270        }
271    }
272#else
273        //check results:
274        for(int i=0; i<length; ++i)
275        {
276                //std::cout << localCosts[i] << std::endl;
277                std::list<std::pair<float, int> >::iterator it = isInTop(res.ResultList, localCosts[i], j.LargerThen);
278                if (it != res.ResultList.end())
279                        pushInTop(res.ResultList, it, localCosts[i], i+add);
280        }
281#endif
282}
283
284void Cryptool::enqueueKernel(cl::CommandQueue& queue, int size, cl::Buffer& keybuffer, cl::Buffer& costs, const Job& j)
285{
286    for (int i = 0; i < (size/subbatch); i++)
287    {
288        enqueueSubbatch(queue, keybuffer, costs, i*subbatch, subbatch, j);
289
290        clock_t now = clock();
291        clock_t timeDiff = now - lastSubbatchCompleted;
292        lastSubbatchCompleted = now;
293        printf("% .2f%% done. %'u keys/sec\n", ((i+1)*subbatch)/(float)size*100, (unsigned int)(subbatch/(timeDiff/(float)CLOCKS_PER_SEC)));
294    }
295
296    int remain = (size%subbatch);
297    if (remain != 0)
298    {
299        enqueueSubbatch(queue, keybuffer, costs, size-remain, remain, j);
300    }
301}
302
303void Cryptool::pushInTop(std::list<std::pair<float, int> >& top, std::list<std::pair<float, int> >::iterator it, float val, int k) {
304        top.insert(it, std::pair<float, int>(val, k));
305    if(top.size() > this->resultSize)
306        top.pop_back();
307}
308
309std::list<std::pair<float, int> >::iterator Cryptool::isInTop(std::list<std::pair<float, int> >& top, float val, bool LargerThen) {
310    if (top.size() == 0)
311        return top.begin();
312
313        if (LargerThen)
314        {
315                if(top.size() > 0 && val <= top.rbegin()->first)
316                        return top.end();
317                for (std::list<std::pair<float, int> >::iterator k = top.begin(); k != top.end(); k++)
318                        if (val > k->first)
319                                return k;
320        }
321        else
322        {
323                if(top.size() > 0 && val >= top.rbegin()->first)
324                        return top.end();
325                for (std::list<std::pair<float, int> >::iterator k = top.begin(); k != top.end(); k++)
326                        if (val < k->first)
327                                return k;
328        }
329
330        return top.end();
331}
332
333void Cryptool::initTop(std::list<std::pair<float, int> >& top, bool LargerThen) {
334        for (std::list<std::pair<float, int> >::iterator k = top.begin(); k != top.end(); k++)
335        {
336            if (LargerThen)
337                k->first = -1000000.0;
338            else
339                k->first = 1000000.0;
340        }
341}
Note: See TracBrowser for help on using the repository browser.