본문 바로가기

개발자/WPF(C#) UI

WPF UI 반응이 느려졌을 때 Tips

반응형

오늘 까지 2주동안 만들어온 WPF UI 프로그램이 드디어 조금씩 버벅이기 시작했다.

이유를 보기 위해서 메모리와 CPU를 체크하였는데 역시나,, CPU 사용률이 너무 높았다.

나와 같은 고민을 하는 사람에게 다음의 MSDN이 도움이 되길 바란다.


CPU 사용량 분석

앱의 성능 문제를 조사하기 위한 좋은 방법은 CPU 사용량을 이해하는 것입니다. CPU 사용량 성능 도구는 C++, C#/Visual Basic 및 JavaScript 앱에서 코드 실행에 소요된 CPU 시간 및 백분율을 보여줍니다.

 

다음 지침은 Visual Studio 성능 프로파일러를 사용하여 디버거 없이 CPU 사용량 도구를 사용하는 방법을 보여줍니다. 이 예제에서는 로컬 머신에서 릴리스 빌드를 사용합니다. 릴리스 빌드는 실제 앱 성능을 가장 잘 보여줍니다. 디버그 빌드를 사용하여 CPU 사용량을 분석하려면 초보자를 위한 성능 프로파일링 지침을 참조하세요.

 

 참고

성능 프로파일러를 사용하려면 Windows 7 이상이 필요합니다.

CPU 사용량 데이터 수집

  1. Visual Studio 프로젝트에서 솔루션 구성을 릴리스로 설정하고 로컬 Windows 디버거(또는 로컬 머신)를 배포 대상으로 선택합니다.

  2. 디버그 > 성능 프로파일러를 선택합니다.

  3. 사용 가능한 도구에서 CPU 사용량을 선택한 다음, 시작을 선택합니다.

  4. 앱이 시작되면 진단 세션이 시작되고 CPU 사용량 데이터가 표시됩니다. 데이터 수집이 완료되면 컬렉션 중지를 선택합니다.

    CPU 사용량 도구에서 데이터를 분석하고 보고서를 표시합니다.

CPU 사용량 보고서 분석

진단 보고서는 총 CPU를 기준으로 가장 높은 CPU에서 가장 낮은 CPU로 정렬됩니다. 열 머리글을 선택하여 정렬 순서 또는 정렬 열을 변경합니다. 필터 드롭다운을 사용하여 표시할 스레드를 선택하거나 선택 취소하고, 검색 상자를 사용하여 특정 스레드 또는 노드를 검색합니다.

Visual Studio 2019부터 실행 부하 과다 경로 확장  실행 부하 과다 경로 표시 단추를 클릭하여 호출 트리 뷰에서 CPU 사용률이 가장 높은 함수 호출을 볼 수 있습니다.

 


CPU 사용량 호출 트리

호출 트리를 보려면 보고서에서 부모 노드를 선택합니다. CPU 사용량 페이지가 호출자/호출 수신자 보기에 열립니다. 현재 보기 드롭다운 목록에서 호출 트리를 선택합니다.

호출 트리 구조

 

외부 코드

코드로 실행되는 시스템과 프레임워크 함수를 외부 코드라고 합니다. 외부 코드 함수는 앱 시작 및 중지, UI 그리기, 스레딩 제어, 기타 낮은 수준 서비스를 앱에 제공합니다. 대부분의 경우 외부 코드에 관심이 없으므로 CPU 사용량 호출 트리에서 사용자 메서드의 외부 함수를 하나의 [External Code] 노드로 수집합니다.

외부 코드의 호출 경로를 보려면 기본 진단 보고서 페이지(오른쪽 창)의 필터 드롭다운에서 외부 코드 표시를 선택한 다음, 적용을 선택합니다. CPU 사용량 페이지의 호출 트리 보기와 외부 코드 호출을 확장합니다. (필터 드롭다운은 자세한 보기가 아닌 기본 진단 페이지에서 사용할 수 있습니다.)

여러 외부 코드 호출 체인은 깊이 중첩되어 있으므로 체인 너비가 함수 이름 열의 표시 너비를 초과할 수 있습니다. 그러면 함수 이름이 ... 로 나타납니다.

찾고자 하는 함수 이름을 찾으려면 검색 상자를 사용합니다. 선택한 줄 위로 마우스를 가져가거나 가로 스크롤 막대를 사용하여 데이터를 봅니다.

CPU 사용량 호출 트리의 비동기 함수

컴파일러에서 비동기 메서드가 발생하면 메서드 실행을 제어하는 숨겨진 클래스를 만듭니다. 개념적으로 클래스는 상태 머신입니다. 클래스에 원래 메서드를 비동기식으로 호출하는 컴파일러 생성 함수와 이를 실행하는 데 필요한 콜백, 스케줄러 및 반복기가 있습니다. 부모 메서드가 원래 메서드를 호출하면 컴파일러는 부모의 실행 컨텍스트에서 메서드를 제거하고, 앱 실행을 제어하는 시스템과 프레임워크 코드의 컨텍스트에서 숨겨진 클래스 메서드를 실행합니다. 비동기 메서드는 일반적으로 하나 이상의 서로 다른 스레드에서 실행되지만 항상 그렇지는 않습니다. 이 코드는 트리의 상단 노드 바로 아래의 [External Code] 노드의 자식으로 CPU 사용량 호출 트리에 나타납니다.

다음 예제에서 [External Code] 아래에 있는 처음 두 노드는 상태 시스템 클래스의 컴파일러 생성 메서드입니다. 세 번째 노드는 원래 메서드에 대한 호출입니다.

생성된 메서드를 확장하면 진행 상황이 표시됩니다.

  • MainPage::GetMaxNumberAsyncButton_Click은 작업 값 목록을 관리하고, 결과의 최댓값을 계산하고, 출력을 표시합니다.

  • MainPage+<GetMaxNumberAsyncButton_Click>d__3::MoveNext  GetNumberAsync에 대한 호출을 래핑하는 48개 작업을 예약 및 시작하는 데 필요한 활동을 보여 줍니다.

  • MainPage::<GetNumberAsync>b__b는 GetNumber를 호출하는 작업의 활동을 보여줍니다.

반응형