目次: 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恐るべしですね。
首都圏外郭放水路 庄和排水機場(埼玉県春日部市)の調圧水槽と第一立坑(たてこう)の見学に行きました。
首都圏外郭放水路とは、洪水多発地域の中川流域(埼玉県の東部)を洪水から保護するため、中川、綾瀬川といった中小河川の水を地下経由で引き込み、ポンプで引き上げて江戸川に放流する仕組みです。
ちなみに国の施設でして、管轄は国土交通省(サイトへのリンク)です。
見学コースの一つである、調圧水槽は、地下神殿との呼び名もあるほどで、広大な空間とたくさんの柱があります。
柱の役割がわかっていなかったのですが、係の方の説明によると、周りの地下水の浮力で調圧水槽が浮き上がってしまうので、重い天井と柱で、水槽を下に押しつけているそうです。
第一立坑は高さ70mの大迫力で、一番上の壁沿いに組まれた足場から下を見ることができます。私は高いところが苦手でして、非常に怖かったです。足が進まないし、変な汗が止まりません。
怖すぎて壁際にずっとしがみついていたため、写真を撮る余裕がありませんでした。一緒に行ったみなさまが高いところが平気なようで、写真をバシバシ撮っていましたので、一枚恵んでもらいました。
高いところ(立坑)はもう懲り懲りですが……、今回参加したコースとは別の見学コース(排水ポンプ室に入れる)もあるらしいので、別コースにもぜひ行ってみたいですね。
目次: 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で表現できないため、後者に引っ掛かるわけです。
異常な演算に対して例外を発生させる設計思想なら分かりますが、乗算命令は異常な結果でも素通しなのに、除算命令は異常な結果だと例外発生します。片手落ちの不思議な仕様です。変なの……。
目次: 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長に無理して詰めている)からすると、仕方ないでしょうね。
どうやっても圧勝してしまう「最弱オセロ」(リンク)が話題ですが、実はその横に「強いオセロ」(リンク)もあります。URLから推測するにこちらの方が先に作られたように見えます。
名前に偽りはなく、ものすごく強いです。私のような素人の実力ですと50石(ほぼ真っ白)〜64石(全て白)で完敗します。終盤に一気にひっくり返され、全く勝てません。
まともにやっても全く勝てなかったので、どんな手でも良いから、1度でも勝てないだろうか?と試行錯誤するうちに、ちょっとしたクセが見えてきました。このAIは「終盤の大逆転」を重視していて、序盤〜中盤は石数が不利でも無視する傾向があります。
このクセを逆手に取り、中盤戦でとにかくゴリ押しして、白を全滅させる作戦を取ると、ごくたまに勝てることがあります。下記はその例です。
中盤で押し切れなければ負けです。20〜30局やりましたが、これ以外の勝ち方はできませんでした……。
RISC-V原典という本も買って読んでいます。どちらかというと頭から読む本ではなく、辞書的な本です。命令一覧の章はとても便利ですね。
RISC-V原典では「過去のアーキテクチャが患ったインクリメンタリズム」と他のアーキテクチャの複雑さを評していましたが、RISC-Vは出来たばかりなので「今」シンプルなのは当然だよね……などと思ったりしました。
RISC-Vは命令セットの独自拡張を許しているため、同じRISC-V CPUを名乗っていても「A社CPUとB社CPUでは、同じバイナリが実行できない」ことがありえます。
ARMやx86も互換性のないCPUは存在しますが、共通の命令セットが大きいためあまり問題にはなりません。一方RISC-Vは共通命令セットが小さい(RV32I、MMUなしのマイコンレベル)ので、非互換性で問題が起きそうですね。ARMでいうとCortex-A系とCortex-M系を混ぜて売るようなもので、混乱を招きそうです……。
このタイプの命令拡張方式で私が思い出したのはARMです。ARMも昔はARMv5TEJのように、対応する拡張命令をアルファベットで追記する、似たような方式を採用していましたが、ARMv6で拡張命令に全て対応したため、拡張命令方式は消滅しました。
私の予想としては、スマートフォン、デジタル家電、PCのような、比較的高性能な分野にはRV64GC(G = IMAFD、multiple, atomic, float, double)が共通命令セットになり、マイコン系にはRV32IかIMくらいが共通命令セットになる、辺りが落としどころかなと思います。
RISC-Vも「インクリメンタリズム」に陥る未来は避けられず、拡張に次ぐ拡張でゴチャゴチャになる未来を迎えると思いますが、20年後、
期待が大きいだけに、将来的にどうなるか、楽しみです。
オーディオは専門ではないし、神の耳も持っていないので、細かい音質うんぬんは全くわからないし、高級○○ケーブルなどはオカルトの一種とすら思っていますが……。
音質で唯一体験したことを思い出したので、メモしておきます。
以前はテレビのファーム開発をしていたため、職場ではテストのために少し良い(1万円〜2万円レベルの)ヘッドホン(SHURE SRH440-A)を使っていました。
何も鳴らしていないのに、ヘッドホンからたまにブーン……という微かなノイズと、バリ、バリ!という大きめのノイズが聞こえていました。
最初、評価ボードか機材の故障を疑っていたのですが、なんと原因は自分のスマホでした。
前者のブーン……ノイズは、ヘッドホンのケーブルをくるくると丸めて束ねた上に、スマホを置いていたため、スマホの電波を拾ってノイズになっていたようです。
たまにしか鳴らないのは、パケット通信のときしか強く電波を発しないからですかね?スマホを机の上に置かないようにしたらノイズは聞こえなくなりました。
家の安いヘッドホンで同じことをしても、ノイズは聞こえなかったので、感度の良いヘッドホンじゃないと拾わない(?)のかもしれません。
後者のバリバリ!ノイズは、ヘッドホンアンプの上にスマホを置きっぱにしたときに鳴っていました。ノイズを増幅するのか、かなり目立つバリバリ音が聞こえていました。
これもスマホとアンプを遠ざけて置くことで、ノイズが消えました。
謎が解ければ何てこと無い原因でしたけど、最初はわからなくて、このヘッドフォン壊れているんだろうか?不良品かしら……?とか思っていました。冤罪でした、ごめんねヘッドホンさん。
音質でもう一つ思い出したのが、先代ノートPC(ThinkPad Edge E420)のアナログオーディオ出力は、常にシューシューというノイズが聞こえていたことです。
2010年は遥かに過ぎて、こんなにノイズが鳴るオーディオがあるはずない、聞き間違いだろうと思いきや、安物のオシロで見てもすぐわかるくらいノイズが載っていてショックでした。Conexantさん勘弁してよ……と思いました。
測定結果は、以前の日記に書いています(2014年10月18日の日記参照)。あれからもう五年も経ったのか。早いものだ。
メモ: 技術系?の話はFacebookから転記しておくことにした。リンクなどを追記。
目次: apt
会社で独自のDebianパッケージを配布する際に、難しくてかなり困ったので、下調べの結果を兼ねてメモしておきます。
やりたいこととしては、独自に作成したDebianパッケージ(*.debファイル)を、
この3つをどのように組み合わせても対応できるような、ディレクトリ構成と、aptサーバーの設定を作成することです。
ディレクトリ構成は、最初から考えるのは大変なので、参考としてDockerのaptリポジトリ(リンク)を見てみます。
debian/ dists/ buster/ : Debian 10.0 edge/ : なんだろ? nightly/ : 1日ごとにビルドされた版 pool/ : *.debが入っているディレクトリ stable/ : 安定版 test/ : テスト版? jessie/ : Debian 8.0 stretch/ : Debian 9.0 wheezy/ : Debian 7.0 gpg : GnuPGの公開鍵、apt-keyで追加する ubuntu/ dists/ artful/ : Ubuntu 17.10 bionic/ : Ubuntu 18.04 LTS cosmic/ : Ubuntu 18.10 disco/ : Ubuntu 19.04 trusty/ : Ubuntu 14.04 LTS xenial/ : Ubuntu 16.04 LTS yakkety/ : Ubuntu 16.10 zesty/ : Ubuntu 17.04 gpg : GnuPGの公開鍵、apt-keyで追加する
こんな作りになっています。debian/distsもしくはubuntu/distsの下に各バージョンのコードネームが並んでいます。例えばdebian/dists/busterであればDebian 10.0用です。
コードネームのディレクトリの下には、各版stable, test用のディレクトリが並んでいます。poolディレクトリは版名ではなくて、パッケージファイル *.debを格納するディレクトリです。
debian/ dists/ buster/ : Debian 10.0 edge/ : なんだろ? nightly/ : 1日ごとにビルドされた版 binary-amd64/ : PC, 64bit用パッケージ情報 Packages : パッケージ一覧 binary-arm64/ : AArch64用パッケージ情報 binary-armhf/ : AArch32用パッケージ情報 Contents-amd64 : PC, 64bit用 Contents-arm64 : AArch64用 Contents-armhf : AArch32用 pool/ : *.debが入っているディレクトリ edge/ : stableと同じ構成 nightly/ : stableと同じ構成 stable/ amd64/ : PC, 64bit用 *.deb arm64/ : AArch64用 *.deb armhf/ : AArch32用 *.deb test/ : stableと同じ構成 stable/ : 安定版 test/ : テスト版 InRelease : GnuPGの署名が追記されたReleaseファイル Release : Contents, PackagesのSHAハッシュ一覧が書かれたファイル Release.gpg : GnuPGの署名だけ書かれたファイル
Debian向けとUbuntu向けはほぼ同じ構成です。
< | 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 | - | - | - |
合計:
本日: