2013-07-23 14 views
6

Przesyłam kod symulacji fizyki z C++ do CUDA.Jak korzystać z polimorfizmu w CUDA

Podstawowy algorytm można rozumieć jako: zastosowanie operatora do każdego elementu wektora. W Pseudokod, symulacja może zawierać następujące połączenia jądra:

apply(Operator o, Vector v){ 
    ... 
} 

Na przykład:

apply(add_three_operator, some_vector) 

by dodać trzy do każdego elementu w wektorze.

W moim kodzie C++ mam abstrakcyjnego operatora klasy podstawowej, z wieloma różnymi implementacjami konkretnymi. Ważną metodą jest operator klasy { wirtualna podwójna operacja (podwójne x) = 0; Komponent operatora (operator lo, operator ro); ... }

Implementacja AddOperator może wyglądać następująco:

class AddOperator : public Operator{ 
    private: 
     double to_add; 
    public: 
     AddOperator(double to_add): to_add(to_add){} 
     double operator(double x){ 
      return x + to_add; 
     } 
}; 

Klasa operator ma metody skalowania i komponowania konkretne implementacje Operatora. Ta abstrakcja pozwala mi po prostu na komponowanie operatorów "liści" w bardziej ogólne przekształcenia.

na przykład:

apply(compose(add_three_operator, square_operator), some_vector); 

doda trzy następnie kwadratowych każdy element wektora.

Problem polega na tym, że CUDA nie obsługuje wywołań metod wirtualnych w jądrze. Moja obecna myśl polega na używaniu szablonów. Następnie wywołania jądra będą wyglądały mniej więcej:

apply<Composition<AddOperator,SquareOperator>> 
    (compose(add_three_operator, square_operator), some_vector); 

Jakieś sugestie?

+6

wierzę 'funkcje virtual' wymagają kompilacji z' -arch = sm_20' lub wyższej. Jednak zaleciłbym izolowanie twojego polimorfizmu od kodu hosta, który uruchamia jądro. Nawet jeśli w końcu uzyskasz kompilację, spodziewam się, że wydajność wysyłania funkcji wirtualnych w kodzie SIMD będzie rozczarowująca. –

+5

Zgadzam się z Jared. Nawet w CPU, jeśli te same operacje są stosowane do każdego elementu dużych wektorów, rozważałbym refaktoryzację, aby polimorfizm był na wyższym poziomie, a wywołania metod wirtualnych nie były w twoich wewnętrznych pętlach. Gdy to zrobisz, równoległość będzie znacznie bardziej wydajna (w CUDA, OpenMP lub cokolwiek innego). Możesz również rozważyć Thrust w tym zakresie. – harrism

+0

Dzięki za opinię. Właściwie używam już narzędzia Thrust. Idę naprzód z szablonami. – user2611717

Odpowiedz

1

Coś takiego może ...

template <class Op1, class Op2> 
class Composition {...} 

template <class Op1, class Op2> 
Composition<Op1, Op2> compose(Op1& op1, Op2& op2) {...} 

template<class C> 
void apply(C& c, VecType& vec){...}