コグノスケ


link 未来から過去へ表示(*)  link 過去から未来へ表示

link もっと前
2017年12月1日 >>> 2017年12月1日
link もっと後

2017年12月1日

ARMでCubeHash

先日(2017年11月30日の日記参照)CPUによるモナコインというかLyra2REv2の計算で、ボトルネックとなっていたCubeHashをSSE化してみました。今回はARMでチャレンジしてみます。

Raspberry Pi 3(ARM Cortex A53/1.2GHz x 4)でCPUマイナーを実行してみるとたったの8kH/sしか出ません。4コア並列で動作させると32kH/sとなり、きっちり4倍になるのは素晴らしい(※)ですが、x86_64 CPUの1コアにも敵わないです。

NEONにもIntrinsicsがあることを知ったので、不親切なNEON命令のマニュアルと戦いながら、CubeHashをNEON化してみたところ、10kH/sほどになりました。

NEONを使ったCubeHashの素朴な実装

#if defined(__ARM_NEON__)
#  include <arm_neon.h>
#endif

//...

#define NEON_ROTL(x, n) do { \
		uint32x4_t mw0, mw1; \
		mw0 = vshlq_n_u32((x), (n)); \
		mw1 = vshrq_n_u32((x), 32 - (n)); \
		x = vorrq_u32(mw0, mw1); \
	} while (0);

#define NEON_SWP(a, b) do { \
		uint32x4_t mw; \
		mw = b; \
		b = a; \
		a = mw; \
	} while (0);

#define NEON_STEP5(x) do { \
		uint64x2_t mw; \
		mw = vreinterpretq_u64_u32((x)); \
		mw = vextq_u64(mw, mw, 1); \
		x = vreinterpretq_u32_u64(mw); \
	} while (0);

#define ROUND_ONE_NEON    do { \
		mxg = vaddq_u32(mx0, mxg); \
		mxk = vaddq_u32(mx4, mxk); \
		mxo = vaddq_u32(mx8, mxo); \
		mxs = vaddq_u32(mxc, mxs); \
		NEON_ROTL(mx0, 7); \
		NEON_ROTL(mx4, 7); \
		NEON_ROTL(mx8, 7); \
		NEON_ROTL(mxc, 7); \
		NEON_SWP(mx0, mx8); \
		NEON_SWP(mx4, mxc); \
		mx0 = veorq_u32(mx0, mxg); \
		mx4 = veorq_u32(mx4, mxk); \
		mx8 = veorq_u32(mx8, mxo); \
		mxc = veorq_u32(mxc, mxs); \
		NEON_STEP5(mxg); \
		NEON_STEP5(mxk); \
		NEON_STEP5(mxo); \
		NEON_STEP5(mxs); \
		mxg = vaddq_u32(mx0, mxg); \
		mxk = vaddq_u32(mx4, mxk); \
		mxo = vaddq_u32(mx8, mxo); \
		mxs = vaddq_u32(mxc, mxs); \
		NEON_ROTL(mx0, 11); \
		NEON_ROTL(mx4, 11); \
		NEON_ROTL(mx8, 11); \
		NEON_ROTL(mxc, 11); \
		NEON_SWP(mx0, mx4); \
		NEON_SWP(mx8, mxc); \
		mx0 = veorq_u32(mx0, mxg); \
		mx4 = veorq_u32(mx4, mxk); \
		mx8 = veorq_u32(mx8, mxo); \
		mxc = veorq_u32(mxc, mxs); \
		mxg = vrev64q_u32(mxg); \
		mxk = vrev64q_u32(mxk); \
		mxo = vrev64q_u32(mxo); \
		mxs = vrev64q_u32(mxs); \
	} while (0)

#define SIXTEEN_ROUNDS_NEON   do { \
		int j; \
		uint32x4_t mx0, mx4, mx8, mxc; \
		uint32x4_t mxg, mxk, mxo, mxs; \
		mx0 = vld1q_u32((void *)&x0); \
		mx4 = vld1q_u32((void *)&x4); \
		mx8 = vld1q_u32((void *)&x8); \
		mxc = vld1q_u32((void *)&xc); \
		mxg = vld1q_u32((void *)&xg); \
		mxk = vld1q_u32((void *)&xk); \
		mxo = vld1q_u32((void *)&xo); \
		mxs = vld1q_u32((void *)&xs); \
		for (j = 0; j < 16; j ++) { \
			ROUND_ONE_NEON; \
		} \
		vst1q_u32(&x0, mx0); \
		vst1q_u32(&x4, mx4); \
		vst1q_u32(&x8, mx8); \
		vst1q_u32(&xc, mxc); \
		vst1q_u32(&xg, mxg); \
		vst1q_u32(&xk, mxk); \
		vst1q_u32(&xo, mxo); \
		vst1q_u32(&xs, mxs); \
	} while (0)

//...

#if defined(__ARM_NEON__)
#  define ROUND_ONE    ROUND_ONE_NEON
#  define SIXTEEN_ROUNDS    SIXTEEN_ROUNDS_NEON
#else
#  define ROUND_ONE    ROUND_ONE_SLOW
#  define SIXTEEN_ROUNDS    SIXTEEN_ROUNDS_SLOW
#endif

前回と同様にcpuminer-multiのマクロに無理矢理はめ込んで実装しています。NEONを触るのは初めてで、非効率的な書き方になっているかもしれません。お気づきの点があれば教えてくださいませ。

(※)AMD A10-7600は昨日書いた通り1コア145kH/sですが、4コア並列だと145 x 4 = 580kH/sとはならず、少し効率が落ち490〜500kH/sほどになります。

コンパイラの本気はどこ行った

前回SSE化したときは1ラウンドの処理だけ書き換えれば事足りましたが、今回NEON化したときは16ラウンドのループも書き換える必要がありました。

何故かというとx64と違ってarmhfの場合、コンパイラがあまり良い結果を出力してくれないからです。gcc-7.2 x64の場合、

  • load
  • add
  • xor
  • store

このような処理をループさせても、生成されたバイナリの逆アセンブルを見ると、

  • load
  • add
  • xor
  • ※に戻る
  • store

以上のようにload/storeの無駄を検知してループ「外」に追い出してくれました。しかしgcc-4.9 armhfの場合、ループ「内」にload/storeが残ってしまい、かなり遅くなります。

原因としてgccのバージョンが古い、アーキテクチャの最適化がこなれてない、NEONのIntrinsicsを使うと最適化が制限される、などいくつか考えられますが、今のところ分かりません。gcc-7にしたらコンパイラが賢くやってくれるようになれば一番楽ですけどね……。

編集者:すずき(2021/05/14 22:57)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link もっと前
2017年12月1日 >>> 2017年12月1日
link もっと後

管理用メニュー

link 記事を新規作成

<2017>
<<<12>>>
-----12
3456789
10111213141516
17181920212223
24252627282930
31------

最近のコメント5件

  • link 20年6月19日
    すずきさん (04/06 22:54)
    「ディレクトリを予め作成しておけば良いです...」
  • link 20年6月19日
    斎藤さん (04/06 16:25)
    「「Preferencesというメニューか...」
  • link 21年3月13日
    すずきさん (03/05 15:13)
    「あー、このプログラムがまずいんですね。ご...」
  • link 21年3月13日
    emkさん (03/05 12:44)
    「キャストでvolatileを外してアクセ...」
  • link 24年1月24日
    すずきさん (02/19 18:37)
    「簡単にできる方法はPowerShellの...」

