クラウドでASICを利用する時代の必読論文が出ていたので紹介する(Bitcoin、Litecoin、H.265動画変換、ディープラーニング用のASIC試作/検討からのあふれる知見:ISCA2016)

2016年8月24日水曜日

どのような論文か

クラウドを構築するデータセンターでのASIC(特定用途向け集積回路)利用が伸びるというのを大前提として(実際、お金に直結するBitcoinではASICマイニングが主流だから当然だよね!と)、業界の流れ分析に始まり各種ワークロードの特性分析から総所有コスト最適化、排熱シミュレーションまでを幅広く扱った論文です。超オススメです。
次のURLから入手できます。
最初にこの論文を読んだ時は、12ページ(参照込みで13ページ)とコンパクトながら怒涛の情報量であったため、大変衝撃を受けました。「特に読むべきポイントは?」と聞かれたら「全部!」と答えたいところですが、せっかくなので本エントリではいくつかポイントを絞って紹介してみます。
ちなみに発表資料内で「今回の研究のために8種類のBitCoinマイナー*1を購入してリバース・エンジニアリングしたよ。サンディエゴへ見においでよ」とスナックに書いていたりします(図1)。本気度がやばいです。
図1 ASIC Clouds Exist Today(ISCA2016での発表資料PDFのp.16より)
[*1] マイニング用のチップ/ボード/クラスタを指している

前提

発表資料のp.4で、今回の話の前提を紹介しています。
コンピューティングがモバイルのSoCとクラウド(データセンター)へ二極化し、デナード則の終焉とダークシリコン問題を意識した設計が必要な時代

クラウドで使われつつあるASIC

データセンターでFPGAを使っている例としてはMicrosoftのProject Catapultや各種HFT(High Frequency Trading)がよく知られています。
いっぽう、ASICの利用(ASIC Cloud)例として論文内ではBitcoinのマイニング専用マシンを主要なものとして紹介しています。プロセス世代としては、当初130/110nmという旧世代プロセスで始まったものの、65nm→55nm→28nm→Intel 22nm/TSMC 16nmプロセスのものへと爆発的に進化していったと紹介されています。
本blogエントリを書いている2016年8月下旬の時点では、クラウドでのASIC利用といえばAlphaGoの李・セドル氏対局でも使われたGoogleのTPU(Tensor Processing Unit)*2が有名です。おそらくこの論文が投稿されたタイミングではTPUが発表されていなかったため、論文内ではカバーされていません。

TCO(総所有コスト)が最低になるポイントを探る

ASIC化にあたってはどれだけの電力と資金を投下してどれだけのパフォーマンスを得るか、という選択をおこないます。ここでは設計上のいくつかのパラメータ設定が重要です。
チップのコア電圧を下げると消費電力を劇的に下げられる反面、稼働可能な最大クロック数も低下します。このため、1チップあたりの処理性能が落ちます。
ある程度コア電圧を下げて1チップあたりの消費電力を削り、その一方でサーバスペースへ大量のチップを実装して適切な通信系を整備することでボード全体の性能を高めることになります。
しかしチップ数を増やすことでインターコネクトが複雑化したり、実装面積が不足してデータセンター内の領域を圧迫してしまっては元も子もありません。
この論文では、なんとこの面の分析をきっちりおこなっています。まず、パフォーマンスあたりのコストと処理あたりのエネルギーという2軸のパレート最適を分析しています(例:図2)。そして、これらの状態群に対して、各パラメータへの適切な重み付けをおこなうことでTCO(総所有コスト)の最適化検討までおこないます。
図2 Bitcoinマイニング用ASICのパレートカーブ(投稿論文PDFのp.19より)
外部メモリへのアクセス性能が重要な場合は、1つの処理チップあたりいくつのDRAMチップを接続するか、などでも性能が変わります。このため動画変換(H.265)のケースでは重要要素として検討されています。
データセンターでのASIC利用の前提は「チップの設計や製造にかかるコストよりも消費電力とファシリティ維持コストのほうが支配的になる」ことですが、その中でも具体的なコスト最適化プランの枠組みが提示されていることの意味は大きいと感じました。

ボードへのチップ配置方法に関する検討

チップの安定稼働にとって熱は敵なので、うまい排熱方法を確立しておく必要があります。
データセンター内では通常、サーバラック手前から冷たい空気を吸気し、ラック内のサーバモジュールを冷やし、背面へ排気するという構造をとります*3。このため、背面に近いチップほど前面に近いチップからの排熱を受けた熱い空気を使って排熱することになり、効率が悪くなります。
この論文ではサーバモジュール(ボード)上の各要素が発する熱を勘案して排熱効率を数値流体力学によってシミュレーションしています。
図3 ASIC Server Thermal Optimization(ISCA2016での発表資料PDFのp.33より)
そして、チップをどのように配置すると排熱効率を高められるかという検討もおこなっています。
図4 ASIC Placement: Duct Wins(ISCA2016での発表資料PDFのp.34より)
普通に並べたもの<チップを入れ違いに並べたもの<ダクトを設置したもの、という結果が紹介されています。
[*3] 液浸によって冷却するシステムも見かけますが、コストやメンテナンス性の面から少なくとも商用データセンターにおいて現時点の主流ではありません

各ユースケースにあわせた性能ファクタ検討

ISCA 2016での発表資料のp.40に、アクセラレータの特性を決める要素が各ユースケースの評価と共に紹介されています。
図5 Accelerator Properties(ISCA2016での発表資料PDFのp.40より)
  • Bitcoinは特定プリフィックスを持つハッシュのゴリ押し検索という計算特性から、ロジックをいかに詰め込んでひたすらに回せるかが重要(On-chip Logic Intensityに偏ったケース)
  • LitecoinはScryptという、計算に一定のメモリ領域が必要でランダムアクセスの必要もあるという計算特性から、チップ上に搭載するメモリとの兼ね合いが重要(On-chip RAM Intensityに偏ったケース)
  • 動画変換(H.265)は対象データ量が多くDRAMアクセスのスループットが必要なことからDRAM or I/O Intensityが高い(他の根拠は論文内で示されていないものの、内部で利用される計算式の複雑さのためOn-chip Logic Intensityも高めの評価と解釈)
  • 畳み込みニューラルネット(DaDianNaoベース)は大量のDRAMアクセスが発生するのに加えてチップ間の通信にHyperTransport(HT)を利用するため、Latency Sensitivityを強く評価

おわりに

本エントリではこの論文の良さの5%も伝えられていない気がします。ここで紹介しなかった要素が多いのに加えて、ここで紹介した内容だけに関しても、それぞれもっと具体的なことが論文に書かれているので、ぜひ読んでみてください。

Chiselでの非同期リセットについての現状整理、RocketChip事情を添えて

2016年8月23日火曜日

同期リセットと非同期リセット

HDLから回路の初期状態を設定するための主要な方法として、同期リセットと非同期リセットがあります。
これらの差について詳しくは述べませんが、FPGAの文脈ではXilinxが同期リセットを推奨し、Alteraが非同期リセットを推奨しているという事情があります*1
Chiselで回路を組むうえで、(特にASICの)レジスタ初期化に非同期リセットを表現する仕組みが欲しいと感じたことがある方も多いでしょう。今回はChiselの処理トリガ実装を簡単に紹介したうえで、非同期リセットに関する現状と議論を整理します。
[*1] 同期リセットと非同期リセットでの配置配線結果差については@marsee101さんのFPGAの部屋 FPGAの非同期リセットと同期リセットの比較シリーズが詳しいです。

Chisel 2.2.35時点の処理トリガ実装

Chiselの最終出力がVerilog HDLである以上、Chiselが持つ表現力の限界はVerilog HDLコードのエミッタ部分を読めばわかるはずです。
Chisel 2.2.35に含まれる、指定信号のエッジにあわせた処理をおこなうためのVerilog HDLコード生成部分は次のとおりです(https://github.com/ucb-bar/chisel/blob/7dd686d968/src/main/scala/Verilog.scala#L531-L536を抜粋*2)。
  for ((clock, dom) <- clkDomains ; if !dom.isEmpty) {
    if (res.isEmpty) res.append("\n")
    res.append("  always @(posedge " + emitRef(clock) + ") begin\n")
    res.append(dom)
    res.append("  end\n")
  }
各クロックドメインにロジックが含まれていれば、クロックの立ち上がりエッジにあわせてクロックドメインのコードを書き出すという具合ですね。
Chiselのソースコード上でposedgeというキーワードが登場するのは、この部分とVerilog HDL用のキーワード列挙部分のみです。ちなみにposedgeと対をなすnegedgeは、テストハーネスコードの生成部分(と、posedge同様Verilog HDL用のキーワード列挙部分)でしか登場しません。
つまり、ChiselのVerilog HDLコード生成系はposedgeでの駆動、しかも個別のクロック信号に基づく処理を記述する能力しかありません。
このため、Chiselで組んだ回路から次のようなVerilog HDLコードを直接生成することはできません。
always @(posedge clk or negedge RST) begin
...
end
BlackBoxを利用してゴリ押せば別ですが、BlackBox内のコードは当然Chiselの言語仕様もランタイムも一切文句をつけてくれない(=守ってくれない)エリアです。JavaScriptのevalと同程度には気を配って使うべきでしょう。
[*2] Chiselのコードはhttps://github.com/ucb-bar/chisel/blob/7dd686d96/src/main/scala/Verilog.scala#L1-L29に記載のライセンスに基づいて利用しています

Chiselでの非同期リセットサポートに関するissuesと議論

非同期リセット不要論

ChiselのMLアーカイブにAsync reset in generated Verilog always blocksというスレッドがあります(2015/02/17-2015/03/18)。
マクロを使えばなんとかなるよ!というたくましい解決方法などが提案されていますが、原則的にChisel側で非同期リセットをサポートするつもりはないという結論です。当時UCB内での議論はhttps://groups.google.com/d/msg/chisel-users/4cc4SyB5mk8/AVSI-GLjrmUJに集約されていたようです*3
この半年ほど後にGitHubのissueとしても似た話がSupport for asynchronous resets in Verilog backend #549(2015/09/27-引き続きopen)として出ていました。
[*3] これが公式見解かというと微妙なところですが、少なくとも返信しているのはUCBの博士課程(Architecture Researchではない?)に在籍されていた方なので、学内主流の意見を取り上げて投稿しているものと解釈しました

2016年8月の急展開

非同期リセットのサポートはChisel 2で決着がつきませんでしたが、Chisel 3のバックエンドであるFIRRTLのSupport for asynchronously-resettable registers #219というissue(2016/08/05-)によってサポートの見通しが立ちました。
事態が動くきっかけになったのはRocketChipのAdd asynchronous FIFOs as an option for clock domain crossings. #190というpull-reqです。これは、RocketChip内で利用している回路間接続ユーティリティであるjunctionsライブラリ(https://github.com/ucb-bar/junctions)をRocketChip側で独自に拡張してFIFO機能を持たせようというものです。
このpull-reqへレビュアーとしてアサインされた方が「すでにjunctions側でこの実装を書いていたけれど、MemとSeqMemをふたつのクロックドメインから安全に利用できない限りマージすべきでないためしなかった。同じ理由でこっちもダメ」と突っぱねたことで流れが変わってきました。科学と魔法が交差した瞬間ですね。
この事情説明に続いて非同期リセットが必要という話が展開され、同氏の「SiFiveの人たちに、とにかく全リセットを非同期にすべきとうるさく言っているけれど、今のところ効果なし」というコメントがダメ押しとなってついに前述のfirrtl#219へと至りました。enhancement扱いなので優先度はさほど高くありませんが、これまでよりもかなり前進しました。
なお、時系列がややこしいのですが、前述のRocketChipへのpull-reqと前後して、当初Gitのsubmoduleとして取り込まれていたjunctionsはRocketChip側リポジトリの中にソースコードレベルで取り込まれるようになりました。さらに、2016/08/20のコミットで置き場所がhttps://github.com/ucb-bar/rocket-chip/tree/7b20609d4/src/main/scala/junctionsへと移動しました。pull-reqやコード本体を追う際には注意しましょう。

進むChisel 3、置いていかれるChisel 2

FIRRTL/Chisel 3で非同期リセットをサポートする方針になったのは良いのですが、現在主流のChisel 2はどうなるのでしょうか。
Chisel 2に対する各種の修正/変更は最近あまり優先度高くおこなわれない状況にあります。
たとえば、Chisel 2で複数クロックドメインを生成して、それらの間でデータのやり取りをおこなうコードを書いた場合、C++バックエンドを生成するとErro in C++ backend : (error: ‘T54’ was not declared in this scope) #464のようなエラーへ頻繁に行き当たります。要はC++コード生成部分で中間状態(wireと同等のもの)のスコープを適切に処理できておらず、暗黙のクロックに依存するコードが生成されるためですが、このissueは長く放置されています。
Chisel 2の問題に対する取り組み指針を伺わせる別の例としては、Compilation Error when assigning from other clock #696というクロックドメインまたぎに関するissueへのコメントが挙げられます。
このなかに、
Then again, it may be worth punting on this issue (to chisel3). A clock domain check is particularly amenable to a FIRRTL pass and, further, it is a FIRRTL pass that users may want to customize.
という発言があります。不要不急の変更をChisel 2に加えるのはなるべく避け、問題解決はFIRRTL/Chisel 3でおこないたいということですね。
このようにChiselプロジェクトの進行を見ていると、全体的に「はやくFIRRTLベースのChisel 3へ移行して、つぎはぎだらけのC++/Verilog HDL生成系から解放されたい。つらい苦しい」という雰囲気が出ています。

結論

Chisel 3では非同期リセットがサポートされる見込みです。非同期リセットを書きたい用途ではChisel 3への移行をそろそろ考え始めたほうがいい(今すぐ非同期リセットを使えるとは言っていない)です。どうしてもすぐに使いたければ、yet another Scalaでデジタル回路を書く仕組み: Spinal HDLを参考にChiselインスパイア系言語であるSpinal HDLを試してみても良いかもしれません。

yet another Scalaでデジタル回路を書く仕組み: Spinal HDL

2016年8月22日月曜日

先日あれこれと調べている時にSpinal HDLを見つけて気になったので、簡単に調べた結果をまとめておきます。今のところは主に自分用の備忘録というか下調べ状態です*1
[*1] そもそもyet anotherというのは3番手以降に出てきたものについて付けられる修飾子な気がしますね

Spinal HDLとは何か

Spinal HDLは、Dolu1990氏が中心となって開発している、ハードウェア(デジタル回路)設計用のScala組み込み言語(DSL)です。Gitのコミット履歴をみる限りでは2015/01/25に始まったものです*2
[*2] これに続く書き溜め分コミットの内容から、実際には2014年8月に開発を開始し、2015年1月に一旦の区切りまで到達したらしいことがわかります
ハードウェア記述言語(HDL)としての立ち位置はChisel HDLと似ています。いわゆる高位合成系ではなく、HaskellのLavaと近い位置付けのDSL+ライブラリ群です。

Spinal HDLとChisel(Chisel HDL)の関係

Chisel → Spinal HDL

登場順序でいうとSpinal HDLはChiselの後発プロジェクトです。ソースコード考古学的な意味ではChisel(Chisel HDL)の派生物にはあたらず、私が把握している限りでのコード共有はありません。Chiselに触発されて生まれた新実装です。
ライセンスも両者で異なります。Chiselは修正BSD(いわゆる3条項BSD)ライセンスです*3。Spinal HDLはコア部分がLGPL 3、周辺ライブラリがMITライセンスです。
[*3] 完全に蛇足ですが、Chiselを開発しているUC BerkeleyはBSD/修正BSDライセンスの本家本元でもあります
もともとDolu1990氏はChiselを使っていて、行き当たった問題などをissuesとしていくつか登録しています(#207, #213, #265)*4
[*4] issueコメントで2014年3月頃からChiselを学び始めたと書いています

ChiselとSpinal HDLの違い

Spinal HDLのドキュメントには「Chiselとどう違うのか?」について詳細に述べたページがあるので、参照してください。かいつまんで紹介すると、次のような問題を指摘しています。

Chiselはいくつか構文上の問題や下回りの実装に起因する実用上の窮屈さを持つ

  • プログラマがミスを犯しやすい局面で警告を出してくれないパターンがいくつかある
  • 標準で用意されているライブラリが物足りない
  • 生成されるVerilog HDLコードが到底人に読めるものではない
  • クロックドメインを複数持つ回路の実装が大変(リセット信号の扱いが中途半端、非同期リセットを持たないなど)
  • Scalaの型とChisel用の型を暗黙変換すべき
これらに対して、issueやPRという形でおこなわれた改善提案があまり実を結んでいないこと、Chiselプロジェクトの立ち上がりから経過した時間の長さを考えると今後も取り込まれる見込みが薄いことからSpinal HDLを開発するに至ったと記されています。

Spinal HDLの機能と仕様に関するメモ

あまりまとまっていませんが、構文面はChiselとキーワード差程度で似ていて、実際に使うと勝手が異なる雰囲気です。
  • 最終出力先のHDLとしてVerilog HDLだけではなくVHDLもサポートする
  • ChiselでModuleクラスを拡張して回路を組むところでComponentクラスを拡張する
    • 出力先としてVHDLも選択できる事情によると考えられる
  • Bundleの扱いはChiselと似ている
    • 互換性のないBundle同士を<>でつなぐのはコンパイルか検証時に弾かれそう(未確認)
  • 論理回路を組んでいく部分は基本的にChiselと似た構文で書ける
    • 演算時のbit幅拡張仕様は異なる雰囲気(未確認)
  • 回路記述負荷を低減するための構文やライブラリがある程度存在する(後述)
  • ChiselのようなC++コード経由でシミュレータ(DUT)を生成してScalaコードとつないでテスト、の仕組みは持たない*5
[*5] Describe testbench from within Spinalで話題になっていますが、当面はRTL(コードの生成)側へ注力するようです。

Spinal HDLの良さそうな点(主観)

クロックとリセットの扱いが圧倒的にChiselよりもうまい

Spinal HDLは作者自身が前述のChiselに対する不満点で書いている、クロックとリセットの扱いに力を入れています。少なくともドキュメントを読む限りでは、これらは圧倒的にChiselよりも練られています。
  • 特にClockingAreaという、モジュール(Component)の一部を指定クロックによって駆動する仕組みがクール
  • Chiselで最近ようやく導入に向かってる非同期リセットも当然のように存在する
  • クロックドメインまたぎで面倒なメタステーブル現象の回避のために、ChiselのAsyncFifoよりも扱いやすいバッファ(BufferCC)を用意している
詳しくはクロックドメインに関するドキュメントを参照してください。

ステートマシン構築の苦労を減らす仕組みを用意している

Spinal HDLが(Chiselと同様)高位合成系ではない以上、アルゴリズム記述のうえで問題になるのがロジックのステートマシンへの分解です。
Spinal HDLの標準ライブラリには、ステートマシン(FSM)を構築して状態間の遷移記述を省力化するライブラリが含まれています(ステートマシンの説明)。
ここでは以下の要素が登場します。
  • 状態開始時の処理: onEntry
  • 状態中の処理: whenIsActive
  • 状態を抜ける際の処理: onExit
これら3種類の処理と、状態間を遷移するためのgoto呼び出しでロジックを構成します*6。ソフトウェア方面から来ると、キーワードを見た瞬間に「ヒッ、gotoだ!!」となるような気もしますが、つまりは必要悪です。
[*6] 2016/07/27のSFM: Added whenIsInactive.コミットで、なんとinactive時の処理も書けるようになりました。whenIsInactiveでステート間のgotoを発生させたらどうなってしまうのか…。
Chiselでenumを使ってシンプルな状態管理をしていくと、どうにもコードのネストが深くなりがちですが、この記法だとある程度コンパクトなコード群に分解できるのがメリットでしょうか。とはいえ、さすがに30-40ステートに及ぶものを書くならば諦めてC/C++からの高位合成系へ放り込んでBlackBoxとして組み込んだほうが良さそうですが。

せっせとComponentを切らなくともロジックの塊を記述できる仕組みがある

ロジックのまとまりを書いてローカルなスコープで利用したい場面は多いです。Spinal HDLでは、Componentを継承してioを定義せずともlightweightにロジック群を書く仕組みとしてAreaを用意しています(Areaの説明)。
実はすでに紹介した指定クロックドメイン用ロジックを書くためのClockingAreaはこの一種です。
Chiselでインライン定義モジュールを作るためには内部でio変数を定義して入出力接続をおこなう必要があります。Chiselは設計上の判断としてこのような仕組みを用意していない印象ですが、クロージャにどっぷり浸かった民としてはやはり欲しいところです。

標準ライブラリに各種バスが揃っていて脳汁が出る

Spinal HDLのライブラリを覗いてみると、AMBA3(AHB-Lite、APB)、AMBA4(AXI4、AXI4-Lite)にAvalonMMもあります。実際に試してみないと性能のほどはわかりませんが、少なくとも既存のIPと指定バスでつないで実験をするあたりまでは省力で進められることを期待できます。

少人数プロジェクトゆえの小回りの効く開発

StateMachineの「泥臭いけど必要」な設計といい、Dolu1990氏が取捨選択を決定できる圧倒的な身軽さがある(そして精力的に開発している)ため進化速度がはやいです。なお弱点はそっくり裏返しで、アクティブ開発者がDolu1990氏含めて2名のみというところですね。

まとめ

Chiselインスパイア系言語/環境のSpinal HDLは、Chiselへの不満を解消するように多くの工夫を凝らして作られています。Spinal HDL環境には、Chiselにも欲しいなーと思うようなものがいくつも存在し、Chiselへ輸入できそうなものも多いです。
Spinal HDL→Chiselの輸入のためにChiselをforkするよりは大人しくSpinal HDLを使っても良いのかも、と感じるところもありました。しかし私がChiselの仕組みで特に気に入っているのがテスト周りで、この仕組みを現状のSpinal HDLは持たないので、すぐにこれを実用してみるイメージは湧いていません。
個人的にはNode.js対io.jsの構図で、Chiselの新仕様をせっせと練る場としてSpinal HDLが機能して、最終的に統合されるシナリオであると安心して両方を掘っていけるのですが、その実現には両者のユーザ規模が1万倍ぐらい足りませんね…。
今回書いたのは実用した評価レポートなどではないため、今後実際に触ってみて印象が変わる可能性も大いにあります。これからもたまにSpinal HDL事情を調べて、時折触ってみようと思います。

Making of "至って普通のWebカメラ"展示 - MFT2016出展記

2016年8月12日金曜日

MFT出展報告

8/6-8/7に開催されたMFT 2016(Maker Faire Tokyo 2016、図1)からぼちぼち1週間が経つので、忘れないうちに振り返りと反省と、そして夏コミ3日目で出る同人誌の宣伝をします。
図1 MFT 2016会場の図

出展したもの

中身のデジタル回路をScala+Chiselで一部自作したWebカメラ(図2)展示と、関連する12ページのコピー本(Scalaでハードウェアを設計するはじめの一歩!、図3)の無料頒布です。
図2 展示したWebカメラっぽいもの

準備にかかった期間

社内で最初に出展の話が出たのは4月の下旬だったと記憶しています。
実際の作業にかかったのは展示のおおよそ8週間前、そこからコミケの原稿準備と並行して休日を突っ込み続けて完成へ至った、というタイムラインです。

準備の流れ

基本的に「実現したい夢仕様」から現実的なラインまで仕様を削っていく作業でした。
お題の大本は4/25発売のFPGAマガジンNo.13掲載の記事です。TMDS変換と出力データのシリアライズをおこなう回路の作成を作成してあとは展示待ちというところでした。が、前日に「コピー本を作って配布したいなぁ」と思いました(図4)。
図4 Slackでふと思いつきを書いたところ
そういうわけで今回は物理パート、論理パート、勉強パートの3面、それと最後に加わったコピー本の順で準備段階のあれこれを紹介します。

物理パート

カメラモジュールを入手してブレッドボード用ワイヤなどで配線

最初にカメラモジュールを注文したのは6月上旬です。この時はOV5642という少々高性能なモジュールを入手しました(お高かったです)。軽く手元のワイヤを投入して接続、動作確認し、「これは配線ノイズでかいので基板を起こさないと厳しい」「早晩モジュールをぶっ壊す」と考えました。
OV5642よりもと、多少扱いの面でも楽(コマンド体系が8-bit列なので)なOV7670を1つ購入し、さきの仮組み状態で仮動作確認しました。これは、まあまあいい感じに動きました。OV7670はOV5642の半額程度で入手できるので、最悪破壊しても泣かずに済むというのもありました。

基板の設計と発注

KiCadで雑基板のスライドを読み、ついに「ああぁぁ、KiCadってこういうことだったの!!」というアハ体験(古い)をしました。
6月下旬、Elecrowへと基板の注文(注文オプションは4-7 days, Shenzhen DHL)をおこないました。なんと2日後には「発送したやで~」というメールが届き、その週内に入手できました。DHLのセンター(最近新しくなったっぽい)へ出向いて荷物をピックアップするという体験、個人的に割と楽しかったので、回を改めて書きます基板をピックアップした足でそのまま秋葉原へ向かい、秋月と千石を回ってコネクタを入手しました。今回は基板上に抵抗もコンデンサも実装しない、単純に可搬性と配線の確実性を確保するためのものなので、そういう感じです。
これ、実は技術書典の日なんですね。とにかく急いで確認せねばということで基板にコネクタをハンダ付けして動作させてみました。

基板の動作確認

OV7670をつないだところ、なんだか動きません。そもそもカメラモジュールの電源が入っていないような挙動です。
元々動いていたユニバーサル基板ベースのものに挿し替えてみても、どうにも反応がありません。
状況を追うこと数十分、コネクタの向きを完全に間違えていた事に気づきました。
これはカメラモジュールを破損させてしまったかなと、恐る恐る(何度も確認して)OV5642を逆向きに挿したところ、少なくともノイズ入りの映像は取得できました

基板失敗からの現実逃避

OV7670を破損させたショックと基板設計ミス(確認は何度かしたつもりだった)のショックでその日は作業をやめて、ひとまず技術書典へ向かいました。
余談ですが、途中で
のアナウンスを見て焦りました。
なんとかギリギリ整理券を確保できた図です。
技術書典から引き上げた後は、さきのショックの影響で数日呑んだくれました。

基板設計リトライ

翌週半ばに気持ちが復活し、直した版の基板設計を仕上げました。そして追加注文したOV7670(今度は念のため2つ買いました)を使って前の基板の表裏逆版がきちんと動作することを確認したうえで入稿しました。特に今回の場合は関係ないのですが、チュートリアル動画の出来がよかったので等長配線(差動ペアではない)とskew調整も込みでやってみました。
図5 KiCadでの回路設計リトライ版
余計なことをした結果またミスってたらどうするかというのは考えました。しかしここらはいろんな仕組みを試してはショット撃ってなんぼです。最悪ダメだったらもう一度いそいで作り直し、Elecrowの特急コースへ金の弾丸を叩き込む覚悟をしていました。PCBのCADデータ入稿時点で6月の末、今回はちょうど1週間程度で発送通知がきました。これで7月の上旬まで溶けた格好です。

リトライ版の動作確認

届いた基板の動作確認をして、問題ないことをあっさり確認できました。
展示の1ヶ月前にはハードウェア側をfixして残りはソフトウェアに充てたいと考えていたので、この時点で時間切れです。いい感じの筐体なども用意することなく、基板強度を活かして剥き出し展示でいくこともほぼ決まりました。コミケ向けの記事執筆に十分な時間を取らないとクオリティ面で問題が残りそうというのも見えていました。

論理パート

前半はコミケに向けて記事を書く傍らでほぼFPGAマガジンNo.13に掲載のままのコードを動作させていました。部品を注文して届くまでの間や基板を発注して届くまでの待ち時間は記事執筆にあてました。
ソフトウェアに関しては、NiosII/eプロセッサからSCCBの16-bitコマンドインタフェースでOV5642をコンフィグするあたりに結構時間を費やしました。しかし物理パートで述べたようにOV7660での動作を先に安定化しないとまずい状況になってきたため、結局コード的にはほぼ雑誌掲載コードのダウンロード版のまま開発を進める方針へと転換しました。
その後、夏コミ用の記事が進捗すると共に、Chisel版のTMDSコードも進捗しました。Chisel版のTMDS変換コードを書き上げてからしばらくは放っていて、休み(いわゆる毎年捨てられてしまう年休)を2日確保してシリアライズ回路のChisel化をおこないました。さらに、PCがなくてもコンフィグ済み状態でFPGAボードを起動できるようにpofファイルを作成してフラッシュメモリ領域へ書き込んで完成ということにしました。

勉強パート

Chiselの各種ドキュメントは、この期間中にあるだけ全部読みました。UCBでのアサインメントの資料なども参考になる部分は一定ありましたが、このあたりは今後紹介してみたいところです。

FPGAマガジン No.13

AlteraのMAX10シリーズFPGAをさまざまに利用するという特集号です。昨年購入したBeMicro Max10がちょうどそのまま使えるな、ということで展示物を考えるヒントになりました。

実用HDLサンプル記述集―まねして身につけるディジタル回路設計

知識と経験の不足を補うために最初に買った本が「実用HDLサンプル記述集―まねして身につけるディジタル回路設計」です。これは良い本なのですが、読み進めるうちに自分が必要としているのはもう少し手前から紹介している本じゃないかなー?と考え始めました。

HDLによる高性能ディジタル回路設計

その後、7月に入ったあたりで「HDLによる高性能ディジタル回路設計 - ソフトウェア感覚を離れてハードウェアを意識する」を買って読みました。
この本は、デジタル回路に関する理解の足りないところを補ううえで大変役立ちました。特にメタステーブル現象など回路動作を不安定にする要因の説明と対策の章が素晴らしいものでした。
また、これまでデジタル回路系はVerilog HDLで書いてきたため、読み始めには「えー、VHDLなのーー?」と思っていました。しかし読み終わる頃にはどっちでもよくなっていた(一定範囲のコードであればVerilog HDLでもVHDLでも問題なく読めるようになった)ので本当にありがたい本です。

コピー本から当日入場まで

思いつき

MFTの会場で新作のコピー本を配布して、あわよくばコミケでのTechBooster本(特にThe Web Explorer 2)の宣伝をしようと思い立ちました。思い付いたのが前日だったので、取り急ぎTechBooster代表のひつじ(@mhidaka)に「記事の冒頭4p収録したいんだけどよいかな?」と転載の打診をしました。結果は「52ページあるし、冒頭4pぐらい構わんじゃろ」という雰囲気だった気がします(記憶が曖昧)。okを得られたので、予告編4ページを含む12ページの冊子を作ることにしました。表紙と裏表紙を除くと新規に書くのは6ページで現実ラインです。ともかく、さっさと退勤して内容を詰めていくことにしました。

骨子を固める

まずは内容の骨子です。内容はコミケで頒布する本の中の記事を補完しつつ予告編となるようにしようと考えました。
また、先日SBT+Chisel向けの環境一式が入ったDockerイメージを作っていて、さらにChisel 3を試すためにそのChisel 3版も作っていました。リンク
これらを利用してサクッとお試し入門してみようという話と、加えてコミケ版でほとんど言及しなかったWindows環境でのChisel開発について補足することにしました。せっかくコピー本なので最新事情(GitHubのChiselリポジトリ上での当日の議論)についても言及し、Chisel 3の現プレビュー版を利用してビルドするとどの程度のエラーが出てくるのか、簡単に試せればそこから次のステップが見えてくるかも、と考えてそれも含めることにしました。

資材調達

書くことが決まったら、まずは資材の調達です。原稿が仕上がらなければ最悪ページ数を減らせば良いのですが、製本工程でつまづくと面倒そうだったので、コピー本向けの製本グッズを購入します。
コピー本といえば縦とじのできるステープラー(ホッチキス)なので、Amazon Prime Nowで買いました。なお、ステープラーだけだと500円ぐらいで、Prime Nowの最低額へあわせるために芯を大量購入すると何万本も手元に残ることになりそうでした。特に買いたいBlu-rayなどもなかったのですが、ちょうど手元在庫が切れていたアサヒのウィルキンソンタンサン(500ml)x24が1,900円だったので、渡りに船という感じでカートへ追加しました(図6)。
図6 Amazon Prime Nowで資材調達
私の出展物は写真中央あたりのモニタに映っているものです。
中央右に見える箱は@tenntennのVRゴーグルです。

原稿の大枠を整備

前述の骨子に従って書き始める前に、最後の段階で足をすくわれると面倒な下回り整備をおこないました。骨子を考えてから一旦頭の中をクールダウンしたいというのもあったので、雑務を先に片付けた格好でもあります。
ここで具体的にやったのはRe:VIEWで冊子を作る際のコンフィグです。まず、今回の冊子は12ページしかないので、目次に1ページ持って行かれては面倒です。表紙の2ページ先のトビラも当然無し、奥付も無し、という具合にconfig.ymlをいじって調整していきました。
この段階で書く内容ごとのページ数は決まっていたため、仮(アタリ)の内容を埋めてレイアウトをざっくり確認しました。とりわけ、Chisel 3のくだりはページ数が極端に少ない(1ページ)ため、なるべく不要な領域を詰めたいという事情がありました。多少レイアウトは不自然になりますが、この章はpostdef扱いにしました。
120ページ級の書籍とは綴じ方から何から違うため、本来は紙面レイアウトのパディングを減らしたいところでした。しかしコミケ版の原稿をそのまま4ページ拾ってきて掲載する都合上レイアウトが変わるのは避けたかったので、そのまま(いわゆるてくぶレイアウトを維持)にしました。
ひとまずその4ページを拾ってきて貼り付けたあたりで着地点が十分に可視化されて、テンションが上がってきました。

原稿執筆

ひたすら書きました。基本的にホームグラウンド(Dockerまわり)の話を中心に書くことにしたため、あまり手が止まらずに進みました。

表紙と裏表紙の作成

あまり手が止まらなかったとはいっても、さすがに途中で疲れてきたので現実逃避に表紙と裏表紙を作りました図7。
図7 頒布した本の表紙(左)と裏表紙(右)
最近はもっぱらAcrobat DC専用と化していたAdobe CCですが、Illustratorが大変役立ちました。
下敷きにしている画像は、今回作った「自称Webカメラ」の写真です。iPhoneでササッと撮りました。
裏表紙は普通に文章を書こうかと思ったのですが、Re:VIEWでは図への回り込みなどを扱いづらいので避けることにしました。Keynoteでぺたぺた貼り付ける策も考えましたが、なるべくWindows上で作業したかったのとKeynoteからPDFへのエクスポート時の画像解像度の扱いが少々不安だったのでやめました。裏表紙もIllustratorで作ることにしました。

完成から印刷・会場へ

表紙と裏表紙が完成して、いくらか追記をおこなって大筋完成後は、文章のおかしなところをセルフレビューしました。展示当日朝に全体を通して確認していくつか軽い変更を加え、「もうこれ以上はいじらない」と覚悟を決めてセブン-イレブンへ向かいました。まず1部出力したところ、サイズをミスって完成サイズがA5になったので慌てて完成がB5になるように設定変更しました。あとは問題なく出力できました。今回の展示物では、19インチモニタが多少持ち運びにくい程度だったので、ささっと荷詰めをして会場へ向かいました(図8)。
図8 さっさと荷詰め
途中で朝ご飯を食べて、展示ブースの下にべろんと貼り付けておく紹介資料をKeynoteでそいやっと作りました。内容は概ね冊子のサマリなのでサクサクできました(なお、これをA3横で作ってしまったため、6人出展のブースで幅を取り過ぎて周りの人に迷惑をかけてしまったりもしました)。あとは最寄りのファミマで印刷してめでたし、です。
ビッグサイトへ移動して設営を終えました(図9)。
図9 設営を終えた会社の有志6名ブース

出展中

トータルで1日目10部、2日目25部を配布しました。部数設定が少なすぎると感じるかもしれません。とにかく余らせたくなかったのと、コンビニのコピー機でそこそこ身軽に印刷できる規模の数にしたかったというのがあります
今回のゴールは「大量に配布する」ではなく、「余らせずになるべく興味を持った人の手に届ける」でした。
考えてみると、10部でもB5用紙60枚相当、15部だと90枚相当あるわけで、手元に残って破棄するよりは少部数にとどめておきたいと感じるものです。

1日目

1日目は10部+見本を作成して持ち込みました。
12時開場で、13時過ぎには残部がなくなっていたようでした(交代で展示番をしていたのですが、戻ってくる前に捌けていました)。
engadgetの方がTwitterで見て欲しかったんですよーと言って持って行ってくれましたよ、と後で教えてもらいました。ありがたや。
自分がブースに居る時はあれやこれやと説明したり、Chiselを布教したりしていました。
実現できているものが凄いとかそういう展示ではなく、こういう作り方(手法)があるよという紹介が主題の展示物というのが初めてだったので、難儀する部分もありました。相手がどういう方なのか分からない、完全なオープンコンテキストの中で説明するのって割とむずいな、みたいなことを今更のように思いました。
HDLでの開発者の方、PyCoRAMとSynthesijerを使ったことのある方、Scalaでソフトウェア開発をしている方など、多くの方と話せたのでよかったです。HDLや高位合成系の経験者の方にChiselの良さは割と紹介しやすいものでした

2日目

2日目は15部を持ち込みました。
なんかミスって最初にA4仕上がりを1部作ってしまいました。15部は例によって(2日目は開始が早いこともあり)13時ぐらいまでに捌けました。そういうわけで、増刷することにしました。幸い文字系のイベントではないためかビッグサイト内のセブン-イレブンの複合機は空き時間が多いことが前日に分かっていました。部数は10と決め打ちして印刷、製本作業をおこないました。
問題は配布方法です。前日から「読んでくれそうな人に届いてほしいな」というところが少々気になっていました。もちろん、気軽に1部持って行って欲しいし、読んでみてワンチャン興味を持って何かにつながれば良いというのが大半の気持ちです。
それでも、前日に興味を持って熱心に話を聞いてくださった方へ残部なしがゆえに渡せなかったという心残りがありました。
こういう場合、鉄板なのは有料頒布(たとえば100円、10円でも可)にすることです。「なんか無料で冊子を配ってるから、とりあえず持って帰って気が向いたら後で読もう」というところから、10円ないし100円という「金銭的に痛くないけれど、明確な意思を持って入手した」という状況へと大きく変わります。今回の場合は、MFT2016前日の告知時点で無料と言い切っていますし、そもそもがコミケ本のプロモーションという位置づけで書いた部分が大きいので、これはダメです。釣り銭の用意もありませんし、一緒に出展していた5人への周知とある程度の負担が必要になる点もあります。
次の策は「見本誌を手にとってくれた方へ無条件でお渡しする」です。自分がブースに居ないタイミングでも、ある程度オペレーションを回しやすい方法だと思います。少々迷いましたが、この時点で展示時間が残半分を割りつつあったので、他の人への周知その他を考えた結果、これも採用しないことにしました。
結果、「10部中の5部は従来通りブースへ置いておいて自由にとってもらえるようにする」「残5部は自分で持ち歩いて、会場内の他ブースの(主に旧知の)方へ挨拶ついでに押し付けたりして回る」ということにしました。これはとても重要な結果につながるのですが、その話は本題から逸れるので別の機会に書きます。最終的には、無事に残部なく(一緒に出展していた社内のメンバーへ渡すつもりだった予備まで含めて)配布できました。

反省

冊子の配り方は目的に応じてあらかじめ工夫を考えておくべき

あまり細かくセグメントすると感じ悪いというのもあって、今回は原則宣伝用と割り切りました。MFTの展示自体にどの程度お金をかけることを許容するかという話でもありますが、やはり効率的に多くの方に届けたいものです。

主要モジュールは2つ買うこと

2つ買うのは高すぎるから無理、というものはそもそも十分な経験を持って扱うのでない限り不適です。避けたほうが良いです。何がおかしいのかをトラブルシュートしていった際に最後にモジュール差し替えて確認という手段をとれるのはとても大きいです。

基板色を黒指定すると、基板パターンがよく分からないので要注意

Elecrowでは基板の色を緑以外に指定しても料金が変わらないので、ついつい他の色を試してみたくなります。
青ならば基板上のパターンが割と見えるのですが、黒を指定すると見えづらいです(図10)。
図10 黒基板でパターンが見えづらい
狙ってやるならば問題ありませんが、基板上のパターンを話のタネにしたい場合には大変な地味さゆえ「よくわからんな?」となります。

基本筋は真面目で良いので、フックになる要素を考える(ダメならダメで諦める)

今回、展示物が気持ちファンキーな見た目になっていたのは、来場者に興味を持ってもらう上で一定の意味があったと感じています。
お題はWebカメラっぽいものですが、本当に普通のWebカメラっぽい出力だと、なんか監視カメラで撮られてる感じがしてブースへ寄り付きたくない感じがします。
今回はカメラモジュール内のレジスタ設定をおこなわずに起動しただけの状態で画を出したので、なかなかファンキーな感じになりました。メディアアート作品?と聞いてくださる方も居たそうです(私がブースに居なかったタイミングで、後から知りました)。今回は半ば怪我の功名というところがあり、あまり意識しすぎるのも良くないのですが、次以降の展示でも「嫌悪感を引き起こさないもの」「なんか気になるもの」というのは意識してみようかな、と感じたところです。

ぼっち開発での戦い方

回路にしてもソフトウェアにしても、レビューしてくれる人が居てチームで組んでいくならば取れる策も一定あります。一人でやる場合、基本戦術は次のとおりです。
  • 慎重に進める。十分に勉強してから取り組む
  • 似た特性の安価なモジュール(壊しても泣かない)で仕組みを十分確立してから高価なモジュールを使う
  • トライアル間隔を狭める
    • 自信がない選択肢に行き会った場合、全ての選択肢に同時張りする(例えば基板設計なら、有力な全候補を書き上げてまとめて入稿する)
      • 片方は失敗してロスする可能性が高いのですが、十分な確信なしで物事を進めなければならない状況は時間的に切羽詰っていることが大半なので、やむなしです
  • 金の弾丸で全てのパーツを余分に購入してバッファを持つ

宣伝

コミックマーケット90(C90)の3日目(8/14)、TechBoosterという技術書サークル(西a-05ab)にて「The Web Explorer 2」という本が出ます。このなかに、私の書いた「Scalaでイージーにハードを設計する」という記事が収録されます。Scala言語とChisel(Chisel HDL)というライブラリを利用してデジタル回路を設計する入門記事です。
図11の、めちゃめちゃかわいい表紙が目印です。
図11 The Web Explorer 2の表紙(イラスト: Jecyさん、デザイン: siosioさん)

そういうわけで

ブースにお越しいただいた皆様、会場で話をできた皆様、運営スタッフの皆様、同僚各位、ありがとうございました。とても良い場でした。
今回作成した12ページの冊子は、コミケが終わって少々落ち着いたら何かしらの形で配布しようと思っています。

(告知) C90 3日目西a-05abでScala+Chisel入門記事の載った技術書が出ます

2016年8月11日木曜日

概要

コミックマーケット90(C90)の3日目(8/14)、TechBoosterという技術書サークル(西a-05ab)にて「The Web Explorer 2」という本が出ます。このなかに、私の書いた「Scalaでイージーにハードを設計する」という記事が収録されます。Scala言語とChisel(Chisel HDL)というライブラリを利用してデジタル回路を設計する入門記事です。
図1.1の、めちゃめちゃかわいい表紙が目印です。


図1.1: The Web Explorer 2の表紙(イラスト: Jecyさん、デザイン: siosioさん)

誰に向けた記事なの

主に想定した読者像は次のとおりです。
  • 普段Javaでコードを書いているソフトウェア開発者
  • Scalaという言語は聞いたことがあるけれど、なんかコンパイル遅そう&怖そうというイメージぐらいしかない
  • CPU上でプログラムを走らせているだけでなく、ハードウェア(デジタル回路)を作ってみたいと感じている。あるいは、なんならFPGA評価ボードは買ってみた
  • Verilog HDLやVHDLの書き方をチラッと調べた結果「えっ、この言語ほんとに書くの?つらくない??」という気持ちになった
  • 普段だいたいmacOS上で開発作業をしている
  • IntelliJ IDEAやAndroid Studioにそこそこ馴染んでいる
簡単にいうと、しばらく前の自分が想定ターゲットです。
デジタル回路に関する事前知識はあまり要求しない作りです。序盤では専用のデジタル回路をわざわざ組む理由はどこにあるのか、どのようなユースケースを探るべきなのか、といった基礎部分もカバーしています。
いっぽう、Scalaの言語仕様に関する説明は最低限に留め、いわゆる「Scalaらしいコードの書き方」にはほとんど触れていません。わりと「行末にセミコロンを打たない&便利構文がいくつか追加されたJava」ぐらいの使い方をしています。これは、私自身のScala経験が浅いという事情に加えて、Scalaの学習よりもChisel HDLの学習にページ数を割きたかったためです*1
[*1] なんたって、Scalaらしいプログラミングスタイルを学べる良書はすでに世の中に存在します。もちろん今回の記事中でも紹介しています。

どういう記事なの

Scala言語とChisel(Chisel HDL)というライブラリを利用してデジタル回路を設計する入門記事です。
主にソフトウェア開発者をターゲットとしています。

内容

  • なぜCPUを使わず、わざわざ専用デジタル回路を作るのか
    • 演算の向き不向き
    • FPGAとASICの簡単な違いとコスト差
  • Scala+Chisel HDLを使うメリットの提示
  • Chisel HDLのごくごく基礎紹介
    • Chisel HDLがなにものであって、なにものでないか
  • とりあえずChisel HDLを使って半加算器を作ってみる
    • テストコードはScalaで書き、シミュレータをもちいた動作検証をおこなう
  • Chisel HDLで実用的な回路開発。TMDS変換(DVI/HDMI用信号変換の一部)回路を書く
    • TMDS変換アルゴリズムの簡単な紹介
    • 実際にChisel HDLでコードを書く
    • Scala版の実装をあわせて作成する
    • Chisel HDL版の動作を検証する
    • FPGAマガジンNo.13に掲載のカメラ出力コードの一部をChisel HDL版に差し替えてシミュレーション結果の性能を比較する
  • よく使われるVCDファイルのダンプを分析する手順の紹介
  • 参考文献
  • おまけ: はじめよう、FPGA!(2016年7月時点で、ひとまず始めるのにオススメのボード紹介)
記事中で紹介したのは割と素直な回路を書く手順で、ややこしいクロックドメインまたぎなどは含まれていません。そのあたりの話も別の機会に書いていきたいと思っています。
今回、Chisel HDLのコーディングに利用した環境はmacOSですが、拙作のDockerイメージを利用することでWindows上での作業も可能であることを確認しています。

うぇ、Web Explorer…?

目次を見てのとおり、この本はWeb系の技術(JavaScript系)がメインの本です。いえ実はTensorFlowでRNNというホットな記事も載っています。
ちなみにThe Web Explorer 2は計128ページの薄い本()ですが、そのうち52ページがScala+Chiselを扱った章です。Scala+Chiselの章に疲れたらWebとTensorFlowの話を読み、それらに疲れたらまた戻ってScala+Chiselの章を読むこともできてお得ですね!!
あと、紙の本にはおまけとして電子版のダウンロードクーポンが付属するとのことです。PDF派(私もです)も安心ですね。なお、私の記事タイトルは@vvakameがつけてくれました。

どこで入手できるの

3日目(8/14 日曜日)西a-05ab(TechBooster、ひかる黄金わかめ帝国の合同ブース)です。予報によると日中の気温が結構な感じになりそうなので、熱中症にお気をつけて。

.NET CoreのテストランナーにNUnitを使う方法

2016年6月24日金曜日

.NET Coreでの自動テスト

.NET Coreは、基本コマンドの中にテストランナーの実行サブコマンドが含みます。
project.jsonファイル内に"testRunner": "..."という記述をおこなっておくと、プロジェクトディレクトリ内で
$ dotnet test
とするだけでビルドからテスト実施、レポート(XMLファイル)出力までを一気に実行できます。

.NETではふつうxUnit使うよね、という風潮

.NET Coreでのテスト実行については公式ヘルプページ(Unit Testing in .NET Core using dotnet test)があります。
このドキュメント内にはxUnitを利用する手順しか書かれていません。しかし個人的にはxUnitのキラキラしたオシャレ雰囲気があまり好きではなくて、泥臭さを感じるNUnitのほうが好みです。
.NET Coreのproject.json内での"testRunner": "foobar"という記述を解釈したランタイムは、src/dotnet/commands/dotnet-test/ConsoleTestRunner.csに従ってdotnet-test-foobarというコマンドを探しにいきます。dotnet-test-nunitというコマンドが存在すればいい感じにテストランナーとして呼び出せるはずです。

.NET Coreにおけるコマンド解決の方法

コマンドを探しにいきますが、一体どのように対象を解決して実行するのでしょうか。
プロジェクトのbinディレクトリもしくはパッケージ参照パスから、一致する名前をもつexeまたはdllを拾ってくることは想像がつきます。具体的にはsrc/Microsoft.DotNet.Cli.Utils/ProjectDependenciesCommandFactory.csを起点とするsrc/Microsoft.DotNet.Cli.Utils/CommandResolutionのコード群による解決がおこなわれます。
コマンド解決部分は1.0.0正式版リリースを前にしてもちょくちょく手が入っているので、正式版が出た後で機会があれば書いてみたいところです。

NUnitの.NET Core向けテストランナーalpha版の使い方

さて、xUnitではなくNUnitを使おうと試行錯誤すること数分、どうやらNUnitの.NET Core対応版がまだリリースされていないらしいことに気付きました。ゴリ押しする方法は提示されています。しかし.NET Core方式のほうが、テストランナーとのレポートのやり取り方法などをきっちり定義しているので、のちのちはCIでの状況モニタなどにおいて下回りのテストランナーを意識せずに結果を利用できるようになって嬉しいはずです。このため、せっかくなら.NET Coreの流儀でやりたいものです*1
実はnuget.orgでNUnitの.NET Core対応alpha版が配布されています*2
本エントリを書いているタイミングでの最新版はdotnet-test-nunit/3.4.0-alpha-1です。
使いかたはとてもシンプルです。マルチプロジェクト構成をとる場合は、さきほどのUnit Testing in .NET Core using dotnet testページのxUnit向けガイドに途中まで従ってglobal.jsonを書くなどしておきましょう。
そしてテストプロジェクト側では次のようなproject.jsonファイルを作成します。
{
  "version": "1.0.0-*",
  "dependencies": {
    "NETStandard.Library": "1.5.0-rc2-24027",
    "NUnit": "3.2.1",
    "NUnitLite": "3.2.1",
    "dotnet-test-nunit": "3.4.0-alpha-1",
    "ReVIEWBlogger": "1.0.0"
  },
  "testRunner": "nunit",
  "frameworks": {
    "netstandard1.5": {
      "imports": [
        "dnxcore50",
        "netcoreapp1.0",
        "portable-net45+win8"
      ]
    }
  },
  "runtimes": {
    "win10-x86": {},
    "win10-x64": {},
    "osx.10.11-x64": {},
    "debian.8-x64": {}
  }
}
ここで、"ReVIEWBlogger": "1.0.0"は私の手元のテスト対象パッケージです。手元の環境にあわせて適宜変更してください。
大事な記述が数点あるので整理します。
  • "testRunner": "nunit" .NET Coreへのテストランナー指定
  • "dependencies"
    • "NUnit": "3.2.1" NUnitの本体
    • "dotnet-test-nunit": "3.4.0-alpha-1" NUnitの.NET Core用テストランナー
  • "frameworks": { "netstandard1.5": "imports": [] }
    • "portable-net45+win8" dnxcore50未サポートの依存PCLパッケージ用*3
  • "runtimes" 実行環境に含めたいランタイムの一覧
    • テストランナーでxplatというのはまああんまり想定するものでないので、"platform"指定ではなく"platfroms":でそれぞれ指定していく感じです
    • 一般的なものはここでカバーしていますが、足りない場合は公式のRID一覧ページを参照してください
どれをサボってもうまく動作しないはずです。
ちなみにパス解決の都合上、project.jsonでの記述は"testRunner": "NUnit"などではなく"testRunner": "nunit"と表記する必要があります。私は当初NUnitと記載していて、以下のように「そんな実行ファイルないよ」と怒られていました。
dotnet-test Error: 0 : Microsoft.DotNet.Cli.Utils.CommandUnknownException: No executable found matching command "dotnet-test-NUnit"
   at Microsoft.DotNet.Cli.Utils.ProjectDependenciesCommandFactory.FindProjectDependencyCommands(String commandName, IEnumerable`1 commandArgs, String configuration, NuGetFramework framework, String outputPath, String buildBasePath, String projectDirectory)
   at Microsoft.DotNet.Cli.Utils.ProjectDependenciesCommandFactory.Create(String commandName, IEnumerable`1 args, NuGetFramework framework, String configuration)
   at Microsoft.DotNet.Tools.Test.ConsoleTestRunner.DoRunTests(ProjectContext projectContext, DotnetTestParams dotnetTestParams)
   at Microsoft.DotNet.Tools.Test.TestCommand.DoRun(String[] args)
[*1] .NET Coreのテストランナーサポートについては、NUnitのGitHubリポジトリにてissue(https://github.com/nunit/nunit/issues/1371が立っていて、nuget.orgで配布を始める前の暫定版も配布されていましたが、このblogエントリを下書きで放置している間にクローズされました。
[*2] 本件を調べ始めた当初にはNUnit開発者のプライベートなNuGetリポジトリにてテスト版が公開されていたのですが、nuget.orgへ移動しました。
[*3] .NET Core環境を想定していないパッケージはまだまだ多いです。実際にはportable-net45+win8指定で問題なく動作するものも多いので、この記述は現在の.NET Core用project.json内で頻出します。

.NET Coreのコマンドラインからテストを実行してみる

次のようなコードを書いて実行してみます。
using NUnit.Framework;

namespace ConsoleApplication
{
    [TestFixture]
    public class Program1
    {
        [Test]
        public void TestExpectedToPass()
        {
            Assert.Pass();
        }

        [Test]
        public void TestExpectedToFail()
        {
            Assert.Fail("No luck!!");
        }
    }
}
このようになります。
$ dotnet test
Project ReVIEWBlogger (.NETCoreApp,Version=v1.0) was previously compiled. Skipping compilation.
Project ReVIEWBlogger.Tests (.NETStandard,Version=v1.5) will be compiled because inputs were modified
Compiling ReVIEWBlogger.Tests for .NETStandard,Version=v1.5

Compilation succeeded.
    0 Warning(s)
    0 Error(s)

Time elapsed 00:00:06.2825436


NUnit .NET Core Runner 3.4.0
Copyright (C) 2016 Charlie Poole
Runtime Environment
    OS Platform: Darwin
     OS Version: 10.11
        Runtime: osx.10.11-x64
Test Files
    /Users/muo/workspace/review-blogger/test/ReVIEWBlogger.Tests/bin/Debug/netstandard1.5/osx.10.11-x64/ReVIEWBlogger.Tests.dll
Errors and Failures
1) Failed : ConsoleApplication.TestsForTesting.TestExpectedToFail
No luck!!
at ConsoleApplication.TestsForTesting.TestExpectedToFail()
Run Settings
    WorkDirectory: /Users/muo/workspace/review-blogger/test/ReVIEWBlogger.Tests
Test Run Summary
  Overall result: Failed
  Test Count: 2, Passed: 1, Failed: 1, Inconclusive: 0, Skipped: 0
    Failed Tests - Failures: 1, Errors: 0, Invalid: 0
  Start time: 2016-06-13 06:39:19Z
    End time: 2016-06-13 06:39:19Z
    Duration: 0.637 seconds
Results saved as /Users/muo/workspace/review-blogger/test/ReVIEWBlogger.Tests/TestResult.xml
SUMMARY: Total: 1 targets, Passed: 0, Failed: 1.
正しく失敗しますね。
すばらしい。
すばらしいですね。

Project Tangoの最近の変更を軽く追いかけたメモ

2016年6月6日月曜日

C APIのヘッダ的な意味で。
じきにUE4+Tangoの組み合わせで使いたいので、ベースリビジョンにはhttps://github.com/opaquemultimedia/ProjectTangoPluginに取り込まれているものを利用。
そしてProject TangoのSDKダウンロードページhttps://developers.google.com/project-tango/downloads?hl=ja#project_tango_sdk_filesから得られる最新(2016年5月にリリースされた"Mira"のもの)を入手。
簡単にdiffを取れるかなーと思って開いてみると、doxygen用の記法を変えたようでほぼ全行のdiffが出てきた。最低限1行コメントを削ったり行末スペースを加工してdiffを取ったところ、それでも2,000行ぐらいのdiffがでてきた。
コメントの再フォーマットなどの影響をずいぶん受けていると感じたため、clocコマンドで複数行コメントを削り、それをある程度手加工したうえでclang-formatへ通して最低限まともな感じにした*1
得られたdiffがhttps://gist.github.com/muojp/9db610e6dc14be97a033a160c9d89674
いくつかenumの追加と構造体追加にそれら関連の定数追加、そして現状どこまで本気で動くか分からないユーティリティ関数がいくつか*2追加されている。
ん???
- TANGO_RECORDING_MODE_SCENE_RECONSTRUTCION = 1,
+ TANGO_RECORDING_MODE_SCENE_RECONSTRUCTION = 1,
どこが違うっけ、としばし悩んでRECONSTRUCTIONのtypo修正かーーーと気付いた。
Android本体でも時折あったやつですね。今回は時間切れにつきここまで。
UE4.11+に対応していない理由に関して、https://github.com/opaquemultimedia/ProjectTangoPlugin/issues/1#issuecomment-223446785になかなか悲しい事情が書かれてた。というわけでTango Coreチームの次リリース時にきっと更新される。
[*2] 元ファイルではexperimentalとわざわざ明記されているものも多い。