Perl - Datenrate von Interfaces abfragen

Echelon1010000

Active Member
Hi

Ich schreibe gerade an einem Perlscript das diverse Systemdaten "einsammelt" und via tcp an einen Serverdienst (lcdproc) weiterreicht. Nun hab ich das Problem das ich nicht an die aktuelle Datenrate der Netzwerkinterfaces herankomme.

Ich hab versucht mit libgrabstat und dem zugehörigen Perlmodul (hab ich bei cpan gefunden) da heran zu kommen. Diese bietet mir eine Funktion mit der ich von einem Interface abfragen kann wieviele Bytes seit dem letzten Aufruf der Funktion gesendet oder empfangen wurden.
Die Idee war, nach dem Aufruf der Funktion ein sleep(1); zu machen und dann die Funktion erneut aufzurufen. Das sollte ausgeben wieviel Bytes in der letzten Sekunde durchgelaufen sind = Bytes/s. Leider ist perl da nicht genau / schnell genug, das Umrechen von B/s in KB/s und anschliessende weiterreichen an lcdproc dauern zu lange. Ich bekomme Zeiten zwischen 0.5 und 2 Sekunden für einen Durchlauf, entsprechend falsch sind auch die "Meßergebnisse".

Jetzt suche ich nach einer anderen Möglichkeit diese Daten zu bekommen. Entweder mit einem anderen Tool / Modul das mir selber diese Daten liefert, ohne das ich eine zeitkritische Schleife bauen muß (wäre mir lieber). Oder aber indem ich eine Möglichkeit finde die Schleife so zu schreiben das sie immer eine bestimmte Anzahl Sekunden dauert und nicht variiert. Angestrebtes Ziel währe hier eine exakte Dauer von einer Sekunde oder weniger.

Weiß da vielleicht jemand wie man das lösen könnte?
Ich hab schon bei cpan gesucht, dort aber, bis jetzt, nichts gefunden (ausser eben libgrabstat). Google hat mir bis jetzt auch nichts ausgespuckt... Vielleicht ist auch mein Ansatz falsch, aber mir fällt nichts besseres ein.

Ich bin für jeden Tip dankbar...


Gruß, Echelon
 
Mal als Anregung: du koenntest es mit signalen versuchen, also jede sekunde wird eins gesendet und weckt das programm auf, und das koennte von einem anderen thread oder programm,das dass genau macht. kommen. In deinem script selber koenntest du das Modul Time::HiRes verwenden, da bekommst du mit time eine bessere Aufloesung, und koenntest verspaetungen irgendwie kompensieren.

Was aber imho auch ein problem ist,das ist die aufloesung der computeruhr und wie sleep intern arbeitet. Das haengt aber imho nicht mit perl zusammen, siehe dazu auch kernelbuecher, wie timer implementiert werden( z.B. Richard Stevens, TCP/IP Vol.2, The implementation, da ist ein Kapitel drueber, vielleicht findet sich aber auch ein anderes, neueres Buch).

Naja, aber 100% genauigkeit gibt es eh nicht, da BSDs nicht Realtime OS sind.
 
Hi,
also so richtig verstehe ich deine Anwendung nicht ;-) Was bringt dir die aktuelle Datenrate über den Zeitraum von einer Sekunde, wenn vielleicht genau vor und nach dieser Sekunde die Datenrate eine andere ist?
Warum nicht den Traffic zusammen mit time() in ein File schreiben und beim nächsten Aufruf wieder auslesen. So hast du das Zeitinterval (sekunden-)genau und auch den kompletten Traffic und nicht nur in einem Augenblick.
Habe mal sowas ähnliches mit rrdtool gemacht, einfach mit cron die rohen gesendeten und empfangenen Bytes aus ifconfig geholt und dann in rrdtool geschrieben, das regelt dann den Rest und du kannst dann Durchschnitte über alle möglichen Zeiträume wieder rausholen. Als Bonus gibts sogar schöne Png's ;-)
Viel Erfolg ;-)
 
Hi

Danke erstmal für deinen Tip :)
Ich hab sowas schon versucht und die Subroutine die die Werte abfragt mit fork() in einen eigenen Prozess "ausgelagert". Leider hat das auch nicht funktioniert. Flaschenhals ist und bleibt die Kommunikation mit dem Daemon der die Werte annehmen soll.

Eine 100%ige Genauigkeit muß eigentlich nicht gegeben sein, allerdings, wenn ich 40KB/s Durchsatz habe und mir das Script Werte zwischen 10KB/s und 180 KB/s liefert ist das dann doch etwas zu ungenau ;)

Irgendwie muß das gehen, es gibt ja schon Tools die die Werte darstellen. Zum Beispiel iftop aus den Ports (Was allerdings nicht in Perl geschrieben wurde). Ich habe nur noch kein Tool gefunden das mir die Werte in eine brauchbaren Form ausgibt, also entweder abfragbar über eine tcp Verbindung (mbmon liefert Temperatur und Lüfterdrehzahl über tcp aus) oder eben als Perlmodul/Schnittstelle die ich direkt einbinden kann.

Das Modul HiRes habe ich schon eingebunden, allerdings ist der Haken immer noch daran daß das Script zu lange und, am problematischsten, einen nicht vorhersagbaren Zeitraum benötigt um die Werte zu abzufurfen und zu verarbeiten.

Leider also noch keine Lösung in Sicht, trotzdem Danke für die Hinweise.

Gruß, Echelon
 
Hi

Die Funktion liefert nicht die Datenrate. Sie liefert die gesendeten (oder empfangenen) Bytes seit ihrem letzten Aufruf.
Beispiel (pseudocode):

LOOP:
my $blah=get_rx_bytes(tun0);
print $blah;
sleep (1);
goto LOOP;

Würde mir die Anzahl Bytes ausgeben die seit dem letzten Aufruf (vor einer Sekunde) empfangen wurden. Wenn ich das einmal pro Sekunde mache erhalte ich logischerweise die Bytes / Sekunde.

Leider ist perl nicht genau genug bzw. die Ausführung des Scripts zu langsam. Daher ist der Zeitraum zwischen zwei Aufrufen != 1 Sekunde. Dementsprechend erhalte ich nicht meine gewünschten Bytes/s sondern irgendwas zwischen Bytes/s und Bytes/zwei_sekunden.

Kurz: Ich suche also nach einer Möglichkeit mit Perl die aktuelle Datenrate zu ermitteln den mein tun0 (oder rl* oder ed* oder *sondtwas) gerade jetzt im Moment hat. Meine Methode funktioniert ja nicht...

Die Idee mit dem "in ein File schreiben" ist ansich nicht schlecht. Allerdings brauche ich die Auswertung mehr oder weniger "sofort" da die Werte, nachdem die an lcdproc übergeben wurden, auf einem LC Display dargestellt werden. Wenn (m)ein Tool die erst nach ein paar Sekunden ausliest und darstellt ist das etwas zu spät...

Danke aber trotzdem für den Hinweis.

Gruss, Echelon
 
Echelon1010000 schrieb:
...
Zum Beispiel iftop aus den Ports (Was allerdings nicht in Perl geschrieben wurde). Ich habe nur noch kein Tool gefunden das mir die Werte in eine brauchbaren Form ausgibt ...

Ein anderer Ansatzpunkt:

Das Programm "iftop" läuft bei freshmeat unter "System :: Networking :: Monitoring". Sucht man in dieser Kategorie findet man ca. 193 Projekte die mittels Perl erstellt wurden. Vielleicht ist da etwas brauchbares für dich dabei, oder eines dieser Projekte liefert ggf. eine brauchbare Routine, Module oder sonst was...

Schon mal daran gedacht? Nur so als Idee... :)
Ach, ja... viel Spaß beim durchforsten ;)
 
ahh... langsam verstehe ich ;-) Und du musst wirklich jede Sekunde neue Werte haben? Ist das kein Overhead? Naja, egal...
Kann garnicht verstehen, dass das solche Probleme mit der Zeit gibt. Habe hier ein Spript , welches eine Datei einliest, ein paar Sachen sortiert und dann drei Files schreibt, dass dauert < 70ms und im Schnitt 40ms. Werde das zuhause mal genauer testen.
Das Problem scheint doch dann das lcdproc zu sein?!? Und wenn das solche Hänger > 1s hat (was ich kaum glauben kann... eine Sekunde ist für den Rechner mehr als ne Ewigkeit und ich hab ja zu Heise nen Ping von 20ms) bringts doch auch nichts die Daten genauer einzulesen.
Ansonsten würde ich zwei Skripte machen... eins sammelt Daten und schreibt sie in ein File, jede Sekunde oder was auch immer und das andere schickt sie an das lcdproc. Somit entkoppelt von der Latenz von lcdproc.
 
