Como comparar a saída de um processo em execução?

5

Estou executando uma avaliação de desempenho no simulador gem5 , que mantém a impressão no terminal durante a execução. Eu já armazenei uma amostra do mesmo benchmark em um arquivo de texto .

Agora, quero comparar o fluxo de saída que está sendo impresso no console com o arquivo de texto da execução anterior. Se houver uma diferença na saída em comparação com o arquivo de texto, a simulação deverá ser finalizada automaticamente.

O benchmark leva muito tempo para ser executado. Estou interessado apenas no primeiro erro na execução atual, para que eu possa economizar tempo de espera até a execução ser concluída para comparar as duas saídas.

    
por Insanely curious 28.10.2014 / 08:59

3 respostas

3

Eu não pude resistir a confundir um pouco mais sobre encontrar uma maneira adequada de comparar a saída de um proces em execução (no terminal) contra um arquivo "golden run", como você mencionou.

Como capturar a saída do processo em execução

Eu usei o comando script com a opção -f . Isso grava o conteúdo do terminal atual (textual) em um arquivo; a opção -f é atualizar o arquivo de saída em cada evento de gravação para o terminal. O comando de script é feito para manter registro de tudo o que acontece em uma janela de terminal.
O script abaixo importa essa saída periodicamente.

O que esse script faz

Se você executar o script em uma janela de terminal, ele abrirá uma segunda janela de terminal, iniciada com o comando script -f . Nesta (segunda) janela de terminal, você deve executar o seu comando para iniciar o processo de benchmark. Embora esse processo de benchmark produza seus resultados, esses resultados são periodicamente (a cada 2 segundos) em comparação com a sua "corrida de ouro". Se uma diferença ocorreu, a saída diferente é exibida no terminal "principal" (primeiro) e o script é encerrado. Uma linha aparece no formato:

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

explanation:

error: (<golden_run_result>, <current_differing_output>)

Após essa saída, você pode fechar com segurança a segunda janela, executando seus testes.

Como usar

  • Copie o script abaixo em um arquivo vazio.
    Quando você olha para o arquivo "golden run", a primeira seção (antes do início do teste real) é irrelevante e pode ser diferente em sistemas diferentes. Portanto, você precisa definir a linha onde a saída real começa. No seu caso eu configurei para:

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

    altere se necessário.

  • Defina o caminho para o seu arquivo "golden run".
  • Salve o script como compare.py , execute-o pelo comando:

    python3 /path/to/compare.py
    

    '

  • uma segunda janela é aberta, dizendo Script started, the file is named </path/to/file>
  • nesta segunda janela, execute seu teste de benchmark, o primeiro resultado diferente aparece na primeira janela:

Comotestei

Eucrieiumpequenoprogramaqueimprimeaslinhasdeumaversãoeditadadesuacorridadeouro,umaporuma.Eufizoscriptcompará-loaoarquivo"golden run" original.

O script:

#!/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)
    
por Jacob Vlijm 30.10.2014 / 13:33
3

Você pode usar diff util.

Suponha que você tenha o seu arquivo dourado, e outro que eu mudei.

Não tenho o seu programa em execução, por isso escrevi esta simulação:

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

Ele lê um outro arquivo (bad_file), e sai linha por linha a cada segundo.

Agora, execute este script e redirecione-o para log file.

$ simulate > log &

Também escrevi um script de verificação:

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

Não se esqueça de torná-lo executável chmod +x checker.sh .

Este script leva dois argumentos. O primeiro argumento é o caminho para o arquivo dourado, segundo caminho de argumento para o seu arquivo de log.

$ ./checker.sh path_to_golden path_to_log

Este número de linhas de contagem de verificador você tem agora no seu arquivo log , e compare com exatamente o mesmo número de linhas em golden_file .

Você executa o verificador a cada segundo e executa o comando kill se necessário

Se você quiser, pode escrever a função bash para executar checker.sh a cada segundo:

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

Parte da resposta anterior sobre diff

Você pode compará-los linha por linha como arquivo de texto

De 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

Se compararmos nossos arquivos:

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

Veremos esta saída:

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

Mostra a linha que difere

E aqui está o comando final, supondo que você não queira verificar as primeiras 15 linhas:

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

Ele mostrará todas as diferenças em duas colunas. Se você só quer saber se existe alguma diferença use isto:

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

Não imprimirá nada se os arquivos forem os mesmos

    
por c0rp 28.10.2014 / 09:44
0

Não tenho ideia de quão complicados são os dados de entrada, mas você pode usar algo como awk para ler cada linha à medida que ela entra e compará-la a um valor conhecido.

$ 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

Neste caso, estou alimentando um fluxo de números com atraso de tempo e awk está sendo executado até que a primeira variável na entrada (a variável somente aqui) seja igual a 2, depois saia e ao fazê-lo, prende o fluxo.

    
por Oli 28.10.2014 / 09:15