반응형
Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- FreeBSD
- SQLite
- 구조와 원리
- Golang
- 커널
- Programming
- Preprocessor
- UNIX
- newSQL
- bash
- 포인터변수
- 포인터
- UNIX Internals
- 함수포인터
- kernel
- Pointer
- Windows via c/c++
- 전처리기
- 컴퓨터 강좌
- 약어
- TiDB
- 한빛미디어
- DBMS 개발
- 긴옵션
- getopts
- OS 커널
- go
- TiKV
- Symbol
- DBMS
Archives
- Today
- Total
sonumb
Go - release/debug 모드 빌드하기 - 2 본문
개요
https://sonumb.tistory.com/124
개요 및 전반적인 이야기는 윗 글을 참조하고, 전편에 이어 방안 2에 대한 소스코드를 보여주려한다.
'모드에 따른 빌드하기'의 방안 2에 대해 간단히 설명하자면,
- 빌드시, 빌드모드를 소스코드에 기록하기 (실제로는 하드디스크의 파일의 내용을 바꾼다는 의미가 아니라, 파일 내용을 메모리로 로딩 후, 메모리 내에 변수를 수정한다는 것이다.)
- 코드에 기록된 빌드모드로 동작
이다.
여기서 가장 중요한것은 빌드 모드를 소스코드에 기록하는 것은 "go build -ldflag
" 의 '-X
' 옵션이다. 이에 대한 설명은 아래 링크에서.
소스파일들
main.go
파일
package main
import (
"fmt"
"time"
)
func foo() {
_, _, fnname, err := GetTraceInfo()
if err == nil {
println(fnname)
}
time.Sleep(time.Second)
fmt.Println("foo() : done")
}
func bar() {
Trace()
time.Sleep(1 * time.Second)
fmt.Println("bar() : done")
}
func main() {
foo()
bar()
}
trace.go
파일
package main
import (
"fmt"
"runtime"
"errors"
"strings"
)
type TraceFunc func()
const (
traceMode_Release = iota + 0
traceMode_Debug
traceMode_Max
)
var (
BuildType = "Release"
traceMode = traceMode_Release
)
func init() {
switch BuildType {
case "Release":
traceMode = traceMode_Release
case "Debug":
traceMode = traceMode_Debug
}
if strings.EqualFold(BuildType, "debug") == true {
traceMode = traceMode_Debug
}
}
func GetTraceInfo() (string, int, string, error) {
pc, file, line, ok := runtime.Caller(1)
if ok == false {
return "", 0, "", errors.New("invalid calling")
}
fn := runtime.FuncForPC(pc)
if fn == nil {
return "", 0, "", errors.New("unknown method")
}
return file, line, fn.Name(), nil
}
var trFunc = [traceMode_Max]TraceFunc {
trace_Release,
trace_Debug,
}
func trace_Release() {
// do nothing
}
func trace_Debug() {
pc, file, line, ok := runtime.Caller(1)
if ok == false {
return
}
fnName := ""
fn := runtime.FuncForPC(pc)
if fn != nil {
fnName = fn.Name()
}
fmt.Printf("%s:%d %s()\n", file, line, fnName)
}
func Trace() {
trFunc[traceMode]()
}
Makefile
파일
all: release
DEBUG := "Debug"
release:
go build -o buildSystem2
debug:
go build -ldflags '-X "main.BuildType=Debug"' -o buildSystem2
clean:
rm -f buildSystem2
실행 및 결과
$ make clean all; ./buildSystem2
rm -f buildSystem2
go build -o buildSystem2
main.foo
foo() : done
bar() : done
$ make clean debug; ./buildSystem2
rm -f buildSystem2
go build -ldflags '-X "main.BuildType=Debug"' -o buildSystem2
main.foo
foo() : done
/Users/sonumb/work/go_exam/buildsystem2/trace.go:72 main.Trace()
bar() : done
$
성능 차이
두 방식 간의 성능 차이는 확실히 존재한다. 개념적으로도 함수를 한번 더 호출하는 두 번째 방식이 성능이 떨어질 것으로 예측할 수 있다.
릴리즈 모드, 즉 비어있는 Trace() 함수를 10억번 호출하는데, 아래와 같은 차이가 있다.
방안1: 비어 있는 trace()를 호출 |
방안2: Trace()함수 내에서 함수포인터를 이용한 호출(if문은 없음) |
$ time buildSystem real 0m0.221s user 0m0.217s sys 0m0.003s |
$ time buildSystem2 real 0m1.077s user 0m1.072s sys 0m0.004s |
수치상으로는 5배이지만, 10억회 호출할 동안 다른 일처리(파일, 소켓 I/O)로 인해 이 정도 성능차이는 아주 적게 반영될 것이다.
가령 "10분 0.2초 VS. 10분 1초" 같은 느낌...
따라서, 두 방식간의 차이는 성능보단 구현 용이성 및 형상 관리 측면에서 접근하는 것이 옳을 것으로 판단된다.
반응형