C - CPU Auslastung beim Datei speichern reduzieren

#2428319
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 ? ?
#2428576
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
Gast #2428579
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.
#2428700
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
Persönliche Seite #2428918
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
Gast #2428936
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.
#2429983
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.
#2430004
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.
#2430032
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...
#2430049
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.
Gast #2430099
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.
Gast #2430105
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.
Persönliche Seite #2430109
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
Gast #2430123
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!
Gast #2430129
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.
Gast #2430159
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.
#2430728
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 ! !

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren