Выходной буфер 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].

РЕДАКТИРОВАТЬ: это мой код на С++:

#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 может быть поведением undefined, хотя я нахожу это маловероятным. Вы хотели использовать побитовое И в индексе? Вы используете только одну рабочую единицу, верно?   -  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] = (символ)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
См. stackoverflow.com/questions/2861401/. Похоже, ваш тип данных uchar может быть проблемой (даже если у вас включено расширение)   -  person Tom Fenech    schedule 06.11.2013