프로그래밍/랩뷰 기술자료

랩뷰 VI 실행 속도 향상방법

에이티에스 2023. 3. 26. 10:21
728x90

LabVIEW가 VI를 컴파일하고 일반적으로 매우 빠르게 실행하는 코드를 생성한다고 해도, 사용자는 시간에 결정적인 VI를 다룰 때 가능한 최상의 성능을 얻고자 할 것입니다. 이 섹션은 실행 속도에 영향을 주는 요소를 다루고 가능한 최상의 성능을 얻도록 도움을 주는 몇몇 프로그래밍 기술을 제안합니다.

다음 아이템을 조사하여 느린 성능의 원인을 결정합니다:

  • 입력/출력(파일, GPIB, 데이터 수집, 네트워크)
  • 화면 디스플레이(큰 컨트롤, 컨트롤 오버랩핑, 너무 많은 디스플레이)
  • 메모리 관리(배열과 문자열의 불충분한 사용, 불충분한 데이터 구조)
  • 컴파일러 최적화(편집기 응답이 VI 실행 속도와 균형을 맞추도록 컴파일러 조절)

실행 오버헤드와 SubVI 호출 오버헤드와 같은 다른 요소는 일반적으로 실행 속도에 최소한의 영향을 줍니다.

 

입력/출력

입력/출력(I/O) 호출은 일반적으로 많은 오버헤드를 초래합니다. 입출력 호출은 종종 계산 작동 시간보다 훨씬 더 많은 시간이 걸립니다. 예를 들면, 간단한 시리얼 포트 읽기 작동은 상당한 밀리초의 오버헤드를 가질 수 있습니다. 이 오버헤드는 시리얼 포트를 사용하는 모든 어플리케이션에서 발생하는데, 그 이유는 I/O 호출이 OS의 몇개의 계층을 통해 정보를 전달하는 것을 포함하기 때문입니다.

아주 많은 오버헤드를 전달하는 가장 좋은 방법은 만들어내는 I/O 호출의 수를 줄이는 것입니다. 더 작은 데이터 양을 전달하기 위해 여러 I/O 호출을 만들어내는 것보다 각 호출마다 많은 양의 데이터를 전달하도록 VI를 구성한다면 성능은 향상됩니다.

예를 들어, 데이터 수집(NI-DAQmx) VI를 생성하는 경우, 데이터를 읽는데 두가지 옵션이 있습니다. [AI 샘플 채널] VI와 같은 단일 포인트 데이터 전달 함수를 사용할 수 있거나, [AI 웨이브폼 얻기] VI와 같은 여러 포인트 데이터 전달 함수를 사용할 수 있습니다. 100 포인트를 수집해야 한다면, 타이밍을 만들기 위해 기다림 함수를 가진 루프에서 [AI 샘플 채널] VI를 사용합니다. 또한 100 포인트를 원한다는 것을 나타내는 입력을 가진 [AI 웨이브폼 얻기] VI를 사용할 수 있습니다.

[AI 웨이브폼 얻기] VI를 사용하여 훨씬 더 크고 더 정확한 데이터 샘플링 속도를 만들 수 있습니다. 이 VI가 데이터 샘플링을 관리하기 위해 하드웨어 타이머를 사용하기 때문입니다. 또한, [AI 웨이브폼 얻기] VI가 훨씬 더 많은 데이터를 전달하지만, 이 VI에 대한 오버헤드는 [AI 샘플 채널] VI를 한번 호출하는 것에 대한 오버헤드와 대략적으로 같습니다.

 

화면 디스플레이

프런트패널에서 컨트롤을 자주 업데이트하는 것은 어플리케이션에서 가장 시간을 많이 소비하는 작동 중 하나일 수 있습니다. 특히 그래프 및 차트와 같은 더 복잡한 디스플레이 중 일부를 사용하는 경우가 이에 해당됩니다. 대부분의 인디케이터는 오래된 데이터와 같은 새 데이터를 받을 때 인디케이터를 다시 그리지 않지만, 그래프와 차트는 항상 다시 그립니다. 다시 그리는 속도가 문제가 되면, 최상의 해결책은 프런트패널 객체의 수를 줄이고 프런트패널 디스플레이를 가능한 한 간단하게 유지하는 것입니다. 그래프와 차트의 경우에, 오토스케일링, 스케일 마커, 앨리어스 제거 라인 그리기, 눈금을 꺼서 디스플레이의 속도를 증가시킬 수 있습니다.

다른 종류의 I/O에서 처럼, 컨트롤을 디스플레이할 때 특정한 양의 고정된 오버헤드가 있습니다. 차트와 같은 특정한 컨트롤을 사용하여 여러 포인트를 한 번에 인디케이터로 전달할 수 있습니다. 매번 차트에 더 많은 데이터를 전달하여 차트 업데이트의 수를 최소화할 수 있습니다. 데이터가 들어올 때마다 각 포인트를 디스플레이하는 대신, 차트 데이터를 배열에 모아 여러 포인트를 한 번에 디스플레이하면 데이터 디스플레이 속도를 크게 향상할 수 있습니다.

 

실행하는 동안 프런트패널을 닫는 SubVI를 디자인할 때, 디스플레이 오버헤드는 걱정하지 않아도 됩니다. 프런트패널을 닫으면 컨트롤에 대한 그리기 오버헤드를 가지지 않으므로, 그래프는 배열보다 더 많은 계산을 요구하지 않습니다.

멀티스레드 실행 시스템에서, 고급≫동기화된 디스플레이 바로 가기 메뉴 아이템을 사용하여 컨트롤과 인디케이터 업데이트를 연기할 것인지 설정합니다. 기본적으로, 컨트롤과 인디케이터는 비동기 디스플레이를 사용하는데, 이것은 실행 시스템이 프런트패널 컨트롤과 인디케이터로 데이터를 전달한 후에, 실행을 즉시 계속할 수 있다는 것을 의미합니다. 그 후에 어떤 포인트에서, 사용자 인터페이스 시스템은 컨트롤이나 인디케이터를 업데이트할 필요가 있다는 것을 인식하고 다시 그려 새 데이터를 보여줍니다. 실행 시스템이 빠르게 연속적으로 컨트롤을 여러번 업데이트하려고 시도하면 중간에 개입하는 몇개의 업데이트를 못 볼 수도 있습니다.

 

대부분의 어플리케이션에서 비동기 디스플레이는 사용자가 보는 것에 영향을 주지 않고 실행 속도를 상당히 끌어올립니다. 예를 들면, 불리언 값을 1초에 수백 번 업데이트할 수 있는데, 이는 인간의 눈으로 구별할 수 있는 것보다 더 많은 업데이트입니다. 비동기 디스플레이는 사용자 인터페이스 스레드에 의해 업데이트가 자동적으로 더 느린 속도로 줄도록 하여 실행 시스템이 VI를 실행하는데 더 많은 시간을 사용하도록 허용합니다.

동기화된 디스플레이를 원하면, 컨트롤과 인디케이터에서 마우스 오른쪽 버튼을 클릭하고 바로 가기 메뉴에서 고급≫동기화된 디스플레이를 선택하여 메뉴 아이템 옆에 확인 표시를 합니다.

  노트  모든 데이터 값을 디스플레이하기 위해 필요한 경우에만 동기화된 디스플레이를 활성화합니다. 동기화된 디스플레이를 사용하면 멀티스레드 시스템 성능에 큰 불이익이 발생합니다.

또한 패널 업데이트 연기 프로퍼티를 사용하여 프런트패널 업데이트를 위한 새로운 모든 요청을 연기할 수 있습니다.

또한, 프런트패널에 놓는 모니터 셋팅과 컨트롤은 VI의 성능을 향상시킬 수 있습니다. 모니터의 색 농도와 해상도를 더 낮추고 모니터를 위한 하드웨어 가속을 활성화합니다. 하드웨어 가속에 대한 추가적인 정보는 해당 OS의 문서를 참조하십시오. 또한 일반 팔레트의 컨트롤 대신에 클래식 팔레트의 컨트롤을 사용하면 VI의 성능을 향상시킬 수 있습니다.

 

메모리 관리

VI의 메모리를 관리하여 최적의 실행 속도를 내려면 다음 사항을 참조하십시오.
  • 데이터 크기를 계속하여 바꾸는 것을 피하면 LabVIEW가 해당 데이터의 복사본을 만들지 않아도 됩니다.
  • 조작하기 쉬운 데이터 타입을 사용하여 효과적인 데이터 구조를 개발하면 추가적인 데이터 복사본의 생성을 피할 수 있습니다.
  • 컴파일된 코드를 분리하지 않고 LabVIEW의 현재 버전에 VI를 저장합니다.

 

컴파일러 최적화

큰 VI의 경우 LabVIEW 컴파일러는 VI의 실행 속도를 빠르게하는 최적화를 제한하여 편집기 응답을 향상합니다. 큰 VI의 개발을 마칠 때 실행 속도가 편집기 응답보다 우선하도록 LabVIEW를 설정할 수 있습니다. 전체 빌드 스펙에 컴파일러 최적화 세트 모두를 적용하도록 LabVIEW를 설정할 수 있습니다.

 

어플리케이션 안에서 데이터 전달하기

LabVIEW 어플리케이션 내에서 데이터를 전달하는 기술은 여러가지가 있으며 그 중 하나를 선택할 수 있습니다. 다음의 리스트는 가장 일반적인 방법을 효율적인 순서대로 나타냅니다.
  1. 와이어―와이어를 사용하여 데이터를 전달하면 LabVIEW가 성능이 최적화되도록 컨트롤할 수 있습니다. 데이터에 하나의 쓰기와 하나 이상의 읽기가 있기 때문에 데이터 흐름 언어에서 가장 빠른 기술입니다.
  2. 피드백 노드―피드백 노드를 사용하여 이전 VI 또는 루프 실행에서 온 데이터를 저장합니다. subVI, 함수, 또는 subVI와 함수로 이루어진 그룹의 출력을 같은 VI, 함수, 또는 그룹의 입력에 연결하고 옵션 대화 상자의 블록다이어그램 페이지에서 사이클내에 피드백 노드 자동 삽입을 활성화하면 피드백 노드가 자동으로 나타납니다. LabVIEW는 기본설정으로 사이클내에 피드백 노드 자동 삽입을 활성화합니다. 피드백 노드는 초기화 터미널을 이동하는지 여부에 따라 VI, 함수, 또는 그룹의 마지막 실행에서 나온 데이터를 기억하고 있다가 이를 다음 실행으로 전달하거나 새로운 초기값을 설정합니다. 루프에서 시프트 레지스터는 피드백 노드와 같은 방식으로 데이터를 저장하지만 루프에 와이어를 확장해야 합니다.
  3. 시프트 레지스터―루프 안에 스토리지나 피드백을 필요로 한다면 시프트 레지스터를 사용합니다. 시프트 레지스터는 쓰기와 읽기 밖으로 그리고 쓰기와 읽기 안으로 데이터를 전달합니다. 데이터 접근에 있어서 이러한 밀접한 스코프는 LabVIEW의 효율을 최대화합니다. 루프에 와이어를 확장하지 않고도 같은 기능을 사용하려면 시프트 레지스터를 피드백 노드로 대체합니다.
  4. 글로벌 변수와 기능적인 글로벌 변수―단순한 데이터와 단순한 접근을 위해 글로벌 변수를 사용합니다. 크거나 복잡한 데이터에 대해, 글로벌 변수는 모든 데이터를 읽고 전달합니다. 기능적인 글로벌 변수를 사용하여 LabVIEW가 얼마나 많은 데이터를 반환하는지 컨트롤합니다.

 

컨트롤, 컨트롤 참조, 프로퍼티 노드를 변수로서 사용하기

VI 사이에 데이터를 전달하기 위해 컨트롤, 컨트롤 참조, 프로퍼티 노드를 사용한다 할지라도, 그들은 사용자 인터페이스를 통해 작동하기 때문에 변수로 사용하도록 디자인되지 않았습니다. 사용자 인터페이스 동작을 수행할 때 또는 병렬 루프를 멈출 때만 로컬 변수와 그 값 프로퍼티를 사용합니다.

