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

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

ExternalClient: fixed segmentation fault on systems with vendor specific libGL.so

File size: 13.7 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_STRING
15
16#include "Cryptool.h"
17
18unsigned long DiffMicSec(timeval & start, timeval & end)
19{
20    return (end.tv_sec - start.tv_sec)*1000000 + (end.tv_usec - start.tv_usec);
21}
22
23Cryptool::Cryptool()
24{
25    cl_int err;
26
27    kernel = 0;
28    platformChoice = -1;
29    deviceChoice = -1;
30
31    // Get platform information
32    std::cout<<"Getting platform"<<std::endl;
33    err = cl::Platform::get(&platforms);
34
35    if(err != CL_SUCCESS)
36    {
37        std::cerr << "Platform::get() failed (" << err << ")" << std::endl;
38        throw std::exception();
39    }
40    if (platforms.size() <= 0)
41    {
42        std::cerr << "No platforms available!" << std::endl;
43        throw std::exception();
44    }
45
46    //Iterate over all platforms to generate output for platform choosing by user
47    std::vector<cl::Platform>::iterator i;
48        std::cout << "Number of platforms: " << platforms.size() << std::endl << std::endl;
49        for(i = platforms.begin(); i != platforms.end(); ++i)
50        {
51                std::cout << "Platform Profile: " << (*i).getInfo<CL_PLATFORM_PROFILE>(&err).c_str() << std::endl;
52                std::cout << "Platform Version: " << (*i).getInfo<CL_PLATFORM_VERSION>(&err).c_str() << std::endl;
53                std::cout << "Platform Name: " << (*i).getInfo<CL_PLATFORM_NAME>(&err).c_str() << std::endl;
54                std::cout << "Platform Vendor: " << (*i).getInfo<CL_PLATFORM_VENDOR>(&err).c_str() << std::endl;
55                std::cout << std::endl;
56
57            if(err != CL_SUCCESS)
58            {
59                std::cerr << "Platform::getInfo() failed (" << err << ")" << std::endl;
60                throw std::exception();
61            }
62
63            //Get all devices for the current platform to show device information for each device
64                (*i).getDevices((cl_device_type)CL_DEVICE_TYPE_ALL, &devices);
65
66                std::cout << "There are " << devices.size() << " devices for this platform." <<std::endl;
67
68                for (std::vector<cl::Device>::iterator z = devices.begin(); z != devices.end(); ++z) {
69                        cl_device_type dtype = (*z).getInfo<CL_DEVICE_TYPE>();
70                        std::cout << "  Device Type: ";
71                        switch (dtype) {
72                                case CL_DEVICE_TYPE_ACCELERATOR:
73                                        std::cout << "CL_DEVICE_TYPE_ACCELERATOR" << std::endl;
74                                        break;
75                                case CL_DEVICE_TYPE_CPU:
76                                        std::cout << "CL_DEVICE_TYPE_CPU" << std::endl;
77                                        break;
78                                case CL_DEVICE_TYPE_DEFAULT:
79                                        std::cout << "CL_DEVICE_TYPE_DEFAULT" << std::endl;
80                                        break;
81                                case CL_DEVICE_TYPE_GPU:
82                                        std::cout << "CL_DEVICE_TYPE_GPU" << std::endl;
83                                        break;
84                                }
85
86            std::cout << "  Platform ID: " << (*z).getInfo<CL_DEVICE_PLATFORM>() << std::endl;
87            std::cout << "  Name: " << (*z).getInfo<CL_DEVICE_NAME>().c_str() << std::endl;
88            std::cout << "  Vendor: " << (*z).getInfo<CL_DEVICE_VENDOR>().c_str() << std::endl;
89            std::cout << "  Driver version: " << (*z).getInfo<CL_DRIVER_VERSION>().c_str() << std::endl;
90            std::cout << "  Is device available?  " << ((*z).getInfo<CL_DEVICE_AVAILABLE>() ? "Yes" : "No") << std::endl;
91            std::cout << "  Device ID: " << (*z).getInfo<CL_DEVICE_VENDOR_ID>() << std::endl;
92            std::cout << "  Max clock frequency: " << (*z).getInfo<CL_DEVICE_MAX_CLOCK_FREQUENCY>() << "Mhz" << std::endl;
93            std::cout << "  Local memory size: " << (*z).getInfo<CL_DEVICE_LOCAL_MEM_SIZE>() << std::endl;
94            std::cout << "  Global memory size: " << (*z).getInfo<CL_DEVICE_GLOBAL_MEM_SIZE>() << std::endl;
95            std::cout << "  Max memory allocation: " << (*z).getInfo<CL_DEVICE_MAX_MEM_ALLOC_SIZE>() << std::endl;
96            std::cout << "  Cache size: " << (*z).getInfo<CL_DEVICE_GLOBAL_MEM_CACHE_SIZE>() << std::endl;
97            std::cout << "  Extensions: " << (*z).getInfo<CL_DEVICE_EXTENSIONS>().c_str() << std::endl;
98            std::cout << "  Execution capabilities: " << std::endl;
99            std::cout << "    Execute OpenCL kernels: " << ((*z).getInfo<CL_DEVICE_EXECUTION_CAPABILITIES>() & CL_EXEC_KERNEL ? "Yes" : "No") << std::endl;
100            std::cout << "    Execute native function: " << ((*z).getInfo<CL_DEVICE_EXECUTION_CAPABILITIES>() & CL_EXEC_NATIVE_KERNEL ? "Yes" : "No") << std::endl;
101
102                        std::cout << std::endl;
103                }
104        }
105
106        if(platforms.size() > 1) {
107                while(platformChoice<0 || platformChoice>=(int)platforms.size()) {
108                        std::cout << "Choose your platform!" << std::endl;
109                        std::cin >> platformChoice;
110                }
111        } else {
112                std::cout << "Choosing only available platform." << std::endl;
113                platformChoice=0;
114        }
115
116        if(devices.size() > 1) {
117                while(deviceChoice<0 || deviceChoice>=(int)devices.size()) {
118                        std::cout << "Choose the device to calculate on!" << std::endl;
119                        std::cin >> deviceChoice;
120                }
121        } else {
122                std::cout << "Choosing only available device." << std::endl;
123                deviceChoice=0;
124        }
125
126
127    /*
128     * If we could find our platform, use it. Otherwise pass a NULL and get whatever the
129     * implementation thinks we should be using.
130     */
131
132    cl_context_properties cps[3] = { CL_CONTEXT_PLATFORM, (cl_context_properties)platforms.at(platformChoice)(), 0 };
133
134    std::cout<<"Creating CL context" << std::endl;
135    context = new cl::Context(CL_DEVICE_TYPE_ALL, cps, NULL, NULL, &err);
136
137    if (err != CL_SUCCESS) {
138        std::cerr << "Context::Context() failed (" << err << ")\n";
139        throw std::exception();
140    }
141   
142    // results
143    costs = cl::Buffer(*context, CL_MEM_WRITE_ONLY, sizeof(float)*subbatch, NULL, &err);
144
145    if(err != CL_SUCCESS)
146    {
147        std::cerr << "Failed allocate to costsbuffer(" << err << ")\n";
148        throw std::exception();
149    }
150   
151    localCosts = new float[subbatch];
152
153    gettimeofday(&lastSubbatchCompleted, NULL);
154
155    // required for thousand/million separator in printf
156    setlocale(LC_ALL,"");
157}
158
159void Cryptool::buildKernel(const Job& j)
160{
161    if (j.Src == "")
162    {
163        if (kernel != 0)
164            return;
165        else
166        {
167            std::cout << "Source transmission failure!" << std::endl;
168            throw std::exception();
169        }
170    }
171
172    cl_int err;
173
174    std::cout<<"Compiling CL source\n";
175    cl::Program::Sources sources(1, std::make_pair(j.Src.c_str(), j.Src.length()));
176
177    cl::Program program = cl::Program(*context, sources, &err);
178    if (err != CL_SUCCESS) {
179        std::cerr << "Program::Program() failed (" << err << ")\n";
180        throw std::exception();
181    }
182
183    err = program.build(devices);
184    if (err != CL_SUCCESS) {
185
186                if(err == CL_BUILD_PROGRAM_FAILURE)
187                        {
188                                cl::string str = program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(devices[0]);
189
190                                std::cout << " \n\t\t\tBUILD LOG\n";
191                                std::cout << " ************************************************\n";
192                                std::cout << str.c_str() << std::endl;
193                                std::cout << " ************************************************\n";
194                        }
195
196                //If there is an -33 error thrown here, you are most commonly trying to run an unsupported OpenCL version
197        std::cerr << "Program::build() failed (" << err << ")\n";
198        throw std::exception();
199    }
200
201        delete kernel;
202
203    kernel = new cl::Kernel(program, "bruteforceKernel", &err);
204    if (err != CL_SUCCESS) {
205        std::cerr << "Kernel::Kernel() failed (" << err << ")\n";
206        throw std::exception();
207    }
208}
209
210JobResult Cryptool::doOpenCLJob(const Job& j)
211{
212    res.Guid = j.Guid;
213    cl_int err;
214
215    buildKernel(j);
216
217    std::cout << "Using device named: " << getDeviceName() << " to calculate." << std::endl;
218    //Use the chosen device to calculate on!
219    cl::CommandQueue queue(*context, devices[deviceChoice], 0, &err);
220    if (err != CL_SUCCESS) {
221        std::cerr << "CommandQueue::CommandQueue() failed (" << err << ")\n";
222        throw std::exception();
223    }
224
225    // key
226    cl::Buffer keybuffer = cl::Buffer(*context, CL_MEM_READ_ONLY, j.KeySize*sizeof(float), NULL, &err);
227    if(err != CL_SUCCESS)
228    {
229        std::cerr << "Failed to allocate keybuffer(" << err << ")\n";
230        throw std::exception();
231    }
232
233    err = queue.enqueueWriteBuffer(keybuffer, 1, 0, j.KeySize*sizeof(float), j.Key);
234    if(err != CL_SUCCESS)
235    {
236        std::cerr << "Failed write to keybuffer(" << err << ")\n";
237        throw std::exception();
238    }
239
240    this->compareLargerThan = j.LargerThen;
241    this->resultSize = j.ResultSize;
242    res.ResultList.resize(j.ResultSize);
243    initTop(res.ResultList, j.LargerThen);
244
245    //execute:
246    std::cout<<"Running CL program with " << j.Size << " calculations!\n";
247    enqueueKernel(queue, j.Size, keybuffer, costs, j);
248
249    std::cout<<"Done!\n";
250
251    return res;
252}
253
254void Cryptool::enqueueSubbatch(cl::CommandQueue& queue, cl::Buffer& keybuffer, cl::Buffer& costs, int add, int length, const Job& j)
255{
256    timeval openCLStart;
257    gettimeofday(&openCLStart, NULL);
258        cl_int err;
259
260        err = kernel->setArg(0, keybuffer);
261        if (err != CL_SUCCESS) {
262                std::cerr << "Kernel::setArg() failed (" << err << ")\n";
263                throw std::exception();
264        }
265
266        err = kernel->setArg(1, costs);
267        if (err != CL_SUCCESS) {
268                std::cerr << "Kernel::setArg() failed (" << err << ")\n";
269                throw std::exception();
270        }
271
272        err = kernel->setArg(2, add);
273        if (err != CL_SUCCESS) {
274                std::cerr << "Kernel::setArg() failed (" << err << ")\n";
275                throw std::exception();
276        }
277
278        err = queue.enqueueNDRangeKernel(*kernel, cl::NullRange, cl::NDRange(256, 256, 256), cl::NullRange);
279
280        if (err != CL_SUCCESS) {
281                std::cerr << "CommandQueue::enqueueNDRangeKernel()" \
282                    " failed (" << err << ")\n";
283                throw std::exception();
284        }
285
286        err = queue.finish();
287        if (err != CL_SUCCESS) {
288                std::cerr << "Event::wait() failed (" << err << ")\n";
289                throw std::exception();
290        }
291
292        queue.enqueueReadBuffer(costs, 1, 0, sizeof(float)*length, localCosts);
293        err = queue.finish();
294        if (err != CL_SUCCESS) {
295                std::cerr << "Event::wait() failed (" << err << ")\n";
296                throw std::exception();
297        }
298
299    timeval openCLEnd;
300    gettimeofday(&openCLEnd, NULL);
301#ifdef _OPENMP
302#pragma omp parallel
303    {
304        std::list<std::pair<float, int> > localtop;
305        int eachChunk = length/omp_get_num_threads();
306        int from = omp_get_thread_num()*eachChunk;
307        int to = from + eachChunk;
308        if(omp_get_thread_num() == omp_get_num_threads()-1)
309        {
310            to = length;
311        }
312        for(int i=from; i<to; ++i)
313        {
314            std::list<std::pair<float, int> >::iterator it = isInTop(localtop, localCosts[i], j.LargerThen);
315            if (it != localtop.end() || it == localtop.begin())
316                pushInTop(localtop, it, localCosts[i], i+add);
317        }
318        // merge it
319#pragma omp critical
320        {
321            std::list<std::pair<float, int> >::iterator itr;
322            for(itr = localtop.begin(); itr != localtop.end(); ++itr)
323            {
324                std::list<std::pair<float, int> >::iterator posInGlobalList = isInTop(res.ResultList, itr->first, j.LargerThen);
325                if (posInGlobalList != res.ResultList.end())
326                    pushInTop(res.ResultList, posInGlobalList, itr->first, itr->second);
327            }
328        }
329    }
330#else
331        //check results:
332        for(int i=0; i<length; ++i)
333        {
334                //std::cout << localCosts[i] << std::endl;
335                std::list<std::pair<float, int> >::iterator it = isInTop(res.ResultList, localCosts[i], j.LargerThen);
336                if (it != res.ResultList.end())
337                        pushInTop(res.ResultList, it, localCosts[i], i+add);
338        }
339#endif
340
341    timeval finishedSubbatch;
342    gettimeofday(&finishedSubbatch, NULL);
343
344    unsigned long totalMic= DiffMicSec(openCLStart, finishedSubbatch);
345
346    printf("Completed a subbatch in %.3f seconds. %.2f%% spent on OpenCL, %.2f%% on sorting.\n",
347            (float)totalMic/1000000, DiffMicSec(openCLStart, openCLEnd)/(float)totalMic*100, DiffMicSec(openCLEnd, finishedSubbatch)/(float)totalMic*100);
348
349}
350
351void Cryptool::enqueueKernel(cl::CommandQueue& queue, int size, cl::Buffer& keybuffer, cl::Buffer& costs, const Job& j)
352{
353    for (int i = 0; i < (size/subbatch); i++)
354    {
355        enqueueSubbatch(queue, keybuffer, costs, i*subbatch, subbatch, j);
356
357        timeval now;
358        gettimeofday(&now, NULL);
359        unsigned long timeDiffMicroSec = (now.tv_sec - lastSubbatchCompleted.tv_sec)*1000000 + (now.tv_usec - lastSubbatchCompleted.tv_usec);
360        lastSubbatchCompleted = now;
361        float keysPerSecond = subbatch/((float)timeDiffMicroSec/1000000);
362        printf("% .2f%% done. %'u keys/sec %u seconds remaining\n", ((i+1)*subbatch)/(float)size*100, (unsigned int)keysPerSecond,
363                (unsigned int)((float)(size-(subbatch*(i+1)))/keysPerSecond));
364    }
365
366    int remain = (size%subbatch);
367    if (remain != 0)
368    {
369        enqueueSubbatch(queue, keybuffer, costs, size-remain, remain, j);
370    }
371}
372
373void Cryptool::pushInTop(std::list<std::pair<float, int> >& top, std::list<std::pair<float, int> >::iterator it, float val, int k) {
374        top.insert(it, std::pair<float, int>(val, k));
375    if(top.size() > this->resultSize)
376        top.pop_back();
377}
378
379std::list<std::pair<float, int> >::iterator Cryptool::isInTop(std::list<std::pair<float, int> >& top, float val, bool LargerThen) {
380    if (top.size() == 0)
381        return top.begin();
382
383        if (LargerThen)
384        {
385                if(top.size() > 0 && val <= top.rbegin()->first)
386                        return top.end();
387                for (std::list<std::pair<float, int> >::iterator k = top.begin(); k != top.end(); k++)
388                        if (val > k->first)
389                                return k;
390        }
391        else
392        {
393                if(top.size() > 0 && val >= top.rbegin()->first)
394                        return top.end();
395                for (std::list<std::pair<float, int> >::iterator k = top.begin(); k != top.end(); k++)
396                        if (val < k->first)
397                                return k;
398        }
399
400        return top.end();
401}
402
403void Cryptool::initTop(std::list<std::pair<float, int> >& top, bool LargerThen) {
404        for (std::list<std::pair<float, int> >::iterator k = top.begin(); k != top.end(); k++)
405        {
406            if (LargerThen)
407                k->first = -1000000.0;
408            else
409                k->first = 1000000.0;
410        }
411}
412
413std::string Cryptool::getDeviceName()
414{
415    return std::string(devices[deviceChoice].getInfo<CL_DEVICE_NAME>().c_str());
416}
Note: See TracBrowser for help on using the repository browser.