Wskazówki wyboru hostingu lub serwera

Kilka pytań na które warto znaleźć odpowiedzi podczas wybierania jednej z wielu ofert firm oferujących usługi hostingowe.

Kopie zapasowe

  1. Kiedy i jak często tworzone są kopie zapasowe?
  2. Jak długo przechowywane są kopie zapasowe?
  3. Co zawierają kopie (pliki, zawartość bazy danych)?
  4. Jak wygląda proces odzyskiwania danych?
  5. Jak szybko można odzyskać dane?

Sprzęt

  1. Jakie są możliwość rozbudowy sprzętu?
  2. Czy można samodzielnie zwiększyć pojemność dysków lub pamięci RAM?

Oprogramowanie

  1. Jakie preinstalowane oprogramowanie jest dostępne?
  2. Czy mamy dostęp do konta administratora?

Transfer

  1. Czy istnieje oraz ile wynosi limit transferu oraz szybkości łącza internetowego?
  2. Jak naliczane są opłaty za przekroczenie transferu?

Obsługa

  1. Ile wynosi koszt obsługi serwisowej oraz administracji?
  2. Jak długi jest czas reakcji na awarie lub zgłoszenia awarii?
  3. Jaką niezawodność usług zapewnia firma (SLA)?
Zaszufladkowano do kategorii Inne | Możliwość komentowania Wskazówki wyboru hostingu lub serwera została wyłączona

Autocompleter – wydajne i elastyczne automatyczne uzupełnianie treści

Obecnie prawie każda strona WWW posiada wyszukiwarkę. Nieodłącznym elementem wyszukiwarki jest funkcja podpowiadania (lub przewidywania) tekstu wpisywanego przez użytkownika.

Wiele stron jest wykonanych przy użyciu PHP oraz MySQL. Wykonanie mechanizmu podpowiadania treści w języku PHP jest proste, ale ma pewne wady. Przede wszystkim, zapytanie użytkownika trafia najpierw do parsera PHP, a dopiero potem do bazy danych (czyli do miejsca, w którym następuje faktyczne przetwarzanie danych). Po drugie, operacje wyszukiwania odbywają się w MySQL (zwykle przy pomocy operatora LIKE), co niekoniecznie pozytywnie przekłada się na wydajność.

Możemy zastosować wyszukiwarki takie jak Sphinx czy Solr, ale pierwsza z nich nadal wymaga PHP (lub innego języka), ponieważ nie możemy się do niej podłączyć z poziomu JavaScriptu, a druga jest ogromną aplikacją (nie potrzebujemy, aż tylu funkcji) oraz wymaga Javy co dla niektórych administratorów samo w sobie jest przeszkodą (z powodów znanych tylko im ;)).

Zawsze interesowały mnie zagadnienia związane z wyszukiwaniem i przetwarzaniem informacji, więc postanowiłem wykonać aplikację, która rozwiąże powyższe problemy. Aplikacja działa jako serwer HTTP, obsługuje obecnie dwa rodzaje źródeł danych (JSON, MySQL), zwraca dane w formacie JSONP. Treści są indeksowane przy pomocy algorytmu Radix Tree. Istnieje możliwość implementacji własnych źródeł danych oraz indeksów.

Lista funkcji:

  • definiowanie wielu źródeł danych (każde źródło danych może zostać dołączone do dowolnego indeksu),
  • obsługa plików w formacie JSON,
  • obsługa bazy MySQL,
  • definiowanie wielu indeksów (każdy indeks może korzystać z dowolnej liczby źródeł danych),
  • obsługa filtrów tekstowych (każdą frazę można filtrować przed dodaniem jej do indeksu oraz przed uruchomieniem wyszukiwania),
  • całe API oraz obsługa dostępne przez HTTP,
  • podgląd stan usługi przez HTTP,
  • podgląd statystyk usługi oraz wyszukiwania przez HTTP.

Lista dostępnych filtrów:

  • zamiana na wielkie znaki (uppercase filter),
  • zamiana na małe znaki (lowercase filter),
  • usuwanie znaków lub fraz (ignore filter),
  • zamiana znaków lub fraz (replace filter),
  • obcinanie znaków z początku lub końca frazy (trim filter),
  • usuwanie fraz zbyt krótkich lub zbyt długich (length filter).

Lista planowanych funkcji:

  • implementacja cache’a służącego do przechowywania wyników wyszukiwania,
  • implementacja lokalnego magazynu danych służącego do przechowywania zawartości indeksów tak, aby ponowne uruchomienie aplikacji nie wymagało ponownego pobierania danych ze źródeł danych.

Obecna wersja nie jest stabilna, ale działa :) Program można uruchomić pod systemem Windows (jest dostępny projekt dla MS Visual C++ 2010 Epress) oraz pod Linuksem (obecnie brak Makefile, ale pojawi się w niedługim czasie).

Kod źródłowy aplikacji jest dostępny w serwisie GitHub. Źródła zostały udostępnione na licencji GNU.

Zaszufladkowano do kategorii C++, Linux, Windows | Możliwość komentowania Autocompleter – wydajne i elastyczne automatyczne uzupełnianie treści została wyłączona

Miners

Przedstawiam pierwszą wersję niewielkiej gry o nazwie Miners. Gra polega na zarządzaniu grupą stworzeń, które bardzo lubią kopać tunele w ziemi oraz zwiedzać jaskinie. Niestety, w podziemiach oprócz cennych klejnotów znajdują się pułapki oraz niebezpieczne potwory.

