DVDを英国から個人輸入してみた

DVDの個人輸入が2chでちょっと祭りになっていた。英AmazonのDVD売上げのベスト10に日本のアニメが出てしまい、メジャーアニメタイトルの在庫がなくなるほどの盛況ぶりでした。このとき、つい出来心で頼んだDVDがようやく届きはじめたのです。
結論としては思っていたよりはるかに良いです。
さてDVDはリージョンコードや映像形式の違いにより、海外で購入したものを視聴することはできないようになってます。アメリカと日本で劇場公開時期が違っているときなど、劇場公開前にDVDが流通したりするのを防ぐための仕組みです。英国と日本はリージョンコードは同じですがTVの信号形式が異なるため、一般的なDVDプレイヤーやTVでは個人輸入したDVDを見ることはできません。ですがパソコンは英国で使われているPAL信号形式も、日本で使われているNTSC信号形式でも再生することができます。
PAL形式とNTSC形式にはいくつか大きな違いがあります。その一つが解像度です。日本で使われるNTSC形式の水平走査線の数は525本、英国で使われているPAL形式の水平走査線の数は625本、英国のほうが二割ほど解像度が高いのです。HDTVの720pは水平走査線が720本。これには及ばないまでも、パソコンで見てると明らかに画質が違うんですよ。
流石に同じDVDを二枚も持っていないので、動画を比較して提供できないのが残念。

屋外の常夜灯をLEDに変えてみました。

IMG_5230
個人輸入していたLEDが届きました。常夜灯として屋外についている、12Vのハロゲンランプの代わりです。35W→3Wに消費電力が減りました。消費電力もさることながら、温度が気になっていたんですよ。芝生のところにあるので、そのうち悪条件が重なると燃え移ったりしないかと不安だったのです。
IMG_5236
石壁にスポットをあてて、間接照明になってます。3Wで足りるか不安だったんですけど、まぁ大丈夫な様です。

codファイルを使用したデバッグ

リリース後のアプリケーションで例外が発生した場合、codファイルを使用して例外の発生した行を特定することができます。
コンパイル時に生成された、アセンブリ言語のコードと、コンピュータ語のコードを保存することができます。プロジェクトのプロパティを開いて、C/C++の出力ファイルにある「アセンブリの出力」を変更して、「アセンブリコード、コンピュータ語コード、ソースコード」を選択します。これでビルド時に拡張子codのファイルが生成されます。
マップファイルを使用することで、例外オフセットから障害が発生したアドレスを調べられることは「マップファイルを使用したデバッグ」で解説しました。

Address Publics by Value Rva+Base Lib:Object
0000:00000001 ___safe_se_handler_count 00000001
0000:00000000 ___ImageBase 00400000
0001:00000000 _wmain 00401000 f crashTest.obj
0001:00000020 ?funcA@@YAHXZ 00401020 f crashTest.obj
0001:00000050 ?funcB@@YAHH@Z 00401050 f crashTest.obj
0001:00000090 ?funcC@@YAXXZ 00401090 f crashTest.obj

ここで例外の発生している関数funcBと例外オフセットアドレスの差を求めます。この場合、例外オフセットが0x1064、 関数の先頭アドレスが0x1050で、差分は0x14(20)バイトです。ここでcodファイルのfuncBの場所を参照します。

PUBLIC ?funcB@@YAHH@Z ; funcB
; Function compile flags: /Odtp
; COMDAT ?funcB@@YAHH@Z
_TEXT SEGMENT
_val$ = -4 ; size = 4
_arg1$ = 8 ; size = 4
?funcB@@YAHH@Z PROC ; funcB, COMDAT

; 29 : {

00000 55 push ebp
00001 8b ec mov ebp, esp
00003 51 push ecx

; 30 : char *val = NULL;

00004 c7 45 fc 00 00
00 00 mov DWORD PTR _val$[ebp], 0

; 31 : strcpy(val, “Hello World”); // 1.ソースコードの31行目で例外が発生している

0000b 8b 45 fc mov eax, DWORD PTR _val$[ebp]
0000e 8b 0d 00 00 00
00 mov ecx, DWORD PTR $SG-6
00014 89 08 mov DWORD PTR [eax], ecx // 2.ここで例外が発生している
00016 8b 15 04 00 00
00 mov edx, DWORD PTR $SG-6+4
0001c 89 50 04 mov DWORD PTR [eax+4], edx
0001f 8b 0d 08 00 00
00 mov ecx, DWORD PTR $SG-6+8
00025 89 48 08 mov DWORD PTR [eax+8], ecx

; 32 : printf(“call funcB”);

00028 68 00 00 00 00 push OFFSET $SG-7
0002d ff 15 00 00 00
00 call DWORD PTR __imp__printf
00033 83 c4 04 add esp, 4

; 33 : return 0;

00036 33 c0 xor eax, eax

; 34 : }

00038 8b e5 mov esp, ebp
0003a 5d pop ebp
0003b c3 ret 0
?funcB@@YAHH@Z ENDP ; funcB
_TEXT ENDS

0x0014バイトの個所を探すと、2.の個所で例外が発生していることがわかります。これは1.で示されるソースコード上の31行目にあたります。この作業でリリース後のアプリケーションでもソースコード状の何処で例外が発生しているのか特定することができます。

SSEを有効にして最適化する

Visual Studio 2005から標準でMMX、SSE、SSE2命令を有効にした最適化をおこなえるようになりました。これらマルチメディア拡張命令を使用することで高速化を試みてみましょう。プロジェクトのプロパティを開き、C/C++のコード生成で「拡張命令セットを有効にする」のオプションを変更します。
SHA-256のサンプルプログラムを実行してみました。以下はその実行速度です。
設定なし・・14103ms
SSE・・・・・13604ms(3.5%)
SSE2・・・・12932ms(8.3%)
SSE2を有効にしただけで、8%ほどパフォーマンスが改善されています。
VC++コンパイラのSSE対応は一部の演算命令をSSE2のものに置き換えているだけで、Intel製のC++コンパイラように自動でベクトルか化を行うものではありません。ただしSSE命令を使用することによって使用できるレジスタの値が増え、その結果メモリ転送量が減って高速化する場合があるという程度のようです。
SHA-256のサンプルプログラムをベクトル化してみました。以下はその実行速度です。
SSE2(ベクトル化)・・・・17532ms
むしろ遅くなっています。
SHA256アルゴリズムはもともとベクトル化にはあまり向いていません。4ブロック128ビット分を一度に演算していますが、ベクトル化できるのは途中までで、最後に手前のブロックとの演算結果との計算は単純に4ブロック分を一度に演算するわけにはいかないからです。それを別にしてもあまりにも遅くなっている気がします。
実はSSE命令にはいくつかパフォーマンス上の欠点があります。
一つ目は16バイト分のメモリに一度にアクセスするため、キャッシュにヒットしない場合の性能低下が大きくなるのです。
二つ目はアライメントの問題。16バイト境界にアライメントされていないメモリへのアクセスは非常に遅くなるのです。
ハッシュ値の計算もととなるバイト列は都合が良いようにはアライメントされていません。これを128bit変数にセットする部分のオーバーヘッドが大きくてベクトル化の恩恵を相殺してしまっています。
SHA-256のサンプルプログラムにSSEの_mm_prefetch命令を4行ほど追加してみました。
SSE2(プリフェッチ)・・・・11918ms(15.5%)
SSEにはCPU内部のメモリキャッシュ動作を制御する命令が追加されています。大量のデータにアクセスする場合、キャッシャ制御命令を使ってメモリバスが使われていない隙間の時間に、データをキャッシュメモリに読みだすことができます。1ブロック分の処理中に、次に使用するブロックをキャッシュに読み込むことで、6%以上高速化しています。
IntelのCPUではキャッシュメモリを32バイトごとに管理しています。_mm_prefetch命令を導入する場合には32バイト毎に、メモリアドレスを指定する必要があります。
AES暗号のサンプルプログラムで「拡張命令セットを有効にする」のオプションを同じように実行してみました。以下はその実行速度です。
設定なし・・36052ms
SSE・・・・・45021ms(-24.8%)
SSE2・・・・45817ms(-27.0%)
むしろ遅くなっています。最適化の成否を高度に判断するものではないようです。よって使用する場合にはソースごとに適用するか否かをプログラマがハンダする必要があるようです。

VisualStudio 2005 Remote Debugの設定

・OSの設定
アプリケーションを実行するコンピュータにユーザアカウントを追加します。開発環境を動作させているコンピュータにログインする時に使用している同じアカウント名とパスワードで管理者ユーザを作成します。
コントロールパネルの管理ツールにあるローカルセキュリティポリシーを起動して、ローカルポリシーのセキュリティオプションにある「ローカルアカウントの共有とセキュリティモデル」の設定を「クラシック」に変更します。
ファイアウォールが有効になっている場合にはリモートデバッグを実行できません。必ず無効にしてください。
・Remote Debuggerのインストール
アプリケーションを実行するコンピュータに対してVisual Studio 2005インストールCDのvsRemote Debugger\x86\rdbgsetup.exeを実行してリモートデバッガをインストールしてください。
・デバッグ用ランタイムDLLのインストール
VC++で作成したネィテブアプリケーションのデバッグにはランタイムDLLが必要です。ランタイムDLLの導入を行わないと、デバッグ版のアプリケーションを実行することができません。以下のフォルダにあるデバッグ用ランタイムDLLを、デバッグするアプリケーションの実行ファイルと同じ場所にコピーします。このときDLLファイルだけではなく、マニュフェストファイルも一緒にコピーしてください。
C:\Program Files\Microsoft Visual Studio 8\VC\redist\Debug_NonRedist\x86\Micorosft.VC80.DebugOpenMP
C:\Program Files\Microsoft Visual Studio 8\VC\redist\Debug_NonRedist\x86\Microsoft.VC80.DebugCRT
C:\Program Files\Microsoft Visual Studio 8\VC\redist\Debug_NonRedist\x86\Microsoft.VC80.DebugMFC
・デバッグの手順
アプリケーションを実行するコンピュータにて「VisualStudio 2005 リモートデバッガ」を起動します。
その後、VisualStudioの開発環境からデバッグのプロセスにアタッチを実行してください。修飾子にアプリケーションを実行するコンピュータのコンピュータ名を指定すると、実行されているプロセスの一覧が表示されるので、デバッグするプロセスを選択します。
サービスのデバッグを行いた場合には、「VisualStudio 2005 リモートデバッガ構成ウィザード」を起動してリモートデバッガがサービスとして動作するように設定します。
・デバッガをサービスとして動作させる
ログイン前のアプリケーションの動作や、サービスとして登録したアプリケーションをデバッグするには、デバッガをサービスとして動作させる必要があります。プログラムメニューから「Visual Studio 2005 リモートデバッガ構成ウィザード」を実行することでサービスとして登録できます。ですが、これだけではまだサービスとしてリモートデバッガを利用することはできません。
リモートデバッガをサービスとして動作させるには、コントロールパネルの管理ツールからサービスを起動してください。Visual Studio 2005 Remote Debuggerというサービスが登録されています。サービスのプロパティを開いて自動起動に変更してください。同時にサービスを実行するアカウントに管理者権限を持つユーザアカウントを指定します。このあと再起動すると、リモートデバッガはサービスとして起動します。