위키북스에서 "조엘 온 소프트웨어" 저자로 유명한 조엘이 쓴 똑똑하고 100배 일잘하는 개발자 모시기를 보내주셔서 읽어봤습니다. 개발자를 선발하고 개발 조직을 운영하는 방법에 대해 저자의 생각을 아주 명료하게 전달하고 있는 책이더군요.

초일류 프로그래머는 초일류 제품을 만들고 회사를 먹여 살리기 때문에 개발자를 뽑는 일은 사운을 좌지우지할 정도로 중요한 일임에는 틀림이 없습니다. 가장 잘하는 개발자와 못하는 개발자의 생산성 차이가 10배 이상이라는 연구 결과는 아주 많습니다. 10x Software Development

하지만 작은 회사에서 귀하신 몸인 "슈퍼 개발자"를 모셔오기란 무척 힘들기 때문에 조엘의 회사인 포크 크릭 소프트웨어사는 아직 졸업이 한참 남은 대학생들을 인턴으로 받아서, 감동과 환희를 선사한 후에 끈끈한 관계를 유지해서 회사로 데려오는 전략을 많이 쓰고 있습니다.

조엘의 논리는 괜찮은 개발자들은 이미 대학교 1-2학년 때 성숙한 경지에 접어든다는 것이죠. 심지어 고등학교 때부터 미리 계약해 두고 후원하는 것까지 생각하고 있다는 조엘입니다.

저도 예전에 상당한 쇼킹한 후배에 대한 기억이 있습니다. 대학 신입생 환영회에서 이야기하다보니 한 후배는 자기가 중고등학교 때 이미 운영체제로 FreeBSD와 리눅스를 쓰고 C/C++, 자바도 아닌 헤스켈로 코딩을 해왔다더군요. 특별히 옆에서 누가 가르쳐준 것도 아니고 그냥 혼자서 말이죠. (그냥 한 두번 HelloWorld 짜본 것이 아니고 상당히 잘한다는 사실은 나중에 알게 되었습니다)

컴퓨터도 음악이나 미술처럼 태어날 때부터 신동들이 있는 걸까요? 메릴랜드에서 교환학생 할 때도 Cyclone이랑 언어 만드는 쪽에 연구참여 하려고 찾아가서 Cyclone 연구는 주로 누가 하냐고 물었더니, 메릴랜드대, 하버드대, AT&T와 더불어 고등학생 1명이 한다더군요. 처음에는 영어가 딸려서 잘못 들은 줄 알았습니다.

리눅스에도 예전에 커널 maintenance 하는 애중에 굉장히 어린 친구가 있었던 걸로 아는데, 암튼 슈퍼 히어로가 많은 분야인 것 같습니다. 중언부언했는데, 결론을 말하자면 그런 슈퍼 인재를 잡는 회사는 땡잡는 다는 것 정도랄까요?

CUDA

Posted 2008/07/10 05:38
마소 7월 호에는 NVIDIA의 GPU 프로그래밍 모델인 CUDA에 대해 원고를 작성했습니다. GPU는 병렬 프로그래밍 있어서는 CPU 보다 앞서간 면이 있는 만큼 CUDA 프로그래밍 모델은 기본적으로 data parallel한 프로그래밍 모델입니다. OpenGL이나 DirectX의 그래픽스 API를 변용해 사용하는 고전적인 GPGPU 방식을 탈피해 programmability를 대폭 늘렸습니다. 물론, GPU는 여전히 CPU가 아니기 때문에 자연스럽지 못한 추상화(abstraction)도 여기저기 널려 있긴 합니다. CUDA에 대한 자세한 소개는 마소 7월호를 보세요 :)


Joe Armstrong과의 인터뷰

Posted 2008/07/10 05:14
Thinking Parallel이란 블로그에서 작년 초에 Erlang을 만든 Joe Armstrong과 Parallel Programming에 대한 인터뷰를 나눈 것이 있더군요.

Joe Armstrong은 Erlang의 창시자답게 shared-memory programming과 message passing 중 어떤 방식이 더 좋냐는 질문에 shared memory에서 lock 잡다가 문제 생기면 회복할 방법이 없음을 강조하며 적극적으로 message passing 스타일을 옹호하고 있습니다. 대신 trasactional memory는 살짝 message passing과 같이 끼워서 괜찮다는 식으로 넘어가고 있습니다.

parallel programming의 미래가 pure message passing에서 온다는 부분은 저는 동의하기가 약간 어렵습니다. pure message passing의 많은 장점에도 불구하고, 여전히 mutable한 shared state로 표현하는 데이터 구조가 가장 직관적인 경우가 너무 많기 때문입니다. 일례로, 웹개발자가 가장 애용하는 DOM tree는 타고 나기를 mutable shared state의 집합이니깐요.

pure message passing을 이용한 간단한 parallel programming model도 Erlang의 장점인 것을 분명하지만, 저는 분산 컴퓨팅(distributed computing)이나 결함허용(fault-tolerant) 관련된 기능을 프로그래밍 언어에 잘 녹여 넣은 부분을 더 높게 평가합니다. 실제로 Ericsson의 스위치, 라우터 장비에서 안정적으로 돌아간 경력이 있기도 하고요.

멀티코어 시대의 새로운 분산 프로그래밍 모델은 앞으로 소프트웨어가 풀어야할 가장 큰 과제입니다. Erlang이 좋은 모델을 제시한 것은 분명하지만, 멀티코어 문제가 Erlang이 이야기하는 pure message passing 모델만으로 해결될 것 같지는 않다는 게 제 생각입니다.

[dW] Dead like COBOL

Posted 2008/06/30 19:01
자바는 이제 낡고 오래된 기술이라는 이야기가 나온 게 이미 꽤 시간이 흘렀습니다. 책 이름에 "beyond Java"가 붙은 책이 베스트셀러가 되는가 하면, 자바의 대안으로 여러 스크립트 언어들이 활발히 개발되고 있습니다. IBM dW의 Dead like COBOL은 이렇게 위기에 처한 자바의 앞날에 대해 이야기하고 있습니다.

이  글에 별로 새로운 내용은 없습니다. 자바 5에서 이미 한계를 드러낸 프로그래밍 언어 자바만 보지 말고, 자바 플랫폼, 자바 가상 머신, 새로운 자바 플랫폼 언어(그루비, 스칼라 등)에 주목하라는 것입니다. 결론은 자바는 쉽게 없어지지 않을 거라는 것이죠.

저는 개인적으로 자바 가상 머신을 타겟으로 새로 개발되는 여러 언어에 관심이 많습니다. 예전에 스칼라에 대한 글을 쓴 적도 있었는데, 특히 자바와는 패러다임이 다른 함수 언어가 스크립트 언어를 JVM 위에 돌리려는 노력이 지속적으로 이루어지고 있습니다.

올해 쿼드 코어(코어 4개)를 시작으로 2년마다 코어 수가 2배씩 늘어가는 멀티코어 시대를 맞이했습니다. 과거 슈퍼 컴퓨터를 만들던 HPC(High Performance Computing) 분야 외에도 멀티코어 시대의 병렬 프로그래밍(Parallel Programming) 대한 아무런 준비가 없기 때문에 소프트웨어 개발자들은 당분간 혼돈의 시기를 살아갈 가능성이 큽니다.

하지만 대중적으로 사용되는 프로세서 중에도 이미 멀티코어 프로세서가 있는데 그 대표주자가 Cell Broadband Engine (CBE) Processor(줄여서 Cell 프로세서)입니다. PC에서는 아직 쿼드 코어도 일반화되지 않았지만 Cell 프로세서는 무려 9개의 코어를 가지고 있습니다. Cell 프로세서 프로그래밍이 어렵다고 소문이 나 있는 것도 이 때문입니다.

인텔의 코어 2 쿼드 프로세서는 4개의 동일한 코어를 가진 반면 Cell은 1개의 PPE(PowerPC Processing Element)와 8개의 SPE(Synergistic Processing Element)로 이루어져 있습니다. PPE는 PowerPC 아키텍처를 가진 메인 프로세서이고 8개의 SPE는 보조 프로세서 역할을 합니다. SPE는 각각 코드와 데이터를 저장할 수 있는 256kB의 로컬 스토어와 128비트의 레지스터를 128개 가지고 있습니다. SPE는 SIMD를 수행하는 데 최적화된 프로세서라고 보시면 됩니다.

Cell 프로그래밍은 크게 2가지 이유로 어렵습니다.

1) 메모리 모델

SPE 프로그래밍을 어렵게 하는 가장 큰 요인 중 하나는 캐쉬가 전혀 없다는 사실입니다. 로컬 스토어에 데이터를 load/store하기 위해서는 명시적으로 명령을 내려야만 합니다.

2) 병렬성

Cell 프로세서의 병렬성은 작게는 PPE와 SPE 모두 SIMD 명령을 지원한다는 점에서 나옵니다. 또한 슈퍼스칼라(superscalar)를 지원하기 때문에 한 클럭의 2개의 명령을 실행할 수 있습니다. 크게는 PPE와 8개의 SPE가 병렬로 동작합니다. PPE는 2개의 하드웨어 쓰레드를 가지고 있기 때문에 총 10개의 태스크가 동시에 수행되는 셈입니다.


멀티코어 프로그래밍에서 제일 중요한 것은 "프로그래밍 모델"입니다. 여러 코어를 효율적으로 활용할 수 있는 프로그래밍 모델을 찾는 것이 가장 큰 과제인 셈이죠. IBM dW의 Unleashing the power of the Cell Broadband Engine은 Cell 프로세서 특징과 프로그래밍 모델을 요약하고 있습니다. 어떻게 SPE를 프로그래밍해야 하는지 dW 기사가 어느 정도 이야기를 하고 있지만 쉬워 보이지는 않습니다. PPE, SPE의 특성, 메모리 모델 등을 다 고려해야만 성능이 난다고 하면 제대로 프로그래밍할 수 있는 사람은 별로 없을 테니깐요.