사용자 인터페이스 동작은 전통적으로 컴퓨터를 느리게 합니다. LabVIEW는 나노초동안 와이어를 통해 더블로 선언된 값을 전달하고, 텍스트 일부를 수백 마이크로초에서 밀리초 사이에 씁니다. 예를 들면, LabVIEW는 100K 배열을 와이어를 통해 0 나노초에서 몇 마이크로초 안에 전달합니다. 이 100K 배열의 그래프를 그리는데 수십 밀리초가 걸립니다. 컨트롤은 사용자 인터페이스가 덧붙여져 있기 때문에, 컨트롤을 사용하여 데이터를 전달하면 컨트롤을 다시 그리게 되므로 메모리를 추가적으로 쓰게 되고 성능이 떨어집니다. 컨트롤이 숨겨져 있으면, LabVIEW는 데이터를 더 빠르게 전달하지만, 컨트롤이 항상 디스플레이될 수 있기 때문에 LabVIEW는 여전히 컨트롤을 업데이트할 필요가 있습니다.

 

멀티스레딩이 사용자 인터페이스 동작에 영향을 주는 방식

LabVIEW는 실행 스레드로부터 사용자 인터페이스 스레드로 전환하기 때문에 사용자 인터페이스 동작을 완성하기 위해 더 많은 메모리를 사용합니다. 예를 들면, 값 프로퍼티를 설정할 때, LabVIEW는 사용자가 컨트롤의 값을 변경하고, 실행 스레드를 멈추고, 사용자 인터페이스 스레드로 스위치하여 값을 변경하는 것을 시뮬레이트합니다. 그 후, LabVIEW는 컨트롤에 데이터를 저장하는 동작 버퍼를 업데이트하고, 프런트패널이 열려 있을 경우, 컨트롤을 다시 그립니다. 그리고 LabVIEW는 전달 버퍼라고 불리는 메모리의 안전한 영역의 실행 스레드로 데이터를 되돌려 보냅니다. 그 후 LabVIEW는 실행 스레드로 다시 되돌아 갑니다. 그 다음에 실행 스레드가 컨트롤을 읽을 때, LabVIEW는 전달 버퍼에서 데이터를 찾고, 또한 블록다이어그램에 데이터를 저장하는 실행 버퍼의 새로운 값을 받습니다.

로컬 또는 글로벌 변수에 쓸 때, LabVIEW는 사용자 인터페이스 스레드로 즉시 전환하지 않습니다. 대신에 LabVIEW는 전달 버퍼에 값을 씁니다. 사용자 인터페이스는 다음의 계획된 업데이트 시간에 업데이트합니다. 단일 스레드 스위치나 사용자 인터페이스 업데이트가 발생하기 전에 변수를 여러번 업데이트하는 것이 가능합니다. 이것은 변수가 단지 실행 스레드에서 작동하기 때문에 가능합니다.

기능적인 글로벌 변수는 전달 버퍼를 사용하지 않기 때문에 일반적인 글로벌 변수보다 더 효과적일 수 있습니다. 기능적인 글로벌 변수는 실행 스레드 안에서만 존재하고 그 값을 열려 있는 프런트패널에 디스플레이하지 않으면 전달 버퍼를 사용하지 않습니다.

 

병렬 블록다이어그램

병렬로 실행되고 있는 여러 블록다이어그램을 가질 때, 실행 시스템은 그 사이에서 정기적으로 전환합니다. 이 루프 중의 일부가 다른 것보다 덜 중요하다면, [기다림(ms)] 함수를 사용하여 덜 중요한 루프가 더 적은 시간을 사용하도록 만듭니다.

예를 들어, 다음의 블록다이어그램을 생각해 봅니다.

 

병렬로 된 두 개의 루프가 있습니다. 루프 중 하나는 데이터를 수집하며 가능한 한 자주 실행해야 합니다. 다른 루프는 사용자 입력을 모니터합니다. 이 프로그램이 구성되는 방식 때문에 루프는 같은 시간을 할당받습니다. 사용자 동작을 모니터하는 루프는 초당 몇 번 실행할 기회를 가집니다.

실제로, 버튼을 모니터하는 루프가 매 1/2초당 한번씩 또는 그보다 덜 자주 실행해도 일반적으로 받아들입니다. 사용자 인터페이스 루프에서 [기다림(ms)] 함수를 호출하여 다른 루프에 상당히 더 많은 시간을 할당합니다.

 

병렬 For 루프 반복

For 루프를 사용할 때, LabVIEW는 순차적으로 루프 반복을 실행합니다. 계산 집약적인 For 루프인 경우, 루프를 병렬 반복 실행하여 성능을 향상시킬 수 있습니다. 병렬 루프 반복를 사용하면 LabVIEW는 여러 프로세서의 장점을 활용하여 For 루프를 더욱 빠르게 실행할 수 있습니다. 하지만, 병렬 루프 반복은 다른 반복 모두에 대해 독립적이어야 합니다. 병렬 가능한 루프 찾기 결과 대화 상자를 사용하여 병렬 가능한 For 루프를 구분할 수 있습니다. 병렬 루프 반복을 활성화하려면, For 루프에서 마우스 오른쪽 버튼을 클릭한 후 바로 가기 메뉴에서 반복 병렬 처리 설정을 선택하여, For 루프 반복 병렬 처리 대화 상자를 디스플레이합니다.

병렬 루프 반복을 활성화하면, 병렬 인스턴스 터미널이

 카운트 터미널

아래에 나타납니다. 이 터미널을 사용하여 특정 반복을 어떤 인스턴스가 실행할지 확인하고 LabVIEW가 사용할 루프 인스턴스의 수를 지정할 수 있습니다.

National Instruments는 병렬 루프 반복에 의해 VI에 문제가 발생하면 LabVIEW가 경고를 나타낼 수 있도록, 에러 리스트 윈도우에 경고를 디스플레이할 것을 권장합니다.

 

SubVI 오버헤드

SubVI를 호출할 때, 그 호출과 연관된 상당한 양의 오버헤드가 있습니다. 이 오버헤드는 특히 밀리초에서 수십 밀리초 단위의 범위를 가질 수 있는 I/O 오버헤드 및 디스플레이 오버헤드에 비해 꽤 작습니다(수십 마이크로초). 그러나, 몇몇 경우에 이 오버헤드가 커질 수 있습니다. 예를 들면, SubVI를 루프에서 10,000번 호출할 수 있다면, 이 오버헤드는 실행 속도에 상당한 영향을 줄 수 있습니다. 이 경우에, SubVI에 루프를 넣을 것을 고려할 수 있습니다.

subVI 오버헤드를 최소화할 수 있는 다른 방법은 VI 프로퍼티 대화 상자의 항목 풀다운 메뉴에서 실행을 선택한 후 우선순위 풀다운 메뉴에서 서브루틴을 선택하여 subVI를 서브루틴으로 만드는 것입니다. 그러나, 이에 따른 결점도 있습니다. 서브루틴은 프런트패널 데이터를 디스플레이할 수 없거나, 타이밍 또는 대화 상자 함수를 호출할 수 없거나, 디버깅 또는 자동 에러 핸들링을 허용할 수 없거나, 다른 VI와 멀티태스크를 할 수 없습니다. 서브루틴은 사용자 상호작용이 필요하지 않으면서 짧게, 자주 실행되는 태스크인 VI에 일반적으로 적합합니다.

세번째로 SubVI 오버헤드를 최소화 하는 방법은 SubVI와 호출자 VI를 인라인 시키는 것입니다. SubVI를 인라인 시킬때 LabVIEW는 SubVI의 컴파일 코드를 호출자 VI의 컴파일 코드에 삽입합니다. 그후에 SubVI를 변경하려면 LabVIEW는 SubVI의 변경사항을 호출자 VI에 포함할수 있도록 재컴파일합니다. SubVI의 인라인은 SubVI를 런타임에서 호출할 필요가 없게 해줍니다. 대신에 LabVIEW는 SubVI 코드를 호출자 VI의 컴파일 코드안에서 실행합니다.

 

SubVI 인라인하기는 작은 SubVI, 루프 안에 있는 SubVI, 연결되지 않은 출력을 가진 SubVI와 단 한번만 호출되는 SubVI에 사용할 때 가장 유용합니다. SubVI를 인라인하려면, VI 프로퍼티 대화 상자의 실행 페이지에서 호출하는 VI로 SubVI 인라인 확인란에 확인 표시를 합니다. 또한 대화 상자의 같은 페이지에 있는 미리 할당된 복제 재호출 실행을 반드시 선택해야 합니다. LabVIEW는 SubVI를 인라인할 때 각 인스턴스의 복제본을 자동으로 미리 할당합니다.

 

