Forum: PC-Programmierung C - CPU Auslastung beim Datei speichern reduzieren


von max .. (vbc2011)


Lesenswert?

hallo,

ich habe ein programm - welches eine 15 MB große Datei (mit 
float-werten)
abspeichert. Dabei steigt kuzrfisitig die CPU-Last auf 100 % - was dazu 
führt - das andere Prozesse (auch mit höherer Prio) kurzzeitig nicht 
abgearbeitet werden können.

Für das Speichern benutze ich die fprintf().
Dateiformat ist CSV (binär-format senkt die Leistung zwar ein wenig - es 
kommt trotzdem teilweise zu hängern in den Prozessen).
Programmiersprache ist C.

Gibt es eine Möglichkeit/Verfahren die CPU beim Speichern einer Datei 
nicht so stark zu belasten ? ?

von Peter II (Gast)


Lesenswert?

Wenn es bei Binary auch noch der Fall ist, dann stimmt etwas mit deinen 
system nicht. Oder dein Code ist suboptimal.

15mb kann man bequem unter 1s rausschreiben und das ohne CPU last.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Du könntest, anstatt alles in einem Rutsch zu speichern, Dir mehr Zeit 
dabei lassen, also zwischen n Datensätzen eine Pause einlegen.

Oder --sofern es das von Dir nicht erwähnte Betriebssystem zulässt-- die 
Priorität Deines Prozesses dynamisch reduzieren.

von (prx) A. K. (prx)


Lesenswert?

max .. schrieb:

> Gibt es eine Möglichkeit/Verfahren die CPU beim Speichern einer Datei
> nicht so stark zu belasten ? ?

Im Disk-Driver DMA einschalten.

von PittyJ (Gast)


Lesenswert?

Kann das vielleicht ein Virenscanner sein, der die Datei nochmals 
analysiert?

von Florian P. (db1pf)


Lesenswert?

Hallo,

evtl hilft es die Daten vorher in eine Variable zu schreiben und erst 
zum Schluss alles auf einmal auf die Platte. Das hat den Vorteil, dass 
du DMA besser aus nützt da alle Daten auf einmal transportiert werden 
können anstatt in kleinen Happen.

Grüße,
Florian

von Udo S. (urschmitt)


Lesenswert?

Das sind doch wohl eher die 2 Millionen fprintf die Float in String 
konvertieren müssen.
Wenn es IO wäre würde die CPU Auslastung nicht auf 100% steigen. Siehe 
z.b. CPU Auslastung in Windows beim Booten.

von Udo S. (urschmitt)


Lesenswert?


von Peter II (Gast)


Lesenswert?

Udo Schmitt schrieb:
> Das sind doch wohl eher die 2 Millionen fprintf die Float in String
> konvertieren müssen.

er schreibt aber das es auch bei binary der FAll ist. Dazu nimmt man 
aber nicht fprintf;

von Udo S. (urschmitt)


Lesenswert?

Peter II schrieb:
> er schreibt aber das es auch bei binary der FAll ist. Dazu nimmt man
> aber nicht fprintf;
Wenn er damit nur das Format beim Öffnen der Datei meint (fopen("...", 
"wb")) schon.

von max .. (vbc2011)


Lesenswert?

hallo,

das sind ja schonmal viel anhaltspunkte. danke dafür!

also - das mit einem sleep(x) während dem speichern habe schon versucht 
- alle n-Werte einen sleep von x ms. Da sieht man deutlich wie die CPU 
Last runtergeht und es kommt auch jeder Prozess wiede dran! ! !

Virenscanner ist durchaus möglich!
Aber die Umwandlung von float in string könnte nat. auch die ursache 
sein!

Ich mache mich mal bzgl. dieser 2 Themen schlau - bzw. gehe der Sache 
mal auf den Grund.

An Florian Pfanner:
Bzgl. DMA - da kenne ich mich leider nicht aus - kannst du mir da noch 
etwas konkreter drauf eingehen ?! ?!

Danke

von Peter II (Gast)


Lesenswert?

max .. schrieb:
> Bzgl. DMA - da kenne ich mich leider nicht aus - kannst du mir da noch
> etwas konkreter drauf eingehen ?! ?!

kopiere einfach mal eine grosse Datei auf deiner Festplatte - wie 
verhält sich das deine CPU? Sie sollte dabei auf keinen Fall auf 100% 
gehen.

Als nächste teste mal ohne das Rausschreiben, wie sich dann dein 
Programm verhält.

von Florian P. (db1pf)


Lesenswert?

Hallo,

normal musst du dich um DMA nicht kümmern. Das macht das Betriebssystem 
für dich. Wenn du z.B. eine Datei aus dem RAM auf die Festplatte 
speichern möchtest, dann gibt das Betriebssystem dem DMA-Controller die 
Anweisung die Daten vom RAM in den Speicher der Festplatte zu schaufeln. 
Die CPU muss sich dann nicht weiter darum kümmern und kann seine Zeit 
mit anderen Threads verbringen.
Wenn du aber jetzt ständig kleine Datenmengen schreibst, so hat DMA 
keinen Einfluss: Das initialisieren der DMA übertragung ist für die CPU 
dann genau so aufwändig wie das direkte schreiben der Daten an die 
Festplatte. Man merkt den Unterschied z.B. bei folgenden Schleifen:
1
for (i=0;i<1000000;i++)
2
{
3
  fwrite("t", 1, 1, fptr);
4
}
1
char buffer[1000000];
2
for (i=0;i<1000000;i++)
3
{
4
  buffer[i]='t';
5
}
6
fwrite(buffer, 1, 1000000, fptr);

Im zweiten Fall werden alle Zeichen auf einmal zur Festplatte 
übertragen, im ersten Fall häppchenweise. Normal ist im Betriebssystem 
zwar noch ein Puffer dazwischen, aber das zweite Programm ist trotzdem 
schneller.
Deshalb programmiere ich solche ausgeben normalerweise so, dass der 
Inhalt der Datei erst im RAM zusammengestellt wird und erst im Anschluss 
in einem Rutsch auf die Platte geschrieben wird.


Ich hoffe ich konnte dir damit weiterhelfen,
Grüße,
Florian

von Μαtthias W. (matthias) Benutzerseite


Lesenswert?

Florian Pfanner schrieb:
> Deshalb programmiere ich solche ausgeben normalerweise so, dass der
> Inhalt der Datei erst im RAM zusammengestellt wird und erst im Anschluss
> in einem Rutsch auf die Platte geschrieben wird.

Und dann noch vorbei an irgendwelchen Bibliotheksfunktionen von C 
(fwrite) sondern direkt mit den OS Funktionen (write unter Unix, 
WriteFile für die DOSe) Das kann auch nochmal deutlich was bringen.

Matthias

von Peter II (Gast)


Lesenswert?

Μαtthias W. schrieb:
> Und dann noch vorbei an irgendwelchen Bibliotheksfunktionen von C
> (fwrite) sondern direkt mit den OS Funktionen (write unter Unix,
> WriteFile für die DOSe) Das kann auch nochmal deutlich was bringen.
ja uns zwar viele Probleme. Dann dann weiss die C-Lib teilweise nichts 
von der Datei. Wenn man dann die Datei gleich noch kopiere oder lesen 
will gibt es merkwürdige effekte.

Es mag vieleicht noch mal 0.1% bringen aber ich würde es nicht 
freiwillig machen.

von max .. (vbc2011)


Lesenswert?

hi,

danke - das sind alles wertvolle tipps.

ich habe mal die Konvert - Funktionen von diesem link
Beitrag "C-Umwandlungsfunktionen für double/int/long nach String"
in mein Programm eingebaut ( da wird in einem Zwischenschritt "manuell" 
ein Float in einen String gewandelt).

Die Vorkonvertierung hat deutlich was an meinen Speicherzeiten bzw. 
CPU-Auslastung und dem Einhalten des Timings anderer Prozesse gebracht.
Speicherzeit von ca. 1.5 s auf 0.3 s gesenkt (leider gibt es selten noch 
Ausreisser mit 1.5s) -> d.h. der Ansatz scheint richtig zu sein ! !

for( idx = 0; idx < Array->Anzahl; idx++ )
{
 ftoa( tempbuf, Array->Wert[idx], preC, postC, accuracy );
 fprintf( CSVDatei, "%s;\n", tempbuf );
}

