Golangでpanicを含んだ関数のテストの書き方

package main

import "fmt"

func main() {
    fmt.Println(a(2))
    fmt.Println(a(0.2))
}

func a(number float64) float64 {
    if number < 1 {
        panic("must be number >= 1")
    }
    return number * number
}
package main

import (
    "fmt"
    "testing"
)

func TestA(t *testing.T) {
    tests := []struct {
        Number float64
        Panic  bool
        Want   float64
    }{
        {
            Number: 1,
            Panic:  false,
            Want:   1,
        }, {
            Number: 2,
            Panic:  false,
            Want:   4,
        }, {
            Number: -1,
            Panic:  true,
            Want:   0,
        },
    }
    for i, test := range tests {
        if test.Panic {
            f := func() { a(test.Number) }
            s := fmt.Sprint("case ", i)
            testpanics(f, s, t)
            continue
        }
        if a(test.Number) != test.Want {
            t.Errorf("mismatch case %v: expected %v,  foud %v", i, test.Number, test.Want)
        }
    }
}

func panics(f func()) (b bool) {
    defer func() {
        err := recover()
        if err != nil {
            b = true
        }
    }()
    f()
    return
}

func testpanics(f func(), name string, t *testing.T) {
    b := panics(f)
    if !b {
        t.Errorf("%s shoud panic and does not", name)
    }
}

参考

https://github.com/gonum/blas/blob/447542bc23b84f8daa64470951a57bb6713d15a1/testblas/level1double.go

https://github.com/gonum/blas/blob/447542bc23b84f8daa64470951a57bb6713d15a1/testblas/common.go

github.com

from twitter❤

twitterの❤を本来の使いみち以外に「リンク先をあとでよむ」と「有意義なメモ」の使い方をしてるけど、最近消化不良気味だったのでこっちに振り返りながらメモ。

最近、将棋AIー>碁AIと流行ってるけど、オセロAIが研究されてたのはそのちょっと前? 自分ではじめてゲーム探索を書いた時にも「リバーシアルゴリズム」という本を参考にした。このときはCODEVSだったのでオセロAIも一度やってみたい。

最近、全探索を見逃しがち

自分のやりたいことは機械学習、深層学習よりも強化学習よりなのかなと思い始めた

大学で助教と一緒に検討した時はmoodleでできるようしたいと話をしたことがある、その後進展はない。

じつはc++のnext_permutationが未だに理解できない

第一志望だった研究室もcookpadからデータを提供されてなにかしたっぽい

やるやる詐欺をしてしまった人狼知能。標準入出力形式にならないかなあ・・・

はまった

組み合わせ・順列の実装は未だに苦手

わかる

ただのリンク集の記事になってしまった。

Linux Mint デスクトップ環境 2017

k0kubun.hatenablog.com

インスパイアです。

そもそもなぜLinuxデスクトップをつかているのか

自作PCでLinuxMintを使っているので環境を揃えたかった。 あとはインスパイア元とほぼ一緒。 環境は自作機PCとMacBookPro(late2013) どちらも英語キーボードを使用

現在のLinuxデスクトップ環境

ディストリビューション: Linux Mint Cinnamon 18.1

UbuntuがUnityを使い始めてからは、Linux Mintに移行しました。 Cinnamonは3Dアクセラレータ推奨ですが、自分の環境では困らない。 MATE(またはUbuntu MATE)と比較すると、好みの問題だと思います。

キーリマッパー:xmodmap+xcape

SandS用に使ってます。

windymelt.hatenablog.com

ターミナル: terminator

F12キーで表示の切り替えができるように、キーの割り当て -> hide_window をF12にしてます。 “~"がでてきて、うまく動かないときは別にGuake Terminalをインストールしておくと治ったりします。

日本語入力: Fcitx+mozc

fcitxの設定->全体の設定(タブ)->拡張オプションの表示☑->

“入力メソッドをオンに" Ralt

“入力メソッドをオフに" Lalt

で, 元karabiner風の切り替えにします。

フォント: デフォルト

ブラウザ:Google Chrome

ツイッター:Google Chrome

パスワードマネージャー: 1Password(iPhone)

これはこれからどうしようか迷い中 とりあえず,よく使うパスワードはGoogleChromeに覚えさせてはいる

音楽プレイヤー: 作業用BGMを検索

最近はアベマTVがつけっぱなしです。。。

MacBookProでのインストー

追記 2017/07/07
なにげなくクリーンインストールしたら、macOSが消えたのでこの方法はおすすめしません。
単に自分が操作を間違えた可能性もありますが、参考にするときは自己責任です。

自作PC(LinuxMint)の"USBイメージライタ"を使って、ダウンロードしたLinux Mintのisoを焼きます。 (MacBookProの)ディスクユーティリティでLinux用のパーテーションを作り電源を切る。 Linux Mintの入ったUSBをMacBookProに挿してoptionキーを押しながら起動させればUSBの"EFI boot"がでてくるので選択してGRUBの画面に進みます、そこでLinux Mintを選択して起動させます。 文字が小さいので Menu->General->Desktop Scaling でDouble(Hi-DPI)を選択します。(これはインストール後にもやります) デスクトップのInstall Linux Mintを選択して、進んでいきます。 Installation type では一番下のSomething elseを選択して、あとはいい感じに進んでください(自己責任で)

このやり方でインストールすると、MacBookProを起動した時はLinux Mintが立ち上がります。macOSを起動させたいときはoptionキーを押しながら起動してHDDを選択します。

起動時に毎回選択したいときにはrEFIndを使うか、GRUBmacOS(/System/Library/CoreServices/boot.efi)を追加する等があるようですがやってません(後者を試したが失敗)。

キーボード

MacBookProのUSキーボードはスペースキーの左右にcommandキーがありますが、自作PCはaltなので後者に合わせます。 menu -> Keyboard -> Options… -> Alt/Win key behavior で Alt is swapped with Win を☑します。 お好みで Ctrl key posotionで Swap Ctrl and Caps Lock を ☑

Function Key

ファンクションキーをデフォルトで使用したいので以下の設定を使う。 AppleKeyboard - Community Help Wiki With .conf file (Recommended)

$ echo options hid_apple fnmode=2 | sudo tee -a /etc/modprobe.d/hid_apple.conf
$ sudo update-initramfs -u -k all
$ sudo reboot

自作PCとMBPではMintの設定言語が違う(日本語と英語)ので記事内ではちょっと混じっちゃいました。

おしまい。

Go言語のpprofとFlameGraph

Go pprof 入門編 (CPU Profile とコマンドラインツール) : KLabGames Tech Blog

Go で利用できるプロファイリングツール pprof の読み方 - Qiita

GolangでFlame Graphを描く | SOTA

GitHub - pkg/profile: Simple profiling for Go

GitHub - uber/go-torch: Stochastic flame graph profiler for Go programs

GitHub - brendangregg/FlameGraph: stack trace visualizer

上記のリンクを参考に先日行われたCODEVSforSTUDENTのプログラムのFlameGraphをだします

予選落ち(全体25位学生18位)しましたが、決勝進出者のプログラム提出日はまだ先なので、細かいことは書きません。

CODE VS for STUDENT 予選7位! - ぴろずメモ

www.youtube.com

pkg/profile

Go言語には標準にプロファイル用のruntime/pprofnet/http/pprofがありますが、runtime/pprofを使いやすくした、Dave Cheney氏のpkg/profileを使います。(元runtime/pprof)

go get github.com/pkg/profile

インストールしてmain関数に1行加えるだけです。

import "github.com/pkg/profile"

func main() {
    defer profile.Start().Stop()
    ...
}

テストには実際の試合の入力ログを使いますが、試合終了のフラグがないのでログの最後にENDを加えて、ソースコードも正常終了させるように変更しておきます。

実際にビルドして、実行します。

[fmhr@Sarah] ~/Dropbox/projects/CODEVS/CODEVSforSTUDENT/go
% go build -o tmp/outprofile src/*.go                                       
[fmhr@Sarah] ~/Dropbox/projects/CODEVS/CODEVSforSTUDENT/go
% tmp/outprofile < sampleInput/1P_20161111_135322_00000000000000000000_00003_stdin.txt
2016/11/21 14:30:43 profile: cpu profiling enabled, /tmp/profile918389017/cpu.pprof
fmhr
W: 4000 H: 5 s: 2000
[1 1 8 8 11]
0(0)0 / 0(0)0
0 0
0 turn: -180 / 180
[1 6 7 11 20]
3(0)0 / 3(0)0
5 0
1 turn: 1.64 / 178.36
[4 4 8 20 16]
6(0)0 / 6(0)0
6 1
()
40 turn: 0.014 / 102.107
GAMEOVER
0 0
41 turn: 0.006 / 102.101
SetTurnSet失敗
2016/11/21 14:32:16 profile: cpu profiling disabled, /tmp/profile918389017/cpu.pprof

デバッグ用のエラー出力と試合用の出力も入ってます(この試合は40ターン目で負けたみたいです)SetTurnSet失敗が追加したENDを読み込んでループから抜けています。

とりあえず、/tmp/profile918389017/cpu.pprofができてることが1行目でわかる。 これを見てみます。

% go tool pprof /tmp/profile918389017/cpu.pprof    
Entering interactive mode (type "help" for commands)
(pprof) top5
79.84s of 98.22s total (81.29%)
Dropped 130 nodes (cum <= 0.49s)
Showing top 5 nodes out of 58 (cum >= 2.62s)
      flat  flat%   sum%        cum   cum%
    56.09s 57.11% 57.11%     66.24s 67.44%  main.deleteLoop
     9.67s  9.85% 66.95%      9.67s  9.85%  runtime.duffcopy
     7.25s  7.38% 74.33%      7.45s  7.59%  main.moveBlock
     4.21s  4.29% 78.62%      6.93s  7.06%  runtime.scanobject
     2.62s  2.67% 81.29%      2.62s  2.67%  math/rand.(*rngSource).Seed
(pprof) 

main.deleteLoop関数が実行時間の6割を占めてるのがわかります。 この関数はゲーム内のフィールドを縦横斜め(2回)を走査して、消えるブロックがなくなるまでループする、ゲームのシミュレータの主要部分です。 (pprof) web をするとグラフにしてくれるのですが見え過ぎるで今回はお預けします。

この結果を使って、FlameGraphをみてみます。

Go言語のpprofからflame graphを見るためには、uber/go-torchを使います。

GitHub - uber/go-torch: Stochastic flame graph profiler for Go programs

go get github.com/uber/go-torch
[fmhr@Sarah] ~/Dropbox/projects/CODEVS/CODEVSforSTUDENT/go
% cd /tmp/profile918389017        
[fmhr@Sarah] /tmp/profile918389017
% ls
cpu.pprof
[fmhr@Sarah] /tmp/profile918389017
% go-torch cpu.pprof 
INFO[15:09:41] Run pprof command: go tool pprof -raw -seconds 30 cpu.pprof
FATA[15:09:41] Failed: could not generate flame graph: Cannot find flamegraph scripts in the PATH or current directory. You can download the script at https://github.com/brendangregg/FlameGraph. These scripts should be added to your PATH or in the directory where go-torch is executed. Alternatively, you can run go-torch with the --raw flag.

肝心のflame graphがはいってませんでした。 PATHかディレクトリにスクリプトを入れろと言われてます。今回は必要なスクリプトだけつっこんでおきます。

[fmhr@Sarah] /tmp/profile918389017
% wget https://raw.githubusercontent.com/brendangregg/FlameGraph/master/stackcollapse-perf.pl
% wget https://raw.githubusercontent.com/brendangregg/FlameGraph/master/flamegraph.pl

パーミションを変更して実行可能にします

% chmod 777 flamegraph.pl stackcollapse-perf.pl 

これで準備完了です。

flame graph

[fmhr@Sarah] /tmp/profile918389017
% go-torch cpu.pprof                           
INFO[15:18:02] Run pprof command: go tool pprof -raw -seconds 30 cpu.pprof
INFO[15:18:02] Writing svg to torch.svg

目的のtorch.svgがでてきました。 (hatenablogにsvgファイルが出せないようなので、jpegに変換してます) f:id:fmhr29:20161121153128j:plain おしまい

Go言語によるWebアプリケーション開発

ソースコードの写生をまるまる1冊したのははじめてだった。テストを先に書く部分(TDD)があるのだけど、エディタ(Intellij)で真っ赤にエラーだしながら進めるのはとても気持ち悪かった。筆者の頭の中に設計があるからできることだと思うんだけど、本に書いてあってほしかった。

p.106 12行目

[誤] log.Faralf("%qに類語はありませんでした\n")
[正] log.Faralf("%qに類語はありませんでした\n", word)