[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: Bash Einzeiler Zeit+Datum letzter Eintrag dmesg



Hallo,

Am Mon, 15 Aug 2011, Rico Koerner schrieb:
>Am 15.08.2011 08:39, schrieb David Haller:
>> Am Sun, 14 Aug 2011, Rico Koerner schrieb:
>>> David hat mich durch den Hinweis auf syslog bei der Fehlersuche jetzt
>>> noch auf einen anderen Lösungsweg gebracht. Da die Zeile aus dmesg auch
>>> in einer Zeile im Syslog auftaucht, braucht man doch gar nicht anfangen
>>> zu rechnen sondern einfach nur die passende Zeile aus dem syslog
>>> ziehen.
>> 
>> Haaalt! Konkretes Beispiel: bei mir schreibt syslog-ng z.B. firewall
>> und /dev/sr0 betreffende Einträge in jew. eigene Logs (die würden mir
>> sonst das eigentliche nur zumüllen). Ergo müßte ich man in mehreren
>> Dateien rumgreppen ... Der letzte Eintrag in dmesg findet sich bei mir
>> grad nur(!) in /v/l/firewall.
>
>Ja, jeder Ansatz hat seine eigenen Vor- und Nachteile.
>Auch die Vorgabe "ohne root" war mir nicht bewußt. Wem die Gruppe adm
>noch zu großzügig ist, kann es ja auch mit ACLs auf syslog versuchen.
>Wenn die Logs abweichend sind, scheitert mein Ansatz natürlich auch,
>u.U. müssten dann mehrere Logs durchsucht werden.
>Dafür ist das Ergebnis genauer, weil die Abweichung zwischen den Zählern
>nicht verfälschen.
>
>> dmesg ist also schon der richtige Ansatz.
>
>Das hab ich ja nicht verworfen.
>
>>> Dort steht die Zeit ja schon am Anfang der Zeile. Somit wird immer die
>>> korrekte Zeit ausgegeben.
>
>Nein, eben nicht. Die Abweichung wurde ja nun schon mehrfach
>festgestellt. Nur deshalb hab ich den Weg verfolgt.

Wie gesagt, ich denke das ist ein Sonderfall. Leider hat Frank keine
"Rohdaten" (uptime, timestamp in dmesg/syslog) mit denen dann
weitergerechnet wird geliefert.

[..]
>> Und die andere Variante, die ebenfalls /proc/uptime ausliest dürfte
>> noch lahmer sein.
>
>Lassen wir mal die Vermutungen beiseite und führen das aus.
>Mein Rechner ist allerdings insgesamt nicht so schnell,

Och, meiner auch nicht, war zum Kaufzeitpunkt vor ~1.5 Jahren schon
eine der langsamsten CPUs (Athlon II X2 250 (2x3.0 GHz)). Mir war
Single-Core Leistung eben wichtiger als 4 Kerne[0] ;)

>Die Ausgangsvariante:
>~# time { for i in {1..1000}; do let lastentry=$(dmesg|tail -n 1|cut -f1
>-d"."|cut -c2-|cut -f2 -d" "); let boot=$(cut -f1 -d. /proc/uptime); let
>lastdate=$boot-$lastentry; date -d "$lastdate seconds ago"; done >
>/dev/null; }
>
>real	0m17.204s
>user	0m5.704s
>sys	0m16.753s
>
>AWK:
>~# time { for i in {1..1000}; do date -d "$(dmesg | gawk -F'[][ ]+'
>'BEGIN{getline<"/proc/uptime";u=$1;} END{printf("%i\n",u-$2);}') seconds
>ago"; done > /dev/null; }
>
>real	0m13.924s
>user	0m5.468s
>sys	0m9.261s

*hehe*

>Syslog:
>~# time { for i in {1..1000}; do LASTENTRY=`dmesg | tail -n1`;
>LASTTIME=${LASTENTRY%%]*}; grep ${LASTTIME#[} /var/log/syslog | cut
>-c-15; done > /dev/null; }
>
>real	0m15.713s
>user	0m5.204s
>sys	0m11.057s

Wobei man hier ergänzen sollte: 'cut -c' oder andere zeichenabhängiger
Kram sind immer "fragil". Musterbasierte wie cut -fN -dX, die awk-
oder sed-Variante sind robuster.

>Bash only:
>~# time { for i in {1..1000}; do LASTENTRY=`dmesg | tail -n1`;
>LASTTIME=${LASTENTRY%%.*}; BOOT=`cat /proc/uptime`; date -d
>"$((${BOOT%%.*} - ${LASTTIME#[})) seconds ago"; done > /dev/null; }
>
>real	0m15.433s
>user	0m4.112s
>sys	0m11.569s
>
>Ja, awk ist hier am schnellsten.
>Erstaunlicherweise ist grep+cut nicht wesentlich schlechter als
>cat+date. Suchen wir doch mal den Zeitfresser.

Wie gesagt: Prozesse starten ist "teuer". Das schlägt hier wohl durch.

>Ich klammer mal die einzelnen Aufrufe aus der Schleife aus:
>~# time { LASTENTRY=`dmesg | tail -n1`; for i in {1..1000}; do
>LASTTIME=${LASTENTRY%%.*}; BOOT=`cat /proc/uptime`; date -d
>"$((${BOOT%%.*} - ${LASTTIME#[})) seconds ago"; done > /dev/null; }
>
>real	0m4.661s
>user	0m1.264s
>sys	0m3.132s
>
>dmesg|tail schluckt schon mal >10s, also schon mal 2/3 der Gesamtzeit.
>
>~# time { for i in {1..1000}; do dmesg; done > /dev/null; }
>real	0m7.649s
>user	0m2.636s
>sys	0m5.152s
>
>Den größten Teil davon benötigt dmesg selbst, ist also nicht vermeidbar.
>Bleiben ca. 3s für tail.
>
>~# time { BOOT=`cat /proc/uptime`; for i in {1..1000}; do
>LASTENTRY=`dmesg | tail -n1`; LASTTIME=${LASTENTRY%%.*}; date -d
>"$((${BOOT%%.*} - ${LASTTIME#[})) seconds ago"; done > /dev/null; }
>
>real	0m12.770s
>user	0m3.708s
>sys	0m9.517s
>
>cat ist auch mit ca. 3s dabei
>
>
>~# time { for i in {1..1000}; do LASTENTRY=`dmesg | tail -n1`;
>LASTTIME=${LASTENTRY%%.*}; BOOT=`cat /proc/uptime`; done; date -d
>"$((${BOOT%%.*} - ${LASTTIME#[})) seconds ago" > /dev/null; }
>
>real	0m12.775s
>user	0m3.960s
>sys	0m9.365s
>
>date ebenfalls.
>
>> Mantra: Prozesse starten, Disk- und Console-I/O ist lahm!
>Dann spar dir doch auch den seq-Aufruf, das kann die bash auch allein. ;-)
>
>-- for i in `seq 1 1000`;
>++ for i in {1..1000};

Ach, alte Gewohnheit, hab 10 Jahre mit bash-2.x programmiert ... Und

1. es ist genau 1 Aufruf pro Durchlauf (und nicht _in_ der Schleife)

2. Der Unterschied ist gar nicht mal groß (kleinster und größer Wert
   aus 3 Durchläufen):

$ time for i in `seq 1 1000000`; do :; done
real    0m2.588s
real    0m2.691s
$ time for i in {1..1000000}; do :; done
real    0m2.245s
real    0m2.273s

Grob geschätzt: die ~0.4s Unterschied sind dem einmaligen Start von
'seq' geschuldet ;) _IN_ der Schleife addieren sich Programmstarts
aber massiv. Und deswegen ist z.B. auch perl statt bash + nochwas sehr
bald "schneller" (und awk noch früher), solange man nicht allzuviele
Module nachlädt[1]. Andererseits kann man mit perl und perl-Modulen
eben dann auch bequem sehr viel mehr machen und auf externe Programme
verzichten, ich sach nur z.B. "Mime" oder "Date" oder eigene 'sort'
Routinen ;) Ist ne Erfahrungssache und gilt ebenso für python oder
sonstwas. Ich mag halt perl (wenn bash/sed/awk nimmer sinnvoll ist).

