graphics.hatenablog.com

技術系テクニカルアーティストのあれこれ

SWIG で配列の受け渡し。

MScriptUtil とかみてるといろいろ思うとこあるよね、というお話。
SWIG で適当に何パターンか書いてみて比較してみる。


ひととおりやってみた感じ、std::vector の右辺値参照を返り値にするのが一番よさそうだった。
まぁ当然といえば当然の話ではある。

適当な自前クラスのインスタンス配列なんかは、結局のところカスタムアロケータでTのデストラクトができるstd::vectorを右辺値参照で返すのが最適っぽい。

あともしかしてメモリ確保が超遅い?

テスト要件

  • 任意個の整数配列に適当な値を詰める

比較パターン

  1. array_class + 生ポインタ引数渡し(MScriptUtil方式)
  2. template + std::vector* 引数渡し (MScriptUtil方式)
  3. std::vector 値返し
  4. std::vector 右辺値参照返し

テストコード

test.i
%module test

%{
#include "test.h"
%}

%include "test.h"

%include "carrays.i"
%array_class(int, IntArray);

%template (IntVector) std::vector<int>;
test.h
#pragma once
#include <vector>

inline void array(int* args, int len)
{
	for (int i = 0; i < len; ++i) args[i] = i;
}

inline void vector(std::vector<int>* args, int len)
{
	args->reserve(len);
	for (int i = 0; i < len; ++i) (*args)[i] = i;
}

inline std::vector<int> vector_value(int len)
{
	std::vector<int> args;
	args.reserve(len);
	for (int i = 0; i < len; ++i) args[i] = i;
	return args;
}

inline std::vector<int> vector_rvalue(int len)
{
	std::vector<int> args;
	args.reserve(len);
	for (int i = 0; i < len; ++i) args[i] = i;
	return std::move(args);
}
test.py
import test
import time

length = 10000
loop = 100000

begin = time.time()
args = test.IntArray(length)
for i in xrange(loop):
    test.array(args, length)
end = time.time()
print "array pre-allocate", end - begin

begin = time.time()
for i in xrange(loop):
    args = test.IntArray(length)
    test.array(args, length)
end = time.time()
print "array allocate    ", end - begin

begin = time.time()
args = test.IntVector()
for i in xrange(loop):
    test.vector(args, length)
end = time.time()
print "vec* pre-allocate ", end - begin

begin = time.time()
for i in xrange(loop):
    args = test.IntVector()
    test.vector(args, length)
end = time.time()
print "vec* allocate     ", end - begin

begin = time.time()
for i in xrange(loop):
    args = test.vector_value(length)
end = time.time()
print "vec value         ", end - begin

begin = time.time()
for i in xrange(loop):
    args = test.vector_rvalue(length)
end = time.time()
print "vec rvalue        ", end - begin
結果
  • length = 10000
1>  array pre-allocate 0.154000043869
1>  array allocate     0.707999944687
1>  vec* pre-allocate  0.569999933243
1>  vec* allocate      1.1360001564
1>  vec value          0.648000001907
1>  vec rvalue         0.210999965668
  • length = 100
1>  array pre-allocate 0.0199999809265
1>  array allocate     0.52999997139
1>  vec* pre-allocate  0.0230000019073
1>  vec* allocate      0.535000085831
1>  vec value          0.0799999237061
1>  vec rvalue         0.058000087738