LoginSignup
1
1

More than 5 years have passed since last update.

メモリ上でI/OテストしてSSDに優しくなる

Last updated at Posted at 2017-10-08

SSDに優しくなりたい

行単位でstage/unstageできるgit GUIクライアントを作っています。
週刊 git GUIクライアントを作る [1] stage/unstage基礎知識編
週刊 git GUIクライアントを作る [2] stage/unstage不完全攻略編

gitを使うアプリケーションなので、そのテストのためにファイルの読み書きが発生します。
コードに対する不安があり、そしてテストコードを書くのが初めてで楽しくて調子に乗ってるため、任意の状況での行の選択パターンを網羅したテストというのを行っていて、現時点では70秒ぐらいかかります。

70秒もずっとファイル読み書きするテストをコードの変更のたびにやっていると「SSDに優しくないな」という気持ちになりました。ビルドもテストも使い捨てるものなので、メモリ上でやれたら嬉しいですね。ちょっと調べてみると、以下の方法で良さそうなので試してみました。

方法

  1. RAM Diskを作る
  2. ビルドの出力先をRAM Diskに変更する

対象環境

  • Windows
  • Gradleプロジェクト

今回使うのはImDiskとgradleだけなので、これ以外に制限は無いはずです。
他の環境でも同様のことは可能だろうと思います。

IOを伴うテストについて

ほかにいい方法があるのかもしれませんが、
現在はgradleプロジェクトでJunit5を使って次のようにテストしています。

  • src\test\resources\以下に、操作対象とするファイルを用意する
  • それがコピーされたbuild\resources\test以下で、ファイルとgitの操作を行う
  • テストリソースとしての.gitフォルダを持ちたくないので、毎回git initから行う

このため、ビルドの出力先をメモリ上に持っていくだけで、目的が達成されます。
なお、実用性は求めていませんが、70秒のテストが60秒ぐらいになりました。

RAM Diskを作る

ImDisk Virtual Disk Driverというのを使いました。
GUI版のImDisk Toolkitもいい感じでした。

参考記事
http://siwon-g.hateblo.jp/entry/20151122/1448195973
http://jinblog.at.webry.info/201402/article_2.html

ビルドの出力先を変更する

  • build.graldeでproject.buildDir変数を変更します。
  • ソースと異なるドライブでも、万事うまくいく雰囲気です。

build.graldeにまとめる

  • 指定のドライブがマウントされているかどうか確認する

    • JavaのFile.listRoots()でドライブの一覧を取得できます
  • マウントされていなければRAM Diskを作ってマウントする

    • 例えば'imdisk -a -s 2g -t vm -o rem -p "/fs:ntfs /q /y" -m ' + G:
    • -s 2gオプションでサイズ指定します。-s -2gのように負の値を指定して、2gを残してそれ以外をめいっぱい使う、ということもできるようです。。
    • -o remオプションでリムーバブルドライブにしています。そうでない場合、管理者権限が必要とされたり、強制アンマウントが必要になったりします。
    • -p "/fs:ntfs /q /y"オプションでファイルをフォーマットできます。なお、GUIクライアントのImDisk ToolkitでRAMディスクを作ってマウントすると、Windowsがフォーマットするかどうか尋ねてきてくれます。
    • -m G:オプションでマウント先を指定します。試してませんが、-m #:と書くと、空いてるドライブ文字を選択してくれます。
build.gradle
def TARGET_DRIVE = 'G:'
def dir = TARGET_DRIVE + '\\project_name\\build'
if (hasDrive(TARGET_DRIVE)) {
    buildDir = dir 
} else {
    def COMMAND = 'imdisk -a -s 2g -t vm -o rem -p "/fs:ntfs /q /y" -m ' + TARGET_DRIVE
    println "Mounting RAM Disk to $TARGET_DRIVE is ..."
    def ret = COMMAND.execute().waitFor()
    if (ret == 0 && hasDrive(TARGET_DRIVE)) {
        println "done by command: "
        buildDir = dir 
    } else {
        println 'failed by command: '
    }
    println ' ' + COMMAND
}
println 'buildDir: ' + buildDir

// 指定のドライブがマウントされているか
static boolean hasDrive(String letter) {
    def drive = File.listRoots().find {
        return it.absolutePath.startsWith(letter)
    }
    return drive != null && drive.exists()
}

ロジックはリモートにpushしてもいいかもしれませんが、ドライブ文字の選択は個人でも環境によって異なるので、そのままだと微妙かもしれません。少しだけ考えてみると、次のような案が思いつきました。

  • .gitignoreしたローカルファイルにドライブ文字を書けるようにする
  • #:を使って、ビルドのたびに作成・削除する

(追記)設定ファイルを利用する

.gitignoreしたローカルファイルにドライブ文字を書けるようにする

上述の案を実際に書いてみました。
config.groovyに設定を書きます。

  • RAM.driveに書かれたドライブ文字を利用してRAM diskを作成
  • RAM.driveが無ければ何もせず、通常のbuildDirを利用
  • RAM.sizeが設定されていばそのサイズを指定、無ければデフォルトのサイズ1GBでRAM diskを作成
  • RAM.sizeが設定されていばその形式でフォーマット、無ければデフォルトのntfsでフォーマット
config.groovy
RAM {
    drive = 'G:'
    size = '2g'
}
/.gitignore
config.groovy
build.gradle
def config = new ConfigSlurper().parse(file('config.groovy').text)
def TARGET_DRIVE = config.RAM.drive ?: ''
if (TARGET_DRIVE) {
    def dir = TARGET_DRIVE + '\\project_name\\build'
    if (hasDrive(TARGET_DRIVE)) {
        buildDir = dir
    } else {
        def size = config.RAM.size ?: "1g"
        def format = config.RAM.format ?: "ntfs"
        def COMMAND = "imdisk -a -s $size -t vm -o rem -p \"/fs:$format /q /y\" -m " + TARGET_DRIVE
        println "Mounting RAM Disk to $TARGET_DRIVE is ..."
        def ret = COMMAND.execute().waitFor()
        if (ret == 0 && hasDrive(TARGET_DRIVE)) {
            println "done by command: "
            buildDir = dir
        } else {
            println 'failed by command: '
        }
        println ' ' + COMMAND
    }
}
println 'buildDir: ' + buildDir

groovyはエルビス演算子?:が使えて気持ちいいですね。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1