Parsing Optimieren
-
Ne sorry is noch uneffizienter
-
Was verstehst du denn unter ineffizient? Wie schnell hättest du's gern, wie schnell läuft es jetzt ...
-
Willst du vielleicht, dass er es sozusagen im Hintergrund macht?
-
also der Ausschnitt is logischerweise ja nur ein sehr kleiner teil eines etwas größeren programms zur system - überwachung. Das Problem ist, dass er mir 50% der gesammten programmlaufzeit in dieser schleife verbring, sprich meine cpu - auslastung hängt immer so zwischen 5 und 8%, wenn das programm läuft.
Laut profiler:
% cumulative self self total
time seconds seconds calls us/call us/call
51,03 1,73 1,73 87141 19.85 19.85 Parsingund das bei einer ungefähren programmlaufzeit von 30min. Da dacht ich mir, dass müsste doch wesentlich schneller gehen, aber mir fällt keine andere Parsmethode ein.
-
@Norb,
ich weiß nun nicht wie groß dein verwendeter
Puffer ist. Aber es sieht so aus als würde
er die Datei in mehreren Blöcken auslesen.Hast du schon mal daran gedacht die Datei
auf einen Schlag zu puffern? Das würde die
Festplattenzugriffe reduzieren.
Und bei einem IDE System ist ein Festplattenzugriff
auf gleichzeitig eine Prozessorbelastung.Zum Parsen hätte ich im Moment
keine besseren Vorschläge.Bye Peter.
-
ja, hab auch schon mit fread versucht, und das ganze auf einmal eingelesen, hat aber keine große verbesserung gebracht.
-
@Norb,
wie oft wird denn dieser Code
in deinem Programm ausgeführt?Wenn das mehrere Male pro Sekunde
geschieht kann man glaube ich nicht
viel machen. Ist ja immerhin eine
"ganz schöne" Arbeit für deine CPU.Das größte Problem was ich sehen ist, dass
du sscanf mehrere Male auf den kompletten
Puffer ausführst.Wenn ich heute Abend etwas Zeit habe versuche
ich mal eine kleine Funktion zu schreiben.
Wenn ich erfolgreich war poste ich den Code
morgen mal.Bye Peter.
-
des wäre supernett, dankeschön!
-
@Norb,
so das habe ich nun in meiner Mittagspause zusammengetippt.
Ich habe es aber weder kompiliert und noch weniger getestet.
Hoffe du kannst damit etwas anfangen.#define NAME_SZ 64 #define DATA_SZ 128 int main( void ) { char *pBuffer = ... long lBufLen = ... long lBegin = 0; long lIndex = 0; char cName[NAME_SZ]; char cData[DATA_SZ]; ... ... /* Data komplett puffern */ ... /* Ueber alle Dateieintraege */ while ( parse( pBuffer, lBufLen, &lBegin, cName, cData ) ) { /* Ich gehe jetzt mal davon aus das die Datei immer gleich ausssieht. Sollte das nicht der Fall sein, muss man via strcmp den aktuellen Wert herausbekommen */ switch ( lIndex ) { case 0: strcmp( pidStat->comm, cData ); continue; case 1: strcmp( pidStat->state, cData ); continue; ... ... ... }; lIndex++; }; return 0; }; int parse( char *pBuf, long lBufLen, long *pBegin, char *pRetName, char *pRetData ) { long lGetPos; long lSetPos; if ( !pBuf || !pBegin ) return 0; /* Naechsten Namen auslesen */ while ( pBuf[lGetPos++] != ':' ) cName[lSetPos++] = pBuf[lGetPos]; /* Ueber ': ' springen */ lGetPos += 2; /* lSetPos zuruecksetzen */ lSetPos = 0; /* Naechsten Wert auslesen */ while ( pBuf[lGetPos++] != '\r' ) cData[lSetPos++] = pBuf[lGetPos]; return 1; };
Bye Peter.
-
Hab noch einige Fehler entdeckt.
Kommt davon wenn man zu schnell etwas posten will#define NAME_SZ 64 #define DATA_SZ 128 int main( void ) { char *pBuffer = ... long lBufLen = ... long lBegin = 0; long lIndex = 0; char cName[NAME_SZ]; char cData[DATA_SZ]; ... ... /* Data komplett puffern */ ... /* Ueber alle Dateieintraege */ while ( parse( pBuffer, lBufLen, &lBegin, cName, cData ) ) { /* Ich gehe jetzt mal davon aus das die Datei immer gleich ausssieht. Sollte das nicht der Fall sein, muss man via strcmp den aktuellen Wert herausbekommen */ switch ( lIndex ) { case 0: strcmp( pidStat->comm, cData ); continue; case 1: strcmp( pidStat->state, cData ); continue; ... ... ... }; lIndex++; }; return 0; }; int parse( char *pBuf, long lBufLen, long *pBegin, char *pRetName, char *pRetData ) { long lGetPos; long lSetPos; if ( !pBuf || !pBegin ) return 0; /* Naechsten Namen auslesen */ while ( pBuf[(*pBegin)+lGetPos++] != ':' ) cName[lSetPos++] = pBuf[lGetPos]; /* Ueber ': ' springen */ lGetPos += 2; /* lSetPos zuruecksetzen */ lSetPos = 0; /* Naechsten Wert auslesen */ while ( pBuf[(*pBegin)+lGetPos++] != '\r' ) cData[lSetPos++] = pBuf[lGetPos]; /* CR/LF ueberspringen */ lGetPos += 2; /* Neue Begin position setzen */ (*pBegin) += lGetPos; return 1; };
Sollte aber grundsätzlich funktionieren.
Falls es nicht klappt versuche ich es heute
Abend wie versprochen nochmal.Bye Peter.
-
Wenn ich Dein Problem richtig verstanden habe, dann liegt der große Zeitverbrauch daran, daß Du, um eine Systemvariable zu füllen, jedesmal (fast) die ganze Konfigurationsdatei sequentiell durchkämmst. So korrekt?
Daher folgender Vorschlag:
- Speichere zu jeder Deiner Systemvariablen ihre Bezeichnung (char*), so wie sie in der Konfigurationsdatei auftauchen soll, und ihren Typ (z. B. string [char*] oder numerisch [unsigned, short, ...])
- Bilde daraus ein sortiertes Array
- Lies die Datei zeilenweise ein
- Parse die Zeile in Variablenname und Wert
- Versuche per binärer Suche, den Variablennamen im Array zu finden
- Fülle die Variable gemäß ihrem Typ mit dem gelesenen WertBOOL DateiLesen(const char* datei, PIDSTAT_TYPE pidStat) { char zeile[ZEILE_SIZE]; char* varname; char* wert; FILE* file = fopen(datei, "r"); if(!file) return FALSE; while(fgets(zeile, ZEILE_SIZE, file)) if(ZeileParsen(zeile, &varname, &wert)) SystemVarFuellen(pidStat, varname, wert); fclose(file); return TRUE; } typedef enum _VarType { VAR_CHAR, VAR_UNSIGNED, VAR_SHORT, VAR_LONG, VAR_STRING } VarType; typedef struct _VarInfo { const char* name; void* elem; VarType type; } VarInfo; BOOL SystemVarFuellen(PIDSTAT_TYPE pidStat, char* varname, char* wert) { static VarInfo vars[] = { { "CapInh", &pidStat->inh, VAR_STRING }, { "CapPrm", &pidStat->prm, VAR_STRING }, { "Name", &pidStat->comm, VAR_STRING }, { "State", &pidStat->state, VAR_STRING }, { "Uid", &pidStat->Uid, VAR_UNSIGNED }, { "VmRSS", &pidStat->rss, VAR_UNSIGNED }, { "VmSize", &pidStat->vsize, VAR_UNSIGNED }, /* etc. */ }; unsigned arrsize = sizeof(vars) / sizeof(VarInfo); VarInfo* var = BinaereSuche(varname, vars, arrsize); if(!var) return FALSE; switch(var->type) { case VAR_STRING: strcpy(*((char**) var->elem), wert); return TRUE; case VAR_UNSIGNED: *((unsigned*) var->elem) = (unsigned) atoi(wert); return TRUE; /* etc. */ } return FALSE; }