Hallo zusammen, bislang war ich immer davon ausgegangen, daß eine Verkettung von Befehlen mehr Zeit in Anspruch nimmt, als wenn ich gleich alles von einem Befehl erledigen lasse. Beispiel: time grep delay= /var/log/mail | sed -e 's_.*\(delay[^,]*,\).*_\1_g' [Ausgabe] real 0m0.239s user 0m0.228s sys 0m0.010s Aber: time sed -n -e '/delay=/s/.*\(delay[^,]*,\).*/\1/gp' /var/log/mail [Ausgabe] real 0m0.405s user 0m0.402s sys 0m0.002s Warum braucht sed... bei real und user fast doppelt so lange als grep... | sed...? Danke+Gruß! -- Andre Tann -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
Warum braucht sed... bei real und user fast doppelt so lange als grep... | sed...?
Weil das Verarbeiten von Regexps prinzipiell eine langsamere Angelegenheit ist. Das grep-Kommando ist speziell dafür optimiert, einzelne Zeilen rauszusuchen, sed hingegen muss alles interpretieren.
Marko Käning, Dienstag 19 Oktober 2010:
Weil das Verarbeiten von Regexps prinzipiell eine langsamere Angelegenheit ist. Das grep-Kommando ist speziell dafür optimiert, einzelne Zeilen rauszusuchen, sed hingegen muss alles interpretieren.
Das würde bedeuten, daß die an sich weniger eleganten Ketten grep | sed | awk... durchaus ihre Berechtigung haben. Der Preis für den Aufruf der Programme scheint niedriger zu sein als der Vorteil, den man durch die Spezialisierung wieder rausholt. # bash -c "time awk '/delay=/ {print}' /var/log/mail > /dev/null" real 0m0.254s user 0m0.252s sys 0m0.002s # bash -c "time sed '/delay=/p' /var/log/mail > /dev/null" real 0m0.225s user 0m0.225s sys 0m0.000s # bash -c "time grep delay= /var/log/mail > /dev/null" real 0m0.017s user 0m0.013s sys 0m0.005s awk ist am langsamsten, grep mit großem Abstand am schnellsten, bei gleicher Aufgabe. Und nochwas: # time grep relay= /var/log/mail | grep delay= > /dev/null real 0m0.021s user 0m0.007s sys 0m0.014s # time grep relay=.*delay= /var/log/mail > /dev/null real 0m0.030s user 0m0.027s sys 0m0.002s Die Verarbeitung des .* ist offenbar auch erheblich teurer, als die grep | grep-Kette. Wieder was gelernt... Danke+Gruß! -- Andre Tann -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
Hallo Andre, On Tuesday 19 October 2010 12:00:14 Andre Tann wrote:
# bash -c "time awk '/delay=/ {print}' /var/log/mail > /dev/null"
Ok, nur awk.
# bash -c "time sed -n '/delay=/ p' /var/log/mail > /dev/null"
Ok, nur sed.
# bash -c "time grep delay= /var/log/mail > /dev/null"
Ok, nur grep.
# time grep relay= /var/log/mail | grep delay= > /dev/null
Achtung. Hier misst du wieder nur das erste grep. Richtig waere # time bash -c "grep relay= /var/log/mail | grep delay=" > /dev/null oder # time grep relay= /var/log/mail | time grep delay= > /dev/null waeren richtig.
# time grep relay=.*delay= /var/log/mail > /dev/null
Und hier faiererweise evt. mit der Bash: # time bash -c "grep 'relay=.*delay=' /var/log/mail" > /dev/null # time grep relay=.*delay= /var/log/mail > /dev/null Und wieder meine Ergebnisse: real 0.23 user 0.05 sys 0.01 real 0.25 user 0.15 sys 0.07 und real 0.45 user 0.39 sys 0.04 Also ca. 0.2 zu 0.4. En letzter Hinweis. Wenn du '*' in der Regexp hast, immer escapen. Falls beim Aufruf von # time grep relay=.*delay= /var/log/mail > /dev/null Zufaellig ein File im aktuellen Directory mit dem Namen "relay=.1234delay=", oder eben irgend etwas anderes als "1234" existiert, koenntest du Probleme bekommen. Roman -- Roman Fietze Telemotive AG Buero Muehlhausen Breitwiesen 73347 Muehlhausen Tel.: +49(0)7335/18493-45 http://www.telemotive.de -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
Roman Fietze, Dienstag 19 Oktober 2010:
# time grep relay= /var/log/mail | grep delay= > /dev/null
Achtung. Hier misst du wieder nur das erste grep. Richtig waere
Ja, Mist, da hast Du recht (auch bei Deiner Mail nebenan...).
Und wieder meine Ergebnisse:
real 0.23 user 0.05 sys 0.01 real 0.25 user 0.15 sys 0.07
und
real 0.45 user 0.39 sys 0.04
Also ca. 0.2 zu 0.4.
Wie kommst Du auf diese Zahlen? Wenn man real+user rechnet, dann hast Du 0,68 bei grep|grep und 0,84 bei grep. Da wäre also das einfach grep um etwa 1/4 langsamer.
En letzter Hinweis. Wenn du '*' in der Regexp hast, immer escapen.
Ja, das ist klar. Weniger klar ist mir dagegen, wie ich richtig escape: grep "blabla*" # das geht grep 'blabla*' # das geht auch Aber: bash -c "grep "blabla*"" bash -c "grep 'blabla*'" bash -c 'grep "blabla*"' Was wäre hier richtig, und warum? -- Andre Tann -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
Andre Tann wrote: [...]
Ja, das ist klar. Weniger klar ist mir dagegen, wie ich richtig escape:
grep "blabla*" # das geht grep 'blabla*' # das geht auch
oder: grep blabal\*
Aber:
bash -c "grep "blabla*"" bash -c "grep 'blabla*'" bash -c 'grep "blabla*"'
Was wäre hier richtig, und warum?
Du musst dir vor Augen führen, welches Kommando was an Informationen erhält ;-) Welche Shell expandiert/interpretiert was? Hier mal was zum Nachdenken: --- cut here --- linux:~> ROOT="root" linux:~> touch root123 # nur " linux:~> bash -cx "grep "root*" /etc/passwd" + grep root123 /etc/passwd #"''" linux:~> bash -cx "grep 'root*' /etc/passwd" + grep 'root*' /etc/passwd root:x:0:0:root:/root:/bin/bash #'""' linux:~> bash -cx 'grep "root*" /etc/passwd' + grep 'root*' /etc/passwd root:x:0:0:root:/root:/bin/bash #mit Variablen: nur " linux:~> bash -cx "grep "$ROOT*" /etc/passwd" + grep root123 /etc/passwd #mit Variablen: nur "''" linux:~> bash -cx "grep '$ROOT*' /etc/passwd" + grep 'root*' /etc/passwd #mit Variablen: nur '""' root:x:0:0:root:/root:/bin/bash linux:~> bash -cx 'grep "$ROOT*" /etc/passwd' + grep '*' /etc/passwd --- cut here --- Andreas -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
Kyek, Andreas, VF-DE wrote:
Andre Tann wrote: [...]
Ja, das ist klar. Weniger klar ist mir dagegen, wie ich richtig escape:
grep "blabla*" # das geht grep 'blabla*' # das geht auch
oder: grep blabal\*
Aber:
bash -c "grep "blabla*"" bash -c "grep 'blabla*'" bash -c 'grep "blabla*"'
Was wäre hier richtig, und warum?
Du musst dir vor Augen führen, welches Kommando was an Informationen erhält ;-) Welche Shell expandiert/interpretiert was?
Hier mal was zum Nachdenken:
--- cut here --- linux:~> ROOT="root" linux:~> touch root123
# nur " linux:~> bash -cx "grep "root*" /etc/passwd" + grep root123 /etc/passwd
#"''" linux:~> bash -cx "grep 'root*' /etc/passwd" + grep 'root*' /etc/passwd root:x:0:0:root:/root:/bin/bash
#'""' linux:~> bash -cx 'grep "root*" /etc/passwd' + grep 'root*' /etc/passwd root:x:0:0:root:/root:/bin/bash
#mit Variablen: nur " linux:~> bash -cx "grep "$ROOT*" /etc/passwd" + grep root123 /etc/passwd
#mit Variablen: nur "''" linux:~> bash -cx "grep '$ROOT*' /etc/passwd" + grep 'root*' /etc/passwd
#mit Variablen: nur '""' root:x:0:0:root:/root:/bin/bash
Sorry, die Zeile verrutscht! Das ist die Ausgabe es Kommandos darüber!
linux:~> bash -cx 'grep "$ROOT*" /etc/passwd' + grep '*' /etc/passwd --- cut here ---
Andreas -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
Hallo Andre, On Tuesday 19 October 2010 13:06:53 Andre Tann wrote:
Wie kommst Du auf diese Zahlen?
Durch einen fehler meinerseits. Ich habe erst mit /var/log/mail gemessen, dann gerechnet, und dann Alles bis auf das Gesamtergebnis mit meinem zusammengebastelten mail um groessere Zeitwerte zu erhalten.
grep "blabla*" # das geht grep 'blabla*' # das geht auch
Zwischen beiden besteht nur der Unterschied, dass du im oberen Fall z.B. noch Environmentvariablen nutzen udn aufloesen koenntest.
bash -c "grep "blabla*""
Eher bash -c "grep \"blabla*\""
bash -c "grep 'blabla*'"
Das ist gut.
bash -c 'grep "blabla*"'
Das auch.
Was wäre hier richtig, und warum?
Die bash mit der du die zweite bash startest interpretiert erst einmal alle Parameter. Dabei wirft sie quasi die aeusserste Schale an Hochkommas weg. Was ueberig bleibt ist ein String. Also z.B. ((inklsuive der Hochkommas die noch ueberig bleiben!!!): 'blabla*' # Fall 2 "blabla*" # Fall 1 und Fall 3 korrigiert Dann geht die zweit Bash ans Parsen, wirft wieder die Hochkommas weg, interpretiert aber Alles was darin war, oder zumindest die Shell Wildcards, nicht. Roman -- Roman Fietze Telemotive AG Buero Muehlhausen Breitwiesen 73347 Muehlhausen Tel.: +49(0)7335/18493-45 http://www.telemotive.de -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
Hallo, Am Die, 19 Okt 2010, Roman Fietze schrieb:
On Tuesday 19 October 2010 13:06:53 Andre Tann wrote:
grep "blabla*" # das geht grep 'blabla*' # das geht auch
Zwischen beiden besteht nur der Unterschied, dass du im oberen Fall z.B. noch Environmentvariablen nutzen udn aufloesen koenntest.
*Mööp* Bei ersterem werden auch nicht-Environment-Variabeln expandiert. Und ausserdem werden innerhalb von "" auch `` und $(), $[] $(( )) expandiert. Innerhalb von '' wird nix expandiert: $ echo "foo $SHELL $[1+2] $((1 + 3)) $(uname -r) `uname -m`" foo /bin/bash 3 4 2.4.37.5 i686 $ echo 'foo $SHELL $[1+2] $((1 + 3)) $(uname -r) `uname -m`' foo $SHELL $[1+2] $((1 + 3)) $(uname -r) `uname -m` Wie immer: set -x hilft sowas nachzuvollziehen (bzw. bash -x / sh -x / ksh -x / ...) $ echo 'foo $SHELL $[1+2] $((1 + 3)) $(uname -r) `uname -m`' + echo 'foo $SHELL $[1+2] $((1 + 3)) $(uname -r) `uname -m`' foo $SHELL $[1+2] $((1 + 3)) $(uname -r) `uname -m` $ echo "foo $SHELL $[1+2] $((1 + 3)) $(uname -r) `uname -m`" ++ uname -r ++ uname -m + echo 'foo /bin/bash 3 4 2.4.37.5 i686' foo /bin/bash 3 4 2.4.37.5 i686 Wildcards/Globbing ('~', '?' und '*') wird innerhalb von "" hingegen nicht ausgeführt, allerdings muß man da innerhalb von `` bzw. $() aufpassen, wann da was noch expandiert wird. Zum Testen z.B. das hier verwenden und in allen Varianten von mit/ohne "" innen/aussen und `` vs. $() mal durchtesten! Mit gesetztem 'set -x'. Und nach nem 'cd ~'. $ echo `echo ~/.bash*history | cat` $ echo `echo .bash*history | cat` (bin mir grad nicht sicher, ob/wann das ~ evtl. anders als ? und * expandiert wird). HTH, -dnh -- Ah, the curse of having old files lying around collecting dust. That file has been sitting on the system for about a decade. Never caused any trouble before now, probably because the teTeX supplied file won out in the kpathsea lottery. -- Harald Hanche-Olsen on the tetex-ML -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
On Tue, October 19, 2010 12:40 pm, Roman Fietze wrote:
On Tuesday 19 October 2010 12:00:14 Andre Tann wrote:
# bash -c "time awk '/delay=/ {print}' /var/log/mail > /dev/null"
Ok, nur awk.
# bash -c "time sed -n '/delay=/ p' /var/log/mail > /dev/null"
Ok, nur sed.
# bash -c "time grep delay= /var/log/mail > /dev/null"
Ok, nur grep.
# time grep relay= /var/log/mail | grep delay= > /dev/null
Achtung. Hier misst du wieder nur das erste grep. Richtig waere
Nein, zumindest das builtin der Bash misst die komplette Zeit: #v+ ~§ time echo 1 | { sleep 10; cat; } 1 real 0m10.007s user 0m0.000s sys 0m0.000s #v- Das binary in time in /usr/bin dagegen verhält sich so wie du sagst.
# time bash -c "grep relay= /var/log/mail | grep delay=" > /dev/null
Würde mich nicht wundern, wenn der Aufruf von bash das Ergebnis verfälschen würde.
En letzter Hinweis. Wenn du '*' in der Regexp hast, immer escapen.
Oder in Anführungszeichen setzen. Das finde ich persönlich logischer. Grüße, Christian -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
Hallo Christian, On Tuesday 19 October 2010 13:20:39 Christian Brabandt wrote:
Nein, zumindest das builtin der Bash misst die komplette Zeit ...
Steht auch so in der man page von bash ... nur hatte ich die Stelle wohl bisher immer ueberlesen. Danke Roman -- Roman Fietze Telemotive AG Buero Muehlhausen Breitwiesen 73347 Muehlhausen Tel.: +49(0)7335/18493-45 http://www.telemotive.de -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
Hallo, Am Die, 19 Okt 2010, Andre Tann schrieb:
Marko Käning, Dienstag 19 Oktober 2010:
Weil das Verarbeiten von Regexps prinzipiell eine langsamere Angelegenheit ist. Das grep-Kommando ist speziell dafür optimiert, einzelne Zeilen rauszusuchen, sed hingegen muss alles interpretieren.
Das würde bedeuten, daß die an sich weniger eleganten Ketten grep | sed | awk... durchaus ihre Berechtigung haben. Der Preis für den Aufruf der Programme scheint niedriger zu sein als der Vorteil, den man durch die Spezialisierung wieder rausholt.
Nein. Du mißt Mist.
# bash -c "time awk '/delay=/ {print}' /var/log/mail > /dev/null" real 0m0.254s [..]
# bash -c "time sed '/delay=/p' /var/log/mail > /dev/null" real 0m0.225s [..]
# bash -c "time grep delay= /var/log/mail > /dev/null" real 0m0.017s [..]
Alles < 1s Gesamtlaufzeit hat kaum mehr Aussagekraft als wenn du die Laufzeiten von deinem Kater auswürfeln läßt. Und dann ist da noch der Einfluß vom Plattencache! Sinnvoll wird's IMHO ab 5s Laufzeit. Kurzum: deine Aufgabe ist zu klein. $ ls -lh /var/log/mail -rw-r----- 1 root root 1.7M Oct 19 12:22 /var/log/mail # chgrp dh /var/log/mail $ { for i in 1 2 3 4 5; do time cat /var/log/mail >/dev/null; d ; } 2>&1 | grep real real 0m0.028s real 0m0.016s real 0m0.039s real 0m0.028s real 0m0.025s [NB: da war die Datei (und cat) schon im Cache] $ loops=$(seq 100); $ { time for i in $loops ; do grep 'relay=' /var/log/mail | \ grep 'delay=' >/dev/null; done; } 2>&1 | grep real real 0m6.501s $ { time for i in $loops ; do fgrep 'relay=' /var/log/mail | \ fgrep 'delay=' >/dev/null; done; } 2>&1 | grep real real 0m6.459s $ { time for i in $loops ; do grep 'relay=' /var/log/mail | \ sed -n '/delay=/p' >/dev/null; done; } 2>&1 | grep real real 0m25.182s $ { time for i in $loops ; do sed -n '/relay=.*delay=/p' \ /var/log/mail >/dev/null; done; } 2>&1 | grep real real 0m46.968s $ { time for i in $loops ; do sed -n '/relay=/{/delay=/p;}' \ /var/log/mail >/dev/null; done; } 2>&1 | grep real real 1m5.630s Hm, das wundert mich jetzt. Kann aber auch an meinem uralt-sed liegen. $ { time for i in $loops ; do awk '/relay=/{ if(/delay=/){ print;}}' \ /var/log/mail >/dev/null; done; } 2>&1 | grep real real 0m11.321s Das wieder nicht. Aber jetzt wird's erst interessant. Man will ja anscheinend nicht nur die ganze Zeile, sondern nur das "delay". Bei mir im Log sieht das eh anders aus, da steht das delay ne Zeile später als das relay. Machen's wir also anders, und pfriemeln das relay aus der Zeile: $ loops=$(seq 25) $ { time for i in $loops ; do fgrep 'relay=' /var/log/mail | \ sed s/.*relay=\([^,]*\).*/\1/p' > /dev/null; done; } 2>&1 | grep real real 0m11.415s $ { time for i in $loops ; do grep 'relay=' /var/log/mail | \ sed s/.*relay=\([^,]*\).*/\1/p' > /dev/null; done; } 2>&1 | grep real real 0m11.507s [BTW: die 2 Werte schwanken recht stark, hab bei beiden auch >14s gehabt] $ { time for i in $loops ; do sed -n '/relay=/s/.*relay=\([^,]*\).*/\' \ /var/log/mail > /dev/null; done; } 2>&1 | grep real real 0m20.074s Hm, mein sed scheint echt ne 'matching-Schwäche' zu haben ... $ { time for i in $loops; do awk '/relay=/{ \ print gensub(/.*relay([^,]*).*/,"\\1","g"); }' /var/log/mail >/dev/null ; done; } 2>&1 | grep real real 0m14.173s Wobei das mit dem 'gensub' nicht die ideale Lösung ist, aber das '\1' korrekt zu übergeben ist auf der Kommandozeile arg mühsam. Ein awk-Script vereinfacht da dann vieles. $ export loops; $ { time perl -e ' foreach(split("\n",$ENV{loops})) { open(L, "<", $ARGV[0]) or die "$!\n"; while(<L>) { m/relay=/ and s/.*relay=([^,]*).*/$1/ and print; } close(L) or die "$!\n" }' /var/log/mail >/dev/null; } 2>&1 | grep real real 0m6.781s Ei, gugg emoll dooo! :-P (und ohne denn Looping säh's noch einfacher aus, z.B: perl -ne 'm/relay=/ and s/.*relay=([^,]*).*/$1/ and print;' *.log (dann macht perl das über-die-Dateien-iterieren selber ;) B::Deparse macht daraus übrigens: perl -e 'while (defined($_ = <ARGV>)) { print $_ if /relay=/ and s/.*relay=([^,]*).*/$1/; }' *.log Wie immer: "Know thy tools!" Daß sed beim pattern-matching echt so lahm ist, ist mir neu (und ich hab jetzt nur mit dem ollen hier getestet). $ bash --version GNU bash, version 2.03.0(1)-release (i386-suse-linux) $ grep --version grep (GNU grep) 2.2 $ sed --version GNU sed version 3.02 $ awk --version GNU Awk 3.0.4 $ perl --version This is perl, v5.10.0 built for i686-linux-thread-multi-64int-ld Ist insofern ein bissl unfair ggü. den ollen GNU tools ;) Ah, läuft doch (ohne Verrenkungen) im zu grep/sed/awk passend alten perl: { time perl5.00503 -e ' foreach(split("\n",$ENV{loops})) { open(L, "<$ARGV[0]") or die "$!\n"; while(<L>) { m/relay=/ and s/.*relay=([^,]*).*/$1/ and print; } close(L) or die "$!\n" }' /var/log/mail >/dev/null; } real 0m10.564s $ perl5.00503 --version This is perl, version 5.005_03 built for i586-linux Und ebenfalls wie immer: manchmal (also wenn die Gesamtlaufzeit eines Scriptes relevant wird) muß man eben selber am konkreten Fall testen (und zwar wenn irgend möglich mit realen Daten!!!). Und wie ich "Scripte" kenne, bleibt es eben *nicht* beim simplen grep | sed 's/a/b/' Sondern man macht noch mehr. Und dann landet man recht schnell an dem Punkt, wo man besser gleich alles in sed/awk/perl (in der Reihenfolge) macht ;) (bei perl dann gern auch gleich mal das 'find ...' per File::Find, wobei einem das nette Tool 'find2perl' auch noch hilft ;) HTH, -dnh -- So Linus, what are we doing tonight? The same thing we do every night Tux. Try to take over the world! -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
David Haller, Dienstag 19 Oktober 2010:
Alles < 1s Gesamtlaufzeit hat kaum mehr Aussagekraft als wenn du die Laufzeiten von deinem Kater auswürfeln läßt.
Hey, was hast Du gegen meinen Kater?
# chgrp dh /var/log/mail $ { for i in 1 2 3 4 5; do time cat /var/log/mail >/dev/null; d ; } 2>&1 | grep real real 0m0.028s real 0m0.016s real 0m0.039s real 0m0.028s real 0m0.025s
Also schauen wir mal: # for x in 1 2 3 4 5; do time sed -n -e '/delay=/s/.*\(delay[^,]*,\).*/\1/gp' \ /var/log/mail > /dev/null; done 2>&1 | grep real real 0m0.495s real 0m0.480s real 0m0.487s real 0m0.479s real 0m0.490s Also so gut kriegt es mein Kater nicht hin.
$ { time for i in $loops; do awk '/relay=/{ \ print gensub(/.*relay([^,]*).*/,"\\1","g"); }' /var/log/mail >/dev/null ; done; } 2>&1 | grep real real 0m14.173s
gensub... wieder was gelernt.
Wie immer: "Know thy tools!"
Ja, stimmt wohl. Mit perl hab ichs halt noch nicht so.
HTH,
Tut es. Danke+Gruß! -- Andre Tann -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
Hallo, Am Die, 19 Okt 2010, Andre Tann schrieb:
David Haller, Dienstag 19 Oktober 2010:
Alles < 1s Gesamtlaufzeit hat kaum mehr Aussagekraft als wenn du die Laufzeiten von deinem Kater auswürfeln läßt.
Hey, was hast Du gegen meinen Kater?
Garnix. Im Gegenteil, ich liebe alle felidae :) Einer meiner IRC-Nicks ist "Amba"[1] ;) Laß ihn halt einmal über deinen Nummernblock latschen und nimm das Ergebnis als Nachkommastellen ;)
# chgrp dh /var/log/mail $ { for i in 1 2 3 4 5; do time cat /var/log/mail >/dev/null; d ; } 2>&1 | grep real real 0m0.028s real 0m0.016s real 0m0.039s real 0m0.028s real 0m0.025s
Also schauen wir mal:
# for x in 1 2 3 4 5; do time sed -n -e '/delay=/s/.*\(delay[^,]*,\).*/\1/gp' \ /var/log/mail > /dev/null; done 2>&1 | grep real
real 0m0.495s real 0m0.480s real 0m0.487s real 0m0.479s real 0m0.490s
Also so gut kriegt es mein Kater nicht hin.
Da machst du allerdings auch was, mir ging's oben darum, wie sehr allein das IO aus dem Cache(!) variieren kann ... (und aus solchen Unterschieden leiten andere eben "Aussagen" her). Hat also immer noch keine Aussagekraft. Ok, für nen ersten Verdacht mag sowas reichen. Und bedenke: meine Kiste ist 10 Jahre alt, auf deiner Kiste "sollten" die Schwankungen rein theoretisch viel geringer sein. Du bekommst aber trotzdem 16ms Abweichung. Und was, wenn jetzt z.B. die awk-Variante zw. 0.485s und 0.512s variiert? Wie gesagt: deine "Aufgabe" ist zu gering um aussagekräftige Daten zu bekommen. Für einen sinnvollen Benchmark müßtest du mit 'init=/bin/bash' booten und dann direkt dein Script laufen lassen. Denn beim booten werden grep und sed und (AFAIR) auch perl aufgerufen, sollten also schon im Plattencache sein. Awk wird AFAIK nicht verwendet. Oder eben, du sorgst wie ich für eine "neutrale" Umgebung (Programme + Daten komplett im RAM) und obendrein dafür, daß die Ausführung lange genug dauert. Die Nachkommastellen der Laufzeit kannst du prinzipiell "wegwerfen". Es gibt einfach zu viel Einflüsse (z.B. vom Prozess- und IO-Scheduler). Und auf Mehrkern-Kisten muß man natürlich auch beachten, auf wievielen Kernen das läuft und Kernwechsel müßte man ggfs. ausschließen (taskset?) bzw. explizit das eine auf einem, und das andere auf dem anderen Kern laufen lassen (BTW: ein grep | sed, das auf zwei Kernen läuft sollte da dann wirklich relevant schneller sein, solange es nicht eh am IO hängt ;) Es kommt also sehr darauf an, wie oft / wann dein Script aufgerufen wird, ob dann die Programme (grep, sed, awk, perl) schon im RAM sind oder nicht, ob die Daten schon im RAM sind, ob's auf zwei oder mehr Kernen laufen kann, und und und ... Beispiel: 44MiB Datei (nicht im Cache): $ time dd if=foo of=/dev/null 90102+1 records in 90102+1 records out real 0m2.607s [ist jetzt im Cache] $ time dd if=foo of=/dev/null 90102+1 records in 90102+1 records out real 0m0.573s Bei perl wird's übrigens noch komplexer, da muß man berücksichtigen, ob Module geladen werden (das finden und laden dieser, ggfs. aus mehreren Dateien bestehenden, kann durchaus relevant Zeit kosten, weil die Dateien erstmal gesucht und geladen werden müssen). Vgl. z.B.: time perl -e '1;' time perl -MDate::Parse -e '1;' time perl -MDate::Manip -e '1;' time perl -MMIME::Parser -e '1;' (jew. mehrfach aufgerufen ;) Generell kann man dennoch davon ausgehen, daß es sich im Normalfall lohnt Module in perl zu verwenden ;)
$ { time for i in $loops; do awk '/relay=/{ \ print gensub(/.*relay([^,]*).*/,"\\1","g"); }' /var/log/mail >/dev/null ; done; } 2>&1 | grep real real 0m14.173s
gensub... wieder was gelernt.
'man awk' hilft ;) Und natürlich 'sed & awk' von O'Reilly :) Ich mag awk. Und sed. Und perl. Und grep. Und bash. Ganz individuell je nachdem was ich machen will :)
Wie immer: "Know thy tools!"
Ja, stimmt wohl. Mit perl hab ichs halt noch nicht so.
Meine Faustregel: ab 3-5 Programmen, die ich aufrufen muß, *kann* sich ein einmaliger Aufruf von perl "lohnen" ... Was mich nicht daran hindert dennnoch bash- (oder auch awk-) Scripte mit ggfs. dutzenden Aufrufen externer Programme zu haben. Aber wenn ich sowas wie grep ... | sed ... | sed ... | grep ... | sed ... sehe wird mir einfach nur schlecht. Beim 'dynip'-Benchmark (Script gibt's per PM ;) gab's sogar Varianten mit perl hinter ner grep/sed Orgie ... Jedenfalls mag ich prinzipiell die "natürlichsprachliche" Art von perl und daß man fast alles auf viele Arten hinschreiben kann. Für manche ist das der Horror, für mich ist das die Möglichkeit, die am besten _lesbare_ Version hinzuschreiben ;) if ( $foo && $bar ) { machwas(); } machwas() if ( $foo && $bar ); $foo && $bar and machwas(); [...] machwas() unless ! $foo && ! $bar ; Je nach Situation (was $foo und $bar und machwas() jew. sind) kann das ein oder andere "einfacher"/"logischer" in den Ablauf passen ;) Ich selber ziehe "prinzipiell" den expliziten Stil samt aller (ggfs. redundanten) Klammern (s. erstes Beispiel) vor, verwende aber durchaus gern auch die anderen Möglichkeiten, wenn die "irgendwie" besser passen / lesbarer sind ;) Und ja, diese Freiheiten bei der Formulierung können auch mißbraucht werden, bei "perlgolf" zum Spaß, aus Unwissenheit zum Gruseln aller anderen. Die Verantwortung liegt aber _immer_ beim Programmierer. Und _das_ finde ich wiederum gut so. Beispiel: $max = [$a => $b] -> [ $a <= $b ]; ## Simon Cozens Das nachzuvollziehen macht Spaß :) Achso, ggfs. nimmt man eine performantere Variante, dokumentiert aber eine besser lesbare als Kommentar ... BTST.
HTH, Tut es.
So soll's sein :) -dnh, jep, echte Zufallssig :) [1] vgl. Panthera tigris altaica[2] [2] http://de.wikipedia.org/wiki/Sibirischer_Tiger und v.a. http://en.wikipedia.org/wiki/Siberian_tiger#History ;) -- If you hack enough tentacles off perl, there will be nothing left. Other languages have tentacles; perl _is_ tentacles. -- Richard Bos -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
Hallo Andre, On Tuesday 19 October 2010 10:58:33 Andre Tann wrote:
time grep delay= /var/log/mail | sed -e 's_.*\(delay[^,]*,\).*_\1_g'
Kann es sein, dass du hier nur die Zeit von grep, aber nicht die von sed mitmisst. Denn es gilt wieder der alte Spruch: "wer misst misst Mist, wer viel misst misst viel Mist". ;) time bash -c "grep delay= /var/log/mail | sed -e 's_.*\(delay[^,]*,\).*_\1_g'" Zudem wuerde ich die Ausgabe zum Testen der Laufzweit lieber erst mal nach /dev/null oder wenigstens eine Datei umleiten. Roman -- Roman Fietze Telemotive AG Buero Muehlhausen Breitwiesen 73347 Muehlhausen Tel.: +49(0)7335/18493-45 http://www.telemotive.de -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
Servus Roman, Roman Fietze, Dienstag 19 Oktober 2010:
Kann es sein, dass du hier nur die Zeit von grep, aber nicht die von sed mitmisst.
Denn es gilt wieder der alte Spruch: "wer misst misst Mist, wer viel misst misst viel Mist". ;)
time bash -c "grep delay= /var/log/mail | sed -e 's_.*\(delay[^,]*,\).*_\1_g'"
Zudem wuerde ich die Ausgabe zum Testen der Laufzweit lieber erst mal nach /dev/null oder wenigstens eine Datei umleiten.
# bash -c "time \ sed -n -e '/delay=/s/.*\(delay[^,]*,\).*/\1/gp' /var/log/mail > /dev/null" real 0m0.431s user 0m0.427s sys 0m0.004s # bash -c "time grep delay= /var/log/mail | \ sed -e 's_.*\(delay[^,]*,\).*_\1_g' > /dev/null" real 0m0.242s user 0m0.243s sys 0m0.005s Sieht aus, wie wenn der gemessene Mist zumindest nicht allzu groß war ;) -- Andre Tann -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
Hallo Andre, On Tuesday 19 October 2010 11:49:27 Andre Tann wrote:
# bash -c "time \ sed -n -e '/delay=/s/.*\(delay[^,]*,\).*/\1/gp' /var/log/mail > /dev/null"
Hier misst du die Zeit von sed. Ok. Die extra Bash ist hierbei inert und unnoetig.
# bash -c "time grep delay= /var/log/mail | \ sed -e 's_.*\(delay[^,]*,\).*_\1_g' > /dev/null"
Hier misst du wieder nur die Zeit von grep. Das "time" muss vor die Bash. Meine Resultate sind (ich habe mir aus allen alten komprimierten mail logs mal ein sehr grosses File zusammengebastelt): # time -p grep delay= /var/log/mail | time -p sed -e 's_.*\(delay[^,]*, \).*_\1_g' > /dev/null real 4.39 user 4.19 sys 0.00 real 4.39 user 4.23 sys 0.02 # time -p sed -n -e '/delay=/ s/.*\(delay[^,]*,\).*/\1/gp' /var/log/mail > /dev/null real 5.79 user 5.74 sys 0.03 Real ist etwas irrelevant, da einer der beiden evt. auf den anderen warten muss. Addiere ich die beiden user-Zeiten zusammen, so komme ich auf 4.4 (Pipe) zu 5.7 (sed alleine). Die Pipe ist bei mir schneller fertig, aber nur weil ich zwei Cores habe. Mache ich jetzt was falsch? Ich glaube nicht. Roman -- Roman Fietze Telemotive AG Buero Muehlhausen Breitwiesen 73347 Muehlhausen Tel.: +49(0)7335/18493-45 http://www.telemotive.de -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
participants (6)
-
Andre Tann
-
Christian Brabandt
-
David Haller
-
Kyek, Andreas, VF-DE
-
Marko Käning
-
Roman Fietze