如何比较正在运行的进程的输出?

如何比较正在运行的进程的输出?

我正在运行基准测试gem5模拟器,它在运行时不断将输出打印到终端。我已经将同一基准测试的样本运行存储在文本文件

所以现在我想将打印到控制台的输出流与之前的黄金运行的文本文件进行比较。如果输出与文本文件有差异,则模拟应自动终止。

基准测试需要花费大量时间才能运行。我只对当前运行中的第一个错误感兴趣,这样我就可以节省等待执行完成以比较两个输出的时间。

答案1

我忍不住继续思考,寻找一种合适的方法来比较正在运行的进程(在终端中)针对您提到的“黄金运行”文件。

如何捕获正在运行的进程的输出

我使用了script带选项的命令-f。这会将当前(文本)终端内容写入文件;选项-f是每次写入终端时更新输出文件。脚本命令用于记录终端窗口中发生的所有事情。
下面的脚本会定期导入此输出。

此脚本的作用

如果您在终端窗口中运行该脚本,它将打开第二个终端窗口,该窗口由命令启动script -f。在此(第二个)终端窗口中,您应该运行命令以启动基准测试过程。当此基准测试过程产生其结果时,这些结果会定期(每 2 秒)与您的“黄金运行”进行比较。如果出现差异,则不同的输出将显示在“主”(第一个)终端中,并且脚本终止。出现一行,格式如下:

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

explanation:

error: (<golden_run_result>, <current_differing_output>)

输出此输出后,您可以安全地关闭第二个窗口,运行测试。

如何使用

  • 将下面的脚本复制到一个空文件中。
    当您查看“黄金运行”文件时,第一部分(实际测试开始之前)无关紧要,并且可能因系统而异。因此,您需要定义实际输出开始的行。在您的例子中,我将其设置为:

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

    如果必要的话,进行更改。

  • 设置“golden run”文件的路径。
  • 将脚本另存为compare.py,通过以下命令运行:

    python3 /path/to/compare.py
    

    `

  • 第二个窗口打开,显示Script started, the file is named </path/to/file>
  • 在第二个窗口中,运行基准测试,第一个不同的结果出现在第一个窗口中:

在此处输入图片描述

我如何测试

我创建了一个小程序,逐行打印编辑版的黄金跑分。我让脚本将其与原始“黄金跑分”文件进行比较。

剧本:

#!/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

您可以使用diffutil。

假设你有你的黄金文件,以及其他我改变了。

我没有运行你的程序,所以我写了这个模拟:

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

它读自其他文件(bad_file),每秒逐行输出。

现在运行该脚本,并将其输出重定向到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

此脚本接受两个参数。第一个参数是黄金文件的路径,第二个参数是日志文件的路径。

$ ./checker.sh path_to_golden path_to_log

此检查器计算您当前log文件中的行数,并将其与 中完全相同的行数进行比较golden_file

你每秒运行一次检查器,并在需要时执行 kill 命令

如果你愿意,你可以编写每秒运行一次的 bash 函数checker.sh

$ 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)

它将在两列中显示所有差异。如果您只想知道是否有任何差异,请使用以下命令:

$ 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,然后退出,并以此阻止流。

相关内容