目次: RISC-V
最近、何かと関わっているRISC-Vの理解のため、エミュレータを書いてみています。先日購入したHiFive Unleashed(2019年5月26日の日記参照)の1st ROMと2nd ROMを拝借して、Linuxがブートする辺りまで作るのが当面の目標です。
スクラッチから作ると辛いので、ARMv5のエミュレータememu(GitHubへのリンク)をベースにして改造して作っています。まがりなりにもARMv5が動いているんだから、RISC-Vも楽勝だろうと思いきや、世の中そんなに甘くありませんでした。
最初にコケたのはUnalignedな命令ロードです。RISC-VのC拡張をサポートする場合32bit境界ではないアドレスから、32bit命令をロードする場合があります。ARMv5ではUnalignedアクセス例外が発生します。
まだ完成していないので、現時点での感想ですが、RISC-Vの命令エンコードは比較的わかりやすい気がします。ただ、ブランチ命令のオフセットは、下記のような並びになっていて、不思議な配置です。
今まで見た中で一番見づらいものは、C拡張命令のバイナリです、これは異様に見づらいです。しかしC拡張の目的(命令長を削るため16bit長に無理して詰めている)からすると、仕方ないでしょうね。
この記事にコメントする
目次: C言語とlibc
今まであまりCPUアーキテクチャの違いを感じたことはありませんが、除算命令を触っていたところ、アーキテクチャによってかなり動きが違っていて面白かったので、メモしておきます。
プログラムは下記のとおりです。
#include <stdio.h>
#include <limits.h>
void f(int a, int b)
{
printf("mul:%08x * %08x = %08x\n", a, b, a * b);
printf("div:%08x / %08 = %08x\n", a, b, a / b);
}
int main(int argc, char *argv[])
{
f(INT_MAX, -1);
f(INT_MIN + 1, -1);
f(INT_MIN, -1); //乗算、除算の動作は未定義
f(INT_MAX, 0); //除算の動作は未定義
}
初めに断っておくと、コメントを打った箇所については、C言語上の仕様上、動作が未定義です。つまり、どんなことでも起こり得ます。不定な結果が返ることもあるし、プログラムが停止することだってあります。
このプログラムをx86 (x86_64, Ryzen 7 2700), ARM (AArch64, Cortex A53), RISC-V (RV64GC, SiFive FU540) のLinux上でそれぞれ実行してみます。
#### x86_64 ####
mul:7fffffff * ffffffff = 80000001
div:7fffffff / ffffffff = 80000001
mul:80000001 * ffffffff = 7fffffff
div:80000001 / ffffffff = 7fffffff
mul:80000000 * ffffffff = 80000000
Floating point exception
#### AArch64 ####
mul:7fffffff * ffffffff = 80000001
div:7fffffff / ffffffff = 80000001
mul:80000001 * ffffffff = 7fffffff
div:80000001 / ffffffff = 7fffffff
mul:80000000 * ffffffff = 80000000
div:80000000 / ffffffff = 80000000
mul:7fffffff * 00000000 = 00000000
div:7fffffff / 00000000 = 00000000
#### RV64GC ####
mul:7fffffff * ffffffff = 80000001
div:7fffffff / ffffffff = 80000001
mul:80000001 * ffffffff = 7fffffff
div:80000001 / ffffffff = 7fffffff
mul:80000000 * ffffffff = 80000000
div:80000000 / ffffffff = 80000000
mul:7fffffff * 00000000 = 00000000
div:7fffffff / 00000000 = ffffffff
当然ながら、動作が定義されている演算は、どのアーキテクチャでも同じ結果です。当たり前ですね。
一方で動作が未定義の演算は、かなり挙動が変わります。
個性が出ますね。
先ほどの例でx86上でINT_MIN / (-1) の除算がクラッシュする原因はidiv命令の仕様です。
Intelの命令仕様書(Intel Architectures Software Developer Manual: Vol 2)のIDIV - Signed Divideのページを見ると、保護モード例外 #DEが発生する条件として、
この2条件が挙げられています。INT_MIN / (-1) は結果が32bitで表現できないため、後者に引っ掛かるわけです。
異常な演算に対して例外を発生させる設計思想なら分かりますが、乗算命令は異常な結果でも素通しなのに、除算命令は異常な結果だと例外発生します。片手落ちの不思議な仕様です。変なの……。
この記事にコメントする
首都圏外郭放水路 庄和排水機場(埼玉県春日部市)の調圧水槽と第一立坑(たてこう)の見学に行きました。
首都圏外郭放水路とは、洪水多発地域の中川流域(埼玉県の東部)を洪水から保護するため、中川、綾瀬川といった中小河川の水を地下経由で引き込み、ポンプで引き上げて江戸川に放流する仕組みです。
ちなみに国の施設でして、管轄は国土交通省(サイトへのリンク)です。
見学コースの一つである、調圧水槽は、地下神殿との呼び名もあるほどで、広大な空間とたくさんの柱があります。
柱の役割がわかっていなかったのですが、係の方の説明によると、周りの地下水の浮力で調圧水槽が浮き上がってしまうので、重い天井と柱で、水槽を下に押しつけているそうです。
第一立坑は高さ70mの大迫力で、一番上の壁沿いに組まれた足場から下を見ることができます。私は高いところが苦手でして、非常に怖かったです。足が進まないし、変な汗が止まりません。
怖すぎて壁際にずっとしがみついていたため、写真を撮る余裕がありませんでした。一緒に行ったみなさまが高いところが平気なようで、写真をバシバシ撮っていましたので、一枚恵んでもらいました。
高いところ(立坑)はもう懲り懲りですが……、今回参加したコースとは別の見学コース(排水ポンプ室に入れる)もあるらしいので、別コースにもぜひ行ってみたいですね。
この記事にコメントする
目次: OpenCL
会社の人にOpenVXの別実装があることを教えてもらったので、試してみました。
以前、ソフトウェア実装のOpenVXライブラリを動かしました(2018年11月14日の日記参照)が、AMDのOpenVXの実装(GitHubへのリンク)を使うと、GPUでOpenVXを動かすことができます。
AMDのOpenVX実装ではありますが、OpenCLを使うのでGPUはRadeonである必要はなく、IntelのGPUでもOKです。これが共通APIたるOpenCLの良いところですね。私は現状Radeonを持っていませんので、Intelの内蔵GPUで動かしてみようと思います。
まずOpenVXライブラリをビルドします。Debianであればopencl-c-headers辺りが必要になるはずです。またGPUドライバとしてIntel GPUドライバのOSS実装であるbeignetを使います。Debianであればbeignet-dev, beignet-opencl-icd辺りのパッケージでインストールできます。
$ git clone https://github.com/GPUOpen-ProfessionalCompute-Libraries/amdovx-core $ cd amdovx-core $ mkdir build $ cd build $ cmake ../ $ make -j4
テストには前回も活躍したOpenVXアプリを使用します。OpenCVのバージョンは3.2です。もし古いバージョンのOpenCVを使っている場合は -lopencv_videoioオプションを外してください(おそらく「そのようなライブラリは存在しない」とエラーが出る)。
g++ solution_exercise1.cpp -Wall -I../include \ -lopencv_video -lopencv_videoio -lopencv_highgui -lopencv_imgproc -lopencv_core \ -lopenvx -L/path/to/amdovx-core/build/lib
前回とほぼ同じですので、さほど難しくないと思います。
ビルドできましたので、実行……をする前に、vxProcessGraphの前後に時間計測のコードを入れておきます。
diff --git a/tutorial_exercises/solution_exercise1/solution_exercise1.cpp b/tutorial_exercises/solution_exercise1/solution_exercise1.cpp
index c7b8e21..ebc07e5 100644
--- a/tutorial_exercises/solution_exercise1/solution_exercise1.cpp
+++ b/tutorial_exercises/solution_exercise1/solution_exercise1.cpp
@@ -30,6 +30,8 @@
* Kari Pulli <kari.pulli@gmail.com>
*/
+#include <sys/time.h>
+
////////
// Include OpenCV wrapper for image capture and display.
#include "opencv_camera_display.h"
@@ -368,6 +370,8 @@ int main( int argc, char * argv[] )
// Process the video sequence frame by frame until the end of sequence or aborted.
for( int frame_index = 0; !gui.AbortRequested(); frame_index++ )
{
+ struct timeval st, ed, el;
+
////////********
// Copy the input RGB frame from OpenCV to OpenVX.
// Use vxAccessImagePatch and vxCommitImagePatch APIs (see "VX/vx_api.h").
@@ -407,8 +411,11 @@ int main( int argc, char * argv[] )
// if the frame_index == 0 (i.e., the first frame of the video
// sequence), otherwise, select the feature tracking graph.
// 2. Use ERROR_CHECK_STATUS for error checking.
+ gettimeofday(&st, NULL);
ERROR_CHECK_STATUS( vxProcessGraph( frame_index == 0 ? graphHarris : graphTrack ) );
-
+ gettimeofday(&ed, NULL);
+ timersub(&ed, &st, &el);
+ printf("ProcessGraph:%d.%06d[s]\n", (int)el.tv_sec, (int)el.tv_usec);
////////********
// To mark the keypoints in display, you need to access the output
実行環境は下記のとおりです。
最初にソフトウェア版のライブラリを実行します。
$ LD_LIBRARY_PATH=/path/to/openvx1.1/out/LINUX/x86_64/release/ ./a.out OK: FILE ../../tutorial_videos/PETS09-S1-L1-View001.avi 768x480 LOG: [ status = -1 ] Hello there! ProcessGraph:0.254740[s] ProcessGraph:0.183655[s] ProcessGraph:0.181082[s] ProcessGraph:0.180022[s] ProcessGraph:0.182914[s] ProcessGraph:0.180622[s] ...
最初のフレームはHarrisCornerによる角検出、それ以降のフレームはトラッキングに要した時間です(そういう内容のデモです)。トラッキングに大体180ms程度、掛かっている様子がわかります。
次に内蔵GPUで実行します。
$ DISPLAY=:1 LD_LIBRARY_PATH=/path/to/amdovx-core/build/lib ./a.out OK: FILE ../../tutorial_videos/PETS09-S1-L1-View001.avi 768x480 LOG: [ status = -1 ] Hello there! LOG: [ status = 0 ] OK: OpenVX using GPU device#0 (Intel(R) HD Graphics Broxton 0) [OpenCL 2.0 beignet 1.3] [SvmCaps 0 0] ProcessGraph:0.030192[s] ProcessGraph:0.016439[s] ProcessGraph:0.015872[s] ProcessGraph:0.015629[s] ProcessGraph:0.015629[s] ProcessGraph:0.015679[s] ...
トラッキングに16ms程度しか掛かりません。正直言ってGPUとしてはローエンドの下の方ですが、J4205のCPU処理と比較すると圧倒的に速いです。GPU恐るべしですね。
この記事にコメントする
| < | 2019 | > | ||||
| << | < | 07 | > | >> | ||
| 日 | 月 | 火 | 水 | 木 | 金 | 土 |
| - | 1 | 2 | 3 | 4 | 5 | 6 |
| 7 | 8 | 9 | 10 | 11 | 12 | 13 |
| 14 | 15 | 16 | 17 | 18 | 19 | 20 |
| 21 | 22 | 23 | 24 | 25 | 26 | 27 |
| 28 | 29 | 30 | 31 | - | - | - |
wiki
Linux JM
Java API
2002年
2003年
2004年
2005年
2006年
2007年
2008年
2009年
2010年
2011年
2012年
2013年
2014年
2015年
2016年
2017年
2018年
2019年
2020年
2021年
2022年
2023年
2024年
2025年
過去日記について
アクセス統計
サーバ一覧
サイトの情報合計:
本日: