ディスクアクセスを確認する方法

MZK-NAS02静音化(ソフトウェア編)で、ディスクアクセスの有無の確認を行っていた方法です。

kernel2.6では、ディスクアクセスの値は、/proc/diskstats で得られます。各フィールドの意味は、 linux/Documentation/iostats.txtを参照。

/proc/diskstats を10秒間隔で参照して、ディスクアクセスを行ったセクタ数を標準出力に表示するperlスクリプトを作りました。

disklog.pl:

@pre;
@pre2;
@pre3;
@cur;
@diff;
$cnt = 0;

open(DISK, "</proc/diskstats");
while(<DISK>){
	chomp();
	@cur = split(/\s+/);
	if($cur[3] eq "rdea"){
		@pre = @cur;
	}
	if($cur[3] eq "rdea2"){
		@pre2 = @cur;
	}
	if($cur[3] eq "rdea3"){
		@pre3 = @cur;
	}
}
close(DISK);

print "        rdea  (r)  (w)  rdea2  (r)  (w)  rdea3  (r)  (w) \n";
while(1){
	sleep(10);
	$cnt++;
	open(DISK, "</proc/diskstats");
	while(<DISK>){
		chomp();
		@cur = split(/\s+/);
		if($cur[3] eq "rdea"){
			for($i=4; $i<15; $i++){
				$diff[$i] = $cur[$i] - $pre[$i];
			}
			if($diff[6] > 0 or $diff[10] > 0){
				$cnt = 0;
			}
			printf("%3dm%2ds ", $cnt*10/60, $cnt*10%60);
			print "rdea ";
			printf("%4d %4d ", $diff[6], $diff[10]);
			@pre = @cur;
		}
		if($cur[3] eq "rdea2"){
			for($i=4; $i<8; $i++){
				$diff[$i] = $cur[$i] - $pre2[$i];
			}
			print " rdea2 ";
			printf("%4d %4d ", $diff[5], $diff[7]);
			@pre2 = @cur;
		}
		if($cur[3] eq "rdea3"){
			for($i=4; $i<8; $i++){
				$diff[$i] = $cur[$i] - $pre3[$i];
			}
			print " rdea3 ";
			printf("%4d %4d ", $diff[5], $diff[7]);
			@pre3 = @cur;
		}
	}
	($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time());
	printf("  %02d:%02d:%02d\n", $hour, $min, $sec);
	close(DISK);
}

# perl disklog.pl

で実行すると、ディスクアクセスが発生していない時間と、readの値、writeの値、現在時刻を表示します。rdeaはディスク全体、rdea2は / のパーティション、rdea3は /storage/rdea3(共有用のパーティション)です。

ただし、これだとPCから切断している間にログを取るには出力が多すぎるので、ディスクアクセスが発生したときのみ指定したファイルにログを吐くバージョンを作りました。

fdisklog.pl:

$slpcnt = 60;

sub sigexit {
	print "exit.\n";
	close(FILE);
	exit(0);
}

$SIG{'TERM'} = 'sigexit';
$SIG{'INT'} = 'sigexit';

$fn = $ARGV[0];
open(FILE, ">$fn") or die "Can't open $fn!\n";

@pre;
@pre2;
@pre3;
@cur;
@diff;
$cnt = 0;

open(DISK, "</proc/diskstats");
while(<DISK>){
	chomp();
	@cur = split(/\s+/);
	if($cur[3] eq "rdea"){
		@pre = @cur;
	}
	if($cur[3] eq "rdea2"){
		@pre2 = @cur;
	}
	if($cur[3] eq "rdea3"){
		@pre3 = @cur;
	}
}
close(DISK);

print FILE "         rdea  (r)  (w)  rdea2  (r)  (w)  rdea3  (r)  (w) \n";
close(FILE);

while(1){
	open(FILE, ">>$fn") or die "Can't open $fn!\n";
	$buf = "";
	($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time());
	$buf .= sprintf("%02d:%02d:%02d ", $hour, $min, $sec);
	sleep($slpcnt);
	$cnt++;
	open(DISK, "</proc/diskstats");
	while(<DISK>){
		chomp();
		@cur = split(/\s+/);
		if($cur[3] eq "rdea"){
			for($i=4; $i<15; $i++){
				$diff[$i] = $cur[$i] - $pre[$i];
			}
			if($diff[6] > 0 or $diff[10] > 0){
				$cnt = 0;
			}
#			$buf .= sprintf("%3dm%2ds ", $cnt*$slpcnt/60, $cnt*$slpcnt%60);
			$buf .= "rdea ";
			$buf .= sprintf("%4d %4d ", $diff[6], $diff[10]);
			@pre = @cur;
		}
		if($cur[3] eq "rdea2"){
			for($i=4; $i<8; $i++){
				$diff[$i] = $cur[$i] - $pre2[$i];
			}
			$buf .= " rdea2 ";
			$buf .= sprintf("%4d %4d ", $diff[5], $diff[7]);
			@pre2 = @cur;
		}
		if($cur[3] eq "rdea3"){
			for($i=4; $i<8; $i++){
				$diff[$i] = $cur[$i] - $pre3[$i];
			}
			$buf .= " rdea3 ";
			$buf .= sprintf("%4d %4d ", $diff[5], $diff[7]);
			@pre3 = @cur;
		}
	}
	if($cnt == 0){
		print FILE $buf . "\n";
	}
	close(DISK);
	close(FILE);
}

出力先をディスクにすると、自分の書き込みを延々と記録してしまうので、/dev/shm などtmpfsの場所にログを吐くことにします。また、logoutしても終了しないようにnohupで実行します。

# cd /dev/shm
# nohup perl fdisklog.pl ./log.txt

これで、PCを落としている間のディスクアクセスを確認できます。