Hi

Sowas ähnliches hab ich, nur nicht mit Dateien, ich forke einen Subprozess mit dem ich das Datensammeln entkoppeln kann.
Zu der Zeitverzögerung:
Ich glaube nicht das es am lcdproc liegt. Kurz zur Funktionsweise von dem Teil.
Der Daemon sitzt auf tcp 13666. Mein script macht eine Verbindung auf, meldet sich als Client an und erzeugt einige "screens", das sind Anzeigen die abwechselnd auf dem Display angezeigt werden.

Nun forke ich meinen Subprozess. Dieser holt sich von dieser Fuktion die Daten und gibt sie an lcdproc weiter. Das sieht dann so aus:

Code:
print $socket  "statgrab-if1,statgrab-if1-rx-v,4,2,$rx\n";

Dafür dürfte er also nicht allzulang brauchen.
Ich vermute den Flaschenhals mittlerweile eher bei der Funktion. Werde mich mal ans austesten machen und genaue Zeitstempel erzeugen was wann wie lang braucht.

Zu dem Zeitproblem: Die Daten sollen (fast)-Echtzeit auf dem Display angezeigt werden, sowohl als Zahlen als auch als Balkendiagramm (rx/tx). Dementsprechend muß ich also auch relativ oft die Werte abholen. (fast)-Echtzeit deswegen weil das Display nur achtmal pro Sekunde aktualisiert wird. Auf eine Sekunde hab ich mich festgelegt weil sich so relativ einfach aus der vergangenen Zeit auf die Datenrate schließen läßt. Klar, ich könnte auch einmal pro Minute aktualisieren. Das ist aber einerseits schon ein wenig von "Echtzeit" entfernt, andererseits behebt das nicht die Differenz von bis zu zwei Sekunden die die Programmschleife dauert.

Anbei mal mein Code an dem ich bastele.

Code:
    my $loopcount=0;
    LOOP:

    # Grab networkstats
    my $network = get_network_io_stats_diff;

    # calculate and display values for $statgrabif1
    if ( $statgrabif1 ne "none")
        {
        my $if1rx=$network->rx($grabstatif1);
        my $if1tx=$network->tx($grabstatif1);
        my $if1krx=sprintf("%.2f",$if1rx/1024);
        my $if1ktx=sprintf("%.2f",$if1tx/1024);

        setstring ("statgrab-if1","statgrab-if1-rx-v",4,2,$if1krx);
        setstring ("statgrab-if1","statgrab-if1-tx-v",14,2,$if1ktx);

        setstring ("statgrab-net","statgrab-net-if1-rx-v",6,2,$if1krx);
        setstring ("statgrab-net","statgrab-net-if1-tx-v",14,2,$if1ktx);

        }
        $loopcount++;
        if ( $loopcount > 20 ) { goto ENDSTATGRABNET; }

        sleep (1);
        goto LOOP;
    ENDSTATGRABNET:
    debug ("Child exiting");
    exit 0
    }

die Funktion "setstring" ist eine sub die die Daten an lcdproc weitergibt.

Für diese Schleife will er eben diese ein bis zwei Sekunden...
Vielleicht hab ichs auch schlecht programmiert, aber ich denke da kann man nicht viel falsch machen. Vielleicht fällt dir ja was ein.

Gruss, Echelon
 
Hi

@steinlaus:

Danke für deinen Tip :)
Ich hab mir die verfügbaren Sachen schon angesehen, allerdings in
sourceforge.net ;) Freshports hatte ich zu dem Zeitpunktz auch schon durch.

Nun ja, die meisten Programme die dort sind haben eine wesentlich höhere Samplerate, von einer Stunde an aufwärts und sind dafür ausgelegt langfristig Statistiken zu erstellen. Da kommts auf ein oder zwei Sekunden auch nicht an. Meine Anwendung sollte allerdings möglichst in Echtzeit (oder nahe dran) die Daten auf dem LC Display darstellen.

Dann gibt es noch einige Lösungen die mit snmp arbeiten. Damit kenne ich mich nun garnicht aus, ist IMO aber auch ein wenig Overkill für eine Routerbox...

Und einige Tools mit denem man Bandbreite / user und/oder Prozess anzeigen kann. Auch nicht das was ich brauchen kann.

Somit also noch keine Lösung, danke dennoch für deinen Hinweis, freshmeat hatte ich tatsächlich übersehen :)

Gruß, Echelon
 
Ein Stueck weiter

Hi

Ich bin mittlerweile ein Stück weiter. Das Tool "bmon" (/usr/ports/net/bmon) ist in der Lage Informationen via udp in Echtzeit an andere Programme zu liefern. Das wäre ja schon das was ich brauche. Dummerweise verstehe ich nicht ganz wie das Protokoll auszuwerten ist, da die Software in C geschrieben wurde.

Kann mir jemand da auf die Sprünge helfen?

Das ist die einzige Doku die ich zum Thema gefunden hab:
Code:
/*
 *                           NODE MESSAGE
 *
 *  0                   1                   2                   3
 *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 * +---------------+---------------+---------------+---------------+
 * | Magic Number  |    Version    |     Offset    |      Flags    |
 * +---------------+---------------+---------------+---------------+
 * |         Total Length          |           Checksum            |
 * +-------------------------------+-------------------------------+
 * |                      Timestamp (seconds)                      |
 * +---------------------------------------------------------------+
 * |                       Timestamp (usecs)                       |
 * +---------------------------------------------------------------+
 * .                                                               .
 * .                         Name of Node                          .
 * .                                                               .
 * +---------------------------------------------------------------+
 * .                                                               .
 * .                        List of Groups                         .
 * .                                                               .
 * +---------------------------------------------------------------+
 *
 *
 *                          GROUP MESSAGE
 *  0                   1                   2                   3
 *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 * +-------------------------------+-------------------------------+
 * |             Type              |             Offset            |
 * +-------------------------------+-------------------------------+
 * .                                                               .
 * .                      Type specific data                       .
 * .                                                               .
 * +---------------------------------------------------------------+
 *
 *
 *
 *                        INTERFACE MESSAGE
 *
 *   0                   1                   2                   3
 *   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 *  +-------------------------------+-------------------------------+
 *  |           Index               |            Offset             |
 *  +---------------+---------------+-------------------------------+
 *  |  Name Length  |  Opts Length  |        Reserved             |C|
 *  +---------------+---------------+-------------------------------+
 *  .                                                               .
 *  .                      Name of Interface                        .
 *  .                                                               .
 *  +---------------------------------------------------------------+
 *  .                                                               .
 *  .                           Options                             .
 *  .                                                               .
 *  +---------------------------------------------------------------+
 *  .                                                               .
 *  .                      List of Attributes                       .
 *  .                                                               .
 *  +---------------------------------------------------------------+
 *
 *                          INTERFACE OPTION
 *   0                   1                   2                   3
 *   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 *  +---------------+---------------+ - - - - - - - - - - - - - - - +
 *  |     Type      |     Length    |         Data or padding       |
 *  +---------------+---------------+ - - - - - - - - - - - - - - - +
 *  .                                                               .
 *  .                               Data                            .
 *  .                                                               .
 *  + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
 *
 *
 *                     DEFINED INTERFACE OPTIONS
 *
 *          +----------------+--------+---------------------+
 *          | Type           | Length |   Description       |
 *          +----------------+--------+---------------------+
 *          | IFOPT_HANDLE   | 4      | Interface handle    |
 *          | IFOPT_PARENT   | 2      | Parent index        |
 *          | IFOPT_LINK     | 2      | Master link         |
 *          | IFOPT_LEVEL    | 2      | Level (tc trees)    |
 *          +----------------+--------+---------------------+
 *
 *
 *                          ATTRIBUTE MESSAGE
 *
 *   0                   1                   2                   3
 *   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 *  +-------------------------------+---------------------------+-+-+
 *  |             Type              |                           |R|T|
 *  +-------------------------------+---------------------------+-+-+
 *  |          RX Overflows         |          TX Overflows         |
 *  +-------------------------------+-------------------------------+
 *  |                            RX Value                           |
 *  |                                                               |
 *  +---------------------------------------------------------------+
 *  |                            TX Value                           |
 *  |                                                               |
 *  +---------------------------------------------------------------+
 */

Das findet sich so in der Datei distribution.h im bmon-Verzeichnis.
Nun ja, kann mir jemand sagen wie ich an die Daten herankommen kann? Wie ich einen udp-Socket aufmache weiß ich, aber wie kann ich die eingehenden Nachrichten empfangen und auswerten?

Falls noch mehr Info benötigt wird bitte Bescheid sagen...

Gruß, Echelon
 
sleep sollte man eh nicht fuer zeitkritische sachen verwenden, die Aufloesung ist grob wie auch die genauigkeit, wie gesagt, man muss es ueber eine zeitabfrage machen( mit Time::HiRes ) und mit einer Funktion wie nanosleep(2) , die nicht eine volle sekunde schlaeft, sondern etwas darunter, dann die zeit abfragt, bei bedarf fuer ein kurzes intervall nochmal schlafen geht, bis die sekunde vergangen ist, usw, bis 1 sekunde vergangen ist.

Und man darf den Fehler nicht machen, dann einfach von 0 wieder anzufangen, man muss die ausfuehrungszeit des vorherigen programmablaufes mit einberechnen.

Was noch ein problem ist, das sind blockierende funktionsaufrufe, wie print auf einen socket, deshalb asynchrone IO verwenden. asynchrone IO und zeitmessung ist aber nicht ganz einfach, frag lieber ein gutes unixbuch( == Stevens oder vielleicht Helmut Herold )
 
Hi

Ich hätte nicht gedacht das meine scheinbar recht einfache Aufgabe so komplex wird.

Ich hab mittlerweile angefangen mich mit diesem bmon zu beschäftigen, das die Daten einsammelt und mir diese via udp anliefern kann. Das würde mir die Aufgabe selbst eine entsprechende Anwendung zu entwickeln abnehmen, was meine Arbeit immens erleichtern würde. Allerdings weiß ich noch nicht wie ich die Daten dann annehmen und verarbeiten kann, da ich das verwendete Protokoll nicht wirklich kenne und so nicht weiß wie die Daten ankommen und auszuwerten sind. Ich werde mich dann morgen mal mit udp im Allgemeinen und dem bmon-Protokoll im speziellen beschäftigen.

Mal sehen ob ich damit bessere Resultate erziele.

Zur Zeitschleife:
Ich denke, nachdem ich hin und herprobiert hab, das es mit meiner Methode so erstmal nicht zu lösen ist. Ich kann es zwar ausgleichen wenn meine Schleife weniger als eine Sekunde braucht, aber wenn mehr als eine Sekunde benötigt wird (z.B. weil meine TCP Verbindung hängt oder die Daten langsam hereinkommen) dann kann ich das nicht kompensieren und muss anfangen auf Basis der tatsächlich vergangenen Zeit herunterzurechnen. Ich denke, das könnte man zu Recht als unsauber bezeichnen...
Ich danke dir aber für die Tips, falls ich (und ich werde mit Sicherheit) wieder was schreibe kann ich das sicher gebrauchen. Der Netzwerkclient ist nicht der einzige Client den ich schreiben will, es ist noch einer für pop3 und Load geplant. Da ists nicht ganz so eng und ich kann die Info dort sicher brauchen...

Aber erstmal werde ich mit bmon anfangen und meinen Netzwerkclient fertig schreiben :)

Grüße, Echelon
 
Noch etwas, ist die 1 sekunde wirklich so wichtig, oder koenntet du auch etwas laengere und variable zeitabstaende akzeptieren.
Wenn ja, dann versuch es doch einfach so:

$time = time() #natuerlich Time::HiRes verwenden

abfrage der gesendeten daten;

sleep(1);

$time2 = time();

nochmal abfrage der daten;

hier kalkulierst du dann mit Hilfe von $time und $time2 das intervall und teilst die differenz der datenraten durch das wirkliche intervall, das wohl etwas laenger als 1 sec ist. Dann schickst du die daten ab.
Den Vorgang wiederholst du dann in einer endlosschleife. Diese methode geht auch unter hoher last, die intervalle werden wohl nur etwas groesser. Hast halt nur ungefaehr eine sek-intervall, die datenrate ist dafuer aber genau.
 
Hi

Danke für den Tip, auf die Idee bin ich noch nicht gekommen. Allerdings hab ich ein paar Zeitmessungen gemacht. Das Ergebnis sieht so aus:
Code:
lo: 1 net: 0.0015110969543457 calc: 0.000602960586547852 set: 0.55401611328125 totl 0.556481838226318
lo: 2 net: 0.000720024108886719 calc: 0.000113964080810547 set: 0.519311904907227 totl 0.520215034484863
lo: 3 net: 0.000390052795410156 calc: 0.000117063522338867 set: 0.399712085723877 totl 0.400292158126831
lo: 4 net: 0.00039219856262207 calc: 0.000117063522338867 set: 1.75984597206116 totl 1.76042795181274
lo: 5 net: 0.000391006469726562 calc: 0.000115871429443359 set: 0.179728984832764 totl 0.180307149887085
lo: 6 net: 0.000388860702514648 calc: 0.000118017196655273 set: 0.319777965545654 totl 0.320359230041504
lo: 7 net: 0.000391006469726562 calc: 0.000118017196655273 set: 0.159677982330322 totl 0.16025710105896
lo: 8 net: 0.000369071960449219 calc: 0.000111103057861328 set: 0.259702920913696 totl 0.260254859924316
lo: 9 net: 0.000393867492675781 calc: 0.000118017196655273 set: 0.189710140228271 totl 0.19028902053833
lo: 10 net: 0.000392913818359375 calc: 0.000118017196655273 set: 0.289711952209473 totl 0.290292978286743
lo: 11 net: 0.000387907028198242 calc: 0.000116109848022461 set: 1.65973281860352 totl 1.66030883789062
lo: 12 net: 0.000427007675170898 calc: 0.000120878219604492 set: 0.409691095352173 totl 0.410310029983521
lo: 13 net: 0.00038909912109375 calc: 0.000116825103759766 set: 0.39968204498291 totl 0.400264024734497
lo: 14 net: 0.000479936599731445 calc: 0.000117063522338867 set: 0.429741144180298 totl 0.430413961410522
lo: 15 net: 0.000422954559326172 calc: 0.000132083892822266 set: 0.399968862533569 totl 0.400609016418457
lo: 16 net: 0.000435113906860352 calc: 0.000121116638183594 set: 0.389736890792847 totl 0.390370845794678
lo: 17 net: 0.00038909912109375 calc: 0.000115156173706055 set: 1.759850025177 totl 1.76042485237122
lo: 18 net: 0.000390052795410156 calc: 0.000114917755126953 set: 0.189707040786743 totl 0.190285921096802
lo: 19 net: 0.000406980514526367 calc: 0.000117063522338867 set: 0.329722166061401 totl 0.330317974090576
lo: 20 net: 0.000387907028198242 calc: 0.000112056732177734 set: 0.159653902053833 totl 0.160226821899414
Hierbei:
lo - Schleifendurchlauf (Nummer)
net - Abfrage der Daten über die Funktion
calc - Umrechnen der Daten von Byte nach KByte
set - Weiterleiten der Daten an lcdproc
totl - Gesamtdurchlauf

Die Differenz zwischen Durchlauf und der Summe der Einzelwerte kommt zustande weil ich die Ausgabe auf dem Bildschirm und den bedingten Rücksprung zum Schleifenbeginn vernachlässige.
Mein Testprogramm sieht so aus:
Code:
my $pid=fork();
if ( $pid == 0 )
    {
    debug ("Child successfully started!");
    my $blubb=0;
    LOOP:

    my $start=time();

    # Grab networkstats

    $bnet=time();
    $network = get_network_io_stats_diff;
    $anet=time();

    # calculate and display values for $statgrabif1
    if ( $statgrabif1 ne "none")
        {
        $bcalc=time();
        my $if1rx=$network->rx($grabstatif1);
        my $if1tx=$network->tx($grabstatif1);
        my $if1krx=sprintf("%.2f",$if1rx/1024);
        my $if1ktx=sprintf("%.2f",$if1tx/1024);
        $acalc=time();

        $bset=time();
        setstring ("statgrab-if1","statgrab-if1-rx-v",4,2,$if1krx);
        setstring ("statgrab-if1","statgrab-if1-tx-v",14,2,$if1ktx);
        setstring ("statgrab-net","statgrab-net-if1-rx-v",6,2,$if1krx);
        setstring ("statgrab-net","statgrab-net-if1-tx-v",14,2,$if1ktx);
        $aset=time();
        }
        $blubb++;
        if ( $blubb > 20 ) { goto ENDSTATGRABNET; }

        $end=time();

        $net=$anet-$bnet;
        $calc=$acalc-$bcalc;
        $set=$aset-$bset;
        $total=$end-$start;
        print "lo: $blubb ";
        print "net: $net ";
        print "calc: $calc ";
        print "set: $set ";
        print "totl $total ";
        print "\n";


        sleep (1);

        goto LOOP;
    ENDSTATGRABNET:
    exit 0
}

Dazu noch die Funktion "setstring" mit der die Daten an lcdproc weitergeleitet werden:
Code:
sub setstring
{
    # sets x,y and value of a string-type widget
    # setstring ( $screen,$name,$x,$y,$value );
    my $screen=$_[0];
    my $name=$_[1];
    my $x=$_[2];
    my $y=$_[3];
    my $value=$_[4];
    print $socket "widget_set $screen $name $x $y $value";
    debug ( "widget_set $screen $name $x $y $value");
    suck();
    return 1;
}

Zu guter Letzt:
Die Funktion suck() Diese nimmt Nachrichten vom Daemon entgegen und wertet sie aus. Das sind einmal Nachrichten über Erfolg/Mißerfolg eines Befehls, andererseits Informationen darüber welcher Screen gerade angezeigt wird und wie lange.

Code:
sub suck {
# fetch answer from server and process it
FETCHME:
my $answer=<$socket>;
# if we recieve one of this ridicoulous "listen" messages
# it will disturb the communication with the server so
# we throw it away and refetch the message from the server
# Note that a screen with "listen" or "ignore" in its name
# may result in a endless loop...
if (index($answer,"listen")>=0)
    {
    debug("Discarded silly listen-message");
    goto FETCHME;
    }

if (index($answer,"ignore")>=0)
    {
    debug ("Discarded silly ignore-messages");
    goto FETCHME;
    }

if (index($answer,"huh?")>=0)
# Something's going wrong, check this out
    {
    debug("error recieved: $answer");
    if (index($answer,"exists")>=0)
        {
        die "Fatal error while registering screen. Server said: $answer\n";
        }
    }

if (index($answer,"success")>=0)
    {
    debug ("success");
    }
return 1
}



Ich bin also soweit das ich weiß wo mein Zeitproblem herkommt. Es ist die Weitergabe der Daten an lcdproc. Während die anderen Teile nur wenige µs brauchen (was man vernachlässigen könnte) dauert die Übergabe an den Daemon im Schnitt eine halbe Sekunde. Teilweise sind auch Aussetzer von 1.5 Sekunden und mehr dabei.

Zu deinem Vorschlag:
Ich werde das mal antesten. Auf die Sekunde bin ich aus zwei Gründen gekommen:
Erstens hatte ich die irrige Annahme das mein Schleifendurchlauf nur sehr sehr wenig Zeit in Anspruch nimmt. Entsprechend dachte ich, ich könnte die Schleife einmal pro Sekunde laufen lassen und hätte dann automatisch, ohne großartig rumzurechnen die KB/s.

Zweitens will ich versuchen die Daten möglichst zeitnah aufs Display zu bringen. Das heißt, der Balken der den Durchsatz anzeigt soll mehr oder weniger in Echtzeit auf Aktivitäten im Netz reagieren. Daher habe ich versucht die Abfragerate möglichst weit hochzuschrauben. Den Overhead der dabei entsteht ist vernachlässigbar: Es wird kaum Last erzeugt und der Client kommuniziert auf lo0. Prinzipiell hätte ich nichts dagegen die Werte noch öfter abzuholen. Das Display wird von lcdproc 8 mal pro Sekunde aktualisiert, ich könnte also eine Echtzeitanzeige bekommen.

Ich sehe im Moment zwei Wege:
Möglichkeit 1:
Datenabfrage und Weiterleitung abkoppeln. Dann kann exakt einmal/Sekunde (oder öfter) die Datenauswertung erfolgen und die Funktion die dafür zuständig ist die Daten ans Display weiterzugeben kann "in Ruhe" die Daten so schnell hochschieben wie sie eben kann.

Möglichkeit 2:
Die Funktion die die Daten an lcdproc gibt schneller machen oder dafür sorgen das das Programm weiterläuft während die Daten noch hochgeschickt werden.

Ich weiß noch nicht wie ich das am sinnvollsten anstelle. Wahrscheinlich werde ich eine Mischung aus deinem Vorschlag und der zweiten Möglichkeit versuchen. Also die Sub schneller machen und die Zeit variabel messen...

Gruß, Echelon

Nachtrag:
Das fiel mir gerade ein: Ich hab das Teil gewissermaßen unter idealen Bedingungen getestet. Eigentlich sind da noch mehr Clients die ebenfalls Daten an lcdproc ausliefern sollen. Das Zeitproblem könnte sich dadurch noch vergrößern, ich weiß nicht wie lcdproc verschiedene parallele Anfragen beantwortet/verarbeitet.
 
Zurück
Oben