다음과 같은 특성을 지닌 SubVI를 인라인해서는 안 됩니다:

  • 재귀 기능 포함
  • 자동 에러 핸들링 사용
  • 프로퍼티 노드  인보크 노드와 같은 특정 블록다이어그램 노드 포함. 이러한 노드는 SubVI 인라인 기능을 활성화하는 경우 편집 시 에러 메시지를 생성합니다.
  • 디버깅 가능. 인라인하려는 SubVI에 대해 디버깅을 비활성화해야 합니다.
  • 다음 VI 타입 중 하나입니다:
    • LabVIEW 클래스의 다이나믹 디스패치 VI
    • CGen 또는 FPGA용 VI
    • 컨트롤 VI ― 사용자 컨트롤 또는 인디케이터를 정의하는 VI
    • 다형성 VI
    • 글로벌 변수 VI
    • X컨트롤 VI
    • X컨트롤 라이브러리의 메소드 VI
    • LabVIEW Control Design and Simulation Module의 시뮬레이션 다이어그램에만 놓을 수 있는 VI

SubVI가 위의 특성을 지니지 않은 경우라도, LabVIEW는 다음과 같은 종류의 호출로 subVI를 인라인하지 않습니다:

  • SubVI에 대한 다이나믹 호출
  • 데이터베이스 접근을 활성화하는 subVI에 대한 호출

마지막으로, SubVI를 인라인할 때, LabVIEW는 우선순위나 선호하는 실행 셋팅을 무시합니다.

 

SubVI를 인라인하여 성능 개선이 이루어지는 예제는 examples\Performance\VI Properties의 VI Execution Properties VI를 참조하십시오.

 

 

공유 변수 오버헤드

네트워크 공유된 변수는 CPU와 메모리에서 상당한 오버헤드를 초래합니다. 사용하는 어플리케이션이 다수의 네트워크 공유 변수를 이용할 경우 단순 메시지 참조 라이브러리(Simple Messaging Reference Library (STM))의 이용을 고려해 보십시오. STM에 대한 보다 더 자세한 내용은 ni.com에서 관련 문서를 참조하십시오.

하나의 연산 디바이스에서 다른 연산 디바이스로 연속적으로 스트링되는 데이터를 보내려면 네트워크 스트림 함수를 이용하십시오.

 

루프에서 불필요한 계산

계산이 매 반복마다 같은 값을 생성한다면 루프에 계산을 넣지 않습니다. 대신에, 루프 밖으로 그 계산을 이동해서 그 결과를 루프 안에 전달합니다.

예를 들면, 다음의 블록다이어그램을 살펴봅니다.

나누기의 결과값은 루프에서 매번 같습니다. 그러므로 다음 블록다이어그램에서 보는 것처럼 루프 밖으로 그 나누기를 이동시켜서 성능을 향상시킬 수 있습니다.

다음 블록다이어그램을 참조하십시오.

이 루프에서 글로벌 변수의 값이 다른 동시에 실행되는 블록다이어그램이나 VI에 의해 바뀌지 않는다는 것을 안다면, 이 블록다이어그램은 글로벌 변수로부터 값을 읽어 들이고 루프를 통해 매번 글로벌 변수에 쓰는 시간을 낭비하는 것입니다.

이 루프에서 다른 블록다이어그램으로부터 읽어 들인 또는 다른 블록다이어그램에 의해 쓰인 글로벌 변수를 요구하지 않는다면, 다음 블록다이어그램을 대신 사용할 수 있습니다.

시프트 레지스터는 SubVI로부터 루프의 다음 반복으로 새로운 값을 전달해야 합니다. 다음 블록다이어그램은 초보자가 저지를 수 있는 일반적인 실수를 보여줍니다. 시프트 레지스터가 없기 때문에, SubVI로부터의 결과값은 새로운 입력값처럼 SubVI로 다시 전달되지 않습니다.

 

VI 실행 속도 - NI

728x90
반응형
그리드형