Jako gracz, nie możemy bezpośrednio sterować postaciami. Każde ze stworzeń samodzielnie wytycza tunele. Czasem tunel przetnie złoża złota, innym razem zostanie zalany wodą. Możemy jedynie pomagać poprzez stawianie blokad uniemożliwiających dalsze kopanie tunelu lub przepływ wody. Jest to istotne, gdyż zalanie całej kopalni jest równoznaczne z zakończeniem gry. Celowo nie używam słowa „przegraniem”, gdy w tej grze nie da się przegrać. Może jedynie zdobyć mniej lub więcej punktów.

Najważniejsze funkcje gry:

  • każdy rozgrywka odbywa się na innej, losowo wygenerowanej mapie,
  • każda mapa zawiera losowe jaskinie, w których możemy znaleźć klejnoty, wodę, potwory lub po prostu pustą przestrzeń,
  • każdy ze stworów kopiących tunele samodzielnie decyduje o tym, w którą stronę podążać.

W kolejnych wersjach pojawią się m.in.:

  • możliwość wydawania prostych poleceń (np. kop tutaj, przejdź tutaj),
  • wznoszenie budynków (np. budynków obronnych przed potworami),
  • powiększenie mapy,
  • lepszej jakości modele oraz tektury,
  • rankingi punktów,
  • różne tryby gry (np. na czas).

Gra jest wykonana w języku C# przy użyciu Windows Forms oraz silnika MOGRE (port Ogre3D dla frameworka .NET).

Pobieranie

0.2b 7z zip
0.1b 7z zip

 

Galeria

Zaszufladkowano do kategorii C#, Gry, Windows | Możliwość komentowania Miners została wyłączona

Microsoft Visual C# Express – błąd przy debuggowaniu aplikacji z argumentami linii poleceń

Gdyby podczas debuggowania naszej aplikacji próbujemy przekazać do naszej aplikacji dodatkowe argumenty wprowadzane przez linię poleceń (Project – Properties – Debug – Command line arguments), możemy otrzymać poniższy komunikat:

The current project settings specify that the project will be debugged with specific security permissions. In this mode, command line arguments will not be passed to the executable. Do you want to continue debugging anyway?

Problem możemy rozwiązać następująco:

  1. Otwieramy właściwości projektu (menu „Project” – „Properties”).
  2. Wybieramy zakładkę „Security”.
  3. Wybieramy opcję „This is a partial trust application”.
  4. Klikamy w przycisk „Advanced”.
  5. Odznaczamy „Debug this application with the selected persmission set”.

Od tej pory możemy debugować aplikację wraz z argumentami wprowadzanymi z linii poleceń.

Zaszufladkowano do kategorii C#, Windows | Możliwość komentowania Microsoft Visual C# Express – błąd przy debuggowaniu aplikacji z argumentami linii poleceń została wyłączona

OpenCL tutorial – część 4

Na koniec przedstawię obiektowe API OpenCL dla języka C++.

Jedyne co musimy zrobić, to pobrać plik „cl.hpp” ze strony Khronosa i umieścić go w tym samym katalogu co plik „cl.h”, czyli „dependencies\OpenCL\include\CL”.

Poniższy przykład wykonuje takie same operacji jak program z poprzedniej części, czyli sumuje dwa wektory.

Kod pliku Main.cpp

#define __CL_ENABLE_EXCEPTIONS
#define __NO_STD_VECTOR

#include <iostream>
#include <fstream>
#include <string>

#include <CL/cl.hpp>

void randomizeArray(cl_int* data, size_t vectorSize)
{
    for (size_t i = 0; i < vectorSize; ++i) 
    {
        data[i] = rand() % 10;
    }
}

