ssdtest manual

ssdtest は SSD の性能を測定してグラフ化するツール群です。 ランダムアクセス性能を 2 次元空間上にプロットします。 平均化した値では見えなかった Turn Around Time, SSD 内外のキャッシュ影響、セクタ消去、ウエアレベリング、エラー訂正、 SSD 内のメモリデバイスアクセス並列度などによると考えられる アクセス速度分布が得られます。

ssdtest 2.00 ダウンロード(ソースコード一式)

サンプル SONY SR-16UY MicroSD card (軽量テスト)
サンプル SONY SR-16UY MicroSD card (完全テスト)

Copyright (C) 2012, 2017 Akinori Furuta <afuruta @m7.dion.ne.jp>


1. 動作条件

1.1. 実行環境

項目 説明
OS Linux kernel 2.6.34 or later, 64bit addressing.
Memory 8GiBytes or more main memory.
Disk Space 1MiBytes to store test programs,
1GiBytes to store test output logs and plots.
Packages gcc, gawk(ubuntu の場合、awk では動作しません), time(外部コマンド), smartctl(smartmontools), hdparm, gnuplot 4.2 or later
ubuntu(debian 系)の環境であれば次のコマンドを実行してパッケージをインストールしてください。
$ sudo apt-get update
$ sudo apt-get install gcc gawk time smartmontools hdparm gnuplot

1.2. テスト対象

項目説明
種別
  • SSD
  • USB memory, SD card (容量、ファイルシステム形式、スピードによっては上手く動作しません)
接続形態SSD の場合は SATA (途中に USB 等の変換アダプタがないこと)
容量
  • SSD: 60GByte 以上の空きが有ること (100GBytes 以上が望ましい)
  • USB memory: 1Gbyte 以上
ボリューム構成シングルパーティション (RAID, Volume Group 不可)
ファイルシステム形式
  • ext3, ext4 など (ボリュームサイズに対し 90% のサイズのファイルを保持できること)
  • FAT/FAT32 ファイルシステムの場合は最大 4095Mibyte のファイルサイズでテストします。

1.3. テストファイルサイズ

空き容量の 90% をテストファイルとして使用します。VFAT(FAT32) ファイルシステム では 4095MiBytes をテストファイルとして使用します。/, /tmp, /home, /var 等を マウントした場所をテストする場合、容量不足に注意してください。容量不足になると、 突然再起動するなど不測の事態が発生します。

1.4. テスト時間

SSD の種類にもよりますが、1 回の完全テスト (ssdtest.sh) に付き 120GBytes の SSD で 12 ~ 48 時間 掛かります。


2. 展開とコンパイル

2.1. 展開・ビルド

次の様にして、ダウンロードしたファイル ssdtest_x.x.tar.gz を展開、コンパイルしてください。

% tar zxvf ssdtest_x.x.tar.gz
% cd ssdtest_x.x
% make

どのコマンドもエラーや警告は出ないはずです。make に成功していれば、次の様に ssdstress コマンドのヘルプメッセージを出力することができます。

% ./ssdstress -h
./ssdstress: Info: Show help.
./ssdstress: Error: Need path name to read/write test.
ssdstress: SSD stress test tool. Copyright (C) 2012, 2017 Akinori Furuta<afuruta@m7.dion.ne.jp>.
Command line: [-f n] [-p {y|n}] [-x {b|r|w}] [-r {y|n}] [-d {y|n}{Y|N}] [-m {y|n}] [-b n] [-u n] [-i n] [-i {u|e}] [-a n] [-e n] [-n n] [-s n] path_name
-f n work file size.
-p{y|n} Fill file with initial image(y: fill, n: truncate)(n).
-x{b|r|w} Random read/write method (b: Do both read and write, r: Do read only, w: Do write only)(b).
-r{s|y|n} Read file from start block to end block (s: read strict check, y: read light check, n: do nothing)(n).
-d{y|n}{Y|N} Add O_DIRECT flag at sequential r/w (y: add, n: not add), at random r/w(Y: add, N: not add)(yY).
-m{y|n} Do block number Marking and check (y: mark and check, n: do not marking)(y).
-b n block size(512).
-u n Sequential read/write blocks per one IO (if zero or not set, same as "-a n" * 2)(0).
-i n Random read/write minimum blocks(1).
-a n Random read/write maximum blocks(8192).
-i {uniform | exponential} Random read/write blocks distribution as uniform or exponential (uniform).
-o n Start block number to read/write(0).
-e n End block number to read/write(0).
-n n number of random read/write access(4096).
-s n random seed number(0).
-z n Sleep time in seconds after test(10).
path_name: File path name to test.
Number n can be specified with unit {k|m|g|t}. k: x1024, m: x1024^2, g: x1024^3, t: x1024^4, p: x1024^5
Output format: sequential write.
cur b/s, total b/s, cur_el b/s, elp b/s, cur_pos, progs, Twrite, Twrite_total, Twrite_elapsed, Telapsed, Tmem_access_total
Output format: random access.
index, elapsed_time, rw, seek_position, length, access_time, bps, memory_access_time
Output format: sequential read.
cur b/s, total b/s, cur_el b/s, elp b/s, cur_pos, progs, Tread, Tread_total, Tread_elapsed, Telapsed, Tmem_access_total

2.2. インストール

インストール機能はありません。システム(/bin, /usr/bin, /usr/local/bin 等)に インストールせずに使用するツールです。起動は、フルパスまたは、カレントディレクトリ から辿れる相対パスで実行ファイルを指定します。

2.3. 生成ファイルを削除する

次のコマンドで生成ファイルを削除します。測定結果はそのまま残ります。

% make clean

3. ツール

実行プログラムは、「テスト実行ツール」、「結果プロット、ページ作成ツール」、 「連続実行用ツール」、「デバック・診断ツール」の 4 群から構成されています。

以下 ${tool_path} は ssdtest ツール群を展開したディレクトリ ssdtest_x.x を指す 相対または絶対パスに置き換えて読んでください。# プロンプトは root 権限で実行 することを意味します。ディストリビューションによっては sudo を付けて起動する ことと解釈してください。$ プロンプトは一般ユーザーで実行することを意味します。

3.1. テスト実行ツール

テスト実行ツールは root 権限もしくは block device に対して直接アクセスできる 権限をもつユーザーで実行します。一般ユーザーでも実行は可能です。しかし、 S.M.A.R.T. 情報、kernel チューニング等が行われずテスト結果から一部の情報が欠落 したり、十分な性能が発揮できないテストになります。

3.2. テスト実行手順

テスト手順は次の通りです。テスト実行、テスト結果をプロット、プロットしたグラフ から HTML ページ作成という順です。

テスト実行

# ${tool_path}/ssdtest.sh [-L ModelNameLabel] /path/to/test

プロット

plotlogseq.sh でシーケンシャルアクセステストの結果をプロットします。 plotlogmix.sh でランダムアクセステストの結果をプロットします。

$ ${tool_path}/plotlogseq.sh log_directory
$ ${tool_path}/plotlogmix.sh log_directory

ページ作成

$ ${tool_path}/htmlplot.sh log_directory > html_page_file.html

3.3. 各ツール詳細

3.3.1. ssdtest.sh, ssdtest_light.sh, ssdtest_usbmems.sh, ssdtest_light_usbmems.sh - SSD, USB メモリ テストスクリプト

ssdtest.sh, ssdtest_light.sh, ssdtest_usbmems.sh, ssdtest_light_usbmems.sh はテスト実行スクリプトです。 それぞれ次の表に示すテストを行います。

スクリプト名機能テスト構成シーケンシャルアクセス単位
(blocks, (bytes))
ランダムアクセス単位
(BlocksMin .. BlocksMax, (BytesMin .. BytesMax))
書き込み量 bytes必要空きメモリ bytes
ssdtest.sh SSD の完全テスト 次の一連のテストを行います。
Step SymbolAccess PatternOS cache
(a1)sequential write enabled
(a2)random read and writedisabled
(a3)sequential read enabled
(a4)remove test file -
(a1)sequential write enabled
(a2)random read and writedisabled
(a3)sequential read enabled
(a4)remove test file -
(a1)sequential write enabled
(a2)random read and writeenabled
(a3)sequential read enabled
(a4)remove test file -
(a1)sequential write enabled
(a2)random read and writeenabled
(a3)sequential read enabled
(a4)remove test file -
2Mi, (1Gi) 1 .. 4Mi, (512 .. 2Gi) FreeSpace * 3.6 + 2.2Ti 約 6.03Gi
ssdtest_light.sh SSD の軽量テスト 次の一連のテストを行います。
Step SymbolAccess PatternOS cache
(a1)sequential write enabled
(a2)random read and writedisabled
(a3)sequential read enabled
(a4)remove test file -
2Mi, (1Gi) 1 .. 4Mi, (512 .. 2Gi) FreeSpace * 0.9 + 570Gi 約 6.03Gi
ssdtest_usbmem.sh USB memory の完全テスト 次の一連のテストを行います。
Step SymbolAccess PatternOS cache
(a1)sequential write disabled
(a2)random read and writedisabled
(a3)sequential read disabled
(a4)remove file -
(a1)sequential write disabled
(a2)random read and writedisabled
(a3)sequential read disabled
(a4)remove file -
(a1)sequential write disabled
(a2)random read and writeenabled
(a3)sequential read disabled
(a4)remove file -
(a1)sequential write disabled
(a2)random read and writeenabled
(a3)sequential read disabled
(a4)remove file -

sequential write、読み出しはキャッシュ無しです。 USB memory 容量が小さい場合は書き込みが全て主記憶にバッファされるのを防ぐためです。

USB memory の容量と速度は多種存在します。このスクリプトのパラメータはどんな USB memory にも適するパラメータではありません。テスト時間が長すぎたり、性能を把握するのには不十分な 結果が得られる場合もあります。

16Ki, (8Mi) 1 .. 64Ki, (512 .. 32Mi) FreeSpace * 3.6 + 45.6Gi 約 128Mi
ssdtest_light_usbmem.sh USB memory の軽量テスト 次の一連のテストを行います。
Step SymbolAccess PatternOS cache
(a1)sequential write disabled
(a2)random read and writedisabled
(a3)sequential read disabled
(a4)remove file -

USB memory の容量と速度は多種存在します。このスクリプトのパラメータはどんな USB memory にも適するパラメータではありません。テスト時間が長すぎたり、性能を把握するのには不十分な 結果が得られる場合もあります。

16Ki, (8Mi) 1 .. 64Ki, (512 .. 32Mi) FreeSpace * 0.9 + 11.3Gi 約 128Mi

Note: グラフのタイトルに OS cache enabled の場合は "without O_DIRECT"、OS cache disabled の場合は "with O_DIRECT" という文言が入ります。
Note: FreeSpace は測定開始時点でボリュームに存在した空き容量です。

それぞれのコマンドラインは次の通りです。スクリプト内で ssdstress を呼び出します。

# ${tool_path}/ssdtest.sh [-L ModelNameLabel] /path/to/test
# ${tool_path}/ssdtest_light.sh [-L ModelNameLabel] /path/to/test
# ${tool_path}/ssdtest_usbmems.sh [-L ModelNameLabel] /path/to/test
# ${tool_path}/ssdtest_light_usbmems.sh [-L ModelNameLabel] /path/to/test

コマンドライン引数は次の通りです。

ParameterDescription
-L ModelNameLabel SSD をテストする場合は任意で指定できます。SSD のモデル名に付加したい文字列を ModelNameLabel で指定します。モデル名の接尾辞として扱われます。
USB memory をテストする場合は、 USB memory または memory card にボリュームラベルを付けていないならば必ず指定してください。
/path/to/test テストしようとする SSD, USB memory をマウントしたパス、またはそれより深い 階層のパスを指定します。ディレクトリを指定すれば、そのディレクトリに UUID 形式 の名前が付いたファイルを生成してテストをします。ファイル名を指定すれば、その名 前でファイルを生成してテストをします。

テスト結果(テストログ)はカレントディレクトリの下に次の名前で生成したディレクト リ内に格納されます。 ModelName は デバイスから読み取ったモデル名です。 ModelNameLabel はテストスクリプトに -L オプションで与えた文字列です。 TestDateTime はテスト実施日時です。 TestFileSize はテストに使用したファイルサイズです。ボリュームの空き容量に対して おおよそ 90% を占めるサイズになります。

log-${ModelName}${ModelNameLabel}-${TestDateTime}-${TestFileSize}

ステップ (a1) から (a4) は次のような動作をします。

Step SymbolMethod
(a1) sequential write

空き容量の 90% まで書き込みます。 1 回のアクセス単位は次の通りです。

テスト対象アクセス単位
SSD1Gi byte
USB Memory16Mi byte

アクセス単位はシステムコールの引数として渡す値です。SSD の場合は SATA ドライバの制限、USB の場合は USB Mass Storage Driver の制限を受けてドライブに対対するアクセス要求は分割されます。ログファイルには max_sectors_kb として分割サイズがバイト数として記録されます。

キャッシュが有効な場合、書き込み始めは OS のキャッシュにため込む動作になります。 書き込み速度は OS の内部処理速度になります。ドライブのアクセス速度より速い速度を示します。

以下 (a2), (a3), (a4) でこのファイルを使用します。

既にテスト用のファイルが存在する場合は、一旦削除して再生成しています。 通常の使用方法であれば、既にファイルが存在することは無いので、削除する処理は起きないはずです。
(a2) random read and write

以下に示す式でブロック数を計算し (a1) で作ったファイルに対して ランダムな均等分布位置で読み出しと書き込みを合計 8192 回行います。ブロックサイズ(最小単位)は 512 バイトです。

RatioL = Log2( BlocksMax / BlocksMin )

Blocks = Int( 0.5 + BlocksMin * 2RatioL * Rand(1.0) )

数式の関数は次の通りです。

functionsdefinitions
Rand(x)random number in range [0, x]
Log2(x)Base-2 logarithm of x
Int(x)convert x to integer by truncating fractional part.

各パラメータは次の通りです。

SSD の場合

ParamsValues
BlocksMin1
BlocksMax4194304 (4Mi)

USB memory の場合

ParamsValues
BlocksMin1
BlocksMax65536 (64Ki)

OS のキャッシュを有効にした場合、キャッシュとドライブの相互の作用によって、ランダムアクセスの 応答時間が 10 秒以上になる場合があります。「プチフリーズ」と呼ばれる現象に相当します。 OS キャッシュ無しの場合には見えなかったドライブの問題が顕在化することがあります。 ssdtest_light_*.sh スクリプトは OS のキャッシュを無効にして単純に状況におけるドライブの実力を 測ることができます。しかし、「プチフリーズ」等の問題を見る場合、キャッシュを有効にして、テストを 行うスクリプト ssdtest.sh, ssdtest_usbmems.sh を使用してください。

(a3) sequential read

テスト用ファイルを最初から最後まで読みます。1 回のアクセス単位は (a1) と同じです。

ドライブによっては直前に行った「(a2) ランダムアクセス」において OS のキャッシュ条件が アクセス速度の乱れ (短期的に急激な速度低下を起こす現象) と関係する場合があります。

(a4) Remove test file created at (a1) step.

(a1)で作成したファイルを削除します。テスト実行中に SIGINT ([Ctrl] + [C]) で中断した場合は、 ファイルを削除します。

3.3.2. ssdstress - アクセステスト核プログラム

ssdtest.sh から呼ばれるバイナリプログラムです。テストの核になる処理です。 直接起動することもできます。パラメータの与え方は ssdtest.sh 内の記述を 参考にして下さい。

# ${tool_path}/ssdstress コマンドラインオプション テストファイル名

3.3.2.1. コマンドライン

コマンドライン書式:
[-f n] [-p {y|n}] [-x {b|r|w}] [-r {y|n}] [-d {y|n}{Y|N}] [-m {y|n}] [-b n] [-u n] [-i n] [-i {uniform | exponential}] [-a n] [-e n] [-n n] [-s n] path_name

コマンドラインオプションの (既定) 内の値と文字列は既定値です。

Option or Argument説明
-f nテスト作業用ファイルサイズ
-p{y|n} シーケンシャルライトテスト実施指定 (既定 n)
-p yシーケンシャルライトを実施する。
-p nシーケンシャルライトを実施しない。
-x{b|r|w} ランダムアクセスで実施するアクセス (既定 b)
-x bRead/Write 両方を実施する。
-x rRead だけ実施する。
-x wWrite だけ実施する。
-r{s|y|n} シーケンシャルリードテストの実施方法 (既定 n)
-r sシーケンシャルリードテストを実施し、内容を厳密に検査する。
-r yシーケンシャルリードテストを実施し、内容を軽く検査する (ブロックアドレスを検査する)。
-r nシーケンシャルリードは実施しない。
-d{y|n}{Y|N} O_DIRECT (OS のキャッシュを使用しない) 指定 (既定 yY)

小文字 yn はシーケンシャルアクセステストに対する指定
大文字 YN はランダムアクセステストに対する指定

-d yシーケンシャルアクセステストは OS のキャッシュを使用しない。
-d nシーケンシャルアクセステストは OS のキャッシュを使用する。
-d Yランダムアクセステストは OS のキャッシュを使用しない。
-d Nランダムアクセステストは OS のキャッシュを使用する。

-d y と -d Y を一緒にして -d yY と指定することが出来できます。

-m{y|n} ファイルイメージ整合検査用の符号を付ける (既定 y)
-m y符号を付ける。
-m n符号を付けない。

テスト作業用ファイルに対して -r s または -r y を使って検査する場合、 -m y を指定してファイルを作成またはテストしてください。

-b n ブロック(アクセス単位)サイズ (既定 512)
このオプションで指定した整数倍が 1 回のアクセスサイズになります。
-b 4096ブロックサイズを 4096 バイトに指定する。
-u n シーケンシャルアクセステストで一度にアクセスするブロック数 (既定 0)
0 を指定した場合は "-a オプションで指定した値" x 2 がブロック数になります。 以下の式の値が 4Gi を超える場合、General Protection Fault が発生することが有ります。

