Go 안의 Go
고퍼 페스티벌
2015년 5월 26일
롭 파이크
구글
키보드 오른쪽, 혹은 마우스로 우측 가장자리 클릭^^
Go in Go
Gopherfest
26 May 2015
Rob Pike
롭 파이크
구글
키보드 오른쪽, 혹은 마우스로 우측 가장자리 클릭^^
Rob Pike
음.. 몇일 후에 GO 1.5 에 대해 이야기하는 자리에 가게 되어서..
개발끈이 짧다보니.. 뭐라도 준비해갈까..해서 그냥 눈에보이는 걸
급하게 번역해봤습니다. 구글번역기 정도의 번역입니다 ;;
화면 우측 상단에 번역 버튼을 올리오니, 헷갈리실때는 영어를 직접 보시고
잘못된 것이 있으면 연락주시면 바로 고쳐보겠습니다. 감사합니다.
음.. 몇일 후에 GO 1.5 에 대해 이야기하는 자리에 가게 되어서..
개발끈이 짧다보니.. 뭐라도 준비해갈까..해서 그냥 눈에보이는 걸
급하게 번역해봤습니다. 구글번역기 정도의 번역입니다 ;;
화면 우측 상단에 번역 버튼을 올리오니, 헷갈리실때는 영어를 직접 보시고
잘못된 것이 있으면 연락주시면 바로 고쳐보겠습니다. 감사합니다.
GO의 1.5 버젼을 맞이하여 , 이제 전체적 시스템은 Go로 쓰여졌습니다.
(그리고 조금의 어셈블러 ^^)
C 는 가버렸습니다.
Side note: gccgo 는 여전히 존재하며
이 talk는 기본 컴파일러, gc에 대해 이야기합니다.
As of the 1.5 release of Go, the entire system is now written in Go.
(And a little assembler.)
C is gone.
Side note: gccgo is still going strong.
This talk is about the original compiler, gc.
Bootstrapping을 위해서죠. (컴퓨터 용어라.. 뭐.. )
(또한 Go는 처음에는 컴파일러 구현 언어로 의도되지 않았습니다. )
Bootstrapping.
(Also Go was not intended primarily as a compiler implementation language.)
입증(validation)을 위한 게 아닌 좀더 실용적인 이유였습니다 :
다음과 같은 잇점을 봤을 때 , 아직 이르긴 합니다.
디자인 문서: golang.org/s/go13compiler
Not for validation; we have more pragmatic motives:
Already seeing benefits, and it's early yet.
Design document: golang.org/s/go13compiler
우리는 단지 런타임 컴파일을 하는 우리의 C컴파일러를 가지고 있었습니다.
우리는 Go로된 단편스택같은, 같은 방식의 ABI를 가진 컴파일러를 원했었습니다.
(헷갈림)
Go로의 전환은 C컴파일러를 제거한다는 것을 의미합니다.
이것은 컴파일러를 GO로 전환하는 것보다 더 중요합니다 .
( 컴파일러 전환의 모든 이유가 runtime에도 적용이 되었습니다.)
오직 하나의 언어가 runtime에 있고, 통합과 스택관리가 쉬워졌습니다.
언제나, 단순성이 가장 고려되었습니다.
We had our own C compiler just to compile the runtime.
We needed a compiler with the same ABI as Go, such as segmented stacks.
Switching it to Go means we can get rid of the C compiler.
That's more important than converting the compiler to Go.
(All the reasons for moving the compiler apply to the runtime as well.)
Now only one language in the runtime; easier integration, stack management, etc.
As always, simplicity is the overriding consideration.
왜 우리는 우리의 도구를 가지고 있을까요?
우리들의 ABI?
우리들의 파일형식?
역사, 친숙함, 나아가기 쉬움. 그리고 속도
GCC, LLVM과 함께 많은 Go의 큰 변화는 더 힘이 들 것입니다.
Why do we have our own tool chain at all?
Our own ABI?
Our own file formats?
History, familiarity, and ease of moving forward. And speed.
Many of Go's big changes would be much harder with GCC or LLVM.
도구를 가지고, Go로 가서 쉬워진 모든 것들 :
마지막 세가지들은 C에서 불가능한 것입니다. :
(Gccgo 는 아직 단편된 스택, 부정확한(스택) 콜렉션을 한동안 가집니다.)
All made easier by owning the tools and/or moving to Go:
The last three are all but impossible in C:
(Gccgo will have segmented stacks and imprecise (stack) collection for a while yet.)
이것들은 각각 큰 발걸음이었고, 빠르게 만들어져갔습니다.(led by khr@).
These were each huge steps, made quickly (led by khr@).
기계의 도움과 수작업으로 많은 것들이 이뤄졌습니다.
안전한 언어에서 런타임을 구현하는 것은 도전이었습니다.
예를 들어서 GC에서 포인터들을 raw bits로 다루기 위해 unsafe 가 사용된 경우가 있긴 합니다.
그러나 당신이 생각하는 것만큼은 많지 않습니다.
다음 세션의 어떤 번역자(여기선 C에서 Go로의 전환을 도와준 사람을 일컫는 듯?:역주) 가 translation(전환)을 많이 도와줬습니다.
Mostly done by hand with machine assistance.
Challenge to implement the runtime in a safe language.
Some use of unsafe to deal with pointers as raw bits in the GC, for instance.
But less than you might think.
The translator (next sections) helped for some of the translation.
왜 처음부터 시작하지않고, 전환을 했냐구요? 정확함과 테스트를 위해서였습니다.
단계:
Why translate it, not write it from scratch? Correctness, testing.
Steps:
첫번째 출력은 (안좋게) GO로 변환되는 한라인씩의 C 였습니다.
이것을 위한 도구는 rsc@로 쓰여졌습니다. (GopherCon 2014 에서 얘기했었죠)
이 일을 위해서 일반적인 C-go 변환기가 아니라 커스터마이징해서 썻습니다.
단계:
yacc)*p++ 같은 C 비슷한 것들은 지우거나 다시 쓰여졌습니다.
Yacc 문법은 sam-powered hands으로 변환되었습니다.
First output was C line-by-line translated to (bad!) Go.
Tool to do this written by rsc@ (talked about at GopherCon 2014).
Custom written for this job, not a general C-to-Go translator.
Steps:
yacc)*p++ as an expression
The Yacc grammar was translated by sam-powered hands.
손으로 다시쓰여진 다음과 같은 룰에 의하여 도움을 받습니다. :
표준 라이브러리를 사용하는 것과 같은 것들을 위해 diff같은 것들이 다시 쓰여졌습니다:
diff {
- g.Rpo = obj.Calloc(g.Num*sizeof(g.Rpo[0]), 1).([]*Flow)
- idom = obj.Calloc(g.Num*sizeof(idom[0]), 1).([]int32)
- if g.Rpo == nil || idom == nil {
- Fatal("out of memory")
- }
+ g.Rpo = make([]*Flow, g.Num)
+ idom = make([]int32, g.Num)
}Aided by hand-written rewrite rules, such as:
Also diff-like rewrites for things such as using the standard library:
diff {
- g.Rpo = obj.Calloc(g.Num*sizeof(g.Rpo[0]), 1).([]*Flow)
- idom = obj.Calloc(g.Num*sizeof(idom[0]), 1).([]int32)
- if g.Rpo == nil || idom == nil {
- Fatal("out of memory")
- }
+ g.Rpo = make([]*Flow, g.Num)
+ idom = make([]int32, g.Num)
}언어간의 다른 시멘틱한 차이때문에 발생합니다.
diff {
- if nreg == 64 {
- mask = ^0 // can't rely on C to shift by 64
- } else {
- mask = (1 << uint(nreg)) - 1
- }
+ mask = (1 << uint(nreg)) - 1
}This one due to semantic difference between the languages.
diff {
- if nreg == 64 {
- mask = ^0 // can't rely on C to shift by 64
- } else {
- mask = (1 << uint(nreg)) - 1
- }
+ mask = (1 << uint(nreg)) - 1
}
Go 에서는, 새로운 도구 grind 가 개발되었습니다. (by rsc@):
프로파일링과 다른 분석들에 의한 변화들:
var 선언을 처음 사용 근처로 두기
Once in Go, new tool grind deployed (by rsc@):
Changes guided by profiling and other analysis:
var declarations nearer to first use
변환기에 의한 출력은 보잘것없는 Go 였습니다. 그리고 10배 느리게 동작했엇습니다.
많은 속도지연이 복구되었습니다.
C 에서 GO로 가면서 나왔던 문제들 :
for 반복문들fmt.Stringer vs C의 varargs
unions는 없고 structs 로 대신함 :부풀어짐
씨 컴파일러는 많은 메모리를 자유롭게 하지 않지만(해제?), Go는 GC를 가집니다.
CPU와 메모리에 오버헤드를 증가시킵니다.
Output from translator was poor Go, and ran about 10X slower.
Most of that slowdown has been recovered.
Problems with C to Go:
for loopsfmt.Stringer vs. C's varargsunions in Go, so use structs instead: bloat
C compiler didn't free much memory, but Go has a GC.
Adds CPU and memory overhead.
프로파일! (이전엔 안했음!)
vars 를 처음 사용에 가깝게 함vars 를 복합적으로 쪼갬(split)math/big
struct필드들을 결합하기 위한 인터페이스나 다른 비법들
drchase@).대부분의 성능fix같은 문제들을 위해
grind, gofmt -r and eg와 같은 툴을 이용하세요.
디버깅 프린트 라이브러리에서 인터페이스 아규먼트를 지우는 것은 전반적으로 15% 를 얻습니다! !
더 많이 해야할 것이 많이 남았습니다.
Profile! (Never done before!)
vars closer to first usevars into multiplemath/bigstruct fieldsdrchase@).
Use tools like grind, gofmt -r and eg for much of this.
Removing interface argument from a debugging print library got 15% overall!
More remains to be done.
변환의 다른 잇점들:
GC는 더 이상 늘어진?, 매달린(dangling) 포인터가 생기는 것에 대해 걱정할 필요가 없다는 것을 말합니다.
백엔드부분이 정리될 기회입니다.
툴 체인 도처에 통합된 386 and amd64 아키텍쳐들
새로운 아키텍쳐가 추가되기 쉬워졌습니다.
통합된 도구들 : 이제는 하나의 컴파일러, 하나의 어셈블러, 하나의 링커.
Other benefits of the conversion:
Garbage collection means no more worry about introducing a dangling pointer.
Chance to clean up the back ends.
Unified 386 and amd64 architectures throughout the tool chain.
New architectures are easier to add.
Unified the tools: now one compiler, one assembler, one linker.
GOOS=YYY GOARCH=XXX go tool compile
하나의 컴파일러; 더이상은 6g, 8g 등등 없습니다 .
5만줄의 포터블한 코드에 관해서.
registerizer가 지금 포터블하지만, 아키텍쳐들은 잘 특징지어졌습니다.
포터블하지 않은 것들 : Peepholing, 사양서에 묶여진 레지스터들.
일반적으로 포터블한 LOC 의 10% 정도..
GOOS=YYY GOARCH=XXX go tool compile
One compiler; no more 6g, 8g etc.
About 50K lines of portable code.
Even the registerizer is portable now; architectures well characterized.
Non-portable: Peepholing, details like registers bound to instructions.
Typically around 10% of the portable LOC.
GOOS=YYY GOARCH=XXX go tool asm
새로운 어셈블러, Go에 모두 있고, 처음부터 r@로 쓰여짐 .
깨끗하고 자연스러운 GO 코드
4000라인 이하, 10%의 기계의존
이전의 yacc과 C 어셈블러와 완벽하게 호환가능
어떻게 이게 가능할까요?
liblink, 지금은 internal/obj)
GOOS=YYY GOARCH=XXX go tool asm
New assembler, all in Go, written from scratch by r@.
Clean, idiomatic Go code.
Less than 4000 lines, <10% machine-dependent.
Almost completely compatible with previous yacc and C assemblers.
How is this possible?
liblink, now internal/obj)
GOOS=YYY GOARCH=XXX go tool link
대부분 C코드에서 수작업-변환, 머신- 변환
오리지널 링커의 일부인 새로운 라이브러리, internal/obj는 기계에 관한 세부사항을 캡쳐하고 오브젝트 파일을 씁니다.
4개의 아키텍쳐들에서 2만 7천 라인 , 대부분 테이블 (과 약간의 안 좋은 것들 )
arm: 4000arm64: 6000ppc64: 5000x86: 7500 (386 and amd64)Example benefit: one print routine to print any instruction for any architecture.
GOOS=YYY GOARCH=XXX go tool link
Mostly hand- and machine- translated from C code.
New library, internal/obj, part of original linker, captures details about machines, writes object files.
27000 lines summed across 4 architectures, mostly tables (plus some ugliness).
arm: 4000arm64: 6000ppc64: 5000x86: 7500 (386 and amd64)Example benefit: one print routine to print any instruction for any architecture.
C 컴파일러가 아닌, 부트스트래핑하는데 GO 컴파일러가 필요
그러므로 소스로부터 1.5를 빌드하기 위해서는 작동하는 GO를 다운로드하거나 빌드하세요. (build 가 두번이나 들어가서..대충 번역합니다;)
우리는 Go 1.4 버젼을 Go 1.5+툴체인을 빌드하기 위한 베이스로 여깁니다. (그 이상버젼도 좋습니다. )
With no C compiler, bootstrapping requires a Go compiler.
Therefore need to build or download a working Go installation to build 1.5 from source.
We use Go 1.4+ as the base to build the 1.5+ tool chain. (Newer is OK too.)
Details: golang.org/s/go15bootstrap
많은 작업을 여전히 하고 있는 중이구요. 1.5 는 거의 완료되었습니다.
미래의 작업:
더 나은 escape 분석
SSA를 사용하는 새로운 컴파일러 백엔드 (C보다 훨씬 쉬운 Go쪽으로)
더 나은 최적화를 가능케 할 것입니다.
PDF(나 xml)로 부터 기계 설명을 생성해낼 것입니다.
순수히 기계-생성된 명령 정의를 가질 것입니다 :
:
"PDF를 읽고 어셈블러 설정을 써낼 것입니다. ".
이미 역어셈블러들을 위해 deploy되었습니다.
Much work still to do, but 1.5 is mostly set.
Future work:
Better escape analysis.
New compiler back end using SSA (much easier in Go than C).
Will allow much more optimization.
Generate machine descriptions from PDFs (or maybe XML).
Will have a purely machine-generated instruction definition:
"Read in PDF, write out an assembler configuration".
Already deployed for the disassemblers.
프로젝트에서 C를 제거하는 것은 큰 진척사항입니다.
코드가 좀더 깔끔해지고 테스트가능해지고 프로파일가능해지고 작업하기 쉬워졌습니다.
새로운 통합된 툴체인이 코드의 양을 줄여주고, 유지보수성을 증가시켜줍니다.
유연한 툴체인, 휴대성은 여전히 중요하게 여겨집니다 .
Getting rid of C was a huge advance for the project.
Code is cleaner, testable, profilable, easier to work on.
New unified tool chain reduces code size, increases maintainability.
Flexible tool chain, portability still paramount.