実行中のプロセスの出力を比較するにはどうすればいいですか?

実行中のプロセスの出力を比較するにはどうすればいいですか?

私はベンチマークを実行していますgem5シミュレータは、実行中に出力を端末に表示し続けます。私はすでに同じベンチマークのサンプル実行をテキストファイル

そこで、コンソールに出力される出力ストリームを、前回のゴールデン ランのテキスト ファイルと比較したいと思います。出力とテキスト ファイルを比較して違いがある場合は、シミュレーションは自動的に終了する必要があります。

ベンチマークの実行には時間がかかります。現在の実行で最初のエラーのみに関心があるので、実行が完了するまで待機して両方の出力を比較する時間を節約できます。

答え1

私は、出力を比較する適切な方法を見つけるためにもう少し考えずにはいられませんでした。実行中のプロセス(ターミナルで) あなたが言及したように、「ゴールデン ラン」ファイルに対して実行します。

実行中のプロセスの出力をキャッチする方法

私はオプションscript付きのコマンドを使用しました-f。これにより、現在の (テキスト) 端末コンテンツがファイルに書き込まれます。-fオプションは、端末への書き込みイベントごとに出力ファイルを更新します。スクリプト コマンドは、端末ウィンドウで発生するすべてのことを記録するために作成されています。
以下のスクリプトは、この出力を定期的にインポートします。

このスクリプトが行うこと

ターミナル ウィンドウでスクリプトを実行すると、コマンドで開始される 2 番目のターミナル ウィンドウが開きますscript -f。この (2 番目の) ターミナル ウィンドウで、ベンチマーク プロセスを開始するコマンドを実行する必要があります。このベンチマーク プロセスが結果を生成する間、これらの結果は定期的に (2 秒ごとに) 「ゴールデン ラン」と比較されます。差異が発生した場合、差異の出力が「メイン」(最初の) ターミナルに表示され、スクリプトが終了します。次の形式の行が表示されます。

error: ('Solutions: 13.811084', 'Solutions: 13.811084 aap noot mies')

explanation:

error: (<golden_run_result>, <current_differing_output>)

この出力の後、テストを実行し、2 番目のウィンドウを安全に閉じることができます。

使い方

  • 以下のスクリプトを空のファイルにコピーします。
    「ゴールデン ラン」ファイルを見ると、最初のセクション (実際のテストが開始する前) は無関係であり、システムによって異なる場合があります。したがって、実際の出力が始まる行を定義する必要があります。あなたの場合は、次のように設定しました。

    first_line = "**** REAL SIMULATION ****"
    

    必要に応じて変更してください。

  • 「ゴールデン ラン」ファイルへのパスを設定します。
  • スクリプトを として保存しcompare.py、次のコマンドで実行します。

    python3 /path/to/compare.py
    

    `

  • 2つ目のウィンドウが開き、Script started, the file is named </path/to/file>
  • この 2 番目のウィンドウでベンチマーク テストを実行すると、最初の異なる結果が最初のウィンドウに表示されます。

ここに画像の説明を入力してください

テスト方法

私は、ゴールデン ランの編集バージョンの行を 1 行ずつ印刷する小さなプログラムを作成しました。スクリプトで、それを元の「ゴールデン ラン」ファイルと比較するようにしました。

スクリプト:

#!/usr/bin/env python3

import subprocess
import os
import time

home = os.environ["HOME"]

# files / first_line; edit if necessaary
golden_run = "/home/jacob/Bureaublad/log_example"
first_line = "**** REAL SIMULATION ****"

# don't change anything below
typescript_outputfile = home+"/"+"scriptlog.txt"
# commands
startup_command = "gnome-terminal -x script -f "+typescript_outputfile
clean_textcommand = "col -bp <"+typescript_outputfile+" | less -R"
# remove old outputfile
try:
    os.remove(typescript_outputfile)
except Exception:
    pass
# initiate typescript
subprocess.Popen(["/bin/bash", "-c", startup_command])
time.sleep(1)
# read golden run
with open(golden_run) as src:
    original = src.read()
orig_section = original[original.find(first_line):]
# read last output of current results so far
def get_last():
    read = subprocess.check_output(["/bin/bash", "-c", clean_textcommand]).decode("utf-8")
    if not first_line+"\n" in read:
        return "Waiting for first line"
    else:
        return read[read.find(first_line):]
    with open(typescript_outputfile, "wt") as clear:
        clear.write("\n")
# loop
while True:
    current = get_last()
    if current == "\n":
        pass
    else:
        if not current in orig_section and current != "Waiting for first line":
            orig = orig_section.split("\n")
            breakpoint = current.split("\n")
            diff = [(orig[i], breakpoint[i]) for i in range(len(breakpoint)) \
                    if not orig[i] == breakpoint[i]]
            print("error: "+str(diff[0]))
            break
        else:
            pass
    time.sleep(5)

答え2

utilを使用できますdiff

あなたがあなたのゴールデンファイル、そして別の私が変えたことです。

プログラムを実行していないので、次のシミュレーションを作成しました:

#!/bin/bash
    while read -r line; do
        echo "$line";
        sleep 1;
    done < bad_file

それは別のファイル (bad_file) をスキャンし、1 秒ごとに 1 行ずつ出力します。

今、このスクリプトを実行し、出力をlogファイルにリダイレクトします。

$ simulate > log &

また、チェッカースクリプトも書きました:

#!/bin/bash

helper(){
    echo "This script takes two file pathes as arguments."
    echo "$0 path/to/file1 path/to/file2"
}

validate_input(){
    if [[ $# != 2 ]]; then 
        helper
        exit 1
    fi

    if [[ ! -f "$1" ]]; then
        echo "$1" file is not exist.
        helper
        exit 1
    fi
    if [[ ! -f "$2" ]]; then
        echo "$2" file is not exist.
        helper
        exit 1
    fi
}

diff_files(){
# As input takes two file and check
# difference between files. Only checks
# number of lines you have right now in
# your $2 file, and compare it with exactly
# the same number of lines in $1
    diff -q -a -w <(tail -n+"$ULINES" $1 | head -n "$CURR_LINE") <(tail -n+"$ULINES" $2 | head -n "$CURR_LINE")
}

get_curr_lines(){
# count of lines currenly have minus ULINES
    echo "$[$(cat $1 | wc -l) - $ULINES]"
}

print_diff_lines(){
    diff -a -w --unchanged-line-format="" --new-line-format=":%dn: %L" "$1" "$2" | grep -o ":[0-9]*:" | tr -d ":"
}

ULINES=15 # count of first unused lines. How many first lines to ignore

validate_input "$1" "$2"
CURR_LINE=$(get_curr_lines "$2") # count of lines currenly have minus ULINES

if [[ $CURR_LINE < 0 ]];then
    exit 0
fi

IS_DIFF=$(diff_files "$1" "$2")
if [[ -z "$IS_DIFF" ]];then
    echo "Do nothing if they are the same"
else
    echo "Do something if files already different"
    echo "Line number: " `print_diff_lines "$1" "$2"`
fi

実行可能にすることを忘れないでくださいchmod +x checker.sh

このスクリプトは 2 つの引数を取ります。最初の引数はゴールデン ファイルへのパス、2 番目の引数はログ ファイルへのパスです。

$ ./checker.sh path_to_golden path_to_log

このチェッカーは、ファイル内の現在の行数をカウントしlog、 内のまったく同じ行数と比較しますgolden_file

チェッカーを1秒ごとに実行し、必要に応じてkillコマンドを実行します。

必要に応じて、checker.sh1 秒ごとに実行する bash 関数を記述できます。

$ chk_every() { while true; do ./checker.sh $1 $2; sleep 1; done; }

diffに関する前回の回答の一部

テキストファイルとして行ごとに比較することができます

からman diff

NAME
   diff - compare files line by line

   -a, --text
          treat all files as text

   -q, --brief
          report only when files differ

   -y, --side-by-side
          output in two columns

ファイルを比較すると次のようになります。

$ diff -a <(tail -n+15 file1) <(tail -n+15 file2)

次の出力が表示されます:

2905c2905
< Solutions: 0.686669
---
> Solutions: 0.686670
2959c2959
< Solutions: 0.279124
---
> Solutions: 0.279125
3030c3030
< Solutions: 0.539016
---
> Solutions: 0.539017
3068c3068
< Solutions: 0.308278
---
> Solutions: 0.308279

異なるラインを表示します

これが最終コマンドです。最初の 15 行はチェックしないものとします。

$ diff -y -a <(tail -n+15 file1) <(tail -n+15 file2)

すべての違いが 2 つの列に表示されます。違いがあるかどうかだけを知りたい場合は、次のようにします。

$ diff -q -a <(tail -n+15 file1) <(tail -n+15 file2)

ファイルが同じ場合は何も印刷されません

答え3

入力データがどれほど複雑であるかはわかりませんが、awk入力される各行を読み取り、それを既知の値と比較するようなものを使用することもできます。

$ for i in 1 2 3 4 5; do echo $i; sleep 1; done | \
  awk '{print "Out:", $0; fflush(); if ($1==2) exit(0)}'
Out: 1
Out: 2

この場合、私は時間遅延された数値のストリームを入力し、awk入力の最初の変数(のみ変数(ここでは 2)が等しくなると終了し、その際にストリームを停止します。

関連情報