Ich führe einen Benchmark durch aufGem5-Simulator, das während der Ausführung die Ausgabe auf dem Terminal ausgibt. Ich habe bereits einen Probedurchlauf desselben Benchmarks in einemTextdatei.
Jetzt möchte ich den Ausgabestream, der auf der Konsole gedruckt wird, mit der Textdatei des vorherigen Golden Runs vergleichen. Wenn es einen Unterschied zwischen der Ausgabe und der Textdatei gibt, sollte die Simulation automatisch beendet werden.
Der Benchmark benötigt viel Zeit. Mich interessiert nur der erste Fehler im aktuellen Lauf, damit ich die Wartezeit bis zum Abschluss der Ausführung einsparen und beide Ergebnisse vergleichen kann.
Antwort1
Ich konnte nicht widerstehen, noch ein wenig weiter zu rätseln, um einen geeigneten Weg zu finden, die Ausgabe einesLaufender Prozess(im Terminal) gegen eine „Golden Run“-Datei, wie Sie es erwähnen.
So erfassen Sie die Ausgabe des laufenden Prozesses
Ich habe den script
Befehl mit der -f
Option verwendet. Dadurch wird der aktuelle (textuelle) Terminalinhalt in eine Datei geschrieben; die -f
Option besteht darin, die Ausgabedatei bei jedem Schreibvorgang im Terminal zu aktualisieren. Der Skriptbefehl dient dazu, alles aufzuzeichnen, was in einem Terminalfenster geschieht.
Das folgende Skript importiert diese Ausgabe regelmäßig.
Was dieses Skript macht
Wenn Sie das Skript in einem Terminalfenster ausführen, wird ein zweites Terminalfenster geöffnet, das mit dem script -f
Befehl gestartet wird. In diesem (zweiten) Terminalfenster sollten Sie Ihren Befehl ausführen, um den Benchmark-Prozess zu starten. Während dieser Benchmark-Prozess seine Ergebnisse erzeugt, werden diese Ergebnisse regelmäßig (alle 2 Sekunden) mit Ihrem „Golden Run“ verglichen. Wenn ein Unterschied aufgetreten ist, wird die abweichende Ausgabe im „Hauptterminal“ (ersten Terminal) angezeigt und das Skript wird beendet. Es erscheint eine Zeile im Format:
error: ('Solutions: 13.811084', 'Solutions: 13.811084 aap noot mies')
explanation:
error: (<golden_run_result>, <current_differing_output>)
Nach dieser Ausgabe können Sie das zweite Fenster sicher schließen und Ihre Tests ausführen.
Wie benutzt man
Kopieren Sie das folgende Skript in eine leere Datei.
Wenn Sie sich Ihre „Golden Run“-Datei ansehen, ist der erste Abschnitt (vor dem eigentlichen Test) irrelevant und kann auf verschiedenen Systemen unterschiedlich sein. Daher müssen Sie die Zeile definieren, in der die eigentliche Ausgabe beginnt. In Ihrem Fall habe ich sie wie folgt festgelegt:first_line = "**** REAL SIMULATION ****"
ändern Sie es bei Bedarf.
- Legen Sie den Pfad zu Ihrer „Golden Run“-Datei fest.
Speichern Sie das Skript unter und
compare.py
führen Sie es mit dem folgenden Befehl aus:python3 /path/to/compare.py
`
- ein zweites Fenster öffnet sich mit
Script started, the file is named </path/to/file>
- Führen Sie in diesem zweiten Fenster Ihren Benchmarktest durch. Das erste abweichende Ergebnis wird im ersten Fenster angezeigt:
So habe ich getestet
Ich habe ein kleines Programm erstellt, das die Zeilen einer bearbeiteten Version Ihres Golden Runs nacheinander ausgibt. Ich habe das Skript so konfiguriert, dass es sie mit der ursprünglichen „Golden Run“-Datei vergleicht.
Das Skript:
#!/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)
Antwort2
Sie können diff
util verwenden.
Angenommen, Sie habendeingoldene Feile undein andererdass ich mich geändert habe.
Ich habe Ihr Programm nicht ausgeführt, deshalb habe ich diese Simulation geschrieben:
#!/bin/bash
while read -r line; do
echo "$line";
sleep 1;
done < bad_file
Es lautet ausein andererDatei (bad_file) und Ausgabe zeilenweise jede Sekunde.
Führen Sie jetzt dieses Skript aus und leiten Sie seine Ausgabe in log
eine Datei um.
$ simulate > log &
Außerdem habe ich ein Prüfskript geschrieben:
#!/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
Vergessen Sie nicht, es ausführbar zu machen chmod +x checker.sh
.
Dieses Skript benötigt zwei Argumente. Das erste Argument ist der Pfad zu Ihrer Golden-Datei, das zweite Argument der Pfad zu Ihrer Protokolldatei.
$ ./checker.sh path_to_golden path_to_log
Dieser Prüfer zählt die Anzahl der Zeilen, die sich derzeit in Ihrer log
Datei befinden, und vergleicht sie mit der exakt gleichen Anzahl von Zeilen in golden_file
.
Sie führen den Checker jede Sekunde aus und führen bei Bedarf den Kill-Befehl aus
Wenn Sie möchten, können Sie eine Bash-Funktion schreiben, die checker.sh
jede Sekunde ausgeführt wird:
$ chk_every() { while true; do ./checker.sh $1 $2; sleep 1; done; }
Teil der vorherigen Antwort zum Thema Diff
Sie können sie Zeile für Zeile als Textdatei vergleichen
Ausman 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
Wenn wir unsere Dateien vergleichen:
$ diff -a <(tail -n+15 file1) <(tail -n+15 file2)
Wir werden diese Ausgabe sehen:
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
Es zeigt die Linie, die sich unterscheidet
Und hier ist der letzte Befehl. Ich gehe davon aus, dass Sie die ersten 15 Zeilen nicht überprüfen möchten:
$ diff -y -a <(tail -n+15 file1) <(tail -n+15 file2)
Es werden Ihnen alle Unterschiede in zwei Spalten angezeigt. Wenn Sie nur wissen möchten, ob es Unterschiede gibt, verwenden Sie Folgendes:
$ diff -q -a <(tail -n+15 file1) <(tail -n+15 file2)
Es wird nichts gedruckt, wenn die Dateien gleich sind
Antwort3
Ich habe keine Ahnung, wie kompliziert Ihre Eingabedaten sind, aber Sie könnten so etwas verwenden, awk
um jede Zeile beim Eintreffen zu lesen und mit einem bekannten Wert zu vergleichen.
$ 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
In diesem Fall füge ich einen zeitverzögerten Strom von Zahlen ein und dieser awk
läuft, bis die erste Variable in der Eingabe (dienurVariable hier) gleich 2 ist, wird dann beendet und hält dabei den Stream an.