2014-06-20 5 views
1

CPU 또는 GPU에서 계산 중입니다. GPU에는 이중 (64 비트) 유형이 없으므로 계산을 실행하는 기준에 따라 다른 반환 유형이 있습니다. 나는API 인터페이스를 유지하기 위해 클래스를 템플릿으로 만들지 않고도 다른 반환 유형을 처리 할 수 ​​있습니다.

#include <iostream> 

// GPU.h 
struct GPU { 
    using Ret = float; 
    Ret vals[5]; 
    void calc() { vals[0] = 0.0f; vals[1] = 1.0f; } // Do some calculation. 
    Ret* res() { return vals; } // Return pointer to result from calc(). 
}; 

// CPU.h 
struct CPU { 
    using Ret = double; 
    Ret vals[5]; 
    void calc() { vals[0] = 1.0; vals[1] = 2.0; } // Do some calculation. 
    Ret* res() { return vals; } // Return result from calc(). 
}; 

// Process.h 
template<class T> 
struct Process { 
    using Ret = typename T::Ret; 
    void calc() { t.calc(); } 
    Ret* res() { return t.res(); } 

    T t; 
}; 

int main() { 
    Process<CPU> p; 
    p.calc(); 
    auto res = p.res(); 
    std::cout << (res[0] + res[1]) << '\n'; 
} 

내 문제는 내가 시도하고 클래스로 프로세스 멤버를 넣으면 내가 그 클래스를 템플릿 필요가있다, 템플릿을 사용하여 다음 작업을 가지고있다. 다음은 Ret 만 두 배가 될 것이라는 것을 알고 있었기 때문에 CPU를 사용할 때 좋았습니다. GPU를 추가하면 내가 CPU/GPU의 선택으로, 프로세스를 변경하지 정말하고 싶은

struct X { 
    Process p; 
}; 

template<class Impl> 
struct X { 
    Process<Impl> p; 
}; 

에, 나는에서 갈 필요가 의미하는 것은 구현 세부 사항 및 프로세스의 사용자입니다 그것에 대해 알거나 선택할 필요가 없습니다.

가 나는 기본 2013가는 약 숀 부모의 이야기를 보았다 예를 사용하여 시도, 다음 파일의 끝 부분 object_t 유형,

https://github.com/boostcon/cppnow_presentations_2012/blob/master/fri/value_semantics/value_semantics.cpp

나는()이 CALC 위해 일하고 얻을 수 있습니다 그것은 무효를 반환합니다. 반환 형식이 다양하기 때문에 res()에서는 작동하지 않습니다. 또한 concept_t에서 템플릿 가상 함수를 지정할 수 없습니다.

template<class R> 
virtual R res() = 0; 

나는 CPU와 GPU의 징벌에 액세스하려고에서 빠른 이동을 했어,하지만 난 concept_t에서 함수 선언의 일부로서 그것을 할 방법을 작동하지 않을 수 있습니다.

내가 아직 시도하지 않은 마지막 생각은 CPU 및 GPU 싱글 톤을 만드는 것입니다. 그럼 난 단지 Process.cpp에서 그들을 사용합니다. Process 멤버 변수를 저장할 필요가 없으며 Process.h는 인터페이스를 유지하면서 CPU 및 GPU에 대해 알 필요가 없습니다.

누구나 내가 깔끔하고 기존 인터페이스를 보존 할 수있는 방법이 없기 때문에 아이디어/권장 사항을 얻었습니다.

+0

유일한 차이점은 반환 형식입니다 같은 예를 들어, 당신의 GPU 결과를 구현 될 수 있을까? 그리고 당신은 다른 컴파일러/빌드를 사용하여 각 플랫폼마다 다른 실행 파일을 생성한다고 가정합니다. typedef를 사용하여 반환 형식을 정의하고 #ifdef를 사용하여 각 빌드에 사용할 형식을 올바르게 정의합니다. –

+0

저는 OpenCL을 사용하고 있습니다. 그래서 CPU 나 GPU에서 동일한 코드를 실행할 수 있습니다. 나를위한 실제 장치 차이를 추상화합니다. 런타임에 유연성이 있어야합니다.OpenCL을 통해 CPU/GPU의 기능을 살펴볼 수 있습니다. 그런 다음 어느 것을 실행할 것인지 선택하고 싶습니다. 따라서 싱글 톤 사용에 대한 나의 생각. –

+0

다양한 솔루션을 생각할 수 있지만 그 결과를 설명하고이를 통해 더 구체적으로 무엇을 할 것인지를 설명해야합니다. –

답변

1

왜 장치에서 얻은 결과를 이중으로 저장하는 것이 좋을까요? Process은 계산 및 결과 변환을 캡슐화하는 일종의 외관입니다. Process 사용자는 장치 및 지원되는 부동 소수점 유형에 상관하지 않습니다. 그들은 double을 사용하고 있습니다.

template<class Device> 
struct Process { 
    void calc() { t.calc(); } 
    double res() { 
     // Device::res returns something you can assign to a double 
     return t.res(); 
    } 

    Device device; 
}; 

편집 : 반환 값이 하나의 값하지만 당신은 장치의 결과 래퍼를 작성 할 수 있습니다 복식의 집합이 아닌 경우.

struct Process { 
    void calc(); 
    const Result& res(); 
}; 

struct Result { 
    virtual ~Result() = default; 
    virtual double operator[](size_t n) const = 0; 
}; 

struct GPUResult { 
    GPUResult(float* r) : results{ r } {} 

    virtual double operator[](size_t n) const { 
     return results[n]; 
    } 
    float* results; 
}; 
+0

조금 단순화 시켰습니다. 유형은 실제로 포인터가됩니다. 하나는 float *이고 다른 하나는 double *입니다. –

+0

@PhilWright 결과를 나타내는 부동 소수점에 대한 포인터를 사용할 때의 요점은 무엇입니까? 'res()'의 호출자가 값을 수정하기를 원합니까? – hansmaad

+0

결과는 단일 값이 아닙니다. 만약 당신이 내 예제 코드에서 이것을 제안하여 혼란스럽게해서 죄송합니다. 아니요,이 경우 메모리를 수정하고 싶지 않습니다. 그러나 다른 경우에는 내가 할 수도 있습니다. 계산이 GPU에서 수행되면 사용 된 메모리는 GPU 액세스 가능 메모리의 어딘가에 있습니다. 다시 CPU 메모리로 복사하는 대신 메모리에 대한 포인터를 얻을 수 있습니다. 따라서 non-const 포인터는 OpenCL API가 반환하는 포인터입니다. [링크] (http://www.khronos.org/registry/cl/sdk/1) –

관련 문제