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

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

Shutdown external client server gracefully

File size: 10.7 KB
RevLine 
[2205]1#include <cstdio>
2#include <cstdlib>
3#include <iostream>
4#include <SDKFile.hpp>
5#include <SDKCommon.hpp>
6#include <SDKApplication.hpp>
7
[2230]8#ifdef _OPENMP
9#include <omp.h>
10#else
11#warning No OpenMP support. Expect performance impacts.
12#endif
13
[2205]14#define __NO_STD_VECTOR
15#define __NO_STD_STRING
16
[2207]17#include "Cryptool.h"
[2205]18
[2258]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
[2207]24Cryptool::Cryptool()
[2205]25{
26    cl_int err;
27
[2207]28    kernel = 0;
29
[2205]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;
[2207]37        throw std::exception();
[2205]38    }
[2212]39    if (platforms.size() == 0)
40    {
41        std::cerr << "No platforms available!" << std::endl;
42        throw std::exception();
43    }
[2205]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;
[2207]59        throw std::exception();
[2205]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";
[2207]70    context = new cl::Context(CL_DEVICE_TYPE_CPU, cps, NULL, NULL, &err);
[2205]71    if (err != CL_SUCCESS) {
72        std::cerr << "Context::Context() failed (" << err << ")\n";
[2207]73        throw std::exception();
[2205]74    }
75
76    std::cout<<"Getting device info\n";
[2207]77    devices = context->getInfo<CL_CONTEXT_DEVICES>();
[2205]78    if (err != CL_SUCCESS) {
79        std::cerr << "Context::getInfo() failed (" << err << ")\n";
[2207]80        throw std::exception();
[2205]81    }
82    if (devices.size() == 0) {
83        std::cerr << "No device available\n";
[2207]84        throw std::exception();
[2205]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    }
[2215]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";
[2259]104        throw std::exception();
[2215]105    }
106   
107    localCosts = new float[subbatch];
[2256]108
[2258]109    gettimeofday(&lastSubbatchCompleted, NULL);
110
[2256]111    // required for thousand/million separator in printf
112    setlocale(LC_ALL,"");
[2207]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;
[2259]124            throw std::exception();
[2207]125        }
126    }
127
128    cl_int err;
129
[2205]130    std::cout<<"compiling CL source\n";
[2207]131    cl::Program::Sources sources(1, std::make_pair(j.Src.c_str(), j.Src.length()));
[2205]132
[2207]133    cl::Program program = cl::Program(*context, sources, &err);
134    if (err != CL_SUCCESS) {
[2205]135        std::cerr << "Program::Program() failed (" << err << ")\n";
[2259]136        throw std::exception();
[2205]137    }
138
139    err = program.build(devices);
140    if (err != CL_SUCCESS) {
141
[2207]142        if(err == CL_BUILD_PROGRAM_FAILURE)
[2205]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";
[2259]153        throw std::exception();
[2205]154    }
155
[2207]156    if (kernel != 0)
157        delete kernel;
158
159    kernel = new cl::Kernel(program, "bruteforceKernel", &err);
[2205]160    if (err != CL_SUCCESS) {
161        std::cerr << "Kernel::Kernel() failed (" << err << ")\n";
[2259]162        throw std::exception();
[2205]163    }
[2207]164}
[2205]165
[2207]166JobResult Cryptool::doOpenCLJob(const Job& j)
167{
[2258]168    res.Guid = j.Guid;
[2207]169    cl_int err;
170
171    buildKernel(j);
172
173    cl::CommandQueue queue(*context, devices[0], 0, &err);
[2205]174    if (err != CL_SUCCESS) {
175        std::cerr << "CommandQueue::CommandQueue() failed (" << err << ")\n";
[2259]176        throw std::exception();
[2205]177    }
178
179    // key
[2212]180    cl::Buffer keybuffer = cl::Buffer(*context, CL_MEM_READ_ONLY, j.KeySize*sizeof(float), NULL, &err);
[2205]181    if(err != CL_SUCCESS)
182    {
183        std::cerr << "Failed to allocate keybuffer(" << err << ")\n";
[2259]184        throw std::exception();
[2205]185    }
186
[2212]187    err = queue.enqueueWriteBuffer(keybuffer, 1, 0, j.KeySize*sizeof(float), j.Key);
[2205]188    if(err != CL_SUCCESS)
189    {
190        std::cerr << "Failed write to keybuffer(" << err << ")\n";
[2259]191        throw std::exception();
[2205]192    }
193
[2230]194    this->compareLargerThan = j.LargerThen;
195    this->resultSize = j.ResultSize;
[2215]196    res.ResultList.resize(j.ResultSize);
197    initTop(res.ResultList, j.LargerThen);
[2205]198
[2207]199    //execute:
[2215]200    std::cout<<"Running CL program with " << j.Size << " calculations!\n";
201    enqueueKernel(queue, j.Size, keybuffer, costs, j);
[2205]202
[2215]203    std::cout<<"Done!\n";
[2205]204
[2207]205    return res;
[2205]206}
[2207]207
[2215]208void Cryptool::enqueueSubbatch(cl::CommandQueue& queue, cl::Buffer& keybuffer, cl::Buffer& costs, int add, int length, const Job& j)
[2212]209{
[2258]210    timeval openCLStart;
211    gettimeofday(&openCLStart, NULL);
[2212]212        cl_int err;
[2207]213
[2212]214        err = kernel->setArg(0, keybuffer);
215        if (err != CL_SUCCESS) {
216                std::cerr << "Kernel::setArg() failed (" << err << ")\n";
[2259]217                throw std::exception();
[2212]218        }
219
220        err = kernel->setArg(1, costs);
221        if (err != CL_SUCCESS) {
222                std::cerr << "Kernel::setArg() failed (" << err << ")\n";
[2259]223                throw std::exception();
[2212]224        }
225
[2215]226        err = kernel->setArg(2, add);
[2212]227        if (err != CL_SUCCESS) {
228                std::cerr << "Kernel::setArg() failed (" << err << ")\n";
[2259]229                throw std::exception();
[2212]230        }
231
[2221]232        err = queue.enqueueNDRangeKernel(*kernel, cl::NullRange, cl::NDRange(256, 256, 256), cl::NullRange);
[2212]233
234        if (err != CL_SUCCESS) {
235                std::cerr << "CommandQueue::enqueueNDRangeKernel()" \
236                    " failed (" << err << ")\n";
[2259]237                throw std::exception();
[2212]238        }
239
240        err = queue.finish();
241        if (err != CL_SUCCESS) {
242                std::cerr << "Event::wait() failed (" << err << ")\n";
[2259]243                throw std::exception();
[2212]244        }
[2215]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";
[2259]250                throw std::exception();
[2215]251        }
[2258]252
253    timeval openCLEnd;
254    gettimeofday(&openCLEnd, NULL);
[2230]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
[2215]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        }
[2230]293#endif
[2258]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
[2212]303}
304
[2215]305void Cryptool::enqueueKernel(cl::CommandQueue& queue, int size, cl::Buffer& keybuffer, cl::Buffer& costs, const Job& j)
[2212]306{
307    for (int i = 0; i < (size/subbatch); i++)
308    {
[2256]309        enqueueSubbatch(queue, keybuffer, costs, i*subbatch, subbatch, j);
310
[2258]311        timeval now;
312        gettimeofday(&now, NULL);
313        unsigned long timeDiffMicroSec = (now.tv_sec - lastSubbatchCompleted.tv_sec)*1000000 + (now.tv_usec - lastSubbatchCompleted.tv_usec);
[2256]314        lastSubbatchCompleted = now;
[2411]315        float keysPerSecond = subbatch/((float)timeDiffMicroSec/1000000);
316        printf("% .2f%% done. %'u keys/sec %u seconds remaining\n", ((i+1)*subbatch)/(float)size*100, (unsigned int)keysPerSecond,
317                (unsigned int)((float)(size-(subbatch*(i+1)))/keysPerSecond));
[2212]318    }
319
320    int remain = (size%subbatch);
321    if (remain != 0)
322    {
[2256]323        enqueueSubbatch(queue, keybuffer, costs, size-remain, remain, j);
[2212]324    }
325}
326
[2207]327void Cryptool::pushInTop(std::list<std::pair<float, int> >& top, std::list<std::pair<float, int> >::iterator it, float val, int k) {
328        top.insert(it, std::pair<float, int>(val, k));
[2230]329    if(top.size() > this->resultSize)
330        top.pop_back();
[2207]331}
332
333std::list<std::pair<float, int> >::iterator Cryptool::isInTop(std::list<std::pair<float, int> >& top, float val, bool LargerThen) {
[2230]334    if (top.size() == 0)
335        return top.begin();
336
337        if (LargerThen)
[2207]338        {
[2230]339                if(top.size() > 0 && val <= top.rbegin()->first)
340                        return top.end();
[2207]341                for (std::list<std::pair<float, int> >::iterator k = top.begin(); k != top.end(); k++)
342                        if (val > k->first)
343                                return k;
344        }
345        else
346        {
[2230]347                if(top.size() > 0 && val >= top.rbegin()->first)
348                        return top.end();
[2207]349                for (std::list<std::pair<float, int> >::iterator k = top.begin(); k != top.end(); k++)
350                        if (val < k->first)
351                                return k;
352        }
353
354        return top.end();
355}
356
357void Cryptool::initTop(std::list<std::pair<float, int> >& top, bool LargerThen) {
358        for (std::list<std::pair<float, int> >::iterator k = top.begin(); k != top.end(); k++)
359        {
360            if (LargerThen)
361                k->first = -1000000.0;
362            else
363                k->first = 1000000.0;
364        }
365}
Note: See TracBrowser for help on using the repository browser.