"-b オプション" * "-a オプション" * 2
-u 10241024 ブロックを指定し、-b 512 だった場合は、 512Ki ( = 1024 x 512 ) バイトがシーケンシャルアクセスで一度にアクセスするバイト数になります。
-i n ランダムアクセステストで一度にアクセスする最小ブロック数 (既定 1)
-i 1最小は 1 ブロックを指定する。
-i {uniform|exponential} -i オプションに数値ではなく uniform または exponential を指定すると、 ランダムアクセステストで一度にアクセスするブロック数の分布を指定します。
-i uniform一様分布にします。
-i exponential指数分布にします。分布の詳細は、 (a2) random read/write を参照してください。
-a n ランダムアクセステストで一度にアクセスする最大ブロック数 (既定 8192)
-a 8192最大は 8192 ブロックを指定する。

-b 512 -i 1 -a 8192 の場合、ランダムアクセステストで OS に read/write 要求するサイズは i=1..8192 の整数とし、 512 * i バイトになります。

ノート: -a オプションはシーケンシャルアクセスで一度に転送する量に影響を与えます。 オプションの影響を無くすには -u オプションを使用してください。 以下の式の値が 4Gi を超える場合、General Protection Fault が発生することが有ります。

"-b オプション" * "-a オプション" * 2
-o n シーケンシャルとランダムアクセステストでアクセスする範囲の開始ブロック 番号、0 がファイルの先頭になる (既定 0)
-o 40964096 ブロックから アクセステストの対象にする。
-b 512 の場合、バイトオフセット 2097152 ( = 512 * 4096 )からアクセスする。
-e n シーケンシャルとランダムアクセステストでアクセスする範囲の終了ブロック 番号、0 を指定すると -f n で指定したサイズのファイル末尾までが範囲になります。(既定 0)
-e 6710886367108863 ブロック目 までをアクセス範囲として指定する。-b 512 の場合、末尾バイトオフセットは 34359738367 ( = 512 * ( 67108863 + 1) - 1) になります。
-n n ランダムアクセステストでアクセスする回数を指定します。read 回数と write 回数を足した回数が -n n で指定した値になります (既定 4096)

それぞれの回で read か write アクセスのどちらを実施するかは疑似乱数で決定します。 read と write アクセスの出現確率は半々です。疑似乱数による確率なので同一条件ならば 再現性があります。正確に半々になりません。

-n 2048アクセス回数を 2048 に指定する。
-n 0 ランダムアクセステストをしない。-z n で指定した休止は実行します。 シーケンシャル read, write のみ実施する場合は、テスト時間短縮のため、 -z オプションの併用も検討してください。
-s n 疑似乱数のシード値を指定します (既定 0)
-s 10シード値を 10 にする。
-z n シーケンシャルアクセステスト、ランダムアクセステスト後に休止 (sleep) する最小時間を指定します。テスト中、Tac="access_time" * 2 が この値より大きければ、休止時間は Tac になります (既定 10)
-z 20休止時間を 20 秒にする。
path_name テストに使うファイル名

数値 n は接尾辞 k, m, g, t, p を付加出来ます。其々 n に k: 1024, m: 10242, g: 10243, t: 10244, p: 10245 を掛ける指定です。

3.3.2.2. 結果出力形式

シーケンシャル write アクセスの出力形式
cur b/s, total b/s, cur_el b/s, elp b/s, cur_pos, progs, Twrite, Twrite_total, Twrite_elapsed, Telapsed, Tmem_access_total
説明
cur b/s直近の転送速度 (bytes/seconds)
total b/sWrite に掛かった時間だけから計算した書き始めからの転送速度 (bytes/seconds)
cur_el b/sWrite とそれ以外の検査符号生成も全て含んだ時間で計算した直近の転送速度 (bytes/seconds)
elp b/sWrite 以外に掛かった時間 (主に検査符号生成) を全て含めても全て含んだ時間で計算した書き始めからの転送速度 (bytes/seconds)
cur_pos次に書き込みを行うバイト位置テスト終了時はファイルサイズと一致します (byte)
progs進捗度を百分率で表しています。0 から 100 の値になります。(%)
TwriteWrite に掛かった時間 (seconds)
Twrite_total書き始めから Write に掛かった時間の合計 (seconds)
Twrite_elapsed書き始めから Write とそれ以外の処理時間 (主に検査符号生成処理) も全て含めた経過時間 (seconds)
Tmem_access_total書き込み以外、主に検査符号生成処理に掛かった時間 (seconds)
シーケンシャル read アクセスの出力形式
cur b/s, total b/s, cur_el b/s, elp b/s, cur_pos, progs, Tread, Tread_total, Tread_elapsed, Telapsed, Tmem_access_total
説明
cur b/s直近の転送速度 (bytes/seconds)
total b/sRead に掛かった時間だけから計算した読み始めからの転送速度 (bytes/seconds)
cur_el b/sRead とそれ以外の符号検査処理も全て含んだ時間で計算した直近の転送速度 (bytes/seconds)
elp b/sRead 以外に掛かった時間(主に符号検査処理)を全て含めても全て含んだ時間で計算した読み始めからの転送速度 (bytes/seconds)
cur_pos次に読み込みを行うバイト位置テスト終了時はファイルサイズと一致します (byte)
progs進捗度を百分率で表しています。0 から 100 の値になります。(%)
TreadRead に掛かった時間 (seconds)
Tread_total読み始めから Read に掛かった時間の合計 (seconds)
Tread_elapsed読み始めから Read とそれ以外の処理時間 (主に符号検査処理) も全て含めた経過時間 (seconds)
Tmem_access_total読み込み以外、主に符号検査処理に掛かった時間 (seconds)
ランダムアクセスの出力形式
index, elapsed_time, rw, seek_position, length, access_time, bps, memory_access_time
説明
indexアクセス連番、 0 から -n オプションで指定した値 -1 までの番号
elapsed_time経過時間、Read/Write 以外に掛かった時間も含む (seconds)
rwアクセス種別 'r' で Read, 'w' で Write
seek_positionランダムアクセス開始位置 (16 進数, byte)
lengthアクセス長 (16 進数, byte)
access_timeアクセス時間 (seconds) 符号検査・検査符号生成に掛かった時間は含んでいません
bpsアクセス長 / アクセス時間 (bytes/seconds)
memory_access_time符号検査、検査符号生成に掛かった時間 (seconds)

3.4. 結果プロット、ページ作成ツール

