OpenCL изходен буфер

Опитвам се да науча основите на OpenCL.

Мислех, че този код в ядрото:

out[ 1 & ((a+b)==(b+a)) ] = (char)1;

Ще генерира същите резултати като:

out[ 1 ] = (char)1;

Може ли някой да ми каже защо генерира различен резултат?

Ето пълния изходен код за моето ядро:

#pragma OPENCL EXTENSION cl_khr_byte_addressable_store : enable
__kernel void hello(__global char * out)
{
    size_t tid = get_global_id(0);
    int a = tid & 0xff;
    int b = (tid >> 8) & 0xff;
    out[ 1 & ((a+b)==(b+a)) ] = (char)1;
}

Ако заменя последния израз с "out[1]=(char)1;" тогава "out[0]" няма да бъде изписано. Но ядрото по-горе ще напише "1" на out[0].

РЕДАКТИРАНЕ: Това е моят C++ код:

#include <utility>
#define __NO_STD_VECTOR // Use cl::vector instead of STL version
#include <CL/cl.hpp>

#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <string>
#include <iterator>

inline void checkErr(cl_int err, const char * name)
{
    if (err != CL_SUCCESS) {
        std::cerr << "ERROR: " << name
                 << " (" << err << ")" << std::endl;
        std::exit(EXIT_FAILURE);
    }
}

int main()
{
    cl_int err;

    cl::vector< cl::Platform > platformList;
    cl::Platform::get(&platformList);
    checkErr(platformList.size()!=0 ? CL_SUCCESS : -1, "cl::Platform::get");
    std::cerr << "Platform number is: " << platformList.size() << std::endl;

    std::string platformVendor;
    platformList[0].getInfo((cl_platform_info)CL_PLATFORM_VENDOR, &platformVendor);
    std::cerr << "Platform is by: " << platformVendor << "\n";
    cl_context_properties cprops[3] = 
        {CL_CONTEXT_PLATFORM, (cl_context_properties)(platformList[0])(), 0};

    cl::Context context(
       CL_DEVICE_TYPE_GPU, 
       cprops,
       NULL,
       NULL,
       &err);
    checkErr(err, "Conext::Context()"); 


    unsigned char outH[2] = {0};
    cl::Buffer outCL(
        context,
        CL_MEM_WRITE_ONLY | CL_MEM_USE_HOST_PTR,
        sizeof(outH),
        outH,
        &err);
    checkErr(err, "Buffer::Buffer()");


    cl::vector<cl::Device> devices;
    devices = context.getInfo<CL_CONTEXT_DEVICES>();
    checkErr(
        devices.size() > 0 ? CL_SUCCESS : -1, "devices.size() > 0");


    std::ifstream file("condition1.cl");
    checkErr(file.is_open() ? CL_SUCCESS:-1, "condition1.cl");
    const std::string prog(std::istreambuf_iterator<char>(file), (std::istreambuf_iterator<char>()));

    cl::Program::Sources source(1, std::make_pair(prog.c_str(), prog.length()+1));
    cl::Program program(context, source);
    err = program.build(devices,""); 
    checkErr(err, "Program::build()"); 


    cl::Kernel kernel(program, "hello", &err);
    checkErr(err, "Kernel::Kernel()");

    err = kernel.setArg(0, outCL);
    checkErr(err, "Kernel::setArg()");


    cl::CommandQueue queue(context, devices[0], 0, &err);
    checkErr(err, "CommandQueue::CommandQueue()");


    cl::Event event;
    err = queue.enqueueNDRangeKernel(
        kernel, 
        cl::NullRange,
        cl::NDRange(65536),
         cl::NDRange(1, 1), 
        NULL, 
        &event);
    checkErr(err, "ComamndQueue::enqueueNDRangeKernel()");

    event.wait();    
    err = queue.enqueueReadBuffer(
        outCL,
        CL_TRUE,
        0,
        sizeof(outH),
        outH);
    checkErr(err, "ComamndQueue::enqueueReadBuffer()");

    for (int i = 0; i < sizeof(outH); i++)
        std::cout << (int)outH[i] << " ";

    std::string str;
    std::getline(std::cin, str);

    return EXIT_SUCCESS;
}

РЕДАКТИРАНЕ 2:

Поне не е причинено от „недефинирано поведение“. Получавам странни резултати и за този код на ядрото:

char result = 0;
for (int a = 0; a < 2; a++) {
    for (int b = 0; b < 2; b++) {
        if ((a+b) != (b+a))
            result |= (1 << (a+2*b));
    }
}

Очаквам, че "резултат" ще получи стойност 0. Но получава стойност 6. Ако променя != на ==, тогава резултатът получава стойност 9. Така че в този код, когато "а" не е равно на "b", тогава (a+b) не е равно на (b+a).

Ако променя кода и задам известна стойност за "a" или "b", тогава резултатът ще бъде 0, както очаквам. Например:

char result = 0;
int a = 1;
/*for (int a = 0; a < 2; a++)*/ {
    for (int b = 0; b < 2; b++) {
        if ((a+b) != (b+a))
            result |= (1 << (a+2*b));
    }
}

person Daniel Marjamäki    schedule 04.11.2012    source източник
comment
Единственото възможно обяснение, което виждам в момента, е, че имплицитното присвояване на size_t на int може да е недефинирано поведение, въпреки че намирам това за малко вероятно. Все пак искахте да използвате побитово И в индекса? Използвате само една работна единица, нали?   -  person Thomas    schedule 04.11.2012
comment
Благодаря. да, предполагам, че може да се дължи на неопределено поведение. Не разбирам вашето. Възнамерявахте ли да използвате побитово И в индекса.. защото доколкото виждам, аз го използвам и изглежда правилно. Не съм сигурен какво е работна единица, затова добавих C++ кода.   -  person Daniel Marjamäki    schedule 04.11.2012
comment
Имах предвид, че тъй като операторът == връща това, което би се считало за булево, би изглеждало по-смислено да се използва операторът && (логическо И) върху него. Но така или иначе това е доста заплетено ядро, така че предполагам, че няма особено значение. Ще го погледна отново сутринта, трябва да поспя - дано дотогава някой да е разрешил мистерията.   -  person Thomas    schedule 04.11.2012
comment
ах благодаря. Опитах се също да изпиша [((a+b)==(b+a))? 1 : 0] = (char)1; но получавам същите резултати с това.   -  person Daniel Marjamäki    schedule 04.11.2012
comment
Защо използвате cl::NDRange(65536) във вашето извикване на ядрото? Има ли конкретна причина? (По-запознат съм със суровите C обвързвания, отколкото с C++, но мисля, че това е глобалният параметър за работния размер)   -  person Thomas    schedule 05.11.2012
comment
Исках a и b да имат всички стойности от 0 до 255.   -  person Daniel Marjamäki    schedule 06.11.2012
comment
Освен това... промяната на 65536 на по-малка стойност не помага. Циклите for в моя код EDIT2 пак ще генерират лоши резултати.   -  person Daniel Marjamäki    schedule 06.11.2012
comment
Даниел опитахте ли да премахнете CL_MEM_USE_HOST_PTR?   -  person James Beilby    schedule 07.11.2012
comment
Съжалявам за късния отговор. Току-що опитах това и това не работи добре. Ако просто коментирам CL_MEM_USE_HOST_PTR, грешката е зададена. Може би имахте предвид нещо различно?   -  person Daniel Marjamäki    schedule 17.11.2012
comment
Мога да създам и стартирам примера за add_numbers на DrDobbs (drdobbs.com/parallel/a-gentle-introduction-to-opencl/). И има условие. Възнамерявам да експериментирам с него.   -  person Daniel Marjamäki    schedule 18.11.2012
comment
Когато експериментирам с примерния код на DrDobbs, също получавам неочаквано поведение. Така че за мен изглежда проблемът не е само в моя първоначален C++ код, но и в C кода на DrDobbs.   -  person Daniel Marjamäki    schedule 18.11.2012
comment
@DanielMarjamäki: нормално ли е глобалните и локалните работни размери да имат различни измерения в enqueueNDRangeKernel?   -  person Fabien R    schedule 12.01.2013
comment

Замяната на getModel изглежда причинява проблеми с останалата част от програмата. Така или иначе не е задължително за това, което се опитвате да постигнете.

Лично аз не бих се занимавал с персонализираната таблица, вие не добавяте никаква нова функционалност към класа, която не може да се управлява директно през модела, където така или иначе трябва да се извършва управлението

Също така бих се тревожил за прекомерната употреба на static, тъй като това вероятно ще ви причини някои проблеми, когато програмата стане по-голяма

  -  person Tom Fenech    schedule 06.11.2013