>> Oh, da fällt mir ein: das 'date' kann man sich (mit GNU awk) auch noch
>> sparen:
>> 
>> real    0m4.050s
>> user    0m0.220s
>> sys     0m0.452s
>
>Nur um hier auch den Vergleichswert auf der selben Maschine zu haben:
>~# time { for i in {1..1000}; do dmesg | gawk -F'[][ ]+' ' BEGIN {
>getline < "/proc/uptime"; u = $1; } END { print strftime("%c", systime()
>- (u - $2) ); }'; done > /dev/null; }
>
>real	0m10.197s
>user	0m2.996s
>sys	0m7.248s
>
>ca. 4s bei date gespart, also ähnlich dem Ergebnis vom ausklammern oben.

*hehe*

>Insgesamt ist das damit auch ein schön kurzer Einzeiler, der nur 1
>zusätzliches Programm (gawk) benötigt. Sehr gut. :-)

Noch ein Mantra/ne Faustregel: wer in einer Pipe mehr als genau ein
'cut', 'sed', 'awk' oder 'perl' (python) verwendet, der macht was
falsch. Mit dem jew. nächstgenannten Tool kann man eigentlich immer
das geforderte effektiver erledigen.

>Ich bin zwar nicht der awk-Guru, aber wenn ich es mal einsetze, dann
>auch möglichst ohne Verkettungen mit anderen Programmen.

Gilt auch für sed, perl und andere ;) awk ist für mich oft eine
bequeme und "schlanke" Zwischenstufe zwischen sed und perl. Mit awk
kann man richtig programmieren (Variablen, Funktionen, usw., was mit
sed nicht geht). Ich hab z.B. ein 'headntail' (Version 0.0.1a (alpha),
(c)2003) als awk-Script, das mir z.B. die ersten und letzten 10 Zeilen
einer Datei ausgibt:

$ seq 10 | headntail -2 | xargs
1 2 9 10

Mit head/tail kommt man um zweimalige Lesen der Datei nicht rum, mein
Script macht das zwar auch, aber einmal nur zum Zeilenzählen mit
'wc -l'[2].

War auf jedenfall eine sehr lehrreiche awk-Programmierübung für
mich[3] und ist sogar teils sinnvoll kommentiert ;)

>Damit sollten wir dem OP jetzt genügend Anregungen für seinen
>Programmierspaß gegeben haben. ;-)
>
>Wobei mein Spaß daran auch nicht zu kurz kam. :-)

Prima. So soll es sein :)

-dnh, der die Tage endlich mal das ISO von seiner ersten Linux-CD
    gezogen hat: Debian-1.3.1_chip_ed.iso vom Dec. 1997 aka "bo" :)
    Auch deswegen lunger ich hier auf der ML rum, obwohl ich aktuell
    kein Debian im Einsatz habe ...

[0] und mein Hauptrechner davor war seit 2000 ein 500 MHz Athlon, der
    langsamste den's je gab ;) Allerdings hab ich seit ~4 Jahren nen
    Zweitrechner mit nem Athlon 64 X2 3800+EE (2x2.0 GHz), der
    inzwischen nur noch Fileserver macht (und dessen NT zu sterben
    scheint *grumpf*).

[1] da bremst aber v.a. das Finden und Laden (I/O) der Module

[2] ob das awk-intern evtl. effizienter ginge habe ich nie ausprobiert

[3] bei Interesse (->per PM kundtun bitte) mail ich das gern per PM
    oder lad's ggfs. auf meine Webseite.

-- 
Wenn der Mailserver platzt, werden halt nochmal 80 GB dazugesteckt.
Ist billiger als die Arbeitszeit zum Aufräumen.     -- Marc Haber


Reply to: