私は式を表現し評価するためにDAG(有向非循環グラフ)を使用しています。各ノードは操作(+
,-
,/
,*
、蓄積など)を表し、表現全体の評価は、各ノードをトポロジカルにソートされた順序で順次評価することによって達成される。各ノードは基底クラスRefNode
を継承し、仮想関数がと評価され、それが表す演算子に従います。 Nodeクラスは、演算子を表すファンクタでテンプレート化されています。ノードの評価順序は、vector<RefNode*>
に保持され、各要素には->evaluate()
が呼び出されます。計算グラフの仮想関数呼び出しの回避
いくつかのクイックプロファイリングでは、仮想ノードevaluate
は、オーバーヘッドまたは分岐予測を破棄することによって、加算ノードを2倍[1]だけ減速させることを示しています。
最初のステップとして、タイプ情報を整数として符号化します。それに応じて、static_cast
が使用されます。これは助けになりましたが、それほど大変ではなく、私のコードの熱い部分を飛び回ることはありませんでした。
struct RefNode {
double output;
inline virtual void evaluate(){}
};
template<class T>
struct Node : RefNode {
double* inputs[NODE_INPUT_BUFFER_LENGTH];
T evaluator;
inline void evaluate(){ evaluator(inputs, output); }
};
struct Add {
inline void operator()(double** inputs, double &output)
{
output=*inputs[0]+*inputs[1];
}
};
評価は次のようになります。
Node<Add>* node_1 = ...
Node<Add>* node_2 = ...
std::vector<RefNode*> eval_vector;
eval_vector.push_back(node_1);
eval_vector.push_back(node_2);
for (auto&& n : eval_vector) {
n->evaluate();
}
私は心の性能にベアリング、以下の質問を持っている非常に重要です。
- 私はこのような状況で仮想関数を避けることができる方法は?
- そうでなければ、表現グラフを表現する方法を変更して、複数の操作をサポートする必要があります。そのうちのいくつかは状態を保持し、仮想関数呼び出しを避ける必要があります。
- Tensorflow/Theanoなどの他のフレームワークはどのように計算グラフを表しますか?
[1]私のシステム上での1回の加算操作は、仮想関数と〜1.1nsを必要とせず〜2.3nsかかります。これは小さなものですが、計算グラフ全体はほとんどが加算ノードなので、保存する時間はかなりあります。
あなたは、テンプレートを使用する必要があります。しかし、これはコンパイル時にグラフを知る必要があります。計算グラフが実行時に構築された場合(たとえば、ユーザー入力)、仮想呼び出しを回避する方法はありません。 – MadScientist
仮想関数を避けるために、不思議なテンプレートパターン –
を使用することがあります。Andrewに感謝します。私は@ CRTPを見ましたが、私はこのケースでどのように使用できるかを見て苦労しました。少し拡大してもよろしいですか? – user1893603