(wobei Anzahl = 500000 und Wert vom Typ float ist)

das einmalige schreiben der Datei hat leider keine Auswirkung im 
Vergleich zum häppchenweisen schreiben (siehe oben)- da prüfe ich 
nochmals ob ich da alles richtig mache.

Danke soweit.

von Udo S. (urschmitt)


Lesenswert?

max .. schrieb:
> fprintf( CSVDatei, "%s;\n", tempbuf );

Und da hast du den nächsten printf drin. Da wird wieder Array-Anzahl mal 
ein printf aufgerufen der Format String geparst etc.
Max, es gibt fputs() das ist 10 mal schneller!
also
{
  fputs(fp, tempbuf);
  fputs(fp, "\n");
}

von Udo S. (urschmitt)


Lesenswert?

Peter II schrieb:
> Μαtthias W. schrieb:
>> Und dann noch vorbei an irgendwelchen Bibliotheksfunktionen von C
>> (fwrite) sondern direkt mit den OS Funktionen (write unter Unix,
>> WriteFile für die DOSe) Das kann auch nochmal deutlich was bringen.
> ja uns zwar viele Probleme. Dann dann weiss die C-Lib teilweise nichts
> von der Datei. Wenn man dann die Datei gleich noch kopiere oder lesen
> will gibt es merkwürdige effekte.
>
> Es mag vieleicht noch mal 0.1% bringen aber ich würde es nicht
> freiwillig machen.

Microsoft empfiehlt AUSDRÜCKLICH nicht mehr die file IO Funktionen der C 
Runtime zu benutzen, sondern die WIN32 API Funktionen.
Wir hatten hier mal ein Problem mit einem zyklischen Versatz bei Dateien 
> 2GByte. Es hatte sich herausgestellt, daß das durch das Schreiben mit 
stdio Funktionen kam.
Ein Request bei Microsoft aufgemacht brachte nur die lapidare Meldung 
das wäre bekannt und würde auch nicht gefixt, man solle auf die Windows 
File Funktionen ausweichen.

Toll wenn der Code für 3 verschiedene Unixe, Windows, OS/2 und Host 
laufen musste.

von Peter II (Gast)


Lesenswert?

Udo Schmitt schrieb:
> Microsoft empfiehlt AUSDRÜCKLICH nicht mehr die file IO Funktionen der C
> Runtime zu benutzen, sondern die WIN32 API Funktionen.

wenn man nur noch die API Funktionen nutzt ist es ja ok, man sollte nur 
nicht mixen. Das hatte bei uns mal zu merkwürdigen effekten geführt.

von Robert L. (lrlr)


Lesenswert?

meiner meinung nach sollte man sich zwei buffer machen nicht zu groß, 
nicht zu klein (sagen wir mal zwischen 4kByte und 1Mbyte )

dazu 2 thread (priority unter normal)
der 1 thread bereitet immer die daten auf (zuerst im buffer 1 dann im 2. 
)
während der 2. thread  den buffer 2 auf die platte schreibt (und dann 
den 1.  usw)
der schnellere thread muss immer so lange warten bis der nächste buffer 
fertig ist ..

irgendwer schaut noch, dass der langsamere nach jedem lauf eine kurze 
pause macht..

oder so...

der Haupt-thread macht möglichst wenig (messages abarbeiten, 
progressbar, threads managen...

von Udo S. (urschmitt)


Lesenswert?

Robert L. schrieb:
> meiner meinung nach sollte man sich zwei buffer machen nicht zu groß,
> nicht zu klein (sagen wir mal zwischen 4kByte und 1Mbyte )
>
> dazu 2 thread (priority unter normal)
> der 1 thread bereitet immer die daten auf (zuerst im buffer 1 dann im 2.
> )

Sorry aber man kann auch ein einfaches Speichern von ein paar mehr Daten 
mit einem Jumbo Jet erschlagen
(Meine Meinung)
Vieleicht sollte man vorher einfach mal analysieren wo die Zeit 
verschwendet wird.
Hier war es wohl ganz einfach die unbedarfte Benutzung von fprintf(...) 
in einer Schleife die über ein Millionen Mal durchlaufen wird.
Das printf Funktionen teuer sind habe ich in der ersten Woche C lernen 
gelernt. Ich meine das stand sogar im Kerningham Ritchie.

von Sven P. (Gast)


Lesenswert?

Udo Schmitt schrieb:
> Ein Request bei Microsoft aufgemacht brachte nur die lapidare Meldung
> das wäre bekannt und würde auch nicht gefixt, man solle auf die Windows
> File Funktionen ausweichen.
Na siehst du, wenn dem tatsächlich so ist, wäre das ein guter Grund 
mehr, endlich weg vom MS-Compiler zu gehen...

Ich weiß ja nicht, was und wie dein Programm funktioniert, aber generell 
empfehle ich ganz dringend:
Schreib Programme so, wie sie arbeiten sollen. Wenn ein Programm einen 
sequenziellen Datenstrom in einer Datei ablegen muss, dann soll das auch 
schlicht und ergreifend genau so geschehen. Ohne Threads, low-level-I/O, 
separate Puffer und Zwischenspeicher.

Was diese beiden Testprogramme angeht:
1
/* Variante 1 */
2
for (i=0;i<1000000;i++)
3
{
4
  fwrite("t", 1, 1, fptr);
5
}
6
7
/* Variante 2 */
8
char buffer[1000000];
9
for (i=0;i<1000000;i++)
10
{
11
  buffer[i]='t';
12
}
13
fwrite(buffer, 1, 1000000, fptr);

Ich kann exakt garkeinen Unterschied feststellen, selbst auf meiner 
alten Mühle. Vorallem sollte das aber dein OS nicht ausbremsen. Da 
solltest du mal nachhaken.

von Peter II (Gast)


Lesenswert?

Sven P. schrieb:
> Was diese beiden Testprogramme angeht:/* Variante 1 */
> for (i=0;i<1000000;i++)
> {
>   fwrite("t", 1, 1, fptr);
> }
>
> /* Variante 2 */
> char buffer[1000000];
> for (i=0;i<1000000;i++)
> {
>   buffer[i]='t';
> }
> fwrite(buffer, 1, 1000000, fptr);
>
> Ich kann exakt garkeinen Unterschied feststellen, selbst auf meiner
> alten Mühle. Vorallem sollte das aber dein OS nicht ausbremsen. Da
> solltest du mal nachhaken.

Dann hast du falsch getestet. Ich konnte es ohne Problme bei der 
10fachen Datenmenge nachvollziehen. Was auch klar ist, dann es sind dann 
10.000.000 funktionsaufrufe mehr. Jeder aufruf braucht nun mal ein paar 
Takte, damit muss es einen unterschied geben.

Bei mir waren es bei der 10fache menge 0.1s statt 2 sekunden.


> Ich weiß ja nicht, was und wie dein Programm funktioniert, aber generell
> empfehle ich ganz dringend:
> Schreib Programme so, wie sie arbeiten sollen.
Wenn man so rangeht ist ja klar das die PCs immer schneller werden aber 
die Programme immer langsamer. Man sollte als Programmiere auch mal über 
den Resourcenverbrauch nachdenken.

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Wenn man schon optimieren will dann bitte gleich mit MemoryMappedFiles 
arbeiten, da buffert das BS gleich selbst ;)

Ansonsten stimme ich haku zu, solche Optimierungen ins blaue Bringen 
selten etwas..

Peter II schrieb:
> Man sollte als Programmiere auch mal über
> den Resourcenverbrauch nachdenken.
Welchen? Dein Programm braucht viel mehr Speicher im zweiten fall ;-P

von Sven P. (Gast)


Lesenswert?

Peter II schrieb:
> Dann hast du falsch getestet.
Dann hat er/sie ein falsches Beispielprogramm veröffentlicht.

>> Ich weiß ja nicht, was und wie dein Programm funktioniert, aber generell
>> empfehle ich ganz dringend:
>> Schreib Programme so, wie sie arbeiten sollen.
> Wenn man so rangeht ist ja klar das die PCs immer schneller werden aber
> die Programme immer langsamer.
Das ist Humbug. Es ist nicht deine Aufgabe als Anwendungsprogrammierer, 
Festplatten-I/O zu optimieren, dafür sind Kernelleute zuständig. 
Möglicherweise verschlechterst du mit deinen handgemachten Puffern die 
Performance sogar noch drastisch. Selbstverständlich aber könnte man 
fprintf() durch fputs() ersetzen, wo es möglich ist.

> Man sollte als Programmiere auch mal über
> den Resourcenverbrauch nachdenken.
Also lieber gleich 64 Bit benutzen, weil sonst der unter Windoof 
adressierbare Arbeitsspeicher sonst nicht mehr für den Zwischenspeicher 
ausreicht oder was?
PCs werden in erster Linie immer 'langsamer', weil jeder meint, noch 
zehn Lagen JIT und Script und Wrapper einbauen zu müssen. Mir rollts die 
Zehennägel auf, wenn ich mir angucke, was sich MS unter effizienter 
Anwendungsentwicklung vorstellt.

Die wichtigste Regel beim Optimieren lautet: Tu es nicht.
Die zweit-wichtigste lautet: Tu es noch nicht...
Krieg mal nen klaren Kopf und les The Art Of UNIX Programming, das ist 
wirklich einen Blick wert!

von Peter II (Gast)


Lesenswert?

Sven P. schrieb:
> Das ist Humbug. Es ist nicht deine Aufgabe als Anwendungsprogrammierer,
> Festplatten-I/O zu optimieren, dafür sind Kernelleute zuständig.

Es geht hierbei überhaupt nicht um das IO und irgendwelche Puffer. Der 
unterschied kommt nur von den anzahl der Funktionsaufrufe. Da kann Linux 
oder MS überhaupt nichts machen - das ist aufgabe das Programmieres.

> Mir rollts die
> Zehennägel auf, wenn ich mir angucke, was sich MS unter effizienter
> Anwendungsentwicklung vorstellt.
meinst du .net?

Und warum auf MS schimpfen wenn die Firefox leute selber den Browser als 
HTML darstellen und erweiterungen als Javascript bauen.

von Sven P. (Gast)


Lesenswert?

Peter II schrieb:
> Sven P. schrieb:
>> Das ist Humbug. Es ist nicht deine Aufgabe als Anwendungsprogrammierer,
>> Festplatten-I/O zu optimieren, dafür sind Kernelleute zuständig.
>
> Es geht hierbei überhaupt nicht um das IO und irgendwelche Puffer. Der
> unterschied kommt nur von den anzahl der Funktionsaufrufe. Da kann Linux
> oder MS überhaupt nichts machen - das ist aufgabe das Programmieres.
Doch, zwei Beiträge weiter oben geht es um Puffer, und weiter davor um 
Prioritäten und allerlei Krams.

>> Mir rollts die
>> Zehennägel auf, wenn ich mir angucke, was sich MS unter effizienter
>> Anwendungsentwicklung vorstellt.
> meinst du .net?
Ja, auch.

> Und warum auf MS schimpfen wenn die Firefox leute selber den Browser als
> HTML darstellen und erweiterungen als Javascript bauen.
Macht es das jetzt besser?
FireBug ist ja schon unerträglich langsam. Firefox sowieso.

von max .. (vbc2011)


Lesenswert?

schön das das thema für so viel gesprächstoff sorgt - aber wir sollten 
mal bei dem eigentlichen thema bleiben :)

wie weiter oben vorgeschlagen - habe ich nun zum einen die 
konvert-funktion und zum anderen die fputs() verwendet.

for( idx = 0; idx < Array->Anzahl; idx++ )
{
    ftoa( tempbuf, Array->Wert[idx], preC, postC, accuracy );
    //fprintf( CSVDatei, "%s;\n", tempbuf );
    fputs(tempbuf,CSVDatei);
    fputs(";\n",CSVDatei);
}

Ergebnis ist nun - das alle zeiten wieder gesunkten sind - es tauchen 
jedoch immernoch unregelmäßig zeitliche Peaks auf. Ich denke da spuckt 
einfach noch etwas anderen mit rein.
Aber letztlich wurde durch die ftoa und fputs schon gut optimiert.
Damit würde ich dieses Thema abschließen.

Danke für die Hilfe - weiter so ! !

von Sven P. (Gast)


Lesenswert?

Du bist dir dann auch im Klaren, wo ftoa herkommt, ja?

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.