[p5.js] Optimizing p5.js Code for Performance 번역

Wishtree·2021년 5월 4일
1
post-thumbnail

원문 : https://github.com/processing/p5.js/wiki/Optimizing-p5.js-Code-for-Performance

  1. Words of Caution!
  2. Identifying Slow Code: Profiling
    i. Frames Per Second (FPS)
    ii. Manual Profiling
    iii. Automated Profiling
    iv. Benchmarking
  3. p5 Performance Tips
    i. Disable the Friendly Error System
    ii. Switch Platforms
    iii. Use Native JS in Bottlenecks
    iv. Image Processing
    a. Sampling/Resizing
    b. Frontload Image Processing
    v. DOM Manipulation
    a. Batch DOM Manipulations
    b. Minimize Searching
    vi. Math Tips

주의

성능에 관해서는 처음부터 가능한 한 많은 속도를 내고 싶은 유혹이 있습니다. 코드 작성은 읽기 및 유지 관리가 쉬운 작업과 작업을 완료하는 작업 간의 균형을 유지하는 작업입니다. 성능 최적화에는 종종 약간의 희생이 따르므로 일반적으로 속도 문제가 있음을 알고있는 경우에만 최적화에 대해 걱정해야합니다.

이와 함께 "코드가 아닌 알고리즘 최적화"라는 일반적인 만트라를 명심하는 것이 중요합니다. 때로는 한두 줄의 코드를 마이크로 최적화하면 좋은 결과를 얻을 수 있습니다. 그러나 일반적으로 말해서 가장 큰 이득은 접근 방식을 바꾸는 데서 오는 경향이 있습니다. 예를 들어 이미지의 모든 단일 픽셀을 반복하는 코드가있는 경우 대신 다른 모든 픽셀을 살펴볼 수 있다고 결정하면 확실히 코드 속도를 높일 수 있습니다.

느린 코드 식별 : 프로파일링

코드 속도를 높이는 첫 번째 단계는 일반적으로 코드를 프로파일 링 하는 것입니다. 코드의 각 부분이 실행되는 데 걸리는 시간을 파악하는 것입니다.

초당 프레임 (FPS)

프로그램의 속도를 측정하는 일반적인 방법 중 하나는 렌더링 할 수있는 초당 프레임 수 (FPS)입니다. 코드에 상호 작용이나 애니메이션이 포함 된 경우 일반적으로 일관된 30-60 FPS를 목표로합니다. (여기 60, 30 및 15 FPS가 어떻게 생겼는지 보여주는 데모 가 있습니다.)

두 가지 방법 중 하나로 현재 FPS를 쉽게 볼 수 있습니다.

p5에서는 frameRate()매개 변수없이 호출 하여 현재 FPS를 얻을 수 있습니다. 그런 다음 콘솔에 덤프하거나 화면에 그릴 수 있습니다.

// Draw FPS (rounded to 2 decimal places) at the bottom left of the screen
let fps = frameRate();
fill(255);
stroke(0);
text("FPS: " + fps.toFixed(2), 10, height - 10);

Chrome 또는 p5 편집기를 사용하여 개발자 도구를 열고 "FPS 측정기 표시"옵션을 켜서 FPS 그래프를 얻을 수 있습니다. 시간이 지남에 따라 FPS가 어떻게 변하는 지 볼 수 있기 때문에 좋습니다.

수동 프로파일링

코드 조각이 실행되는 데 걸리는 시간을 확인하려면 코드 실행 시작 시간과 실행 완료 시간을 알고 싶습니다. p5에서는를 사용하여 밀리 초 단위로 현재 시간을 가져올 수 있습니다 millis(). (내부에서이 함수는 네이티브 JS 메서드의 결과를 반환합니다 performance.now()..)

사용하는 코드의 특정 부분을 시간 millis():

let start = millis();

// Do the stuff that you want to time
random(0, 100);

let end = millis();
let elapsed = end - start;
console.log("This took: " + elapsed + "ms.")

일반적으로 프로파일 링하려는 코드를 여러 번 실행 한 다음 실행하는 데 걸린 평균 시간을 찾는 것이 좋습니다. 예제 는 code / 의 성능 테스트를 참조하십시오 .

참고 : console.log()및 println()확실히 당신의 코드를 느리게되므로 프로젝트의 최종 버전에서 제거해야합니다!

자동화 프로파일링

다시 말하지만 Chrome의 개발자 도구와 p5 편집기는 일부 자동화 도구를 사용하여 구출합니다. 으로 CPU 프로파일 , 당신은 당신의 코드 내의 각 기능에 소요되는 시간이 얼마나 볼 수 없이 수동 타이밍 코드를 추가. 복잡한 프로젝트를 처리 할 때 어디서 최적화를 시작해야할지 확신이 서지 않는 경우 이것은 유용한 시작점입니다.

코드를 프로파일 링하려면 개발자 도구 (p5 편집기의 햄버거 아이콘)를 엽니 다. "프로필"탭으로 이동하여 "JavaScript CPU 프로필 수집"을 선택하고 시작을 누르십시오. 그러면 코드 타이밍이 시작됩니다. 충분히 큰 샘플을 녹음했으면 녹음을 중지하고 결과를 살펴보십시오.

Chrome CPU 프로파일러

실제 코드에 대한 CPU 프로파일 러 결과를 보는 것이 유용합니다. 이 섹션의 녹화는 웹캠에서 이미지를 가져와 색상별로 픽셀을 정렬 한 다음 화면에 그리는 p5 스케치입니다 ( code / cpu-profiler-demo 참조 ). 네 가지 주요 기능이 있습니다.

samplePixels -카메라에서 픽셀 세트를 가져옵니다.
sortPixels -샘플링 된 픽셀 정렬
sortHue -주문 방법을 결정하기 위해 두 색상의 색조를 비교합니다.
drawPixels -픽셀을 컬러 사각형으로 화면에 그립니다.
녹화의 기본보기는 관련 타이밍이있는 기능 표입니다. 코드의 모든 함수에 대한 "self"및 "total"시간을 제공합니다. 자체 시간은 다른 함수 에 대한 호출을 제외 하고 함수의 명령문에 소요 된 시간 입니다. 총 시간은 해당 함수 와 호출하는 모든 함수 를 실행하는 데 걸린 시간입니다 .

총 시간에서 samplePixels, drawPixels및 에 거의 동일한 시간이 소요되었음을 알 수 sortPixels있으므로 이들 중 어느 것이 든 최적화를 시도 할 후보가됩니다. 여기서 가장 큰 이득을 가진 가장 쉬운 최적화는 카메라 프레임에서 샘플링 된 픽셀 수를 줄이는 것입니다. 그러면 세 가지 기능이 모두 빨라집니다.

레코딩보기를 "Heavy (Bottom Up)"에서 "Chart"로 전환하면 분석을 더 잘 이해하고 대화식으로 레코딩을 탐색 할 수 있습니다.

Chrome CPU 프로파일러

CPU 프로파일 러가 단순히 함수 이름이있는 테이블을 표시 할 것이라는 점을 감안할 때 코드의 함수에 실제로 이름이있는 것이 중요합니다. 따라서 다음을 수행해야합니다.

"p5.min.js"보다 "p5.js"를 사용하여 p5 함수가 축소되지 않은 이름을 갖도록합니다.
코드에서 익명 함수 를 사용하지 마십시오 .
자세한 내용은 CPU 프로파일 러 문서 를 참조하십시오.

벤치마킹

p5.js 함수의 성능이 낮다는 의혹이 있거나 p5.js에 대한 성능 최적화를 구현하는 작업을하고 싶다고 생각하는 경우 벤치마킹 시스템을 확인해야 합니다 .

p5 성능 팁

이 튜토리얼은 7/21/16에 p5.js 메인 브랜치 의 빌드 를 사용하여 작성 되었습니다. 이는 언급 된 일부 기능 또는 최적화가 p5.js 웹 사이트의 릴리스에서 아직 출시되지 않았 음을 의미 할 수 있습니다. 메인 브랜치에서 사용자 지정 빌드를 생성하려면 여기 의 지침을 따를 수 있습니다 .

FES (Friendly Error System) 비활성화

축소되지 않은 p5.js 파일 (p5.min.js와 반대)을 사용할 때, 예를 들어 함수에 예기치 않은 인수를 입력하는 경우와 같이 때때로 경고하는 친숙한 오류 시스템이 있습니다. 이 오류 검사 시스템은 코드 속도를 크게 저하시킬 수 있습니다 (경우에 따라 최대 10 배까지). 친숙한 오류 성능 테스트를 참조하십시오 .

스케치 맨 위에있는 한 줄의 코드로 이 기능을 비활성화 할 수 있습니다.

p5 . disableFriendlyErrors  =  true ;  // FES 비활성화

function  setup ( )  { 
  // 설정 작업 
}

function  draw ( )  { 
  // 그림 그리기 
}

이렇게하면 성능 저하를 유발하는 FES 부분 (예 : 인수 검사)이 비활성화됩니다. 성능 비용이없는 친숙한 오류 (예 : 파일로드 실패시 설명 오류 제공 또는 전역 공간에서 p5.js 함수 재정의 시도시 경고)는 그대로 유지됩니다. 여기에서 오류 시스템에 대해 자세히 알아볼 수 있습니다 .

플랫폼 전환

가능하면 플랫폼을 전환 해 볼 수 있습니다. p5.js v0.5.2 및 p5 편집기 v0.6.0부터 :

Chrome은 p5 편집기보다 성능이 뛰어납니다.
Chrome은 Firefox, IE 및 Edge를 능가합니다.
Firefox는 IE 및 Edge를 능가합니다.
이는 실행하려는 특정 코드와 사용중인 플랫폼의 버전에 따라 달라지는 일반화입니다. 실제 예제 는 입자 시스템 성능 테스트 를 참조하십시오 .

병목 현상에 네이티브 JS 사용

코드에서 성능 병목 현상이 어디에 있는지 알고 있다면 p5 메서드보다 네이티브 JS 메서드를 사용하여 병목 현상을 가속화 할 수 있습니다.

많은 p5 메서드에는 오버 헤드가 있습니다. 예를 들어 : sin(...)p5가 차수 모드인지 라디안 모드인지 확인해야 sin을 계산할 수 있습니다. random(...)임의의 값을 계산하기 전에 최대 및 / 또는 최소를 통과했는지 확인해야합니다. 이 두 경우 모두 Math.random(...)또는을 사용할 수 있습니다 Math.sin(...).

얻을 수있는 속도 향상은 사용중인 특정 p5 방법에 따라 다릅니다. v0.5.3에서 많은 방법 (예 : 최적화 된 abs, sqrt, log),하지만 여전히 사용하기위한 성능 향상을 볼 수 있습니다 Math.random, Math.sin, Math.min자신의 P5의 대응을 통해. p5 편집기 v0.6.0의 경우 특히 그렇습니다. 기본 대 p5 성능 테스트를 참조하십시오 .

Chrome, running methods 10000000x times:

p5.random took:     	283.88ms
Math.random took: 	190.01ms

p5.sin took:            481.14ms
Math.sin took:          338.33ms

p5.min took:        	781.41ms
Math.min took:    	538.15ms

p5 Editor, running methods 10000000x times:

p5.random took:     	2430.28ms
Math.random took: 	85.56ms

p5.sin took:        	2337.90ms
Math.sin took:    	265.94ms

p5.min took:        	8335.63ms
Math.min took:    	5308.00ms

이미지 처리

샘플링 / 크기 조정
이미지의 픽셀을 반복 할 때 단순히 이미지 크기를 줄이거 나 샘플링하여 쉽게 성능을 향상시킬 수 있습니다. 작업중인 1000 x 1000 이미지가있는 경우 1000000 픽셀을 반복하는 것입니다. 해당 이미지를 500 x 500 (250000 픽셀)으로 절반으로 자르면 이제 이전에 수행 한 반복의 1/4 만 수행하면됩니다. 그것은 상당히 큰 절감입니다.

크기 조정 / 샘플링과 관련하여 여러 옵션이 있습니다.

Photoshop, GIMP 등을 사용하여 런타임 전에 이미지 크기를 조정하십시오. 이렇게하면 크기 조정 알고리즘을 제어하고 필터를 적용하여 이미지를 선명하게 할 수 있기 때문에 최상의 품질 축소 이미지를 얻을 수 있습니다.
p5.Image의 크기 조정 방법을 사용하여 이미지 크기를 조정합니다 . 여기에서 다운 샘플링 보간을 처리하는 방법에 대해 브라우저의 변덕에 빠져 있습니다. (글쎄, 당신은 완전히 지원되지 않는 제어를 가지고 있습니다 ...)
모든 2 번째 (또는 3 번째 또는 4 번째 등) 픽셀을 사용하여 이미지를 샘플링합니다. 간단하고 효과적이지만 많은 픽셀을 건너 뛰면 이미지의 얇은 세부 정보를 잃을 수 있습니다.
각 방법의 적용은 코드 / 크기 조정 이미지 를 참조하십시오 . 실제로는 거의 동일한 성능을 갖는 것으로 보입니다. 가능한 경우 미리 이미지 크기를 조정하면 최종 시각적 개체를 가장 많이 제어 할 수 있습니다. 할 수없는 경우 (예 : 비디오 프레임 처리) 샘플링 또는 크기 조정이 도움이 될 것입니다.

마지막 메모! 이미지의 크기를 과감하게 조정하거나 중요한 세부 사항 (예 : 벡터 아트, 선 그리기, 세부 패턴 등)이있는 이미지가있는 경우 샘플링 또는 크기 조정으로 인해 결과가 매우 좋지 않을 수 있습니다.

마지막 방법 인 반복적 크기 조정은 code / resizing-images 에서도 찾을 수 있습니다 . 이 스택 오버플로 답변 에서 가져온 접근 방식 은 이미지의 크기를 단계적으로 조정하는 것입니다. 이것은 미리 이미지의 크기를 조정할 수없고 정기적 인 크기 조정 방법이 중요한 세부 사항을 삭제하는 경우에 유용합니다.

Frontload 이미지 처리

가능하다면 이미지 처리를 프런트로드하는 것이 가장 좋습니다. 만큼 당신이 동안 할 수있는 수행 setup()하여 그래서, draw()루프는 가능한 한 빨리 할 수 있습니다. 이렇게하면 스케치의 대화 형 부분이 느려지는 것을 방지 할 수 있습니다.

예를 들어, P5 스케치, 추출물에 대한 이미지에서 색상 정보가 필요 및 상점 경우 p5.Color는 동안 객체 setup(). 그런 다음 draw()에서는 즉석에서 다시 계산하는 대신 필요할 때 캐시 된 색상 정보를 조회 할 수 있습니다.

DOM 조작

문서 객체 모델 (DOM)은 우리가 만들고 조작하고 제거 HTML 요소에 대한 액세스를 제공하는 프로그래밍 인터페이스입니다. 실제로 성능을 저하시키는 몇 가지 일반적인 DOM 함정이 있습니다.

일괄 DOM 조작

DOM으로 작업 할 때 브라우저가 모든 변경 사항에 대해 불필요하게 " 리플 로우 "하거나 페이지의 모든 요소를 ​​다시 배치 하지 않도록 해야합니다. 원하는 것은 모든 DOM 변경 사항을 일괄 처리하는 것이므로 많은 작은 변경이 아닌 하나의 큰 변경을 수행 할 수 있습니다. 브라우저가 작은 변경 사항이 많은 페이지를 지속적으로 다시 레이아웃하도록하는 경우이를 일반적으로 레이아웃 스 래싱 이라고 합니다 .

다음 은 리플 로우를 트리거 할 수있는 많은 DOM 메소드와 속성을 나열한 요점 입니다. 브라우저는 가능한 한 "게으르고"리플 로우를 미루려고 할 것입니다.하지만 어떤 것들은 (요소의 요청과 같은 offsetLeft) 리플 로우를 필요로합니다.

변경 사항을 일괄 처리하고 레이아웃 스 래싱을 방지 할 수있는 여러 가지 방법이 있습니다. 불행히도 p5.Element 및 p5.dom 애드온은 현재 일괄 처리를위한 많은 공간을 제공하지 않습니다. 예를 들어, p5.element 만들기 (를 통해 레이아웃 탈곡의 원인이됩니다 offsetWidth과 offsetHeight).

DOM 성능 문제가 발생하는 경우 가장 좋은 접근 방식은 제어하고 일반 JavaScript를 사용하거나 DOM 조작 라이브러리 (예 : fastdom )를 사용하는 것입니다. p5와 네이티브 JS의 DOM 조작 성능 테스트는 code / reflow-dom-manipulation 을 참조하십시오 . 이 경우 리플 로우를 피하는 네이티브 JS는 ~ 400 배 -500 배 더 빠릅니다.

코드를 다시 작성하기 전에 레이아웃 스 래싱이 문제인지 확인하십시오! Chrome 의 타임 라인 도구 는 시작하기에 좋은 곳입니다. 강제 리플 로우를 유발할 가능성이있는 코드를 강조 표시하고 페이지 렌더링과 JS 실행에 소요되는 시간을 보여줄 수 있습니다.

검색 최소화

DOM에서 요소를 검색하는 것은 비용이 많이들 수 있습니다. 특히 draw(). .NET Framework에서 요소에 대한 참조를 저장하여 DOM 조회를 최소화합니다 setup(). 예를 들어, 마우스 커서에서 멀리 떨어지도록 계속 위치를 변경하는 버튼이있는 경우 :

let button;

function setup () {
  // Store a reference to the element in setup
  button = select("#runner");
}

function draw() {
  let x, y;
  // Do some stuff to figure out where to move the button
  button.position(x, y);
}

성능 테스트는 code / cache-dom-lookups 를 참조하십시오 . 테스트에서 요소 캐싱은 지속적으로 요소를 다시 검색하는 것보다 10 배 더 빠릅니다. 성능 향상은 DOM 트리의 깊이와 선택기의 복잡성에 따라 달라집니다.

수학 팁

  • 점 사이의 거리 또는 벡터의 크기를 비교해야하는 경우 거리 제곱 또는 크기 제곱 ( p5.Vector.magSq )을 사용해보십시오 .
function  distSquared ( x1 ,  y1 ,  x2 ,  y2 )  { 
    let  dx  =  x2  -  x1 ; 
    let  dy  =  y2  -  y1 ; 
    return  dx  *  dx  +  dy  *  dy ; 
}
profile
The interactive storytelling web service <Wishtree> is an open source project run by Team Noob. We share tips for effective non-face-to-face teamwork and service development process. Hope it helps a little to the world suffering from corona.

0개의 댓글