블로그 순위?

Posted 2008/05/25 14:25
고감자 님이 HanRSS 구독수를 기반으로 블로그 순위를 뽑으셨네요. 믿기지 않게도 제 블로그가 국내에서 58위에 랭크되어 있습니다. 일일 방문자 수도 많지 않고 글마다 리플도 거의 없는 (아 무플의 슬픔ㅠ.ㅠ) 제 블로그가 이렇게 높은 순위를 기록하고 있다는 사실이 조금 의아합니다.

물론 HanRSS 구독수만 따지면 지금 이 순간 구독하시는 분이 무려 743분이시니 절대 적은 수는 아니지만 고정 독자 수에 비해서 너무 의견이 없어서 항상 의아하게 생각했습니다.

물론 글 내용이 프로그래밍 언어와 컴파일러, 아키텍처 등 특정 분야에 상당히 치우친 것은 사실입니다. 그래도 나름 관심을 가진 분야라 고정 구독하시는 분들일텐데, 대부분의 글에 별 반응이 없어서 사실 아무도 안 읽는 듯한 느낌이 들 정도거든요.

제 스스로가 다른 블로그에 글을 남기거나 의견을 교류하는 데 적극적인 편은 아니라 사실 할 말은 없습니다. 스스로를 블로거라고 생각해 본적도 없고, 내가 글을 쓰는 행위가 블로깅이라고도 생각해 본적도 없긴 하지만, 그래도 활발한 피드백을 받는 블로거 분들을 보면 가끔 부럽긴 합니다.

그리고 보니 간만에 쓴 비기술 글이네요.


업데이트: 많은 분들이 댓글을 남겨주셨네요. 앞으로 더욱 열심히 글을 쓰도록 하겠습니다. 감사감사.

Java Virtual Machine (JVM)과의 인연

Posted 2008/05/22 04:42
저는 JVM에 관련된 글을 종종 쓰는 편입니다. 마소에서 자주 우려먹은 주제 역시 JVM 혹은 자바 내부 구현 쪽이었습니다. 물론 더 이상 JVM 관련 실무를 하지 않으면서 지식의 한계를 느껴서 지금은 프로그래밍 언어로 관심사가 많이 넘어갔습니다.

사실 특례하기 전에는 프로그래밍 언어, 컴퓨터 아키텍처, VM 등에 별로 관심이 없었습니다. 하지만 우연한 기회에 특례로 입사한 회사에서 JVM 관련 일을 하게 되었습니다. 국내에서는 드물게 CDC 급(핸드폰에 들어가는 CLDC급 VM과 달리 J2SE 스펙과 동일한 임베디드용 JVM) 소스 코드를 열심히 볼 기회를 가졌습니다.

JVM 하면서 논문 읽는 법을 배웠고, 복잡한 소프트웨어를 작성하는 방법도 배웠고, 시스템 프로그래밍의 기초를 다졌고, 프로그래밍 언어에 대한 관심을 가지게 되었으니 JVM 명세와 코드는 지금 제가 개발자로 살아가는 데 막대한 영향을 끼친 것 같습니다.

JVM한 덕분에 작년 초에는 삼성소프트웨어멤버쉽(SSM)에서 자바가상머신을 주제로 이틀 간 강의도 했습니다. 준비 기간에 비해서 강의 시간이 너무 많아서(무려 16시간) 무척 힘들었는데 (제 목소리에 졸았을 학생들에게 죄송) 그래도 매우 가치 있는 경험이었습니다.

지금은 예전에 비해서 무척 다양한 일을 하고 있어서 예전만큼 깊이 있게 논문이나 코드를 들여다보고 있지 못해서 조금 답답한 마음도 있습니다. VM이나 코어에 가까운 일을 업으로 삼는 행복을 느낄 수 있는 곳이 많지 않다는 사실도 알게 되었고요. (적어도 국내에서는요)

JVM 관련해서 깊이 있게 보시는 분이 계시면 같이 이야기할 수 있는 자리를 만들어 보는 것도 좋을 것 같다는 생각이 듭니다. 제 블로그는 의견 남겨주시는 분이 거의 없는데, 관심 있으신 분은 적극적으로 의견 좀 남겨주시길.


Method inlining and deoptimization

Posted 2008/05/22 04:18
axis님이 HotSpot Server JVM의 성능 이야기를 하면서 언급하신 공격적인 method inlining과 deoptimization에 대한 이야기를 하려 합니다. 관련 내용은 The Java HotSpot Performance Engine: Method Inlining Example에 이미 잘 정리되어 있습니다.

간단히 정리하면, HotSpot JVM은 final로 선언되어서 서브클래싱될 수 없는 메서드 뿐만 아니라 일반 메서드도 공격적으로 inlining 했다가 서브클래스가 런타임에 로드되면 이를 확인해서 inlining 된 메서드를 도로 푸는(deoptimize)하는 방법을 사용합니다.

inlining의 장점

