VS c# IDE의 매우 높은 CPU 사용량

원본은 여기 있습니다.

원본은 저희 팀의 intellisense 쪽을 맡고 있는 Cryus가 C# editor에서 가끔 CPU가 100%의 사용량을 보이는 이유에 대해 써 놓은것입니다.

밑에는 저의 요약입니다.

............................................................................

아시는지 모르겠지만, MS에 하나의 원칙이 있는데, 고객이 Feedback을 남겨 놓으면 몇일 안에 반드시 답변을 줘야 합니다. 밑에 글은 Oren Novotny 란 분이 Product Feedback bug 에 쓰신 글입니다.

"비록 IDE 자체가 먹통이 되진 않고, 작동은 잘 하지만, 7개의 프로젝트로 구성된 c# 솔루션을 사용중에 CPU가 항상 100%를 유지 합니다."

이 부분에 대해 Cyrus의 결론은 "By Design" 입니다. By Design의 뜻은 이미 짐작 하셨겠지만, 의도된 결과란 뜻입니다.

이제 부터 이유에 대한 요약 들어 갑니다.

우선 이유를 설명 하려면, C# language service에 대해 아셔야 합니다. C# language service라는건 VS에 들어 가는 하나의 component입니다. 이게 제공하는 기능이 뭐냐면, IDE 쓰실때 c# language에 관련된 type colorization이나 keyword highlighting, intellisense, refactoring, parameter help, debugger interaction support  같은 기능을 제공합니다.

Language Service Component 자체는 독립된 VS component입니다. 다른 말로 하면 COM 이란 얘기지요. VS에서 default로 들어 있는 C# language service를 지우고,  Language Service COM Interface만 지원하면, 다른 회사 제품으로 바꾸어 사용하는것도 가능합니다.

하여간, 위의 language service (lan svc)가 하는일을 봐서 짐작하셨겠지만, lan svc의 서비스를 제공하려면 기본적으로 두가지 일을 해야 합니다. 1. 코드 분석이고 2. VS와의 인터렉션입니다.

우선 쉬운 2번 VS와의 인터렉션을 설명 하면, 이건 간단히 말해 사용자와의 인터렉션을 뜻합니다. 사용자가 보는 모든 정보와 사용자가 제공하는 모든 정보는 VS를 통해 Language Service에 제공됩니다. 사용자가 타입을 하면 그 정보는 VS가 받아서 lan svc에 전달해 주고, lan svc는 그 정보를 이용한 후에 그에 대한 결과를 VS에 전달해 주면 VS가 화면에 그 정보를 뿌리게 됩니다. 따라서 2번 VS와의 인터렉션의 포인트는 speed 입니다.

2번 VS와의 인터렉션이 느리게 되면, 사용자가 타입을 할때 마다 혹은 completion list를 부를때 마다, VS가 잠시 먹통이 되는 상황이 발생하게 됩니다. 따라서 이건 무조건 빨라야 합니다.

이제 1번 코드 분석에 대해 말씀드리겠습니다. 아시겠지만 C# IDE는 intellisense나 Type Colorization 같은 기능을 제공합니다. 무슨 말이냐면, 사용자가 c# editor에서 "DateTime<dot>" 을 친다던지, 화면에 DateTime 같은 type이 표시되면, 전자의 경우는 DateTime type 안에 있는 method나 property 들을 completion list에 보여 준다던지 후자의 경우 type에 색깔을 입혀:) 줍니다.

대충 눈치 채셨겠지만, 위에 열거한 기능들을 제공하기 위해선, IDE 자체에서 사용자가 쓴 소스에 대한 정보를 가지고 있어야 합니다. 단순히 텍스트가 아닌, semantic 정보가 있어야 합니다. 여기서 semantic 정보라 함은 예를 들어 사용자가 <dot>을 쳤을때, 현재 위치가 어떤 것 (type, namespace, etc)의 뒤인지, class 이면 class 안에 정의된 method와 property는 무엇이 있는지, nested type은 있는지, super class가 있는지, super class가 있을 경우, 그것중 어떤 method들이 현재 위치에서 사용할수 있는지 등등에 대한 정보를 말합니다.

이 정보를 얻기 위해선 사용자 소스를 컴파일 해야 하는데, 문제는 사용자 소스가 항상 compile 가능한 상태가 아니라는겁니다. 당연하겠죠, 지금 한창 프로그램밍 하는 중간이니 -,-. 따라서 이 코드 분석은 일반적인 compiler와는 다르게, 에러에 대해 무척 관대해야 하고, 엄청 빨라야 하고, 매 초마다 바뀌는 변화를 감당 할수 있어야 합니다. 다시 말하면 사용자가 타입 할때 마다 무척 많은 일들을 해아 한다는겁니다.

이제 우리가 해야 하는 일은 알았고, 어떻게 디자인 하는가에 대한게 남았습니다.

사실 가장 간단한 방법은 사용자가 타입을 할때 마다, 새로 코드 분석을 하는건데, 아쉽게도 이건 거의 불가능합니다. 뭐 조금만 생각해 보면 당연하겠죠. 파일이 수 천개 들어 있는 c# 솔루션을 막 열고, 네임스페이스 이름을 다른거로 바꿘다고 생각해 보십시요. 이 간단한 수정이 주는 semantic 변화는 엄청난데 그걸 또 사용자가 타입 할때 마다 한다는건 가능은 하겠지만 VS가 무척 느리겠죠.

따라서 당연한 결론으로 코드 분석에 대한 일은 2번 VS 인터렉션과 다른 background thread를 만들어서 이 thread에서 모든 코드 분석을 담당하게 하는겁니다. 대충 작동 방식을 얘기 하면, 소스에 변화가 있을때 마다 primary thread - VS 인터렉션 - 에서 background thread에 코드 분석 요청을 하게 됩니다. 그리고 background thread가 코드 분석을 하는 동안 primary thread는 사용자와 계속 반응 하게 되는거죠.

물론 이 모델이 갖게 되는 문제는 가끔 completion list에 나오는 내용이 실제 소스와 약간 다르게 된다는겁니다. - 아직 코드 분석이 background thread에서 끝나지 않았을때-. 하지만 거의 사용자 입장에서 보면 알아채지 못할 수준입니다. 그리고 저희 코드 분석이 무척 빠르기 때문에 보통 사용자들이 타입 하는 중간에 이미 완료 됩니다. 사용자의 수정이 엄청난 semantic 변화를 가져 오지 않는한 100% CPU를 잡아 먹는 일은 없죠.

문제는 사용자가 엄청 큰 c# 솔루션을 VS에서 새로 열었을때 입니다. 생각해 보시면 간단한데, 저희 코드 분석 엔진의 성능은 일반적으로 1초에 약 1메가 바이트의 소스를 분석합니다. 사용자가 새로 솔루션을 열면, lan svc는 솔루션에 있는 모든 파일에 대해 코드 분석 요청을 background thread에 하게 됩니다. 이때 물론 CPU는 100% 가까이 사용하게 되겠죠. 더한 문제는 background thread가 아직 막 연 솔루션에 대한 초기 코드 분석을 하고 있는 와중에 사용자가 계속해서 파일에 대해 수정을 가할때 입니다. 뭐 다시 분석하게 되겠죠. 문제는 아직 모든 소스에 대한 코드 분석 자료가 없는 상황에서는 코드 분석이 더 힘들다는겁니다.

그리고 코드 분석을 위한 background thread는 VS와 인터렉션을 위한 primary thread보다 thread priority 가 낮습니다. 따라서 CPU가 100% 라도 사용자가 실제 VS를 사용함에 있어서는 문제가 없지만, 아직 초기 코드 분석이 끝나지 않은 상황에서 사용자가 계속해서 소스를 수정하게 되면 - 물론 이게 가능하게 하기 위해 priority가 낮게 지정된겁니다. - 코드 분석을 하는 시간이 더 길어 지게 되기 때문에 CPU가 좀 더 오래 100%에 남아 있게 됩니다.

하여간 결론은 C# IDE의 높은 CPU 사용량은 "By Design" 이라는 겁니다.

..

오늘은 여기 까지 수고!!

 -----------------------------------------------------------------------------------------
이 게시자료는 어떠한 보증도 없이 “있는 그대로” 제공되며 또한 귀하에게 아무런 권리도 부여하지 않습니다.