最近、カバレッジ計測を目的に「動的テストツール DT10」(以下、DT10)を採用されるユーザーが増えていて、ターゲット機器によっては、テストポイントによるオーバーヘッドが課題となるケースもあります。オーバーヘッドは接続方式によって大きく差がありますが、それぞれの接続方式において、トレースデータの取り扱いを工夫することで、オーバーヘッドを今よりも削減することが可能です。

DT10ユーザーに最も多く採用されている接続方式である汎用ポート接続においては、カバレッジ計測向けにトレースデータをドライバ内のバッファに取り溜めるカスタマイズ方法を公開しています(ユーザー限定ページです)。これにより、トレースデータを外部に出力する頻度を減らすことで、オーバーヘッドを軽減できて、大変好評です。
次に多く採用されている「ファイル書き出し」方式についても、オーバーヘッドが小さく、ハードウェアによる接続も無く、ドライバの合わせ込みも無く、気軽に直ぐに導入できることを理由に、カバレッジ計測において活用されていますが、汎用ポート接続同様に、データの取り扱いを工夫することで、さらなるオーバーヘッドの削減ができないものか考えました。今回は、Windowsアプリをターゲットにして検証します。

CONTENTS

検証① APIによるオーバーヘッドの違い

現行のDT10の「ファイル書き出し」方式のサンプルドライバでは「fwrite」のAPIを使用しています。テストポイントの通過時にAPIが呼び出されて、ファイルにデータを保存する方式です。今回は5つのファイルを取り扱うAPIを対象に、テストポイントの出力に掛かる時間、つまりAPIがファイルにデータを書き出す時間を計測します。

検証したAPI

  

ターゲットのソースコード

テストポイントの通過時にAPIが呼び出されて、ファイルにデータを保存します。  

「ファイル書き出し」のドライバ処理では、最初のテストポイントを通過した際に、データを書き出すファイルのオープン処理も併せて行います。純粋にデータを出力する時間を計測したいため、ファイルオープンの時間を排除する目的で、ループの前にもテストポイントを挿入して、ここでファイルをオープンしています。なお、テストポイントの時間データは、ドライバ側で付加します。この時間データの付加には、QueryPerformanceCounterを使用しました。

オーバーヘッドの計測方法

– 上の図のように、ターゲットのソースコードに連続で手動挿入した2つのテストポイントをトレースした時の差分時間をDT10アプリで計測します。
– ターゲットのソースコードを実行し、DT10アプリの「2点間実行時間レポート」で計測した時間を確認します。
– ターゲットのソースコードの実行は、ループの回数を変更して、トレースデータのファイルサイズが次の4パターンになるように計測します。100kByte / 1MByte / 10MByte / 100MByte

検証したマシンスペック

Windows 7 Professional Service Pack 1
Core i7 2.20GHz
メモリ:8GB

APIごとのオーバーヘッド検証結果


APIごとのオーバーヘッド(1テストポイントあたりの書き込み時間[ns])

最もオーバーヘッドの小さいAPIは、ファイルマッピングでした。ファイルマッピングは、予め使用するサイズの記憶領域を指定・取得し、そこにデータを書き込む必要があります。明示的にRead/Writeするというよりは、メモリの延長としてファイルを扱う形となり、これによりオーバーヘッドが小さくなったと考えられます。
このAPIは、大量のデータに対しランダムアクセスを行う場合や、プロセス間で同じファイルを共有したいときに使用されることが多いかもしれませんが、データの出力も高速に行えることがわかりました。

検証② バッファを使ったドライバに効果あり

検証①の結果から最もオーバーヘッドが小さかったファイルマッピングですが、記憶領域を予め取得して、そこに出力するという方法のため、テストポイント通過時に呼び出される他のAPIとは、データの取り扱いに違いがあります。他のAPIも予め使用するサイズのバッファを用意した場合はどうなるか?ドライバをさらにカスタマイズし、確保したバッファにデータを出力して、最後にAPIを使用して、バッファのデータを一度に出力する方法で検証してみます。ファイルマッピングに次いでオーバーヘッドの小さかったfwriteでの計測をします。

バッファ実装による検証結果


APIごとのオーバーヘッド(1テストポイントあたりの書き込み時間[ns])

fwriteにバッファを設けることで、テストポイントの通過時は配列にデータを格納するだけになるため、オーバーヘッドが小さくなり、ファイルマッピングとほぼ同等になりました。ドライバにバッファの実装をおこなうことは、オ―バーヘッド削減には、やはり有効です。

検証③ 不具合解析でも有効なAPI

DT10が最も活用される不具合解析において、よくある場面でそれぞれのAPIがどのような挙動をするのか検証してみます。例えば、ターゲットのアプリケーションが強制終了したり、フリーズする不具合を解析したりするケースです。このようなケースでDT10を用いて確認したいのは、フリーズが発生するまでの実行経路です。しかし、ターゲットがフリーズしてしまうと、メモリ上のデータがファイルに出力されないということが起こります。DT10を使って、デバッグやテストしているのに、不具合発生時のログが確認できないのは問題です。

ターゲットのソースコード

検証方法

– ターゲットのコードを変更して、ループ内でわざとNULLポインタアクセスを発生させます。
– ターゲットアプリケーションをわざと強制終了させ、強制終了に至るまでのデータ、すなわち上図の赤い部分のテストポイントのトレースデータを取得できるかどうか確認します。

APIごとのテスト結果

○が該当のデータまでファイルに書き出されたAPI、×は該当のデータがファイルに書き出されずに欠損してしまったAPIです。NULLポインタアクセスの直前まで、きちんとデータをファイルに書き出せたのは、ファイルマッピングとWriteFile関数でした。データの保存性能という点でも、ファイルマッピングのAPIに軍配が上がりました。

まとめ

ファイル書き出しにおいて、APIの違いを検証したところ、予め使用するサイズの記憶領域を指定する必要がありますが、ファイルマッピングのAPIが、カバレッジ計測においても、不具合解析においても、DT10に適していることが分かりました。
次回も引き続き、Linuxでもファイル書き出しのドライバで、いくつかあるファイルシステムによるオーバーヘッドの違いを調べてみます。

今回のファイルマッピングを使ったドライバのカスタム方法については、弊社技術サポートまでお気軽にお問い合わせください。お問い合わせはこちらから。