1) 메서드 콜 오베헤드가 없다
2) dynamic dispatch 오버헤드가 없다
3) constantn folding이 추가로 가능하다. 예를 들어, a.foo() + 2가 있을 때 a.foo()가 3으로 inling되면 3 + 2 = 5로 constant folding이 가능하기 때문이다.


런타임에 컴파일하기 때문에 최적화가 가능한 상황을 표시해두고 최적화한 다음에, 그 가정이 깨어지면 최적화를 푸는 방법이 인상적입니다. 컴파일 타임에 모든 결정을 해야 하는 정적인 컴파일러는 할 수 없는 최적화 방법이기도 합니다.

Functional Programming Creeps into Job Specs는 미국에서 개발자 채용할 때 함수 언어 구사자를 찾는 경우가 조금씩 늘고 있다는 소식입니다. 함수 언어인 Haskell, Ocaml, F#, Erlang, Scheme, Lisp 등이 구인 광고에 이름을 올리기 시작했습니다.

Is Functional Programming the new Python? 은 이런 현상에 대한 논평인데, 기업이 함수 언어 사용자를 찾기 시작한 이유는 2000년 경우 파이썬 개발자를 채용한 것과 같은 심리라는 지적입니다. 즉, 돈 안 되는 이상한 언어를 구사자를 찾을수록 실력 있는 개발자를 뽑을 확률이 높다는 이야깁니다. 함수 언어를 먹고 살기 위해 배우는 언어가 아니라 열의를 가지고 공부해야만 알 수 있는 언어이기 때문에, 함수 언어 구사자를 찾으면 자연적으로 다른 언어 구사자에 비해 실력 좋은 개발자를 뽑을 가능성이 커집니다.

수 십년을 동굴 속에 갖혀 지낸 함수 언어가 멀티 코어, 분산 처리, 결함 허용 등의 키워드와 맞물려 세상으로 나오려고 힘쓰고 있습니다.



까멜레오 소식

Posted 2008/05/14 13:40
까멜레오는 얼마 전에 살짝 윈도 바이너리를 공개해놨는데 아직 베타 테스트 단계(이제 첫 릴리즈를 했음)라 널리 홍보는 하지 않고 있었습니다. 현재 성능 개선 및 안정화 작업으로 한참 바쁘게 보내고 있었습니다.

그런데 오늘 까멜레오 소식이 동시에 여러 곳에서 들어왔습니다. 일단 downloadsquad에서 Chameleo: Open source video player from Korea라는 제목으로 까멜레오 소개 기사가 올라왔습니다. 한국에서 하는 오픈소스 비디오 플레이어라는 제목이 마음에 드네요. 기사 내용은 간략합니다. 까멜레오가 있고, 여러 코덱을 지원하고 Joost나 Babelgum처럼 웹 비디오를 지원하지는 않지만 비트토런트 클라이언트를 내장하고 있다.

그리고 얼마 전에 GigaOM의 LIz Gannes와 까멜레오에 관해 전화 인터뷰를 했었는데, 관련 기사가 오늘 newteevee에 올라왔습니다. 제목은  Chameleo:New Open-Source Video Player입니다.  까멜레오 플레이어는 플러그인을 비롯한 확장성에 초점을 맞추고 있다고 비교적 정확하게 기사를 작성해 주었습니다. (전화 인터뷰에서 강조했습니다^^)  기사 말미에 제가 인터뷰하면서 했던 말도 나옵니다.


NomadConnection CTO Kwang Yul Seo told NewTeeVee that his company plans to release a Linux version of Chameleo this week and a Mac version in June.


일단 기사 내용에도 언급되었지만 까멜레오는 멀티플랫폼을 지원합니다. 윈도 바이너리는 이미 공개되어 있고, 지난주와 이번주에 리눅스 포팅 작업을 어느 정도 마무리 지었습니다. 이번주 금요일에 릴리즈할 0.1.3은 윈도 뿐만 아니라 리눅스 포트도 함께 릴리즈할 예정입니다. 맥 포팅은 계획되어 있는데, 늦어도 6월 말 전에는 릴리즈를 하려고 생각하고 있습니다.

더불어 웹초보님께서 저희보다 더 빠르게 downloadsquad의 글을 발견하고 까멜레오: 한국의 오픈소스 비디오 플레이어라는 제목으로 사용 후기까지 남겨주셨네요. 까멜레오의 장점과 단점을 예리하게 지적해 주셨습니다.  일단 툴팁이 없어서 메뉴 사용이 불편하다는 점은 인지하고 있었고 다음 버전에는 툴팁이 들어갈 예정입니다.



-- 여기부터는 개발자만 읽으세요  --

newteevee 기사 중에 보면 리소스를 좀 많이 먹는다는 지적이 있는데, 지난번에 릴리즈하고 나서 이 문제를 해결하는 데 많은 시간을 보내고 있습니다. valgrind 도구 중 하나인 callgrind도 프로파일링 해본 결과 YUV 비디오를 OpenGL 텍스터로 올리기 위해 RGB로 변환하는 gst-ffmpegcolorspace에서 CPU를 30% 이상 차지하고 있다는 사실을 발견했습니다.