最近の記事20件

  • link 24年4月17日
    すずき (04/18 22:44)
    「[VSCodeとMarkdownとPlantUMLのローカルサーバー] 目次: LinuxVSCodeのPlantUML Ex...」
  • link 23年4月10日
    すずき (04/18 22:30)
    「[Linux - まとめリンク] 目次: Linuxカーネル、ドライバ関連。Linuxのstruct pageって何?Linu...」
  • link 20年2月22日
    すずき (04/17 02:22)
    「[Zephyr - まとめリンク] 目次: Zephyr導入、ブート周りHello! Zephyr OS!!Hello! Ze...」
  • link 24年4月16日
    すずき (04/17 02:05)
    「[Zephyr SDKのhosttoolsは移動してはいけない、その2 - インストール時のバイナリ書き換え] 目次: Zep...」
  • link 24年4月15日
    すずき (04/17 01:47)
    「[Zephyr SDKのhosttoolsは移動してはいけない、その1 - 移動させると動かなくなる] 目次: ZephyrZ...」
  • link 24年4月11日
    すずき (04/17 00:37)
    「[VScodeとAsciiDocとKrokiローカルサーバー] 目次: LinuxAsciiDoc ExtensionはAsc...」
  • link 24年4月12日
    すずき (04/16 00:12)
    「[台湾東部沖地震に寄付] ささやかではありますが台湾東部沖地震に寄付しました。日本の赤十字社→台湾の赤十字(正式名称...」
  • link 22年9月3日
    すずき (04/16 00:08)
    「[MarkDownのその向こう] 目次: Linux簡単なドキュメントやメモはMarkDownで書くことが多いですが、気合を入...」
  • link 22年9月4日
    すずき (04/16 00:08)
    「[Asciidocをさらに活用] 目次: Linux前回(2022年9月3日の日記参照)、Asciidocのプレビュー環境の設...」
  • link 24年3月19日
    すずき (04/16 00:07)
    「[モジュラージャックの規格] 目次: Arduino古くは電話線で、今だとEthernetで良く見かけるモジュラージャックとい...」
  • link 23年6月2日
    すずき (04/16 00:07)
    「[Arduino - まとめリンク] 目次: Arduino一覧が欲しくなったので作りました。 M5Stackとesp32とA...」
  • link 24年4月9日
    すずき (04/12 12:44)
    「[初めて作ったボード動作せず(手で直した)] 目次: Arduino以前(2024年3月24日の日記参照)発注して、全く動ない...」
  • link 24年4月2日
    すずき (04/12 11:00)
    「[KiCadが動かなくなったのでビルド] 目次: ArduinoDebian Testingなマシンをapt-get upgr...」
  • link 24年4月3日
    すずき (04/12 11:00)
    「[初めて作ったボード動作せず(燃えた)] 目次: Arduino以前(2024年3月24日の日記参照)発注したPCBが届いたの...」
  • link 24年3月24日
    すずき (04/12 11:00)
    「[PCBを設計して注文] 目次: Arduinoシューティングの練習でいつもお世話になっているTARGET-1秋葉原店に、6つ...」
  • link 24年3月25日
    すずき (03/26 03:20)
    「[Might and Magic Book One TASのその後] 目次: Might and Magicファミコン版以前(...」
  • link 21年10月4日
    すずき (03/26 03:14)
    「[Might and Magicファミコン版 - まとめリンク] 目次: Might and Magicファミコン版TASに挑...」
  • link 24年3月18日
    すずき (03/19 11:47)
    「[画面のブランクを無効にする] 目次: LinuxROCK 3 model CのDebian bullseyeイメージは10分...」
  • link 24年3月3日
    すずき (03/19 11:07)
    「[解像度の設定を保存する] 目次: LinuxRaspberry Pi 3 Model B (以降RasPi 3B)のHDMI...」
  • link 24年3月14日
    すずき (03/16 23:03)
    「[JavaとM5Stamp C3とBluetooth LE - Bluetoothデバイスとの通信] 目次: ArduinoM...」
link もっとみる

こんてんつ

open/close wiki
open/close Linux JM
open/close Java API

過去の日記

open/close 2002年
open/close 2003年
open/close 2004年
open/close 2005年
open/close 2006年
open/close 2007年
open/close 2008年
open/close 2009年
open/close 2010年
open/close 2011年
open/close 2012年
open/close 2013年
open/close 2014年
open/close 2015年
open/close 2016年
open/close 2017年
open/close 2018年
open/close 2019年
open/close 2020年
open/close 2021年
open/close 2022年
open/close 2023年
open/close 2024年
open/close 過去日記について

その他の情報

open/close アクセス統計
open/close サーバ一覧
open/close サイトの情報

合計:  counter total
本日:  counter today

link About www.katsuster.net
RDFファイル RSS 1.0

最終更新: 04/18 22:44