후처리 개선기
#개발에세이 #02
입사해서 처음 참여했던 프로젝트는 CAE 기계 시뮬레이션 프로그램이었다. 쉽게 생각해서 기계 제품의 프로토타입을 만들기전에 시뮬레이션으로 안전한지에 대한 기준을 주는 해석 프로그램이다. (정해석, 동해석, 열해석, 유동해석, 등등 : 자동차 충돌해석 같은거라고 이해하시는게…)
그 과정을 짧게 보자면 기계의 형상을 모델링하고 (기하형상 : Geometry), 해당 형상을 메쉬(노드 & 요소)로 분할하고, 경계조건 및 하중을 설정하고 해석케이스를 만들어 FEM(유한요소법)으로 해석을 하게 되면 솔버에서 결과가 나오고, 그 결과를 사용자에게 그래픽적으로 표현해주는 프로그램이다.
이번 에세이에서는 이중 가장 마지막 단계인 해석결과에 대한 그래픽적 표현에 대해 다룬다. 이후에는 이를 후처리라고 ^^
처음 입사했을 때 후처리는 VTK(The Visualization Toolkit)이라는 무료 라이브러리를 사용하고 있었다. 후처리 구조는 패서드 패턴과 브리지 패턴으로 구현되어 있었는데, 결과를 파일에서 읽어서(결과 파일이 몇기가씩 나온다) 해당 값을 노드 혹은 요소에 매핑해서 컨투어라는 표현방식으로 보여준다. 에세이 1에서 설명했던 대화상자 만들기를 2달 정도 하고 나서 나에게 부여된 롤이 후처리 담당자였다. 기능 추가 및 성능 개선쪽이었다. 아시겠지만 기능 추가보다는 성능 개선 업무가 훨씬 도전적이고 재미가 있다. ^^
가장 첫번째로 기억나는 성능 개선은 후처리 테이블에 대한 것이었다. 내가 입사할 때만 해도 처리할 수 있는 메쉬의 요소수가 그리 크진 않았다. 하지만 헥사 고차요소의 경우 노드가 20개로 이루어져 있다. 후처리 노드 결과의 경우에 요소수가 10만개만 되어도 결과 테이블 로우가 20 * 100,000 = 2,000,000 일 것 같지만 인접한 요소는 노드를 공유하기 때문에 그렇게까지는 안되지만 암튼 몇십만개는 된다 (기하형상의 모양마다 너무 달라서 ㅋ) 아무튼.. 그 당시 테이블은 BCG라는 유료 라이브러리를 사용하고 있었는데, 첫번째 프로파일링은 요소수 천개 정도로 했던걸로 기억된다.
정말 만단위 로우(컬럼도 꽤 많다 ^^ xyz 좌표, xyz 결과, key, …)를 테이블로 표현하는데 내 예상보다 진짜 오래걸렸다… 첫번째 테이블을 띄우자마자 “어라 이거 문제가 있는데"라는 생각이 들었다. 그래서 실제 타겟이었던 10만개 요소로 해석을 해서 테이블을 띄워보았다. 퇴근하고 출근할 때 까지도 테이블이 표현되지 않았다. “아 이건 머지" 하고 프로세스와 로그를 확인하는데 계속 나오고 있… ;; 정말 이상해보였다. 테스트로 BCG 테이블을 만들어서 100만개 로우를 넣어보았을 땐 금새 나왔다. 생각보다 금방 찾을 수 있을 것 같았다. 아시겠지만 차이가 큰게 차이가 작은것보다 훨씬 개선하기 쉽다 ^^
함수 단위, 라인 단위 프로파일이 끝나고 결과를 보니 답이 나왔다. 정말 누가 했어도 금방 찾았을 개선 항목이었다 ^^ 그리고 이건 실수였다. 초반에 만들어논 함수를 제대로 분석하지 않고 그대로 쓴 실수. 결과 파일이 기가단위로 나오기 때문에 처음 결과 파일을 열어서 하는 것은 특정 결과 (결과도 엄청 종류가 많다)의 파일 포지션을 찾아서 그 결과 파일의 범위, 결과값 사이즈등을 구조체에 담아 메모리에 올려논다. 그리고 사용자가 특정 결과를 요청하면 파일을 열어서 그 위치로 seek 하고 블록으로 뚝 긁어와서 테이블 로우를 만들어서 처리하면 된다. 라고 생각했는데… 아마 처음에 테스트를 위해 만든 함수일꺼다. 아니면 프로브(특정 위치 결과추출) 기능을 위한 노드 혹은 요소 하나의 결과를 가져오는 함수여야 한다. 그러니까 이 함수가 하는 것을 봤더니
파일 열고 특정 결과 위치로 seek하고
해당 노드 혹은 요소결과 위치로 seek(우린 항상 오름차순으로 결과가 나오기로 약속되어 있어서 금방 찾는다)해서
결과를 읽고
파일을 닫고 있었다. ㅠㅠ
여기까지만 보아도 파일 처리를 해보신 분들은 답이 나왔을 것이다. 내가 한 개선을 단 하나다. 특정 결과의 테이블을 요청하면 파일을 열어서 해당 결과 위치로 seek 하고 그 결과 전체 블록을 메모리에 올린 후에 맵(차후 어레이 두개로 성능개선)에 노드 혹은 요소의 키와 결과값을 넣어두고 파일을 닫고, 그냥 BCG테이블 로우형식으로 넣어준거 그게 다였다.
개선 이후에 프로파일링 결과. 하루 이상 나오지 않던 테이블이 길어야 3분 내외로 뚝 하고 그려졌다. 첫번째 한 개선이 노드결과인 변위, 그 뒤로 응력, 힘, 등등을 순차적으로 처리해나갔다. 불과 일주일도 걸리지 않고 성능을 대충 어림잡아 천배이상 개선하였다. 그 당시 진짜 팀원 모두가 정신없이 바빠서 놓치고 있던걸 딱히 입사한지 얼마되지 않에 프로젝트에 깊게 참여할 수 없었던 신입사원이 답답함을 참지 못하고 했던 간단하지만 뿌듯했던 성공경험이었다.
두번째 이게 진짜 큰 성능 개선이었는데, 다시 잠깐 설명하자면 후처리에서 가장 중요한 기능은 컨투어를 표현하는 것이다. 그리고 이 성능에 따라 애니메이션 성능도 좌지우지 된다. 입사하고 2년간은 VTK와의 전쟁이었다. 정말 짜증나는 물건이다. 내부 알고리즘은 괜찮은데 우리가 만든 정보를 VTK에 맞게 변환하고 VTK가 뱉어주는 정보를 우리쪽 정보로 다시 만드는 이 과정이 너무 싫었고 솔직히 말하자면 쓰고 싶지 않은 라이브러리였다. 그러나 나는 그래픽쪽 지식이 그 당시엔 전무해서(지금도 뭐 딱히 그리 있지는 않지만), 주변에서 같이 할 사람을 찾았다. “조훈석” 현 그래픽스 개발팀장… 나랑 정말 많은 일을 함께한 동료이자 스승이었고 친구였다. (근데 빠른 81 -_-)
잠깐 일화를 통해 소개하자면, 이 친구가 CAE 전 제품군의 그래픽스 개발을 이끌었고 기반도 다 잡은 친구인데, 한번은 나에게 와서 지금 그래픽 기반 구조를 고치고 있는데 렌더링(보통 삼각형 천만개 이상) 코드에 if 문을 하나 넣어야 하는 상황이 생겼다고 하더니… if문을 넣지 않기 위해 일주일동안 구조를 다시 뜯어 고치는 사악한 녀석이다 -_-; 내가 알고 있는 모든 개발자 중에 가장 아름다운 코드를 짜며 맵따위는 쓰지 않고, 그래픽 정보는 거의 99프로 이상이 프리미티브 정보이기 때문에 배열만 쓴다. 그것도 [][][][[]] 이정도는 기본으로 다루는 머리가 진짜 좋은 친구이다.
암튼 다시 개선으로 돌아와서, 이 친구랑 함게 하면 VTK를 뺄 수 있을 것 같다고 같이 하자고 했더니, 자기도 그거 고치려고 몇번 제안을 했지만 시간 및 일정상의 이유로 밀렸던 개선 사항이었다. 훈석이하고 같이 해당 내용을 정리해서 어떤 일정을 가지고 개선해보겠다. 예상되는 개선은 이정도다 라고 제안하였고 통과가 되어 진행을 시작하였다. 이미 이 녀석은 그에 대한 청사진이 있는 상태라 개선은 아니 후처리 기반 구조 재개발은 빠르게 진행되었다. 우리의 목표는 30만개 요소의 컨투어를 1초 이내로 그리는 것이었다. (기존에는 3분 이상 소요되었다.) 한 2주정도 지났는데 실제로 1초로 컨투어가 그려졌다. 정말 감격의 순간이었다. 하지만 후처리는 컨투어가 시작이고 그 이후에 수많은 기능들이 있었고 애니메이션이 끝인 험난한 과정이다. 그렇게 하나하나의 기능을 재개발하다가 난관에 부딪힌게 하나 있었는데, 보통 요소의 결과는 노드에 나오지만 사용자는 요소의 특정 위치의 결과를 계산해내는 “On Curve Diagram”이라는 기능을 필요로 하고 이 기능을 재개발하다가 벽에 막혔다. 처음에는 쉽게 접근했는데 아무리 풀어보아도 답이 안나왔다. (기존 VTK버전과 동일한 결과를 내야함)
그래서 우리 제품에서 이런 비슷한 기능이 머가 있나 하고 찾아보니 “Arbitrary Load” 였다. 해당 기능은 내가 필요한 기능의 반대이다. 즉 요소의 특정 위치에 하중을 가하면 그 하중을 동등하게 받도록 노드로 분산하는 기능이었다. 이거다!! 라고 느낌이 와서 해당 개발자를 찾아갔다니 해당 코어 기술은 해석개발팀(유한요소법을 이용한 솔버를 개발하는 팀 : 대부분 박사 가끔 석사, CAE제품 가격의 80프로 비중을 차지)이 가지고 있었고 해당 박사님께 상황을 설명했더니 “Shape Function”이라는 것을 설명해주셨다 ^^
행렬을 통해서 푸는 건데 요소 종류(선, 삼격형, 사각형, 정사면체, 웨지, 육면체) 등에 따라서 해당 행렬이 다 다른 그런 나름 수학이 많이 들어가는 개념이었고 나는 이 행렬의 역행렬을 구해서 처리하면 될 것 같았다. 이때 처음으로 매스매티카를 써보았다. 웨지까지는 그런데로 적용할 만 한데… 육면체는 정말 사악했다. 역행렬을 푼 수식이 텍스트 파일로 100메가가 넘었다;; 이걸 cpp에 담을 순 없기에 요소의 특정 위치를 기준으로 육면체를 반으로 잘라서 어느 웨지에 속한지 찾고 그 다음에는 웨지의 처리 알고리즘을 적용해서 개발하였다. 지금도 해당 기능은 잘 사용되고 있긴 한데, 좀 애매한게 있긴 하다. 아는 사람만 안다.(1e-10… 1e-6) ^^ 하지만 이 정도면 충분히 reasonable 한 결과가 나오니까 ㅎ
세번째 개선은 다름 사람과 했기에 후처리 개선기는 여기까지 세번째는 그 후배를 소개할 때 담기로~
조훈석"
대학교때 보컬을 할만큼 출중한 노래 실력(내 결혼식 축가도 이 친구가), 선형대수학을 머리에 끼고 사는 수학 천재, 그래픽 1인자(지금은 아닐지도? ㅋ), 농부 (주말농장 텃밭가꾸고 사는), 판교 원마을에 자가가 있는 부자(?), 술을 사랑하는 특히 맥주에 관해선 모르는게 없는 술꾼, 근현대사를 빠삭하게 아는 지식인 (술마시면 맨날 우린 6월항쟁부터 역사얘기를 시작한다…;;)