21
Ninja The Performance of Open Source Application [email protected] 2014. 6. 28.

Ninja

Embed Size (px)

Citation preview

Page 1: Ninja

NinjaThe Performance of Open Source Application

[email protected]

2014. 6. 28.

Page 2: Ninja

Ninja OverviewA small build system with a focus on speed

Page 3: Ninja

Ninja

Make 와 같은 빌드 시스템

작고 속도에 최적화

Google Chrome 용으로 시작

Page 4: Ninja

탄생 배경

Google Chome의 소스 파일 크기는 4만개 이상

전체빌드 소요시간 1시간 (i7, 16GB, SSD)

소스 한 줄 수정후 증분 빌드 시간 5분

대부분 Link 작업에 소요됨

Page 5: Ninja

Chrome의 빌드구조

GYP, 플랫폼 독립적인 타겟 프로젝트 생성

Visual Studio, Xcode, Ninja

빌드에 포함할, .cc, .h 등의 파일들의 나열

Ninja, 컴파일러를 실행하여 빌드할 파일을 생성

커맨드라인 명령의 나열

gcc -c foo.c -o foo.o

Compiler, 실제 빌드 작업을 수행

GYP Ninja Compiler

Page 6: Ninja

Ninja가 하는 일

Rule 생성

!

!

변수 cflags = -Wall rule compile command = gcc $cflags -c $in -o $out

rule compile command = gcc -Wall -c $in -o $out build out/foo.o: compile src/foo.c build out/bar.o: compile src/bar.c

추상화

텍스트 기반, 가독성이 중요

Page 7: Ninja

Ninja가 하는 일

빌드가 필요한 대상을 찾기

빌드 의존성 그래프 생성

특정 노드가 수정되었으면 의존성 그래프에 따라 빌드해야할 집합 생성

실행

빌드가 필요한 그래프 간선을 따라다니며 빌드 실행

Page 8: Ninja

Optimizing NinjaA small build system with a focus on speed

Page 9: Ninja

문자열 파싱Chrome은 10MB 이상의 Ninja 스크립트 파일을 생성함

static bool IsIdentifierCharacter(char c) { return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || // and so on... }

cs = set() for c in string.ascii_letters + string.digits + r'+,-./\_$': cs.add(ord(c)) for i in range(256): print '%d,' % (i in cs),

Lookup Table 이용

Page 10: Ninja

정규화

Ninja는 수많은 파일 경로를 다루므로 최적화된 경로 식별 방법 필요

/bar.h/foo/../bar.h

/bar.h/bar.cc /abc.h /abc.c

경로 객체 경로 비교

0x2000

0x3000

Memory Addr

단순 포인터 비교연산

Page 11: Ninja

빌드 로그

이전 빌드와 새로운 빌드간의 로그를 비교해야함

이 역시 다량의 문자열 비교이므로 병목지점임

문자열 대신 명령의 해시를 기록하고 비교

200MB -> 2MB 미만, 20배 시간 단축

Page 12: Ninja

의존성 파일 분석

#include “bar.h” … foo.c

#include “baz.h” … bar.h

class foo; baz.h

#include “bar.h” …

#include “baz.h” …

class bar;

baz.h 수정

모두 재빌드 필요

Page 13: Ninja

의존성 파일 분석방법들

헤더 스캐너 사용, 느리고 부정확

의존성을 일일이 빌드파일에 수작업으로 명시, 유지보수 어려움

컴파일러가 컴파일시점에 출력하게 함.(gcc, visual studio 모두지원)

gcc -> Makefile 형식으로 의존성 출력

총 용량 약 90MB. 빌드시작할때 이걸 모두 분석한 뒤에 빌드를 시작하기엔 시간소모가 큼

의존성 처리시점을 지연

컴파일이 이뤄지는 동안 Ninja가 하는 일은 컴파일러 프로세스 종료를 대기하는 것 뿐, 이시간을 이용

대기시간동안 의존성 정보파일을 파싱, 정규화, 의존성 처리

Page 14: Ninja

빌드의 실행

빌드 실행성능은 전적으로 컴파일러에 의존

병렬실행의 결과를 버퍼에 저장후 순차적으로 출력

명령행 버퍼링.

빌드 성공시 출력은 단 한줄

Ninja가 빠르다는 느낌을 주는데 일조.

조용히 빠르게 치고 빠진다는 특징에서 Ninja의 이름이 비롯됨

Page 15: Ninja

Windows 이슈명령줄의 최대 길이가 비교적 짧음 (8191 chars)

파일연산이 느림

GetFileAttributesEx()는 리눅스의 stat()보다 100배는 느림

파일 의존성 출력 이슈

Visual Studio 의존성 파일 gcc Makefile 형식

변환파일 생성

Page 16: Ninja

Windows 이슈명령줄의 최대 길이가 비교적 짧음 (8191 chars)

파일연산이 느림

GetFileAttributesEx()는 리눅스의 stat()보다 100배는 느림

파일 의존성 출력 이슈

Visual Studio 의존성 파일 gcc Makefile 형식

변환파일 생성

병목지점

Page 17: Ninja

Windows 이슈명령줄의 최대 길이가 비교적 짧음 (8191 chars)

파일연산이 느림

GetFileAttributesEx()는 리눅스의 stat()보다 100배는 느림

파일 의존성 출력 이슈

Visual Studio Ninja 명령행 버퍼링 기능

gcc Makefile 형식

변환명령행 출력

기존의 명령행 버퍼링 기능을 재사용하여 파일작업 제거

Page 18: Ninja

Design PrinciplesA small build system with a focus on speed

Page 19: Ninja

Design Principles더 최적화 하기, Ninja Daemon

PC에 항상 상주하여 파일수정감시, 성능 향상 가능

하지만 Ninja의 설계 원칙은 Simplicity

단순함은 소프트웨어 설계의 미덕

중요한건 얼마나 단순함을 오래 유지하는가

복잡한 작동방식을 동원하는 대신 작업을 줄임으로써 속도를 올린다는 원칙

Page 20: Ninja

Design Principles최대한 많은 기능들을 다른 도구에 위임

GYP, CMake

Ninja 자신은 빌드를 만들어내는 목표 하나에만 집중

덕분에 다른 프로젝트에서 가져다 조립해 사용하기 쉬움

빠른 빌드의 의미

프로젝트가 가볍다는 인상을 주면 프로젝트를 가지고 노는 것이 즐거워진다

가지고 놀기 좋은 코드가 소프트웨어 작성의 목표

Page 21: Ninja

References

http://martine.github.io/ninja/

http://aosabook.org/en/posa/ninja.html