int main()
{
    try
    {
        // Allocate and initialize host arrays
        size_t vectorSize = 32;
        size_t localWorkSize = 8;

        cl_int* a = new cl_int[vectorSize];
        cl_int* b = new cl_int[vectorSize];
        cl_int* c = new cl_int[vectorSize];

        randomizeArray(a, vectorSize);
        randomizeArray(b, vectorSize);

        // Get platforms.
        cl::vector<cl::Platform> platforms;
        cl::Platform::get(&platforms);

        for (cl::vector<cl::Platform>::iterator i = platforms.begin(); i != platforms.end(); ++i)
        {
            cl::Platform platform = *i;
            std::string name;

            platform.getInfo(CL_PLATFORM_NAME, &name);

            std::cout << "Name:\t\t" << name << std::endl;

            platform.getInfo(CL_PLATFORM_VENDOR, &name);

            std::cout << "Vendor:\t\t" << name << std::endl;

            std::cout << std::endl;
        }

        // Create a context.
        cl_context_properties cps[3] =
        { 
            CL_CONTEXT_PLATFORM, 
            (cl_context_properties)(platforms[1])(), 
            0 
        };

        cl::Context context( CL_DEVICE_TYPE_GPU, cps);

        // Get devices.
        cl::vector<cl::Device> devices = context.getInfo<CL_CONTEXT_DEVICES>();

        for (cl::vector<cl::Device>::iterator i = devices.begin(); i != devices.end(); ++i)
        {
            cl::Device device = *i;
            std::string name;

            device.getInfo(CL_DEVICE_NAME, &name);

            std::cout << "Name:\t\t" << name << std::endl;

            device.getInfo(CL_DEVICE_VENDOR, &name);

            std::cout << "Vendor:\t\t" << name << std::endl;

            device.getInfo(CL_DEVICE_VERSION, &name);

            std::cout << "Version:\t" << name << std::endl;

            std::cout << std::endl;
        }

        // Create a command queue.
        cl::CommandQueue queue = cl::CommandQueue(context, devices[0]);

        // Read the OpenCL kernel in from source file.
        std::ifstream file(".\\bin\\Add.cl", std::ifstream::in);
        std::string sourceCode(std::istreambuf_iterator<char>(file), (std::istreambuf_iterator<char>()));

        cl::Program::Sources source(1, std::make_pair(sourceCode.c_str(), sourceCode.length() + 1));

        // Create program.
        cl::Program program = cl::Program(context, source);

        // Build program.
        program.build(devices);

        // Create kernel.
        cl::Kernel kernel(program, "Add");

        // Allocate the OpenCL buffer memory objects for source and result on the device.
        cl::Buffer bufferA = cl::Buffer(context, CL_MEM_READ_ONLY , sizeof(cl_int) * vectorSize);
        cl::Buffer bufferB = cl::Buffer(context, CL_MEM_READ_ONLY , sizeof(cl_int) * vectorSize);
        cl::Buffer bufferC = cl::Buffer(context, CL_MEM_WRITE_ONLY, sizeof(cl_int) * vectorSize);

        // Asynchronous write of data to GPU device.
        queue.enqueueWriteBuffer(bufferA, CL_TRUE, 0, sizeof(cl_int) * vectorSize, a);
        queue.enqueueWriteBuffer(bufferB, CL_TRUE, 0, sizeof(cl_int) * vectorSize, b);

        // Set the Argument values.
        kernel.setArg(0, bufferA);
        kernel.setArg(1, bufferB);
        kernel.setArg(2, bufferC);
        kernel.setArg(3, vectorSize);

        // Launch kernel.
        cl::NDRange global(vectorSize);
        cl::NDRange local(8);

        queue.enqueueNDRangeKernel(kernel, cl::NullRange, global, local);

        // Read back results and check accumulated errors.
        queue.enqueueReadBuffer(bufferC, CL_TRUE, 0, sizeof(cl_int) * vectorSize, c);

        // Print results.
        for (size_t i = 0; i < vectorSize; ++i)
        {
            std::cout << a[i] << " + " << b[i] << " = " << c[i] << std::endl;
        }

        delete[] a;
        delete[] b;
        delete[] c;
    }
    catch (cl::Error error)
    {
        std::cout << error.what() << "(" << error.err() << ")" << std::endl;
    }

    // Press Enter, to quit application.
    std::cin.get();

    return 0;
}

Zdefiniowanie „__CL_ENABLE_EXCEPTIONS” przed dołączeniem pliku „cl.hpp” pozwoli na przechwytywanie wyjątków w przypadku wystąpienia błędów.

Zdefiniowanie „__NO_STD_VECTOR” powoduje, że OpenCL używa własnej klasy wektora. Jeżeli usuniemy definicję, to możemy używać wektora z biblioteki STL.

Kod pliku Add.cl

__kernel void Add(__global int* a, __global int* b, __global int* c, int size)
{
    // Find position in global arrays.
    int n = get_global_id(0);

    // Bound check.
    if (n < size)
    {   
        c[n] = a[n] + b[n];
    }
}

Źródła w serwisie GitLab.

Linki

http://www.thebigblob.com/using-the-cpp-bindings-for-opencl/

Zaszufladkowano do kategorii C++, OpenCL, Wordpress | Możliwość komentowania OpenCL tutorial – część 4 została wyłączona

OpenCL tutorial – część 3 – sumowanie wektorów

W kolejnej części wprowadzenia do OpenCL wykonamy i uruchomimy pierwszy program na GPU. Zadaniem programu będzie sumowanie dwóch wektorów.

Przykładowy kod w C++ dla takiej operacji może wyglądać tak:

const int vectorSize = 10;

int a[vectorSize];
int b[vectorSize];
int c[vectorSize];

for (int i = 0; i < vectorSize; ++i)
{
    c[i] = a[i] + b[i];
}

Pobieramy kod z poprzedniej części kursu.

Na początku utworzymy tablice przechowujące wektory:

size_t vectorNumber = 32;

cl_int* a = new cl_int[vectorSize];
cl_int* b = new cl_int[vectorSize];
cl_int* c = new cl_int[vectorSize];

randomizeArray(a, vectorSize);
randomizeArray(b, vectorSize);

Zmienna „vectorNumber” przechowuje rozmiar wektora. Funkcja „randomizeArray” wypełnia tablice losowymi wartościami. Jej kod zostanie przedstawiony później.

Pierwszą czynnością, którą musimy wykonać jest utworzenie kontekstu, który umożliwi nam wykonywanie poleceń na danym urządzeniu.

cl_context context = clCreateContext(0, deviceNumber, deviceIds, NULL, NULL, NULL);

if (NULL == context)
{
    std::cout << "Failed to create OpenCL context." << std::endl;
}

Następnie tworzymy kolejkę poleceń na wybranym przez nas urządzeniu:

cl_command_queue commandQueue = clCreateCommandQueue(context, deviceIds[0], 0, &error);

Alokujemy pamięć na karcie graficznej dla naszych wektorów. Tworzymy dwa bufory tylko do odczytu, które będą przechowywać wektory A i B oraz jeden tylko do zapisu, do którego zostanie zapisany wynik sumowania:

cl_mem bufferA = clCreateBuffer(context, CL_MEM_READ_ONLY , sizeof(cl_int) * vectorSize, NULL, &error);
cl_mem bufferB = clCreateBuffer(context, CL_MEM_READ_ONLY , sizeof(cl_int) * vectorSize, NULL, &error);
cl_mem bufferC = clCreateBuffer(context, CL_MEM_WRITE_ONLY, sizeof(cl_int) * vectorSize, NULL, &error);

Teraz czas na program w OpenCL. Program w C++ wykonuje sumowanie liczb sekwencyjnie. Najpierw sumuje pierwszą liczbę z wektora A z pierwszą liczbą z wektora B, następnie drugą liczbę z wektora A z drugą liczbą z wektora B itd.

Możemy łatwo zauważyć, że sumowanie pierwszych liczb nie jest w żaden sposób zależne od sumowania drugich liczb. Zamiast wykonywania tych operacji jedna po drugiej, możemy wykonać je równocześnie, co w żaden sposób nie wpłynie na  wynik końcowy.

Poniższy program wykona sumowanie tylko dwóch liczb, a nie całego wektora. Skąd program wie, które liczby ma sumować? Funkcja „get_global_id” zwraca pewien unikalny identyfikator, na chwilę obecną możemy przyjąć, że to rozmiar wektora, który zdefiniowaliśmy w zmiennej „vectorSize”.

Umieszczamy poniższy kod w pliku „Add.cl”:

__kernel void Add(__global int* a, __global int* b, __global int* c, int size)
{
    // Find position in global arrays.
    int n = get_global_id(0);

    // Bound check.
    if (n < size)
    { 
        c[n] = a[n] + b[n];
    }
}

Wczytujemy kod programu z pliku, ładujemy go do GPU i kompilujemy:

    // Read the OpenCL kernel in from source file.
    std::ifstream file(".\\bin\\Add.cl", std::ifstream::in);
    std::string str;

    file.seekg(0, std::ios::end);
    size_t programSize = (size_t)file.tellg();

    str.reserve((unsigned int)file.tellg());
    file.seekg(0, std::ios::beg);

    str.assign(std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>());
    const char* source = str.c_str();

    // Create the program.
    cl_program program = clCreateProgramWithSource(context, 1, &source, &programSize, &error);

    error = clBuildProgram(program, 0, NULL, NULL, NULL, NULL);

Tworzymy kernel i przekazujemy do niego argumenty. Kernel to funkcja zdefiniowana w kodzie programu, który właśnie załadowaliśmy na GPU:

// Create the kernel.
cl_kernel kernel = clCreateKernel(program, "Add", &error);

// Set the Argument values.
error = clSetKernelArg(kernel, 0, sizeof(cl_mem), (void*)&bufferA);
error = clSetKernelArg(kernel, 1, sizeof(cl_mem), (void*)&bufferB);
error = clSetKernelArg(kernel, 2, sizeof(cl_mem), (void*)&bufferC);
error = clSetKernelArg(kernel, 3, sizeof(cl_int), (void*)&vectorSize);

Program jest gotowe, więc możemy przystąpić do wczytania wcześniej przygotowanych danych do GPU i uruchomienia kernela:

// Asynchronous write of data to GPU device.
error = clEnqueueWriteBuffer(commandQueue, bufferA, CL_FALSE, 0, sizeof(cl_int) * vectorSize, a, 0, NULL, NULL);
error = clEnqueueWriteBuffer(commandQueue, bufferB, CL_FALSE, 0, sizeof(cl_int) * vectorSize, b, 0, NULL, NULL);

// Launch kernel.
error = clEnqueueNDRangeKernel(commandQueue, kernel, 1, NULL, &vectorSize, &localWorkSize, 0, NULL, NULL);

// Read back results and check accumulated errors.
error = clEnqueueReadBuffer(commandQueue, bufferC, CL_TRUE, 0, sizeof(cl_int) * vectorSize, c, 0, NULL, NULL);

Funkcja „clEnqueueWriteBuffer” kopiuje dane z hosta (czyli naszego programu napisanego w C++) do GPU, a funkcja „clEnqueueReadBuffer” wykonuje operację odwrotną, czyli kopiuje dane z GPU do hosta.

Funckja „clEnqueueNDRangeKernel” uruchamia kernel. Jako piąty argument przekazujemy rozmiar wektóych, które sumujemy. Kernel zostanie uruchomiony tyle razy, ile wynosi wartość zmiennej „vectorSize”.

Teraz wracamy do kodu kernela i funkcji „get_global_id”. Jeżeli rozmiar wektora (vectorSize) to 32, to funkcja „get_global_id” w pierwszym uruchomionym kernelu zwróci 0, w drugim – 1, w trzecim – 2 itd. Dzięki temu jesteśmy w stanie określić które liczby z wektorów powinien sumować kernel.

Wyniki sumowania będą dostępne w zmiennej „c”. Zobaczmy czy operacja powiodła się:

for (size_t i = 0; i < vectorSize; ++i)
{
    std::cout << a[i] << " + " << b[i] << " = " << c[i] << std::endl;
}

Pamiętamy, aby na koniec posprzątać po sobie i zwolnić pamięć:

// Cleanup and free memory.
clFlush(commandQueue);
clFinish(commandQueue);
clReleaseKernel(kernel);
clReleaseProgram(program);
clReleaseMemObject(bufferA);
clReleaseMemObject(bufferB);
clReleaseMemObject(bufferC);
clReleaseCommandQueue(commandQueue);
clReleaseContext(context);

delete[] a;
delete[] b;
delete[] c;

delete[] platformIds;
delete[] deviceIds;

Kod programu

Kod całego programu powinien wyglądać tak:

#include <iostream>
#include <fstream>
#include <string>

#include <CL/cl.h>

void randomizeArray(cl_int* data, size_t vectorSize)
{
    for (size_t i = 0; i < vectorSize; ++i) 
    {
        data[i] = rand() % 10;
    }
}

int main()
{
    cl_int error = CL_SUCCESS;

    // Get platform number.
    cl_uint platformNumber = 0;

    error = clGetPlatformIDs(0, NULL, &platformNumber);

    if (0 == platformNumber)
    {
        std::cout << "No OpenCL platforms found." << std::endl;

        return 0;
    }

    // Get platform identifiers.
    cl_platform_id* platformIds = new cl_platform_id[platformNumber];

    error = clGetPlatformIDs(platformNumber, platformIds, NULL);

    // Get platform info.
    for (cl_uint i = 0; i < platformNumber; ++i)
    {
        char name[1024] = { '\0' };

        std::cout << "Platform:\t" << i << std::endl;

        error = clGetPlatformInfo(platformIds[i], CL_PLATFORM_NAME, 1024, &name, NULL);

        std::cout << "Name:\t\t" << name << std::endl;

        error = clGetPlatformInfo(platformIds[i], CL_PLATFORM_VENDOR, 1024, &name, NULL);

        std::cout << "Vendor:\t\t" << name << std::endl;

        std::cout << std::endl;
    }

    // Get device count.
    cl_uint deviceNumber;

    error = clGetDeviceIDs(platformIds[1], CL_DEVICE_TYPE_GPU, 0, NULL, &deviceNumber);

    if (0 == deviceNumber)
    {
        std::cout << "No OpenCL devices found on platform " << 1 << "." << std::endl;
    }

    // Get device identifiers.
    cl_device_id* deviceIds = new cl_device_id[deviceNumber];

    error = clGetDeviceIDs(platformIds[1], CL_DEVICE_TYPE_GPU, deviceNumber, deviceIds, &deviceNumber);

    // Get device info.
    for (cl_uint i = 0; i < deviceNumber; ++i)
    {
        char name[1024] = { '\0' };

        std::cout << "Device:\t\t" << i << std::endl;

        error = clGetDeviceInfo(deviceIds[i], CL_DEVICE_NAME, 1024, &name, NULL);

        std::cout << "Name:\t\t" << name << std::endl;

        error = clGetDeviceInfo(deviceIds[i], CL_DEVICE_VENDOR, 1024, &name, NULL);

        std::cout << "Vendor:\t\t" << name << std::endl;

        error = clGetDeviceInfo(deviceIds[i], CL_DEVICE_VERSION, 1024, &name, NULL);

        std::cout << "Version:\t" << name << std::endl;
    }

    std::cout << std::endl;

    // Allocate and initialize host arrays
    size_t vectorSize = 32;
    size_t localWorkSize = 8;

    cl_int* a = new cl_int[vectorSize];
    cl_int* b = new cl_int[vectorSize];
    cl_int* c = new cl_int[vectorSize];

    randomizeArray(a, vectorSize);
    randomizeArray(b, vectorSize);

    // Create the OpenCL context.
    cl_context context = clCreateContext(0, deviceNumber, deviceIds, NULL, NULL, NULL);

    if (NULL == context)
    {
        std::cout << "Failed to create OpenCL context." << std::endl;
    }

    // Create a command-queue
    cl_command_queue commandQueue = clCreateCommandQueue(context, deviceIds[0], 0, &error);

    // Allocate the OpenCL buffer memory objects for source and result on the device.
    cl_mem bufferA = clCreateBuffer(context, CL_MEM_READ_ONLY , sizeof(cl_int) * vectorSize, NULL, &error);
    cl_mem bufferB = clCreateBuffer(context, CL_MEM_READ_ONLY , sizeof(cl_int) * vectorSize, NULL, &error);
    cl_mem bufferC = clCreateBuffer(context, CL_MEM_WRITE_ONLY, sizeof(cl_int) * vectorSize, NULL, &error);

    // Read the OpenCL kernel in from source file.
    std::ifstream file(".\\bin\\Add.cl", std::ifstream::in);
    std::string str;

    file.seekg(0, std::ios::end);
    size_t programSize = (size_t)file.tellg();

    str.reserve((unsigned int)file.tellg());
    file.seekg(0, std::ios::beg);

    str.assign(std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>());
    const char* source = str.c_str();

    // Create the program.
    cl_program program = clCreateProgramWithSource(context, 1, &source, &programSize, &error);

    error = clBuildProgram(program, 0, NULL, NULL, NULL, NULL);

    // Create the kernel.
    cl_kernel kernel = clCreateKernel(program, "Add", &error);

    // Set the Argument values.
    error = clSetKernelArg(kernel, 0, sizeof(cl_mem), (void*)&bufferA);
    error = clSetKernelArg(kernel, 1, sizeof(cl_mem), (void*)&bufferB);
    error = clSetKernelArg(kernel, 2, sizeof(cl_mem), (void*)&bufferC);
    error = clSetKernelArg(kernel, 3, sizeof(cl_int), (void*)&vectorSize);

    // Asynchronous write of data to GPU device.
    error = clEnqueueWriteBuffer(commandQueue, bufferA, CL_FALSE, 0, sizeof(cl_int) * vectorSize, a, 0, NULL, NULL);
    error = clEnqueueWriteBuffer(commandQueue, bufferB, CL_FALSE, 0, sizeof(cl_int) * vectorSize, b, 0, NULL, NULL);

    // Launch kernel.
    error = clEnqueueNDRangeKernel(commandQueue, kernel, 1, NULL, &vectorSize, &localWorkSize, 0, NULL, NULL);

    // Read back results and check accumulated errors.
    error = clEnqueueReadBuffer(commandQueue, bufferC, CL_TRUE, 0, sizeof(cl_int) * vectorSize, c, 0, NULL, NULL);

    // Print results.
    for (size_t i = 0; i < vectorSize; ++i)
    {
        std::cout << a[i] << " + " << b[i] << " = " << c[i] << std::endl;
    }

    // Cleanup and free memory.
    clFlush(commandQueue);
    clFinish(commandQueue);
    clReleaseKernel(kernel);
    clReleaseProgram(program);
    clReleaseMemObject(bufferA);
    clReleaseMemObject(bufferB);
    clReleaseMemObject(bufferC);
    clReleaseCommandQueue(commandQueue);
    clReleaseContext(context);

    delete[] a;
    delete[] b;
    delete[] c;

    delete[] platformIds;
    delete[] deviceIds;

    // Press Enter, to quit application.
    std::cin.get();

    return 0;
}

Źródła w serwisie GitLab.

W następnej części kursu poznamy API dla języka C++.

Zaszufladkowano do kategorii C++, OpenCL, Windows | Możliwość komentowania OpenCL tutorial – część 3 – sumowanie wektorów została wyłączona

OpenCL tutorial – część 2 – listowanie dostępnych urządzeń

Przed nami druga część wprowadzenia do OpenCL. W tej części pokażę jak sprawdzić czy nasz sprzęt obsługuje OpenCL.

Naszym zadaniem jest wypisanie wszystkich urządzeń zainstalowanych w naszym komputerze, które wspierają OpenCL.

Na początek pobierzemy liczbę platform:

cl_int error = CL_SUCCESS;

// Get platform number.
cl_uint platformNumber = 0;

error = clGetPlatformIDs(0, NULL, &platformNumber);

Zmienna platformNumber powinna przechowywać liczbę dostępnych platform, które obsługują OpenCL. Zmienna error zawiera 0 (CL_SUCCESS), jeżeli operacja wykonała się poprawnie lub liczbę różną od zera, jeżeli wystąpił błąd.

Funkcja clGetPlatformIDs ma dwa zastosowania. Pierwsze już znamy, czyli pobieranie liczby dostępnych platform, a drugie to pobieranie listy identyfikatorów dostępnych platform.

Najpierw alokujemy pamięć, a następnie pobieramy identyfikatory:

// Get platform identifiers.
cl_platform_id* platformIds = new cl_platform_id[platformNumber];

error = clGetPlatformIDs(platformNumber, platformIds, NULL);

Skoro znamy już identyfikatory platform, to wykorzystajmy je do pobrania bardziej szczegółowych informacji na temat platform. Dzięki funkcji clGetPlatformInfo możemy poznać takie dane jak nazwa czy producent platformy:

// Get platform info.
for (cl_uint i = 0; i < platformNumber; ++i)
{
	char name[1024] = { '\0' };

	std::cout << "Platform:\t" << i << std::endl;

	error = clGetPlatformInfo(platformIds[i], CL_PLATFORM_NAME, 1024, &name, NULL);

	std::cout << "Name:\t\t" << name << std::endl;

	error = clGetPlatformInfo(platformIds[i], CL_PLATFORM_VENDOR, 1024, &name, NULL);

	std::cout << "Vendor:\t\t" << name << std::endl;

	std::cout << std::endl;
}

Wiemy już na jakich platformach możemy operować, czas na pobranie informacji o konkretnych urządzeniach, które wspierają OpenCL.

Pobieranie informacji na temat urządzeń jest bardzo podobne do pobierania informacji na temat platform. Najpierw pobieramy liczbę urządzeń, następnie alokujemy pamięć na ich identyfikatory, a na końcu pobieramy szczegółowe informacje na temat urządzenia takie jak nazwa czy wersja.

Poniższy kod umieszczamy w pętli, dzięki czemu pobierzemy informacje na temat wszystkich urządzeń we wszystkich platformach:

// Get device count.
cl_uint deviceNumber;

error = clGetDeviceIDs(platformIds[i], CL_DEVICE_TYPE_GPU, 0, NULL, &deviceNumber);

