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 가비지 수집에 소요되는 시간도 절약됩니다.
도움이되지 않은 죄송합니다
왜 도움이되지 않습니까? (해당되는 모든 것을 체크하세요)
의견을 보내 주셔서 감사합니다.
찾고있는 것을 찾을 수 없거나 워크 플로에 대한 질문이있는 경우 시도해보십시오 파운드리 지원.
학습 내용을 개선 할 수있는 방법에 대한 의견이 있으시면 아래 버튼을 사용하여 설명서 팀에 이메일을 보내십시오.
의견을 보내 주셔서 감사합니다.