OpScript 성능 향상

Lua 가비지 수집기 이해

Lua에서 메모리는 스택 또는 힙에 할당 될 수 있습니다. 힙에 할당 된 객체 또는 메모리는 Lua의 가비지 수집기를 통해 회수됩니다. 가비지 수집기가 실행 중일 때 Lua 코드는 앞으로 진행할 수 없으므로 가비지 수집기가 실행되는 빈도를 줄이거 나 가비지 수집량을 줄이면 OpScript의 성능을 향상시키는 데 도움이됩니다.

다음 Lua 구성은 나쁘지는 않지만 가비지 콜렉션 중에 정리해야하는 새 오브젝트를 작성합니다. 이러한 구조가 루프 내에서 사용된다는 점에 특히주의해야합니다.

  • String_one..string_two -문자열 연결 또는 문자열 생성 기능으로 인해 새 객체가 생성 될 수 있습니다. Lua 문자열은 고유하기 때문에 먼저 문자열이 다른 곳에 생성되었는지 확인합니다.
  • { … } -테이블 생성자가 실행될 때마다 새 테이블이 생성됩니다.
  • function() ... end -함수 문을 실행하면 클로저가 생성됩니다. 이것이 n 반복 루프 내에서 실행되면 n 클로저가 생성됩니다.

노트 :  자세한 내용은 lua-users.org.

루프에서“..”피하기

Lua 가비지 수집기 이해의 구체적인 예로,이 권장 사항에서는 편리한 속기 표기법으로 인해 OpScripts에서 일반적으로 사용되는 문자열 연결 연산자 ".."의 사용을 살펴 봅니다.

예를 들어, L- 시스템 설명을 작성하는 데 사용 된 다음 코드를 고려하십시오.

local 결과 = ""

for i = 1, #inputStr do

local char = inputStr : sub (i, i)

local ruleStr = rulesTable [char]

if ruleStr then

결과 = 결과 ..ruleStr

else

결과 = 결과 ..char

end

end

return 결과

result 단단한 루프에 추가됩니다. 편리하지만 이로 인해 많은 수의 문자열 할당과 성능이 저하됩니다. 아래 코드와 같이 루프가 완료된 후에 만 모든 연결을 처리하도록 앞의 코드를 다시 작성할 수 있습니다.

로컬 buf = {}

for i = 1, #inputStr do

local char = inputStr : sub (i, i)

로컬 규칙 Str = rulesTable [char]

if ruleStr then

buf [# buf + 1] = ruleStr

else

buf [# buf + 1] = 문자

end

end

반환 테이블. concat (buf)

위의 예제를 큰 부분으로 실행 Katana 장면 파일은 다음 표에 표시된 것처럼이 기능의 장면 처리 시간을 약 2.5 배 줄였습니다.

문자열 방법

시각

".." 운영자

7.011 초

Table.concat ()

2.681 초

비용이 많이 드는 OpScript를 대체 할 사용자 정의 C ++ Ops 작성을 고려하십시오.

Lua와 OpScript API는 매우 편리하고 다재다능하지만 장면 탐색 시간의 많은 부분을 차지하는 OpScript는 사용자 정의 C ++ Ops에 더 적합 할 수 있습니다.

구체적인 예로, 다음 OpScript를 고려하십시오. 대상 위치는 균일 한 상자 내에서 임의의 위치, 방향 및 배율로 배치됩니다.

로컬 해시 = ExpressionMath.stablehash (Interface.GetOutputName ()))

math.randomseed (해시)

local 희미한 = 10

local s = 0.15

local sx = s * (1 + 0.5 * math.random ())

local sy = s * (1 + 0.5 * math.random ())

local sz = s * (1 + 0.5 * math.random ())

local tx = 2 * dim * (math.random ()-0.5)

local ty = 희미한 * math.random () + sy

local tz = 2 * dim * (math.random ()-0.5)

local 도끼 = math.random ()

local ay = math.random ()

local az = math.random ()

local 축 = Imath.V3d (ax, ay, az) : normalize ()

local 각도 = 360 * math.random ()

local 번역 = Imath.V3d (tx, ty, tz)

local 회전 = Imath.V4d (각도, axis.x, axis.y, axis.z)

local 척도 = Imath.V3d (sx, sy, sz)

Interface.SetAttr ( "xform.group0.translate",

DoubleAttribute (번역 : toTable (), 3))

Interface.SetAttr ( "xform.group0.rotate",

DoubleAttribute (rotate : toTable (), 4))

Interface.SetAttr ( "xform.group0.scale",

DoubleAttribute (scale : toTable (), 3))

(이러한 OpScript는 당연히 고안되었지만 지오메트리를 배치하기 위해 무작위성을 잘 정의 된 분포로 대체하는 것을 상상할 수 있습니다.)

이 OpScript는 다음 C ++ Op로 다시 작성할 수 있습니다.

#include <FnAttribute / FnAttribute.h>

#include <FnGeolib / op / FnGeolibOp.h>

#include <FnGeolibServices / FnExpressionMath.h>

#include <FnGeolibServices / FnGeolibCookInterfaceUtilsService.h>

#include <FnPluginSystem / FnPlugin.h>

#include <cstdlib>

inline double getRandom ()

{

return (double) rand () / ( double RAND_MAX;

}

struct DistributeGeometryOp : public 파운드리 :: 카타나 :: GeolibOp

{

static void 설정 (파운드리 :: 카타나 :: GeolibSetup 인터페이스 및 인터페이스)

{

interface.setThreading (파운드리 :: 카타나 :: GeolibSetupInterface :: ThreadModeConcurrent);

}

static void 요리사 (파운드리 :: 카타나 :: GeolibCook 인터페이스 및 인터페이스)

{

srand (FnGeolibServices :: FnExpressionMath :: stablehash (interface.getOutputName ()));

double 희미한 = 10.0;

double s = 0.15f;

double sx = s * (1.0 + 0.5f * getRandom ());

double sy = s * (1.0 + 0.5f * getRandom ());

double sz = s * (1.0 + 0.5f * getRandom ());

 

double tx = 2.0f * dim * (getRandom ()-0.5f);

double ty = 희미한 * getRandom () + sy;

double tz = 2.0f * dim * (getRandom ()-0.5f);

double 도끼 = getRandom ();

double ay = getRandom ();

double az = getRandom ();

double 축 길이 = sqrt (ax * ax + ay * ay + az * az);

ax / = axisLen;

ay / = axisLen;

z / = 축 길이;

double 각도 = 360.0 * getRandom ();

double translate [] = {tx, ty, tz};

double rotate [] = {각도, 도끼, ay, az};

double scale [] = {sx, sy, sz};

interface.setAttr (

"Xform.group0.translate",

FnAttribute :: DoubleAttribute (번역, 3, 3));

interface.setAttr (

"Xform.group0.rotate",

FnAttribute :: DoubleAttribute (rotate, 4, 4));

interface.setAttr (

"Xform.group0.scale",

FnAttribute :: DoubleAttribute (스케일, 3, 3));

}

};

DEFINE_GEOLIBOP_PLUGIN (DistributeGeometryOp);

void registerPlugins ()

{

REGISTER_PLUGIN (DistributeGeometryOp, "DistributeGeometryOp", 0, 1);

}

다른 무작위 분포까지이 Ops는 동일한 장면을 생성합니다. 그러나 C ++ 버전은 약 3.2 배 빠르게 실행됩니다. 10,000 개의 기본 도형을 배치 할 때 Ops는 다음 리소스를 사용합니다.

Op

CPU 시간

사용 된 메모리

OpScript

0.989 초

54.24 MiB

C ++ Op

0.310 초

53.67 MiB

이 경우 메모리 사용량이 비슷합니다. 그러나 OpScript가 많은 작은 개체를 할당하고 해제하는 경우 C ++로 변환하면 Lua 가비지 수집에 소요되는 시간도 절약됩니다.