if (0 == deviceNumber)
{
	std::cout << "No OpenCL devices found on platform " << i << "." << std::endl;
}

// Get device identifiers.
cl_device_id* deviceIds = new cl_device_id[deviceNumber];

error = clGetDeviceIDs(platformIds[i], CL_DEVICE_TYPE_GPU, deviceNumber, deviceIds, &deviceNumber);

// Get device info.
for (cl_uint i = 0; i < deviceNumber; ++i)
{
	char name[1024] = { '\0' };

	std::cout << "Device:\t\t" << i << std::endl;

	error = clGetDeviceInfo(deviceIds[i], CL_DEVICE_NAME, 1024, &name, NULL);

	std::cout << "Name:\t\t" << name << std::endl;

	error = clGetDeviceInfo(deviceIds[i], CL_DEVICE_VENDOR, 1024, &name, NULL);

	std::cout << "Vendor:\t\t" << name << std::endl;

	error = clGetDeviceInfo(deviceIds[i], CL_DEVICE_VERSION, 1024, &name, NULL);

	std::cout << "Version:\t" << name << std::endl;
}

std::cout << std::endl;

// Free memory.
delete[] deviceIds;

Kompilujemy i uruchamiamy nasz program.

Kod programu

Cały kod powinien wyglądać tak:

#include 
#include 

#include <CL/cl.h>

int main()
{
	cl_int error = 0;

	// Get platform number.
	cl_uint platformNumber = 0;

	error = clGetPlatformIDs(0, NULL, &platformNumber);

	if (0 == platformNumber)
	{
		std::cout << "No OpenCL platforms found." << std::endl;

		return 0;
	}

	// Get platform identifiers.
	cl_platform_id* platformIds = new cl_platform_id[platformNumber];

	error = clGetPlatformIDs(platformNumber, platformIds, NULL);

	// Get platform info.
	for (cl_uint i = 0; i < platformNumber; ++i)
	{
		char name[1024] = { '\0' };

		std::cout << "Platform:\t" << i << std::endl;

		error = clGetPlatformInfo(platformIds[i], CL_PLATFORM_NAME, 1024, &name, NULL);

		std::cout << "Name:\t\t" << name << std::endl;

		error = clGetPlatformInfo(platformIds[i], CL_PLATFORM_VENDOR, 1024, &name, NULL);

		std::cout << "Vendor:\t\t" << name << std::endl;

		std::cout << std::endl;

		// Get device count.
		cl_uint deviceNumber;

		error = clGetDeviceIDs(platformIds[i], CL_DEVICE_TYPE_GPU, 0, NULL, &deviceNumber);

		if (0 == deviceNumber)
		{
			std::cout << "No OpenCL devices found on platform " << i << "." << std::endl;
		}

		// Get device identifiers.
		cl_device_id* deviceIds = new cl_device_id[deviceNumber];

		error = clGetDeviceIDs(platformIds[i], CL_DEVICE_TYPE_GPU, deviceNumber, deviceIds, &deviceNumber);

		// Get device info.
		for (cl_uint i = 0; i < deviceNumber; ++i)
		{
			char name[1024] = { '\0' };

			std::cout << "Device:\t\t" << i << std::endl;

			error = clGetDeviceInfo(deviceIds[i], CL_DEVICE_NAME, 1024, &name, NULL);

			std::cout << "Name:\t\t" << name << std::endl;

			error = clGetDeviceInfo(deviceIds[i], CL_DEVICE_VENDOR, 1024, &name, NULL);

			std::cout << "Vendor:\t\t" << name << std::endl;

			error = clGetDeviceInfo(deviceIds[i], CL_DEVICE_VERSION, 1024, &name, NULL);

			std::cout << "Version:\t" << name << std::endl;
		}

		std::cout << std::endl;

		// Free memory.
		delete[] deviceIds;
	}

	// Free memory.
	delete[] platformIds;

	// Press Enter, to quit application.
	std::cin.get();

	return 0;
}

Wyniki

Program po uruchomieniu powinien dać wynik podobny do poniższego:

Platform:       0
Name:           Intel(R) OpenCL
Vendor:         Intel(R) Corporation

Device:         0
Name:           Intel(R) HD Graphics 4000
Vendor:         Intel(R) Corporation
Version:        OpenCL 1.1

Platform:       1
Name:           NVIDIA CUDA
Vendor:         NVIDIA Corporation

Device:         0
Name:           GeForce GT 650M
Vendor:         NVIDIA Corporation
Version:        OpenCL 1.1 CUDA

Widzimy wszystkie platformy oraz urządzenia, które obsługują OpenCL. W moim przypadku jest to zintegrowana karta graficzna Intel HD Graphics 4000 oraz GeForce GT 650M.

Źródła w serwisie GitLab.

W następnej części kursu wykonamy i uruchomimy pierwszy program OpenCL.

Zaszufladkowano do kategorii C++, OpenCL, Windows | Możliwość komentowania OpenCL tutorial – część 2 – listowanie dostępnych urządzeń została wyłączona

OpenCL tutorial – część 1 – konfigurowanie środowiska

Witam w pierwszej części krótkiego kursu OpenCL. Postanowiłem opisać swoje pierwsze kroki z technologią OpenCL.

Nie będę tutaj przytaczał teorii na temat działania karty graficznej czy historii OpenCL. Skupię się na trzech rzeczach: pobraniu potrzebnych plików, konfiguracji środowiska w systemie Windows oraz podaniu kilku działających przykładów.

Środowisko

W trakcie kursu będziemy używali środowiska Microsoft Visual C++ 2010 Express, ale możemy użyć do tego celu dowolnego środowiska dla języka C++. Przed utworzeniem projektu wchodzimy do ustawień (menu Tools – Options) i dodajemy rozszerzenie „cl”(Text Editor – File Extension). Dzięki temu kod OpenCL będzie kolorowany przez środowisko.

Tworzymy nowy projekt wybierając z menu pozycję File – New – Project, a następnie Win32 Console Application. W kreatorze wybieramy opcje Console Application oraz Empty Project. Dodajemy jeden plik o nazwie Main.cpp i uzupełniamy go standardową funkcją „main”.

OpenCL

Do wyboru mam dwa SDK, jedno dla kart AMD, a drugie NVIDII.

http://developer.amd.com/tools/heterogeneous-computing/amd-accelerated-parallel-processing-app-sdk/

https://developer.nvidia.com/cuda-downloads

W katalogu, w którym zainstalowaliśmy SDK szukamy plików „cl.h” oraz „OpenCL.lib”. Jeżeli pobraliśmy SDK NVIDII, to znajdziemy je w katalogach:

C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v5.0\include\CL
C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v5.0\lib\Win32

Biblioteka dla systemu 64-bitowego w katalogu:

C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v5.0\lib\x64

Ścieżki do powyższych katalogów dodajemy w ustawieniach projektu:

Configuration-Properties - C/C++ - General - Additional Include Directories
Configuration-Properties - Linker - General - Additional Library Directories

Polecam jednak nie ustawiać ścieżek bezwzględnych w projekcie, a zamiast tego skopiować odpowiednie pliki do katalogu z projektem i ustawić ścieżki względne.

Dodajemy również bibliotekę OpenCL.lib w:

Configuration-Properties - Linker - Input - Additional Dependencies

Po wykonaniu tych operacji struktura katalogów powinna wyglądać następująco:

- dependencies
    - OpenCL
        - include
            - CL
                - cl.h
                - cl_d3d9_ext.h
                -  ...
        - lib
            - OpenCL.lib
- OpenCL.sln
- OpenCL.vcxproj
- OpenCL.vcxproj

Kod programu

Sprawdzamy czy wszystko działa poprawnie. W plik Main.cpp dołączamy plik CL/cl.h oraz definiujemy zmienną typu „cl_int”. Jeżeli program skompiluje się bez błędów, to znaczy, że poprawnie przygotowaliśmy nasze środowisko do pracy z OpenCL-em.

Cały kod powinien wyglądać tak:

#include 
#include 

#include <CL/cl.h>

int main()
{
    cl_int hello = 0;

    return 0;
}

Źródła w serwisie GitLab.

W kolejnej części kursu sprawdzimy czy nasz sprzęt obsługuje OpenCL.

Linki

https://developer.nvidia.com/opencl

http://www.khronos.org/registry/cl/specs/opencl-1.0.29.pdf

http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/

http://www.thebigblob.com/getting-started-with-opencl-and-gpu-computing/

Zaszufladkowano do kategorii C++, OpenCL, Windows | Możliwość komentowania OpenCL tutorial – część 1 – konfigurowanie środowiska została wyłączona

The name 'IsolatedStorageSettings’ does not exist in the current context

Aby wyeliminować poniższy błąd:

The name 'IsolatedStorageSettings' does not exist in the current context

należy wykonać dwie czynności:

  1. Dodać „using System.IO.IsolatedStorage;” na początek pliku.
  2. Dodać referencję do pliku „System.Windows.dll”.

Aby dodać referencję:

  1. Klikamy prawym przyciskiem myszy na nazwę projektu w oknie Solution Explorer.
  2. Wybieramy Add Reference…
  3. Przechodzimy do zakładki .NET.
  4. Wybieramy pozycję System.Windows.
  5. Zatwierdzamy klikjąc na przycisk OK.
Zaszufladkowano do kategorii C#, Windows Phone | Możliwość komentowania The name 'IsolatedStorageSettings’ does not exist in the current context została wyłączona

Instalacja node.js w systemie Debian

Pobieramy źródła:

wget http://nodejs.org/dist/v0.6.10/node-v0.6.10.tar.gz
tar xvzf node-v0.6.10.tar.gz
cd node-v0.6.10/

Konfigurujemy, kompilujemy i instalujemy:

./configure
make
make install

Aplikacje zostaną zainstalowane do katalogu /usr/local/bin. Poprawność instalacji możemy przetestować wywołując program „node”. Uruchomi się konsola, w której można wykonywać polecenia JS np.:

> a = 2;
2
> b = 3;
3
> a + b;
5

Konsolę zamykamy naciskając dwukrotnie kombinację Ctrl + C.

Możemy uruchomić prosty serwer. Tworzymy plik hello.js wraz z poniższą zawartością (przykład z dokumentacji):

var http = require('http');
http.createServer(function(req, res){
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World\n');
}).listen(1337, "193.17.184.252");

a następnie uruchamiamy serwer:

node hello.js
Zaszufladkowano do kategorii Linux, Oprogramowanie | Możliwość komentowania Instalacja node.js w systemie Debian została wyłączona