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

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

Fixed some memory leaks

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