LoginSignup
3
3

More than 5 years have passed since last update.

Goでリリースビルド時にコンパイルから外れるassertionパッケージつくったよー

Last updated at Posted at 2017-05-25

はじめに

  • assert 無いの不便
  • panic でもいいけどリリースビルドには含めたくない
  • go build 時に -tags=release するとコンパイルから省かれる assertion パッケージつくった

つくったもの

追記

よくよく考えたら if の中で panic するのと同じかー。Equalsとかはむしろ関数呼び出し分遅くなる。

結論 : ビルド時に行単位で消し去る方法ほしい

さらに追記

  • パフォーマンス重視の場合のために、定数 assert.ENABLED を追加。constなのでインライン化されて消える。
if assert.ENABLED && v != 1 {
    panic(assert.NewMsg(v, 1))
}
  • 入力引数評価のせいで遅くなるのを回避するために関数で渡すように変更し、 1 ns/op まで高速化
assert.Equals(func() (assert.G, assert.W) { return v, 1 })
assert.WithMsg(func() (bool, string) { return v == 1, assert.NewMsg(v, 1) })

つかいかた

これだけ。アサーションエラーすると問答無用で panic します。

import "github.com/ryskiwt/assert-go"

v := 1

// CASE 1 (about 0.33 ns/op)
if assert.ENABLED && v == 0 {
    panic(assert.DefaultMsg)
}
// -> panic: assrtion error


// CASE 2 (about 0.33 ns/op)
assert.Do(v == 0)
// -> panic: assrtion error


// CASE 3 (about 1.00 ns/op)
assert.Equals(func() (assert.G, assert.W) { return v, 0 })
// -> panic: assrtion error: got=1, want=0


// CASE 4 (about 1.00 ns/op)
assert.WithMsg(func() (bool, string) {
    return v == 0, assert.NewMsg(v, 0)
})
// -> panic: assertion error: got=1, want=0

ビルド時のはぶきかた

Build for Debug

普通にビルドするとアサーションは省かれる

$ go build

Build for Release

-tags=assert つけてビルドするとアサーションが有効になる

$ go build -tags=assert

ベンチマーク

結果

$ go test -run NONE -bench . -benchmem                                                                                                                    +[develop]
testing: warning: no tests to run
BenchmarkNone-4             2000000000           0.31 ns/op        0 B/op          0 allocs/op // no assertion
BenchmarkFlag_True-4        2000000000           0.33 ns/op        0 B/op          0 allocs/op // fastest
BenchmarkDo_True-4          2000000000           0.31 ns/op        0 B/op          0 allocs/op // fastest
BenchmarkEquals_True-4      2000000000           1.01 ns/op        0 B/op          0 allocs/op // 3 times slower
BenchmarkWithMsg_True-4     2000000000           0.96 ns/op        0 B/op          0 allocs/op // 3 times slower
BenchmarkDo_False-4         2000000000           0.32 ns/op        0 B/op          0 allocs/op
BenchmarkFlag_False-4       2000000000           0.31 ns/op        0 B/op          0 allocs/op
BenchmarkEquals_False-4     2000000000           1.11 ns/op        0 B/op          0 allocs/op
BenchmarkWithMsg_False-4    2000000000           1.03 ns/op        0 B/op          0 allocs/op
PASS
ok      github.com/ryskiwt/assert-go    12.039s
  • boolで渡す assert.Do か、 assert.ENABLED の場合はほぼ影響なし (0.33 ns/op)
  • funcで渡す assert.Equalsassert.WithMsg は3倍くらい遅い (1.00 ns/op)
$ go test -run NONE -bench . -benchmem -tags=assert                                                                                                       +[develop]
testing: warning: no tests to run
BenchmarkNone-4             2000000000           0.31 ns/op        0 B/op          0 allocs/op
BenchmarkFlag_True-4        2000000000           0.32 ns/op        0 B/op          0 allocs/op
BenchmarkDo_True-4          1000000000           1.95 ns/op        0 B/op          0 allocs/op
BenchmarkEquals_True-4      30000000            58.8 ns/op        16 B/op          2 allocs/op
BenchmarkWithMsg_True-4      5000000           335 ns/op          64 B/op          4 allocs/op
BenchmarkDo_False-4         panic: assertion error

goroutine 27 [running]:
panic(0xe5c40, 0xc420490030)
    /usr/local/Cellar/go/1.7.3/libexec/src/runtime/panic.go:500 +0x1a1
pgithub.com/ryskiwt/assert-go.Do(0x16fedc00)
    /path/to/repos/src/github.com/ryskiwt/assert-go/debug.go:9 +0x80
pgithub.com/ryskiwt/assert-go_test.BenchmarkDo_False(0xc4200ac280)
    /path/to/repos/src/github.com/ryskiwt/assert-go/benchmark_test.go:47 +0x3e
testing.(*B).runN(0xc4200ac280, 0x1)
    /usr/local/Cellar/go/1.7.3/libexec/src/testing/benchmark.go:139 +0xaa
testing.(*B).run1.func1(0xc4200ac280)
    /usr/local/Cellar/go/1.7.3/libexec/src/testing/benchmark.go:208 +0x5a
created by testing.(*B).run1
    /usr/local/Cellar/go/1.7.3/libexec/src/testing/benchmark.go:209 +0x7f
exit status 2
FAIL    github.com/ryskiwt/assert-go    7.332s

おわりに

  • 関数の中身を空にしとけば、インライン展開されて消えてなくなるかな〜と期待したけど甘かった(引数は評価されちゃう)
  • Golangの関数呼び出し結構コスト高い
  • 低レイヤあんまり分かってない素人の作なので、つっこみください
  • インターフェース使いにくいとかもコメントください。改善します
  • 既出だよ馬鹿野郎っていうのも、つっこみください(あるならそっち使いたい)

本日は以上です。

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3