**********************************************************************
ワーク S3-a
テーマ:【SWEST/ACRi共同企画セッション】入門者向けFPGAアクセラレータ開発ハンズオンワークショップ
講師:安藤 潤(ザイリンクス株式会社 データセンターグループ)
参加人数:15名
**********************************************************************

・セッションの目標
  FPGAアクセラレータについて幅広く浅く説明する。

・事前準備
  ハンズオンでACRiルームを使う。

・ACRiとは?
  FPGAを盛り上げる会。
  FPGA布教活動をしている。
  ウェビナーや討論会、入門者向けハンズオンで活動している。
  ACRiブログやACRiルームといった無償でFPGAを利用できる利用環境を提供している。

・ACRiルームの登録
  できたらアカウント登録をして、ハンズオンを一緒にやってほしい。

・自己紹介:組込みと私の関係
  10年ほど液晶ディスプレイコントローラ向けのデジタルIP開発をしていた。主に画像処理。
  絵をきれいにするという事でなく、液晶の特性の弱いところを補って、より正確に絵を表示する処理のデジタル回路の開発を行っていた。
  液晶パネルの価格は安いほど良い、消費電力も低くないといけない。どうやって回路を書けばよいのかで苦労した
  (補足:遅いプロセスで動作周波数を満たし、かつ回路規模にも気をつけなければいけませんでした)。
  後半は案件がすごくたくさんあり、2,3か月にIPを何個もリリースしないといけないということで、設計生産性を考えさせられた。

  デジタルIP開発の傍ら、ディスプレイコントローラーの中に8ビットのCPUを入れようという話があった。
  ファームウェアやCPU周りの設計・検証を担当していた。
  I2CとかSPIに悩まされた。

  その後、ザイリンクスに組込みエンジニアとして入社。
  現在はデータセンターグループでアクセラレータカード担当。
  サーバーにFPGAを指して、それを計算に利用するというカードのこと。

・FPGAアクセラレータとは?
  用途に応じて回路を書き換えられる半導体。
  半導体の製品はふつう一度回路を作ったら大量生産して、機器に載せる。
  生産した後でも回路の中身を書き換えられるので、いろいろな分野で使われている。

・利用例
  SUBARUのレヴォーグのステレオカメラのデジタル処理や、火星探査ロボットに乗っかっていって、画像処理に使われた。
  CPUより18倍速く動作できる。
  火星探査ロボットでは最初はモーター基板に使われたらしい。

・ザイリンクスAlveo
  ザイリンクスはFPGAを専業で作っている会社。
  ここ3年くらいからアクセラレータカードを自社で作っている。
  サーバーのPCIスロットにカードを接続するとCPUの処理をFPGAに肩代わりできる。
  システム全体を高速化しようという製品を作っている。
  Alveoのアクセラレータカードではザイリンクスでも最大規模のFPGAを搭載している。
  ACRiルームでは5台挿されたサーバーが用意されている。

・CPUやGPUとの違い
  ・動作周波数
    CPU 3GHz。GPU 1.5GHz。FPGAは300MHzとCPUやGPUより少ない。
    回路を変更できるようにした結果のオーバーヘッドが発生するから。

  ・並列度
    CPU ~数十コア。GPU ~数千コア。FPGAは任意である。
    回路を自由に変更できるから。

  ・メモリ帯域
    同じものを使っているので同じ。

  ・アーキテクチャ
    CPU、GPU
    あらかじめプロセッサが作りこまれた状態で、命令セットアーキテクチャがあって、階層型キャッシュメモリがあるという風に構造が決まっている。
    そのうえでコンパイラが用意されていて、ソフトウェアを書いて動かす。

    FPGA
    そもそもアーキテクチャが無くて自由。
    画像処理であれば、画像処理専用のアーキテクチャを入れるといった風にいろいろな用途に応じて作ることができる。
    そのうえで非常に高い並列度で動くようにすることで、動作周波数が少なくとも早く計算できる。

  ・まとめると
    GPUはたくさんのデータを並列に処理するのが得意。
    FPGAはたくさんの計算を並列に処理するのが得意。

・FPGAアクセラレータってどうやって開発するのか
  コンパイラもないのにどうするの?
  ザイリンクス社がAlveo開発環境としてVitisを用意している。
  VitisでC++でアクセラレータが書ける。
  ソフトウェアを書ける人であればなじみやすいようになっている。
  どうやって書くのかを勉強する場として、HLSチャレンジを作りました。
  Vitisを使うと組込みから大規模なアクセラレータカードまで同じ設計フロー、同じソースコード、同じツールで開発できる。
  ホストプログラムにはOpenCL Runtime APIを利用。
  ザイリンクス社が勝手に決めたものでなく、一般に規格が決まっているAPI。
  後ろでFPGAが動いているのかGPUが動いているのかあまり意識しないで動かせる。
  カードを購入せずとも、ツールだけ使うことも可能。

・Vitisを出した理由、優れている点
  従来のアクセラレータ開発だとホストの上で動くアプリケーションがあってその一部を早くしたい。

・従来のFPGAアクセラレータ開発
  アプリの重いところをFPGAで動かそうと回路として切り出す。
  切り出しただけでは使い方がわからない。
  ホストとFPGAの間で通信しなければならないので、FPGAにPCIe I/Fを入れて、データコピーのためのDMAを入れて、カーネルを動かすための制御やメモリコントローラーが必要になる。
  さらに細かいことを言うと、カードをどうやって管理するのか、FPGA回路の中を回路を書き換える仕組みをどうやって実装するのかといった考慮が必要になる。

  アクセラレータの実現までに膨大な開発工数が必要。
  相当な技術力、経験がある会社でないと使えなくなってしまう。

・VitisによるFPGAアクセラレータ開発
  この問題をVitisを使って解決する。
  ユーザーが設計しなければならないのはホストのアプリケーション部分、切り出したカーネル部分になる。
  そこさえ設計すれば、あとはザイリンクス社が足回りとなる部分をあらかじめ設計済みの状態で提供する。
  FPGAのプラットフォームもザイリンクス社が用意し、検証もしている。

  Vitisがやってくれるのはユーザーが作ったカーネルとプラットフォームをつなぎ合わせる部分である。
  必要な制御、データパス、メモリコントローラを入れてくれる。

  それにより、ユーザーからするとアプリケーションとカーネル部分のみを作ればよくなる。
  非常に早くFPGAアクセラレータを作ることが出来る。

・高位合成によるカーネル設計
  アプリケーションの重い部分を切り出すカーネルですが、カーネルの作り方はいろいろある。
  Vivadoで使っていたRTLで作る方法もあるが、高位合成で作るカーネルも非常にオススメ。
  高位合成はC++を使ってハードウェアを記述する。
  ハードウェアを記述すると高位合成ツールがRTLという回路の状態に変換してくれる。
  C++を書くと抽象度の高く、簡単にシンプルな記述が出来る。

・利点
  Cなのでソフトウェアで実行すると高速にシミュレーションできる。
  生成されたRTLの検証も自動でできる。
  HLSチャレンジはHLSのコードをいかに書くのかにフォーカスしている。

・C++でハードウェアを書くとは?
  数式を書くとパイプラインが生成される。
  回路にどうやってデータが入り、何処に出力されるのかを自分でC++で書くことで、数式周りのデータを共有する部分、データの出力、ループを回す制御をツールが勝手にやってくれる。
  C++で書くと、コードに集中できる。

  すべてHLSで何とかできるというわけではない。
  RTLでないと書けない部分もあるので、適材適所。

・伝えたいこと
  アクセラレータをHLSで記述することが出来る。
  HLSをうまく使いこなして、開発を高速化していこう。

質問
  Q 手元のPCでもハンズオンが出来るか?
  A 手元のPCで直接HLSコードを記述して、それを直接HLSチャレンジのサイトに投げることで参加可能。

・Alveoデモ
  1.PYNQのデモ
  2.Gzipでデータ圧縮を行うデモ
  を行う。

  ・開発の流れ
    リモートデスクトップでACRiルームにつなぐ。
    そのためのポート転送をする。
    ACRiルームにログインするとUbuntu18.04の画面になる。
    ここでPYNQを動かす。
    /opt/pynq-notebooks/start.sh というスタートスクリプトを叩いていただくと、Jupyter Notebookが立ち上がる。

  ・プログラムの例
    今動かそうとしているのはaとbのベクトルを足して、cを出力するもの。
    コードの中のプラグマは最近のHLSだとデフォルトで追加してくれる。
    コードを書いた後はコンパイルする。
    普通のソフトウェアならコンパイルして、オブジェクトファイルにして、リンクして、実行するという流れです。
    HLSでもその流れは変わらない。

    Cをコンパイルして、.xoというオブジェクトファイルにする。
    やっているのはCをRTLに変換してパッケージにしているだけ。

    カーネルの入れ物部分に何を使うのか選択する。

    次にリンクをする。
    コンパイルした.xoファイルを渡して、プラットフォームを指定してリンクすると .xclbinファイルが作られる。
    この中にFPGAに書き込む回路の情報が入っている。

  1.PYNQデモ
    ・PYNQのコードについて
      PYNQを使うと非常に簡単にFPGAの回路を作ることが出来る。
      回路情報を含む.xclbinファイルを読み込む。
      FPGAに回路がプログラムされる。
      Cのコードのカーネルのインスタンスを取得する。
      メモリをアロケーションするホスト、FPGAどちらのマッピングも行われる。
      CPU側のメモリのデータを初期化する。
      ホストのメモリの中身をFPGA側のメモリにコピーしている。
      FPGAのメモリに用意が出来たので、FPGAが動くように命令する。
      そうすると、FPGAが裏で動いて計算結果が得られるので、ホストのメモリに結果をコピーしている。
      セッション中ではPYNQコードを動かして、成功している。

  2.Gzipでの圧縮デモ
    Gzipの処理をFPGAに入れて、どのくらい早いかを確認する。
    CPUのシングルスレッドでやった場合、マルチスレッドで行った場合、FPGAで行った場合を比較する。
    使用するのは圧縮処理の比較に用いられるデータセット。
    データセット1個分と、10個を重ねたもので実行する。

    ・実行結果
      CPUのシングルスレッドでやった場合:圧縮率 2.73倍、かかった時間 2.25秒、スループット 94.19MB/s
      マルチスレッドで行った場合:圧縮率 2.74倍、 かかった時間 0.44秒、 スループット 481.67MB/s

      FPGAでの実行に失敗した。
      source /tools/Xilinx/Vitis/2020.2/settings64.sh && source /opt/xilinx/xrt/setup.shを打ち忘れていた。
      ザイリンクスのドライバを読み込むのを忘れていた。
      .xclbinファイルを読み込んで実行した。
      FPGAで行った場合を比較: 圧縮率 2.77倍、 かかった時間 0.4秒、 スループット 4885.2MB/s
      CPUで実行するよりもかなり速いスピードが出ていることが分かる。

・ACRi HLSチャレンジ
  新コンテンツ提供の動機
  ACRiルームをもっと利用してもらいたい。
  ACRiルームはかなり高性能なFPGAカードやサーバをただで使えるすごい取り組みだから皆様にもっと使ってほしい。

  HLSの活用を広めたい
  自分自身が設計の開発生産性に悩まされた。
  HLSを使って早く開発することが出来たらよいな。
  HLSの勉強をしたいが、どのように勉強したらよいかわからない人への勉強の場の提供をしたい。


・HLSチャレンジ
  HLSコード投稿サイト
  お題があるので、お題に沿った回路を書いてもらってその性能を競う。

  必ずしも性能を出したいというものではなく、まずは回路としてきちんと変換されて動くのかをやってもらって、性能を上げるテクニックを少しずつ勉強して頂きたい。

  お題に出ている回路はカーネルとしてVitisに入れれば、FPGAのアクセラレータで動かすことが出来る。
  HLSチャレンジのお題を勉強すると、アクセラレータ開発もマスターできる。

・利用の流れ
  1.HLSチャレンジにログイン
  2.チャレンジ(お題)を選択
  3.チャレンジをダウンロード ※ACRiルームを活用(お手元でC言語をかくだけでも可能)
  4.コードを作成
  5.コードをチェック
  6.HLSチャレンジに投稿する

  1.HLSチャレンジにログイン
    ログイン githubかメールアドレスでログインする。
    メールアドレスはわかるが、それ以外の個人情報は集めない。

  2.チャレンジ(お題)を選択
    トップページを見てもらうと、チャレンジが並んでいる。
    ここは好きなものを選んでよい。

    今回はベクトルの要素を倍にして返す問題を扱う。
    開くと、問題文が書いてあり、このインターフェースを満たすカーネルを作ってくださいというお題がある。
    回路の満たすべき条件やいつまでオープンしているのかといった条件が設定されている。
    最初は気にしなくてよい。
    回路を並列化して早くしたいときに、制限に引っ掛からないか気を付ける必要がある。

    提出期限とは?
    チャレンジが公開され、開催中までのコードでランキングをとる。
    開催後も提出、採点は出来る。

  3.チャレンジをダウンロード
    ここからは実際にACRiルームを使ってカーネル書いていく。
    ACRiルームにダウンロードする簡単な方法は
    ダウンロードー>ターミナルにコピーを使って
    ACRiルームのターミナルに貼り付けると、問題丸ごとのコピーができる。
    ターミナルへコピーを行うと、チャレンジが展開される。

  4.コードを作成
    展開したチャレンジデータには問題文やカーネルヘッダ、ソースがある。
    カーネルソースの中身を具体的に実装する。
    カーネルソースの動作を確認するためのテストベンチ、採点条件があって、採点するためのスクリプトも入っている。

  5.コードをチェック
    採点スクリプトに実行権限を与えて実行する。
    セミコロンを忘れていたのでエラーといった採点もされる。

    ・採点の流れ
      CSIM
      コードをソフトウェアとしてCPU上でそのまま実行している。
      正しく動作することを確認する

      HLS
      Cで書かれたコードをRTLに変換する。
      問題なく変換できるかを確認する。

      CoSIM
      生成されたRTLをハードウェアとして実行して正しく動作するかを確認する。
      与えられたお題に対して、どのくらいのサイクルで計算したか、どのくらい早く計算したかを確認する。

      論理合成
      RTLをFPGAにプルするためのステップを行う。
      回路の詳しいリソース使用量がわかる。
      実行に時間がかかるので、仮採点ではスキップする。
      実行するにはvhls-checkに-sオプションをつける。

    HLSチャレンジサイトではこの4つを確かめる。
    おてもとのでテストパスすると動作周波数やリソース使用量の見積り、シミュレーションサイクル数や実行時間見積りが出る。
    誰が短い時間で計算できたかを競っていく。

  6.HLSチャレンジに投稿する
    提出すると、のちに結果が出る。

・オススメの取り組み方
  HLS初心者はどういう風にコードを書けば正しくRTLに変換されて動くのかを勉強してほしい。
  HLS上級者はランキングを競ってほしい。
  そうすると、HLSチャレンジサイト上にノウハウが蓄積される。

・ハンズオン(12:20~)
  ハンズオンの流れ
   1.ユーザー登録
   2.チャレンジをダウンロード
   3.コードを書いて自己採点
   4.HLSチャレンジサイトに投稿する

  中級、上級者は書き方を工夫する。
  画面を見ながら一緒に進めていく。

  ・ハンズオンの課題
    取り組むチャレンジは入力されるfloat配列の要素の平均と分散を計算し、出力するもの。

    利用の流れ1から6通りにやっている。
    採点スクリプトでPASSしたらコードをコピーして、HSLチャレンジサイトに投稿する。
    あとはHLSチャレンジサイト側の採点を待つ。

  ・注意点
    リモートデスクトップでログインしている方だと、チャレンジ貼り付けがうまくいかない場合がある。
    その場合はテキストエディターに貼って.shをつけて保存する。
    bash ./tmp.shのようにすると展開できる。

  ・コメント
    論理合成をするので提出から結果が出るまで時間がかかる。
    動作周波数の見積りとリソースの見積りが正確になる。
    ただ、時間がかかるのが問題。

    カーネルのコードを書き換えて早くなるかどうかはサイクル数をいかに短くするかという問題になる。

  ・今回の問題のヒント
    平均を求めるにはまず足し合わせる必要がある。
    足し合わせる計算が浮動小数点数の場合、ボトルネックになりがち。
    今回はFloatの計算に2サイクルかかってしまう。
    短いサイクル数で計算するには、滞りなく処理することが望ましい。
    解決策として、足しこみに時間がかかるなら、足しこみの回路を2つにしてしまえばよい。

    #pragma HLS UNROLL factor=2 によって2個の回路でsumを計算する。
    プラグマはコンパイラ指示子。
    このコードはこのように変換してくださいとお願いする書き方である。
    同じ回路を二個並べてsumを計算し、最後に足し算する。

    また、固定小数点数で演算する解決策もある。

    コードの書き方は他にもたくさんある。
    初心者は他にどのようなものがあるのか勉強してみてください。

・質問
  Q 文が2つ続いていたとする 文に計算に依存関係がないとする。
    何も指定していなくても並列で計算できるのか?指定しないとできないか?
  A 基本的には順番に実行するような回路ができる。

  Q この文とこの文を並列に実行したい場合はどうする?
  A for文が複数ある場合に処理を並列で実行するよう指示するDATAFLOWというプラグマがある。

  Q for文ではなく、2つの文をを実行する場合は?
  A その場合もDATAFLOWで大丈夫 データフローではfor文、1個の式、関数呼び出しなども並列化する。

■まとめ
  ここではVitisを使って、FPGAアクセラレータを作成した。
  前セッションのセッションS2-a 【SWEST/ACRi 共同企画セッション】PYNQでお手軽に始めるFPGAシステム開発とは異なる方法で開発をしている。
  Vitisを使うことで、アプリケーション、カーネルのみの開発に注力できるのは大きな強みである。
  また、高位合成というC++からハードウェア言語を自動生成する技術も大変便利である。
  こういった道具をうまく使いこなして、開発工程を加速するべきである。

  また、高位合成の勉強の場としてHLSチャレンジというコンテンツがある。
  高位合成に興味のある方はACRiルームと併用して、練習できるので、是非とも挑戦してみてほしい。

以上。