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

Last change on this file was 8983, checked in by kopal, 7 months ago

Complete CrypTool 2 project

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