벤치마크와 프로파일링의 결과가 서로 상충될때
By SeukWon Kang
작업하고 있는 goguelike2에서 사용하는 작은 패키지 하나를 github 공개 repository 에 올렸습니다.
https://github.com/kasworld/wrapper
인데
내용을 보면 뭐 이런 간단한 걸 올린 것일까? 하고 생각할만한 패키지입니다.
패키지의 기능은 최대 값이 있는 정수가 범위를 벗어 나지 않도록 wrap around 해주는 것입니다.
실제 사용은 오른 쪽 끝을 넘어가면 왼쪽으로 나와서 무한해 보이는 필드 를 만들기 위한 기능을 제공하기 위해서 만든 것인데.
원래는 func WrapInt(v, l int) int { return (v%l + l) % l }
같이 아주 간단한 함수를 만들어 사용하고 있었습니다.
그나마 위 함수도 v의 값이 아주 크거나 아주 작을 때도 작동하게 하기 위한 고려가 되어 있습니다.
문제는 언제 나처럼
go tool pprof “http://localhost:9002/debug/pprof/profile”
같이 프로파일을 돌려 보니
어마 무지한 시간을 (거의 25% 정도? ) 잡아 먹고 있던 것이었습니다.
어라 % 가 비록 나누셈 이긴 하지만 현대의 x86-64가 나누기가 그렇게 느리다고?
그럼 테이블 기반으로 바꿔볼까? 하고 만든 것이 wrapper 입니다.
다만 테이블 기반이기 때문에 상정 범위 밖 일때는 에러가 ( out of index 같은 ) 나게 됩니다.
상정 범위는 프로그램상 제어 가능한 범위인
폭이 W 일때 -W 에서 +2*W 이내 입니다.
그리고 프로파일을 돌렸더니 기대한대로 사용량이 확 줄어 들더군요.
그래서 한껀 해결! 하고 있었는데 좀 찜찜해서 여러 형태의 wrapper 함수들을 만들고
benchmark 를 해보았습니다.
go test -bench=.
goos: linux
goarch: amd64
pkg: github.com/kasworld/wrapper
BenchmarkWrap-8 1000000 1634 ns/op
BenchmarkWrapTable-8 1000000 1645 ns/op
BenchmarkWrapSimple-8 1000000 1635 ns/op
BenchmarkWrapFull-8 1000000 1227 ns/op
BenchmarkWrapIf-8 500000 2494 ns/op
BenchmarkWrapIfSimple-8 1000000 1546 ns/op
PASS
ok github.com/kasworld/wrapper 9.053s
과 같이 나옵니다.
wrapfull함수가 위의 wrapint함수의 구현 입니다. 가장 빠르지요.
뭔가 이상해서 ( 프로파일 결과와 벤치마크 결과가 상충되는 ) 살펴봐도 현재까지는 이유를 못 찾고 있습니다.