結果をプロットする機能は bash スクリプトと gnuplot で構成されています。出力形 式は PNG です。gnuplot のバージョンによって若干グラフの出来上がりが違います。

次の表は結果をプロットするためのスクリプト一覧です。SSD をテストした結果をプロットするには、 plotlogseq.sh, plotlogmix.sh の 2 つを使います。

ScriptDescription
plotlogseq.sh SSD のシーケンシャルアクセステスト ((a1) sequential read, (a3) sequential write") の結果をプロットします。
plotlogmix.sh SSD のランダムアクセステスト ((a2) random read and write) の結果をプロットします。
plotlogseq_usbmems.sh

High Speed 接続 USB memory のシーケンシャルアクセステスト ((a1) sequential read, (a3) sequential write") の結果をプロットします。

グラフの軸スケールと範囲を High speed 接続 USB memory に合う様に調整してあります。 遅い USB memory をプロットしてスケールや範囲が合わない場合はスクリプトを修正してください。 USB 3.0 Super Speed 対応の早い USB memory や UHS1 対応の Micro SD, SD card をテスト した結果をプロットする場合は plotlogseq_uhs1.sh の方が適している場合があります。

plotlogmix_usbmems.sh

High Speed 接続 USB memory のランダムアクセステスト ((a2) random read and write) の結果をプロットします。

グラフの軸スケールと範囲を High speed 接続 USB memory に合う様に調整してあります。 遅い USB memory をプロットしてスケールや範囲が合わない場合はスクリプトを修正してください。 USB 3.0 Super Speed 対応の早い USB memory や UHS1 対応の Micro SD, SD card をテスト した結果をプロットする場合は plotlogmix_uhs1.sh の方が適している場合があります。

plotlogseq_uhs1.sh

UHS1 SD Card (Micro SD Card) のシーケンシャルアクセステスト ((a1) sequential read, (a3) sequential write") の結果をプロットします。

グラフの軸スケールと範囲を UHS1 SD card (Micro SD card) または Super speed USB memory に合う様に調整してあります。スケールや範囲が合わない場合はスクリプトを修正してください。

plotlogmix_uhs1.sh

UHS1 SD Card (Micro SD Card) のシーケンシャルアクセステスト ((a2) random read and write) の結果をプロットします。

グラフの軸スケールと範囲を UHS1 SD card (Micro SD card) または Super speed USB memory に 合う様に調整してあります。遅い USB memory をプロットしてスケールや範囲が合わない場合はスクリプトを 修正してください。USB 3.0 Super Speed 対応の早い USB memory や UHS1 対応の Micro SD, SD card をテスト した結果をプロットする場合は plotlogmix_uhs1.sh の方が適している場合があります。

グラフのスケールと範囲が適切でなく、結果がプロットされない、はみ出す、振れ幅が小さいなどの 問題が起きた場合は、スクリプト plotlogseq_usbmems.sh, plotlomix_usbmems.sh, plotlogseq_uhs1.sh, plotlogmix_uhs1.sh で設定している次の環境変数を調整してください。

Exporting environment variableDescription
SEQUENTIAL_TRANSFER_SPEED_MINシーケンシャルアクセスの最低転送速度を指定します。
SEQUENTIAL_TRANSFER_SPEED_MAXシーケンシャルアクセスの最高転送速度を指定します。
RANDOM_TRANSFER_SPEED_MINランダムアクセスの最低転送速度を指定します。
RANDOM_TRANSFER_SPEED_MAXランダムアクセスの最高転送速度を指定します。

3.4.1. plotlogseq.sh, plotlogseq_usbmems.sh, plotlogseq_uhs1.sh - シーケンシャルアクセステストプロットスクリプト

シーケンシャルアクセステスト結果をプロットします。PNG ファイルが生成されます。 htmlplot.sh で使用する情報も生成します。

$ ${tool_path}/plotlogseq.sh [-L model_name] [log_directory]
$ ${tool_path}/plotlogseq_usbmems.sh [-L model_name] [log_directory]
$ ${tool_path}/plotlogseq_uhs1.sh [-L model_name] [log_directory]
parameterdescription
-L model_name グラフのタイトル部分を構成するモデル名を model_name に差し替えます。 空白を含めることはできません。
log_directory ssdtest.sh が生成したログ結果を保存したディレクトリです。 省略するとカレントディレクトリを指定した事になります。ディレクトリ名は次の様な書式です。
log-${Model}-${TestDateTime}-${TestFileSize}

3.4.2. plotlogmix.sh, plotlogmix_usbmems.sh, plotlogmix_uhs1.sh - ランダムアクセステストプロットスクリプト

ランダムアクセステスト結果をプロットします。PNG ファイルが生成されます。 htmlplot.sh で使用する情報も生成します。

$ ${tool_path}/plotlogmix.sh [-L model_name] [log_directory]
$ ${tool_path}/plotlogmix_usbmems.sh [-L model_name] [log_directory]
$ ${tool_path}/plotlogmix_uhs1.sh [-L model_name] [log_directory]
parameterdescription
-L model_name グラフのタイトル部分を構成するモデル名を model_name に差し替えます。 空白を含めることはできません。
log_directory ssdtest.sh が生成したログ結果を保存したディレクトリです。 省略するとカレントディレクトリを指定した事になります。ディレクトリ名は次の様な書式です。
log-${Model}-${TestDateTime}-${TestFileSize}

3.4.3. htmlplot.sh - HTML ページ作成スクリプト

プロットした図を HTML ページにまとめます。次の様にコンソール出力結果をリダイレ クトしてページファイルに格納してください。

$ ${tool_path}/htmlplot.sh [-L model_name] [log_directory] > html_page_file.html
parameterdescription
-L model_name ページのタイトル部分を構成するモデル名を model_name に差し替えます。 空白を含めることはできません。
log_directory ssdtest.sh が生成したログ結果を保存したディレクトリです。 plotlogseq.sh, plotlogseq_usbmems.sh, plotlogseq_uhs1.sh, plotlogmix.sh, plotlogmix_usbmems.sh, plotlogmix_uhs1.sh で プロットした PNG ファイルも含んでいるディレクトリです。 省略するとカレントディレクトリを指定した事になります。 ディレクトリ名は次の様な書式です。
log-${Model}-${TestDateTime}-${TestFileSize}
html_page_file.html htmlplot.sh から HTML 形式でテキストが出力されるのでリダイレクトして html_page_file.html に格納してください。

3.5. 連続実行用ツール

3.5.1. 連続実行と同時プロットをするための環境

テストを連続実行をする環境で同時プロットをするとテスト結果に影響を与える可能性 が有ります。テスト環境とプロット環境を分離することをお勧めします。

NFS を使用して分離する環境例を次に示します。

Machine execute SSD test (test)           Machine execute plot (plot)
+---------------------------+             +-------------------------------+
| Execute ssdtestloop.sh    |-- Network --| Execute pageupdaterloop.sh    |
| NFS client                |             | NFS server                    |
|                           |             |                               |
+---------------------------+             +-------------------------------+

テスト(ssdtestloop.sh) 実行マシン (test)

NFS client として設定し、NFS マウントポイント以下にテスト結果を格納する様にし ます。マウントオプションは -o rw です。これ以外のオプションは環境に合わせて 設定してください。

プロット(pageupdaterloop.sh) 実行マシン (plot)

NFS server として設定し、NFS export ディレクトリ以下のテスト結果をプロットする 様にします。export オプションは rw,async,anonuid=UserId,anongid=GroupId です。 UserId, GroupId はプロットを行うプログラムを走らせる user ID と group ID です。普通は自分自身の User ID, Group ID を指定することになります。これ以外の オプションは環境に合わせて設定してください。

anonuid, anongid は ssdtestloop.sh (およびこれから起動されるプログラム群) が root 権限で書き込むファイルに付与される uid, gid となります。

3.5.2. 環境構築例

以下に NFS 設定、SDD マウントが済んだ後の操作例を示します。plot# はプロット 実行マシン (plot) 上での操作、test# はテスト実行マシン (test) での操作です。 plot 上でプロットを実行する userid, groupid は 1000, 1000 としています。

ノート: ${tool_path} は plot, test 両マシンでそれぞれ、適したパスに置き換えてください。

NFS 共有するディレクトリ作成

plot# mkdir -p /export/share1
plot# cd /export/share1
plot# chmod a+rw .
plot# chmod +t .
plot# mkdir loop_test
plot# chown 1000:1000 loop_test

NFS 共有する

plot# vi /etc/exports
/export/share1 test(rw,async,anonuid=1000,anongid=1000) この行を追加
plot# exportfs -a

NFS 共有したディレクトリをマウント、テスト実行

test# mkdir -p /mnt/shared1
test# mount -o rw plot:/export/share1 /mnt/share1
test# cd /mnt/shared1
test# cd loop_test
test# ${tool_path}/ssdtestloop.sh -C 20 /ssd/mount/point
Note: /ssd/mount/point は SSD をマウントしたポイントです。

プロット自動更新実行

plot$ cd /export/share1/loop_test
plot$ ${tool_path}/pageupdaterloop.sh .

3.5.3. ssdtestloop.sh - ssdtest.sh を連続実行するスクリプト

ssdtest.sh を連続実行します。

# ${tool_path}/ssdtestloop.sh -C LoopCount [-L ModelNameLabel] /path/to/test
Option or ArgumentDescription
-C LoopCount 連続実行する回数を LoopCount 回にします。
-L ModelNameLabel SSD のモデル名に付加したい文字列を ModelNameLabel で指定します。 モデル名の接尾辞として扱われます。USB Memory の場合はモデル名を 採取できない場合があります。この場合は必ず指定してください。
/path/to/test テストしようとする SSD をマウントしたパス、またはそれより深い 階層のパスを指定します。ディレクトリを指定すれば、そのディレクトリに UUID 形式 の名前が付いたファイルを生成してテストをします。ファイル名を指定すれば、その名 前でファイルを生成してテストをします。

テスト結果(テストログ)はカレントディレクトリの下に次の名前で作ったディレクトリ に格納されます。テストの繰り返し毎に、TestDateTime がテスト開始時刻に 更新されて新しいディレクトリの下に結果が格納されます。

log-${ModelName}${ModelNameLabel}-${TestDateTime}-${テストファイルサイズ}

カレントディレクトリの下に ssdtestloop_$PID_loop.txt というファイルが作成され ます。$PID の部分はプロセス ID です。このファイル書かれた数値を増減させると、 連続実行する回数を調整できます。

3.5.4. pageupdater.sh - 連続実行して生成した複数のログを HTML ページにする

ssdtestloop.sh で連続実行して生成した複数のログ(ディレクトリ)の HTML ページを 生成し、連続実行結果をまとめたページを生成します。pageupdaterloop.sh から呼び出 されるスクリプトです。

$ ${tool_path}/pageupdater.sh [update-directory]

update-directory は ssdtestloop.sh を実行した(実行している)カレントディレクト リを指定します。update-directory 以下にテスト結果を格納した log-* ディレクトリ が ssdtestloop.sh によって作られた(作られている)ディレクトリです。省略した場合は update-directory はカレントディレクトリになります。

3.5.5. pageupdaterloop.sh - 連続実行結果を逐一 HTML ページに変換する

ssdtestloop.sh で逐一生成されるログを一定間隔でプロット、 HTML ページ更新をするツールです。

$ ${tool_path}/pageupdaterloop.sh \
  [-T IntervalTime] [update-directory] > html_page_file.html
Option or ArgumentDescription
-T IntervalTime 更新周期を IntervalTime 秒に指定します。(既定 60)
update-directory ssdtestloop.sh を実行した(実行している)カレントディレクト リを指定します。update-directory 以下にテスト結果を格納した log-* ディレクトリ が ssdtestloop.sh によって作られた(作られている)ディレクトリです。省略した場合 は update-directory はカレントディレクトリになります。
html_page_file.html 各 log-* ディレクトリ以下に作られたページにリンクを貼った インデックスページを格納するファイルを html_page_file.html に格納します。 リダイレクトで保存してください。

3.6. デバック・診断ツール

3.6.1. Make mtTest - MT19937 アルゴリズム検証

乱数生成アルゴリズム MT19937 が正しく動作するか検査する機能です。検証用の既知 結果と照合します。

$ cd ${tool_path}
$ make mtTest

4. 技術ノート

4.1. SSD をマウントする際のヒント

4.1.1. TRIM (discard) 対応

SSD をマウントする際に -o discard を付けると、ファイルシステムが対応して いれば TRIM コマンドが使われます。ssdtest の場合、ファイルの削除は殆ど しないため、効果が薄いかもしれません。次のコマンドライン入力例は SSD の /dev/sdb1 パーティションを discard オプションを付けてマウントする例です。

# mkdir /mnt/sdb1
# mount -o discard /dev/sdb1 /mnt/sdb1

4.1.2. パーティション・アラインメント

パーティションアラインメントを確認するには /sbin/fdisk に -u オプションを 指定して起動しパーティションテーブルを LBA 単位で表示して下さい。

4.2. O_DIRECT

測定プロットのタイトルなどに入る単語 O_DIRECT はファイルを open する際の フラグです。

4.2.1. "with O_DIRECT"

O_DIRECT が付いているテスト (with O_DIRECT) は、OS のキャッシュを使わない アクセスをします。SSD の性能をそのまま測定します。

4.2.2. "without O_DIRECT"

O_DIRECT が付いていないテスト (without O_DIRECT) は、OS のキャッシュを使う アクセスをします。実際の使用感に近い測定結果となります。SSD の機種によっては アクセス時間が長くなる傾向が出てきます。例えば 1~2MiBytes のアクセスにも 関わらず 1 ~ 10 秒程掛かる場合が出てきます。

4.3. カーネルパラメータチューニング

カーネルパラメータを調整して SSD の性能が出やすいようにしています。

4.3.1. /sys/block/${SSD_DEVICE_NAME}/queue/read_ahead_kb

シーケンシャルアクセステストでは Linux の既定値と同じ 128KiByte に 設定しています。環境変数 SEQUENTIAL_READ_AHEAD_KB で設定できます。

ランダムアクセステストでは、0KiByte に設定しています。環境変数 RANDOM_READ_AHEAD_KB で設定できます。Linux の既定値と違うので、実使用状態で 出る性能と違う測定結果が得られる可能性が有ります。測定の方が転送速度が高め に出る傾向が有ると考えられます。

4.3.2. /sys/block/${SSD_DEVICE_NAME}/device/max_sectors

1 回のデバイスに対するトランザクションで read/write する最大セクタ数の 上限値です。次の max_sectors_kb の上限値を決めています。 Linux kernel version, device driver, 転送経路のコントローラチップ, アクセス先のデバイスによってはこのノードが存在しないこともあります。

ノードが存在し書き込み可能な場合は、値を増やすと転送効率が上昇し 性能が上がります。

しかし、何らかの不具合を起こす可能性もあります。ssdtest ツールはこの パラメータを変更しません。デバイスの純粋な性能を見るためには値が大きい方が 望ましいです。大きくする場合は転送データを比較するなど入念なテストを行う ことをお勧めします。

4.3.3. /sys/block/${SSD_DEVICE_NAME}/queue/max_sectors_kb

1 回のデバイスに対するトランザクションで read/write する 最大セクタ数です。max_sectors または ドライバ内の制限値がこのパラメータの最大値を決めています。

標準的な Linux の環境では、シーケンシャルアクセステスト、 ランダムアクセステスト双方で 30Mi byte を設定しています。 Linux の既定値は 512Ki byte です。既定値に対して大きな値にして性能向上を 狙っています。

4.3.4. /proc/sys/kernel/hung_task_timeout_secs

hung_task_timeout_secs が存在する場合、テスト中は 0 に設定し、長時間処理が 滞った場合でも強制 kill しない様にしています。テスト中 1 回の system call による read/write 時間が 100 秒を超えることが有り、さらに既定値の 120 秒を 超えた場合テストが中断してしまう場合が有りました。

4.3.5. テスト終了後のカーネルパラメータ

テスト終了後、カーネルパラメータはテスト実行前に設定されていた値に 戻ります。

4.4. 専有メモリと swap 設定

ssdstress プロセスで約 6.5GiByte 使用します。page lock を試みます。常に 6.5GiByte を主記憶に保持できる環境が理想です。他のプロセスでメモリを多く使用 しない様にして下さい。例えば、runlevel 3 にして GUI を停止してください。

swap の設定は変更していません。外乱を少なくするため、メモリが 8GiByte 以上 ある場合は、メモリを多く専有するプロセスを停止し swap を off にするとよりよい 結果になると考えられます。

4.5. テスト間の休止時間

シーケンシャルアクセステストとランダムアクセステストの間、パラメータを 変えたランダムアクセステストの間、一定のテスト休止時間を設けています。OS の cache に残留したアクセスの消化、遅延されているファイルシステムを 構成している管理情報の更新、SSD 内の処理収束を待つ時間です。休止期間が 無い場合、シーケンシャルアクセスに於いて、転送速度が大きく乱れる現象を 確認しています。

SSD 内の処理については推定するしかないのですが、wear leveling, 保留していたエラー訂正後の書き戻し処理が行われている可能性が有ります。

4.6. 書き込みデータ

書き込みデータは MT19937 アルゴリズムを使用した疑似乱数で生成しています。 書き込みデータの破損が無いか検査用の符号を付加しています。検査用の符号は ブロック位置とチェックサムで構成されています。

圧縮手法を使用して高速化している SSD ではその効果が出ずに、結果が低い 転送速度を示すことがあります。

ランダムアクセステスト、シーケンシャルアクセステストの read にて破損が 発見された場合、テストは Fail します。破損検査は、転送速度に影響が出ない 程度で軽く行っています。

万が一、テスト対象の SSD が書き込みデータパターン照合等により、テスト用の 特殊な挙動をしていると考えられる場合は環境変数 SEED に乱数の種値を設定して ください。SEED 値を変更するとランダムアクセスパターンも変化します。

4.7. 検査符号生成、符号検査と OS のページ管理の関係

検査符号生成と符号検査するもう一つの目的は OS のページ管理による影響を 減らすことを狙っています。

4.7.1. 確実な read() 実行

Linux ではまだ積極的に取り入れていないはずですが、read() システムコールで 読み出したデータをプログラムから memory read するまで主記憶に配置しない場合が あるOS が存在します。memory read をしなければ read() システムコールはデバイス から何も読みだしません。アクセスエラー等の例外的な事象の正確性は犠牲に なりますが、多くの場合、支障をきたすことはありません。

この様な OS の最適化の影響を減らすため符号検査を実施しています。 memory_access_time, Tmem_access_total の異様な増加が認められる場合、read() システムコールに何らかの最適化が施されている可能性が有ります。

4.7.2. page lock

ssdstress は mmap でメモリを確保する際 page lock を試みます。page lock をして常に主記憶上に read と write バッファを確保します。page lock が 出来なかった場合は、ランダムアクセス時 read 前は 0x0 を、write 前は 検査符号をバッファに書き込み、バッファを出来る限り主記憶に配置されている 状態にします。

4.8. 32bit プロセッサ または 小メモリ環境での実行

ssdstress.c は 32bit プロセッサ上でもコンパイル・実行可能です。 32 bit プロセッサ上で ssdtest_usbmem.sh, ssdtest_light_usbmem.sh が使用可能です。これらの必要メモリ量は 120Mibyte です。 主記憶が少ない環境でも実行可能です。

ssdtest_usbmem.sh, ssdtest_light_usbmem.sh を SSD に対して 使用することが可能です。使用した場合、テスト規模が縮小され、 ランダムアクセステストの転送長は最長 32Mi byte になります。 得られる性能データにピーク性能が含まれない場合が有ります。 あるいは SSD 内のキャッシュメモリが 16Mi byte 以上ある場合、 書き込み速度はキャッシュメモリに書き込むまでの処理を測る事になり、 不揮発メモリへの書き込み速度が測定されない場合があります。

性能測定範囲、必要メモ量を調整するには ssdtest_usbmem.sh, ssdtest_light_usbmem.sh スクリプト内で設定している次の 環境変数の値を調節してください。

Exporting environment variableDescription
RANDOM_BLOCKS_MAX ランダムアクセスで一度に read/write するブロック数の最大値。 必要メモリ量は約 BLOCK_SIZE * RANDOM_BLOCKS_MAX * 3 + 32Mi byte です(BLOCK_SIZE = 512)。テスト中に同時にプロットする場合は +100Mi byte 程度を見込んで下さい。
SEQUENTIAL_BLOCKS シーケンシャルアクセスで一度に read/write するブロック数。 RANDOM_BLOCKS_MAX * 2 以下の値であること。

5. 履歴

5.1. 変更履歴一覧

主な変更点は次の通りです。

VersionDateUpdates
0.72012/11/18
  • リリース開始
0.712012/12/23
  • 説明文書追加
  • MT-Random (mt19937ar) 添付文書追加
  • gnuplot 4.2 対応
  • htmlplot.sh: HTML ページにアクセス時間 100 秒越えを記録した数を表示
  • htmlplot.sh: HTML ページに総書き込みバイト数、総読み込みバイト数表示
  • 連続テストスクリプト追加
  • gcc コマンドライン文法変更対応
1.02012/12/31
  • HTML 説明文書追加
  • テスト対象ボリュームのファイルシステムが FAT, FAT32 だった場合、 テストファイルサイズを 4095Mibyte にする。
  • テストログディレクトリのオーナーをカレントディレクトリと同じにして、 read/write 可にする。
  • テストエンジン ssdstress.c 最適化強化
  • ssdstress.c: Read/Write buffer の page lock を試みるようにした。 page lock ができない場合は page fault をテスト中に起こさない 様にする。
  • ssdstress.c: 出力フォーマットのタイトル行の列名修正
  • pageupdater.sh, pageupdaterloop.h: 連続テスト用ページ更新ツールで 引数無しの場合、カレントディレクトリを対象とするようにした
  • mt19937ar.c 最適化強化
  • make clean でエラーが出る問題解消
1.012013/01/02
  • 配布ファイル日付をリリース日時に付け直さず、開発作業で使っている ファイルの日付とした。
  • typo 修正。
2.002017/1/17
  • テキスト説明文書 README_JP 廃止
  • テスト方法変更: ランダムアクセステストにてブロック数分布を 指数関数分布に変更し、時間短縮、書き込み負荷軽減、 プロット鮮明化をした。
  • 転送長 - アクセス時間のグラフの縦軸・横軸を入れ替え 縦軸: アクセス時間 - 横軸: 転送長とした。
  • グラフプロットの Model Name を差し替えられる様にした。
  • ubuntu 14.04 またはそれ以降でテスト対象のボリュームを誤認識する 問題を解消した。
  • gnuplot 5.0 対応: エラー、格子の色変わり対応、タイトル文字列の 一部が添え字などに変形する問題対応
  • UHS1 SD card (MicroSD card) 向けプロットスクリプトを追加
  • テストスクリプト整理

6. ライセンス

6.1. SSD テストプログラム群

次のファイル群は 2 条項 BSD ライセンスです。

htmlplot.sh, pageupdater.sh, pageupdaterloop.sh, plotlogmix.sh, plotlogmix_uhs1.sh, plotlogmix_usbmems.sh, plotlogseq.sh, plotlogseq_uhs1.sh, plotlogseq_usbmems.sh, ssdtest.sh, ssdtest_light.sh, ssdtest_light_usbmems.sh, ssdtest_usbmems.sh, ssdtestcommon.sh, ssdtestloop.sh, random-ts_at.gnuplot, random-at_tl.gnuplot, random-ts_tl.gnuplot, sequential-ts_pr.gnuplot, ssdstress.c, Makefile, readme.html

6.2. MT19937 アルゴリズム

次の MT19937 アルゴリズムソースと文書は Makoto Matsumoto 博士と Takuji Nishimura 博士と が作成したソフトウエアであり、3 条項 BSD ライセンスです。

mt19937ar.c, mt19937ar.h, mt19937ar.out, mtTest.c, readme-mt.txt

公開に感謝します。プログラム間の整合性と 64bit 環境でコンパイルできる様に するための修正、コメント部分を doxygen スタイルにする修正を施しています。

Licence Notice

Copyright 2012, 2017 Akinori Furuta <afuruta @m7.dion.ne.jp>
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.