현재 OpenGL 셰이더를 이용해  YUV to RGB 변환하는 부분과 SIMD 명령셋인 MMX, SSE, SSE2 등을 이용해 칼라 스페이스 변환하는 부분 코드를 작성하고 있는 중입니다. 이 문제가 해결되면 성능 문제는 어느 정도 해결될 것으로 보입니다.

이번주 금요일에 까멜레오 2번째 릴리즈인 0.1.3 릴리즈를 예정하고 있습니다. 아직 베타 릴리즈인 만큼 따뜻한 사랑과 애정으로 지켜봐주세요. 개발자 입장에서 프로그램은 자식 같아서 어디가서 안 좋은 소리 듣고 오면 가슴이 참 아프답니다. 비굴비굴. (__)


Virtualization의 종류

Posted 2008/05/13 04:17
요즘 자주 듣는 단어 중에 하나가 가상화(virtualization) 기술입니다. 보통 운영체제 위에 또 다른 운영체제를 설치할 수 있게 해주는 VMware나 Parallels Desktop 등 통해 익숙해졌으리라 생각합니다.

가상화는 생각보다 넓은 범주의 기술을 의미하는데, 크게 다음 3가지로 나눠 볼 수 있습니다.

1) 머신-수준 가상화(Machine-Level Virtualization) : 이 범주에 속하는 대표적인 프로그램이 VMware, Parallels Desktop, Virtual Box 등입니다.

2) 시스템-수준 가상화(System-Level Virtualization) : Paravirtualilzation이라고도 불리며 Xen이 대표적입니다.

3) 언어-수준 가상화(Language-Level Virtualization) : 프로그래밍 언어 수준의 가상 머신을 의미하며 JVM과 .NET이 대표적인 언어 수준 가상화입니다.


저는 언어 수준 가상화만 관심 가지고 보고 있었는데, 요즘은 조금 더 밑으로 내려가도 재미있는 이슈가 많은 것 같다는 생각이 듭니다.

Dynamic Profiling

Posted 2008/05/13 04:14
JIT를 제공하는 Java Server VM이 정적으로 컴파일된 C/C++ 수준 혹은 그 이상의 성능을 보일 수 있는 중요한 이유 중에 하나는 런타임에 수집한 데이터를 가지고 컴파일을 최적화하기 때문입니다.

다음 코드를 예로 봅시다.

for (i = 0 ; i < 10; i++) {
    if (cond) {
        g();
    } else {
        h():
    }
}

루프 안의 g 혹은 h 함수를 inline 할지 말지 결정하려면 cond이 true일 확률이 높은지 false인 확률이 높은지 알 수 있어야 합니다. 만약 cond가 거의 항상 true라면 g를 inline하고 h는 그냥 두어야 할 것입니다. 하지만 런타임 정보가 없는 C/C++ 컴파일러은 이런 최적화를 수행하기는 힘듭니다.

이런 한계 때문에 요즘은 일반적인 컴파일러들도 런타임 정보를 활용해 추가적인 최적화를 하기도 합니다. 일례로 인텔 컴파일러는 바이너리가 동적 프로파일링(dynamic profiling)을 수행하도록 한 번 컴파일한 후에, 이를 실행해 얻은 프로파일링 데이터를 바탕으로 다시 한 번 컴파일해 최적화된 코드를 생성할 수도 있습니다.


파이썬 구현들

Posted 2008/04/30 21:05
흔히 파이썬하면 파이썬 언어 명세보다는 Guido van Rossum이 작성한 CPython을 의미하는 경우가 많습니다. 하지만 CPython 외에도 파이썬을 구현한 프로젝트가 많이 있었습니다. 한 때 많은 사람들의 관심을 받았던 Stackless Python을 필두로 시작된 파이썬 구현은 현재 JVM과 .NET에 올라간 Jython, IronPython으로 이어지고 있습니다. 파이썬으로 파이썬을 구현하자는 PyPy 프로젝트도 있습니다.

더 이상 개발되지는 않지만 실험적인 파이썬 구현으로는 PyVM과 Vyper가 있었습니다. 그 중 Vyper는 John Max Skaller OCaml로 작성한 파이썬 구현입니다. 당시 파이썬 스코핑(scoping) 룰에 불만을 품고 시작해 좀 더 빠르고 함수적인 파이썬을 만들려는 시도였습니다. IBM dW에 보면 Stackless Python의 Christian Tismer와 Vyper의 John Max Skaller와 인터뷰가 있더군요. 하지만 지금은 Vyper의 홈페이지 링크조차 깨진 채 존재하지 않는군요. 아아. Vyper가 커뮤니티의 도움을 얻어 CPython과 더불어 성장해줬다면 조금 더 함수형인 파이썬이 나왔을지도 모르겠습니다.

Crossing borders

Posted 2008/04/30 16:47
IBM dW의 연재 중에 Crossing borders는 프로그래밍 언어와 기술 간의 경계를 뛰어넘어 새로운 세계를 맛 보자는 뜻으로, 다양한 함수 언어를 소개하고 있습니다.

헤스켈 소개

Crossing borders: Explore functional programming with Haskell


얼랑 소개

Crossing borders: Concurrent programming with Erlang


비함수형 개발자에게 함수 언어의 개념을 소개하는 것은 비교적 쉽습니다만, 그 다음 단계인 함수 언어로 실제 어플리케이션을 작성하는 일과는 상당한 괴리가 있는 것으로 보입니다. 저 역시 함수 언어에 관심 갖고 공부해온 지가 꽤 오래되었지만 비교적 최근에서야 업무를 비롯해서 시험적으로 조금씩 써보는 정도거든요.

특히, 함수 언어를 실제 어플리케이션 작성에 쓰기 위해 반드시 풀어야할 문제는 IO, 외부 함수 호출, 동시성(concurrency) 등인 것 같습니다. Real World Haskell은 Haskell로 연습 문제만 풀지 말고 실제 어플리케이션을 작성할 수 있도록 가이드하자는 취지해서 작성되고 있는 책인데, 얼마나 성공적일지 지켜봐야겠습니다.


Memoization

Posted 2008/04/30 01:51
순수(pure) 함수, 다른 말로 참조 투명한(referential transparent) 함수는 수학적인 함수와 마찬가지로 같은 인자를 넣으면 언제나 같은 값을 돌려줌을 보장하는 함수입니다. 간단한 예로, OCaml로 작성된 다음 피보나치 수열 함수(fib)는 참조 투명한 함수입니다.

let rec fib = function
    0 | 1 as i -> i
    | i -> fib (i - 1) + fib (i - 2)


위 fib 함수는 비효율적으로 작성되어 있기 때문에 무척 느립니다. 이런 순수 함수를 최적화하는 방법으로 알고리즘 자체를 꼬리 호출(tail recursion)하도록 변경하거나 더 나은 알고리즘을 찾는 방법 등도 있겠지만, 함수를 그대로 두고 메모리 공간을 희생해서 속도를 향상하는 최적화 방법으로 기억(memoization)이 있습니다.

다음 memo 함수는 Developing Applications With Objective Caml에서 발췌한 예입니다.

let memo f =
        let table = ref [] in
        let rec find_or_apply entries x =
            match entries with
                (x', y) :: _ when x' = x -> y
            | _ :: entries -> find_or_apply entries x
            | [] ->
                    let y = f x in
                    table := (x, y) :: !table;
                    y
        in
        (fun x -> find_or_apply !table x)

이 함수의 타입은

val memo : ('a -> 'b) -> ('a -> 'b)


로 원래 함수와 동일한 타입의 함수를 리턴합니다. 코드를 살펴보면 table을 두고 계산 결과를 저장해서 한 번 f(e) 값이 불리면 두 번째 불리는 f(e)는 새로 계산하지 않고 저장된 값을 쓰게 됩니다. 일종의 동적 프로그래밍(dynamic programming) 기법입니다.

기억(memorization)이 가능한 이유는 함수가 참조 투명하기 때문입니다. 매번 호출할 때마다 값이 바뀌는 함수라면 이전 함수의 결과를 저장해뒀다가 재활용하는 것이 불가능하기 때문입니다.

어느 정도 속도 향상이 있었는지 측정하기 위해서 시간을 재는 함수를 다음과 같이 만들어 봅니다.


let time f x =
    let start = Sys.time () in
    let y = f x in
    let finish = Sys.time () in
    Printf.printf "Elapsed time: %f seconds\n" (finish -. start);
    y
;;

OCaml은 함수 언어고 a + b라고 해서 a를 b보다 먼저 연산(evaluation)한다는 보장이 없습니다. IO의 경우는 순서가 중요하기 때문에, IO의 순서를 정하기 위해서 위와 같이 let 구문을 연달아 늘어 놓는 방법을 많이 씁니다. 앞서 let이 새로운 스코프(lexical scope)을 만들기 때문에 순서가 보장되게 됩니다.

let memo_fib = memo fib;;

time memo_fib 35;;
time memo_fib 35;;


fib를 memo로 감싸서 memo_fib 함수를 정의한 다음에 2번 불러보면 두 번째는 이미 계산된 저장 값을 가져 오기 때문에 매우 빠르게 계산됨을 확인할 수 있습니다.

Elapsed time: 2.579000 seconds
Elapsed time: 0.000000 seconds


자바 as 에스페란토 for JVML

Posted 2008/04/30 00:15
전통적으로 프로그래밍 언어의 외부 인터페이스(외부 함수 호출)는 주로 C로 되어 있었습니다. 자바의 JNI(Java Native Interface)가 대표적이고, 파이썬도 Python/C API를 제공합니다. 함수 언어 OCaml로 C 인터페이스를 제공하고, Haskell도 마찬가집니다.

C는 프로그래밍 언어계의 에스페란토인 셈인데 C가 이렇게 널리 쓰이는 이유는 다음과 같습니다.

1. C는 표준화된 언어이다 (ISO C)
2. C는 운영 체제 구현 언어로 가장 많이 사용된다. 대표적으로, Unix, Windows, MacOS 등이 모두 C로 구현되어 있다.
3. 많은 라이브러리가 C로 구현되어 있다.
4. 대부분의 프로그래밍 언어가 C 인터페이스를 제공하기 때문에, 프로그래밍 언어가 C 인터페이스만 제공하면 다른 언어와 바인딩도 가능하다. 일례로, Pycaml은 OCaml C 인터페이스로 Python/C API를 호출해 파이썬을 바인딩한다.


자바 가상 머신에서 동작하는 언어에서는 자바가 C를 대체하는 새로운 에스페란토가 되고 있습니다. 자바는 앞서 C가 프로그래밍 언어 인터페이스로 많이 사용되는 이유가 모두 맞아 떨어집니다.


1. 자바는 표준화된 언어다 (Java Language Specification)
2. 자바는 자바 플랫폼 구현 언어로 사용된다. 자바 라이브러리는 모두 자바로 작성되어 있다.
3. 많은 라이브러리가 자바로 구현되어 있다.
4. 대부분의 JVML이 자바 인터페이스를 제공하기 때문에, 프로그래밍 언어가 자바 인터페이스만 제공하면 다른 언어와 바인딩도 가능하다.




OCaml 프로그램 최적화

Posted 2008/04/29 20:45
프로그래밍 언어를 공부를 단계별로 나눈다면

(1) 프로그래밍 언어의 문법를 파악
(2) 프로그래밍 언어의 의미(semantics)를 이해
(3) 프로그래밍 언어 커뮤니티가 사용하는 관례와 용법 파악
(4) 프로그래밍 언어 내부 구현(컴파일러, 인터프리터) 지식을 활용한 최적화 코드 작성

정도의 순서로 진행될 것입니다. OCaml은 일반적으로 상당히 빠른 머신 코드로 컴파일될 수 있다고 알려져 있지만 OCaml 컴파일러가 어떤 최적화 기법을 사용하는지 알면 더욱 더 효율적인 코드를 짤 수 있을 것입니다. 

예를 들어, 다중 인자를 받는 OCaml 함수를 정의할 때 두 가지 방법을 사용할 수 있습니다. OCaml QnA의 Making code run fast라는 글에서 인용했습니다.

fun x y z -> ...


fun (x, y, z) -> ...


첫 번째는 커리(curried) 형태이고, 두 번째는 언커리(uncurried) 함수로 여러 인자를 하나의 튜플로 만든 형태입니다. 

개발자가 느끼기에 두 코드가 하는 일은 거의 동일하지만 OCaml 컴파일러 입장에서 봤을 때는 달라지는 부분이 생깁니다. OCaml 바이트코드 컴파일러(ocamlc)의 경우, 커리 함수는 힙(heap) 할당 없이 스택에 변수를 넘겨서 함수 호출을 수행함을 보장합니다. 반대로 언커리 함수는 힙에 튜플을 만들어서 넘깁니다. 호출된 함수 안에서는 다시 튜플에서 각각의 원소를 꺼내 와야 하기 때문에 커리 함수에 비해 속도가 느려집니다.

그런데 반드시 이렇게 되어야만 하는 것도 아닙니다. 네이티브 컴파일러(ocamlopt)는 두 경우 모두 힙에 할당하지 않고 레지스터를 이용해 파라미터를 전달하기 때문에 두 함수는 성능 차가 없어집니다.

또 하나의 예로, 대부분의 Lisp이나 ML 컴파일러는 부동소수점 계산이 느립니다. 가비지 콜렉션, 다형성/타입 추상화 등 때문에 부동소수를 힙에 할당하고 포인터를 저장하는 방식으로 구현된 경우가 많기 때문입니다. float 두 개 더하려면 포인터를 2개 읽어서 float를 가져와 더한 다음에 그 결과를 다시 포인터가 가리키는 주소에 저장해야 하기 때문에 속도가 느려질 수밖에 없습니다.

컴파일러가 부동소수점을 언박싱(unboxing)하는 최적화를 하면 이 문제를 완화시킬 수 있습니다. 다만 컴파일러가 모든 케이스를 자동으로 언박싱할 수 없기 때문에 몇 가지 트릭을 사용하게 되고, 이런 트릭을 모르는 개발자는 속도가 느린 프로그램을 작성할 수밖에 없게 되는 것이죠.

예전에 조엘(Joel) 아저씨가 "The Law of Leaky Abstraction"을 이야기했는데 그 말이 딱 맞아떨어지는 부분입니다. 프로그래밍 언어를 추상화시켜서 내부 구현을 모르도록 만들어놨지만 결국 제대로 사용하려면 내부 구현을 상당 부분 알아야 한다는 것이죠.


GODI

Posted 2008/04/29 20:02
OCaml의 라이브러리(표준 라이브러리 제외)는 GODI 프로젝트를 통해 관리되고 있습니다. GODI 툴 체인(godi_console)을 사용하면 OCaml 라이브러리를 쉽게 설치/제거할 수 있습니다. GODI 라이브러리 목록은 camlcity.org 홈페이지에 링크되어 있는데,  생각보다 별로 많지 않은 것 같네요. Perl의 CPAN와 비교하면 약간 부끄러울 정도랄까요? godi_console로 확인해보니 164개의 라이브러리가 있군요.

GODI로 설치된 OCaml 라이브러리는 다음과 같이 로딩합니다. 예를 들어, Bitmatch라는 라이브러리 로딩하려면 다음과 같이 합니다.


skyul@skyul-desktop:~$ ocaml
        Objective Caml version 3.10.1
# #use "topfind";;
- : unit = ()
Findlib has been successfully loaded. Additional directives:
  #require "package";;      to load a package
  #list;;                   to list the available packages
  #camlp4o;;                to load camlp4 (standard syntax)
  #camlp4r;;                to load camlp4 (revised syntax)
  #predicates "p,q,...";;   to set these predicates
  Topfind.reset();;         to force that packages will be reloaded
  #thread;;                 to enable threads

- : unit = ()
# #require "Bitmatch";;
No such package: Bitmatch
# #require "bitmatch";;
/opt/godi/lib/ocaml/site-lib/bitmatch: added to search path
/opt/godi/lib/ocaml/site-lib/bitmatch/bitmatch.cma: loaded
# open Bitmatch;;
# Bitmatch.create_bitstring 10;;
- : Bitmatch.bitstring = ("\000\000", 0, 10)

OCaml 죽이기

Posted 2008/04/29 00:57
OCaml 프로그램은 이론적으로 절대 크래시가 날 수 없습니다. 외부 모듈(C로 작성된 코드)를 호출한 경우가 아니면 죽을 수가 없게 타입 시스템 자체가 디자인되었기 때문입니다.

하지만 강한 타이핑(strong typing)하는 언어라도 직렬화(OCaml에서는 Linearization 용어 사용, 자바의 Serialization과 같은 개념)를 지원하면 타입 시스템을 얼마든지 깨먹을 수 있게 됩니다. OCaml은 Marshal 모듈을 사용해 직렬화를 하는데, Marshal 모듈을 이용하면 다음과 같이 'a 타입을 'b 타입으로 강제로 바꾸는 함수(C의 캐스팅)를 작성할 수 있습니다.


# let magic_copy a =
    let s = Marshal.to_string a [Marshal.Closures] in
        Marshal.from_string s 0;;
val magic_copy : 'a -> 'b = <fun>


이렇게 작성한 후에 다음과 같이 int 타입을 float로 강제로 변환한 후에 덧셈을 하면 크래시가 발생하고 프로그램이 죽게 됩니다.

# (magic_copy 2 : float)  +. 4.5;;
Segmentation fault



프로그래밍 언어 성능 측정

Posted 2008/04/28 20:40
프로그래밍 언어의 특성 중 실용적인 관점에서 가장 중요한 요소 중 하나는 성능입니다. 요즘 동적 언어가 인기를 얻는 것을 보면 생산성이 성능보다 더 높은 점수를 얻고 있는 것 같긴 하지만, Python이나 Ruby를 .NET이나 JVM으로 포팅해서 HotSpot이나 JIT을 이용하려는 시도는 성능은 여전히 중요한 요소임을 반증합니다. (물론 .NET이나 JVM의 방대한 라이브러리를 재활용하고 다른 언어로 작성된 프레임워크를 사용하려는 목적도 큽니다.)

프로그래밍 언어 자체의 성능은 비교할 수가 없습니다. C 언어라도 컴파일러가 거지같으면 굉장히 느릴 수 있고, 옛날에 느리다고 욕먹던 Java도 근래 많은 최적화를 한 서버 JVM을 사용하면 C/C++과 유사한 정도로 성능이 올라가기도 하니깐요. 따라서 프로그래밍 언어 보다는 프로그래밍 언어의 구현을 놓고 성능을 비교해야 합니다.

그런데 벤치마크라는 게 컴파일러나 인터프리터 몇 개 갖다 놓으면 바로 비교가 되는 것이 아니고 또 별도의 벤치마크 프로그램을 통해 간접적으로 테스트해야만 합니다. 어떻게 벤치마크 할 것이냐를 놓고 이견이 많고 시끄러울 수밖에 없습니다. 어떤 언어는 과학 연산만 죽어라고 하는 벤치마크에는 매우 취약한 반면에 문자열 연산이 많은 벤치마크에는 좋은 성능을 보여줄 수도 있으니깐요.

어느 정도 신빙성이 있는지는 모르겠지만, Debian에서 프로그래밍 언어를 비교하는 벤치마크를 하나 제공하고 있습니다. The Computer LanguageBenchmarks Game인데, Gentoo나 Debian이 깔린 리눅스 머신에서 몇 가지 벤치마크의 성능을 순서대로 보여줍니다. 모든 벤치마크를 모든 언어에 대해 돌려보니, Java 6 -server의 성능이 인상적이고, 함수 언어인 Clean, Haskell GHC, OCaml 등도 상당히 좋네요.

« PREV : 1 : 2 : 3 : 4 : 5 : ... 13 : NEXT »