Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

fwrite() von verschiedenen quellen

12 views
Skip to first unread message

Markus Lausser

unread,
Jan 19, 2002, 11:33:32 PM1/19/02
to
Hallo mal wieder.

Ich will von verschiedenen quellen in ein und die selbe Datei schreiben.
Es koennen durchaus 10 verschieden Quellen sein, eine quelle will pro
Sekunde oft in die Datei schreiben (einige hundert Mal kann schon sein).
Jede quelle schreibt an eine bestimmte Position, Ueberschneidungen
gibt es nicht (multi source download).

Wie loest man das am besten?
Kann man fuer jede Quelle die Datei oeffen und schreiben?
Im moment oeffne ich die Datei nur einmal und seeke bei jedem
schreibvorgang an die richtige stellen, allerdings scheint etwas ineffizient
zu sein.
Oder sollte ich am besten die Daten puffern und dann in groesseren Paketen
schreiben, damit ich fseek() nicht so oft brauche.

Eigentlich interessiert mich, ist es recourcesaufwenig fseek() ein paar
tausend mal pro sekunde aufzurufen?

Markus.

Erich Frühstück

unread,
Jan 19, 2002, 11:51:33 PM1/19/02
to
In article <slrna4ki4j....@sauron.forwiss.uni-passau.de>,

Das IO-System wird hoch belastet. Sieh dir mal mmap an.

Grüße
Erich
--
EFEU is great (development tools, C libraries, interpreter language, ...).
Get the open source from http://efeu.cybertec.at now.

Stefan Mussmann

unread,
Jan 20, 2002, 4:27:33 AM1/20/02
to
Markus Lausser <lau...@sauron.forwiss.uni-passau.de> schrieb:

> Kann man fuer jede Quelle die Datei oeffen und schreiben?
> Im moment oeffne ich die Datei nur einmal und seeke bei jedem
> schreibvorgang an die richtige stellen, allerdings scheint etwas ineffizient
> zu sein.
> Oder sollte ich am besten die Daten puffern und dann in groesseren Paketen
> schreiben, damit ich fseek() nicht so oft brauche.

Ich hab' in dem Bereich zwar auch noch keine Versuche angestellt, aber ich
könnte mir vorstellen, daß es performanter wäre, für jede Quelle eine eigene
Pufferdatei anzulegen. Am Ende des Downloads werden dann diese Datenbloecke
mittels fread/fwrite zu einer Gesamtdatei zusammengesetzt...


Ciao,
Stefan

--
MCSE = Minesweeper Consultant & Solitaire Expert

Markus Lausser

unread,
Jan 20, 2002, 6:46:42 PM1/20/02
to
On Sun, 20 Jan 2002 05:51:33 +0100, Erich Frühstück wrote:
> > Eigentlich interessiert mich, ist es recourcesaufwenig fseek() ein paar
> > tausend mal pro sekunde aufzurufen?
>
> Das IO-System wird hoch belastet. Sieh dir mal mmap an.

Ok, mmap sieht vielversprechend aus, jetzt funktioniert das
aber bei mir nicht.

ich oeffne die datei mit (wobei die datei nicht existieren muss).

fd = open(filename, O_WRONLY|O_CREAT,
S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);

buffer = mmap(NULL, 1048576, PROT_WRITE, MAP_SHARED,
fd, offset);
/* offset kann hinter dem fileende liegen. */
result =
recv(source, &(buffer[pos]), few_kbs, 0);

mmap() schlaegt hier fehl mit errno 13 [Permission denied].
Die datei wurde mit den richtigen permissions erstellt.
Was stimmt hier nicht?
Kann man mmap auf dateiteile anwenden, die noch nicht existieren?
mmap() bringt jedenfalls den gleichen fehler, auch wenn die Datei
schon in genuegender Groesse existiert.

Markus.

Erich Frühstück

unread,
Jan 21, 2002, 12:13:32 AM1/21/02
to
In article <slrna4mlmq....@sauron.forwiss.uni-passau.de>,

Die Datei muss auch zum lesen geöffnet werden:
O_WRONLY -> O_RDWR.

Die Datei muss bereits die richtige Grösse haben (abfrage mit lstat),
wenn nicht, hilft z.B.
char c = 0;
lseek(fd, SIZE - 1, SEEK_SET);
write(fd, &c, 1);

mmap kann auch auf Dateiteile angewand werden. Alle Adress- und
Größenangaben für mmap müssen auf die Speicherseitengröße
ausgerichtet sein (man 2 getpagesize).

Markus Lausser

unread,
Jan 21, 2002, 11:26:28 AM1/21/02
to
On Mon, 21 Jan 2002 06:13:32 +0100, Erich Frühstück wrote:
> > Ok, mmap sieht vielversprechend aus, jetzt funktioniert das aber bei
> > mir nicht.
> >
> > ich oeffne die datei mit (wobei die datei nicht existieren muss).
> >
> > fd = open(filename, O_WRONLY|O_CREAT,
> > S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
> >
> > buffer = mmap(NULL, 1048576, PROT_WRITE, MAP_SHARED,
> > fd, offset);
> > /* offset kann hinter dem fileende liegen. */
> > result =
> > recv(source, &(buffer[pos]), few_kbs, 0);
> >
> > mmap() schlaegt hier fehl mit errno 13 [Permission denied]. Die datei
> > wurde mit den richtigen permissions erstellt. Was stimmt hier nicht?
> > Kann man mmap auf dateiteile anwenden, die noch nicht existieren? mmap()
> > bringt jedenfalls den gleichen fehler, auch wenn die Datei schon in
> > genuegender Groesse existiert.
>
> Die Datei muss auch zum lesen geöffnet werden:
> O_WRONLY -> O_RDWR.

Hm, haette ich auch selbst darauf kommen koennen.

> Die Datei muss bereits die richtige Grösse haben (abfrage mit lstat),
> wenn nicht, hilft z.B.
> char c = 0;
> lseek(fd, SIZE - 1, SEEK_SET);
> write(fd, &c, 1);
>
> mmap kann auch auf Dateiteile angewand werden. Alle Adress- und
> Größenangaben für mmap müssen auf die Speicherseitengröße
> ausgerichtet sein (man 2 getpagesize).

Bereits gemacht, das steht auch in der manpage (ja, ich hab sie gelesen:)
Btw. kann ich auch fopen() und dann mmap(..., fileno(file), ...) benutzen?
Ich benutze naemlich normalerweise die f-funktionen...

Danke vorerst fuer die hilfreichen tipps.

Markus.

Felix von Leitner

unread,
Jan 21, 2002, 1:46:01 PM1/21/02
to
Thus spake Markus Lausser (lau...@sauron.forwiss.uni-passau.de):

> Ich will von verschiedenen quellen in ein und die selbe Datei schreiben.

Aus einem Prozeß oder aus mehreren?

> Es koennen durchaus 10 verschieden Quellen sein, eine quelle will pro
> Sekunde oft in die Datei schreiben (einige hundert Mal kann schon sein).
> Jede quelle schreibt an eine bestimmte Position, Ueberschneidungen
> gibt es nicht (multi source download).

Spielt genau keine Rolle, solange die zu schreibenden Daten in den
Speicher passen.

> Wie loest man das am besten?

man mmap, man pwrite.

> Kann man fuer jede Quelle die Datei oeffen und schreiben?

Ja.

> Im moment oeffne ich die Datei nur einmal und seeke bei jedem
> schreibvorgang an die richtige stellen, allerdings scheint etwas ineffizient
> zu sein.

Mehrere Dateien mache das nicht effizienter.

> Oder sollte ich am besten die Daten puffern und dann in groesseren Paketen
> schreiben, damit ich fseek() nicht so oft brauche.

Das Betriebssystem puffert für dich, wenn es nicht völlig für den Fuß ist.

> Eigentlich interessiert mich, ist es recourcesaufwenig fseek() ein paar
> tausend mal pro sekunde aufzurufen?

Nein. Bei einer intelligenten libc kostet libc gar nichts, weil es lazy
evaluiert werden kann. Und wenn jeweils ein write folgt, dann ist das
halt ein syscall, davon kann man unter Linux auf einem modernen Rechner
echt viele machen.

#include <unistd.h>
main() {
long l;
for (l=0; l<1000000; ++l)
lseek(0,0,0);
}

läuft bei mir nicht mal ne viertel Sekunde lang.

Felix

Oliver Blasnik

unread,
Jan 21, 2002, 7:10:48 PM1/21/02
to
Hmhmh, eigentlich wollt ich mich garnich einmischen, aber... ;)

Felix von Leitner <usenet-...@fefe.de> schrieb

[seek/write und Performanz]

> > Wie loest man das am besten?
> man mmap, man pwrite.

Da kann ich nur zustimmen, nur bei Folgendem nicht mehr wirklich:

> > Oder sollte ich am besten die Daten puffern und dann in groesseren Paketen
> > schreiben, damit ich fseek() nicht so oft brauche.
> Das Betriebssystem puffert für dich, wenn es nicht völlig für den Fuß ist.

Ohne jetzt die exakte Implementation zu kennen behaupte ich ungesehen, dass
ein seek nach einem write (spätestens jedoch vor dem nächsten write) eventuell
vorhandene Buffer flushed. Es ist nicht wirklich einfach, grade mal nen File-
pointer zu ändern und trotz allem einen (linearen) Buffer zu verwalten ;)
Bei einem mmaped File sieht das schon wieder etwas anders aus, da kann man
schön zaubern...

> > Eigentlich interessiert mich, ist es recourcesaufwenig fseek() ein paar
> > tausend mal pro sekunde aufzurufen?
> Nein. Bei einer intelligenten libc kostet libc gar nichts, weil es lazy
> evaluiert werden kann.

Ich tippe mal drauf, dass das letztere "libc" ein "fseek" sein sollte?
In diesem Falle hast Du mit Deiner Antwort natürlich auch recht, nur mag
da jemand gerne noch ein paar Bytes in die Datei schreiben, in der er wie
ein Wilder durch-die-Gegend-seekt (so klingt es jedenfalls).

> davon kann man unter Linux auf einem modernen Rechner
> echt viele machen.

Hm. Sorry, aber das ist für mich ein Gates-Ansatz: Hey, wir haben doch
schnellere Rechner, da braucht sich keiner um Optimierung zu kümmern.

> Felix

Sorry, Olli

Markus Lausser

unread,
Jan 21, 2002, 8:40:28 PM1/21/02
to

Wenn ich Dich richtig verstanden habe dann kann ich es mit einer der
folgenden Moeglichkeiten machen (ich habe nur einen Prozess):
* Datei pro Quelle oeffnen und zur richtigen Position springen,
und dann pro quelle einfach subsequent schreiben
* Datei einmal oeffnen, und jede Quelle seeked bei jeden Schreibvorgang
immer zur richtigen Position
* mmap fuer jede Quelle benutzen und in den Speicher schreiben

Die Zieldatei kann uebrigens bis zu 1GB gross sein (oder sogar noch groesser,
was aber selten der Fall ist)

Ich frage mich nun, warum Du mir oben mmap() empfiehlst, wenn die
anderen beiden Loesungen genauso funktionieren.

Markus.

Felix von Leitner

unread,
Jan 22, 2002, 5:18:42 AM1/22/02
to
Thus spake Oliver Blasnik (r...@taunus-biker.de):

> > > Oder sollte ich am besten die Daten puffern und dann in groesseren Paketen
> > > schreiben, damit ich fseek() nicht so oft brauche.
> > Das Betriebssystem puffert für dich, wenn es nicht völlig für den Fuß ist.
> Ohne jetzt die exakte Implementation zu kennen behaupte ich ungesehen, dass
> ein seek nach einem write (spätestens jedoch vor dem nächsten write) eventuell
> vorhandene Buffer flushed.

Behaupten kannst du alles mögliche, aber es ist sinnvoll, dich auf
Sachen zu beschränken, bei denen du dich auskennst. Betriebssysteme
gehören offensichtlich nicht dazu.

> Es ist nicht wirklich einfach, grade mal nen File-
> pointer zu ändern und trotz allem einen (linearen) Buffer zu verwalten ;)
> Bei einem mmaped File sieht das schon wieder etwas anders aus, da kann man
> schön zaubern...

Was denkst du denn, wie der kernel read() und write() implementiert?
Der mappt natürlich auch das File in den Speicher und fummelt dann
darin herum! lseek ist das Setzen einer Variablen im Kernel Space.

> > > Eigentlich interessiert mich, ist es recourcesaufwenig fseek() ein paar
> > > tausend mal pro sekunde aufzurufen?
> > Nein. Bei einer intelligenten libc kostet libc gar nichts, weil es lazy
> > evaluiert werden kann.
> Ich tippe mal drauf, dass das letztere "libc" ein "fseek" sein sollte?

Nein. fseek ist in der libc, lseek ist ein Syscall.

Warum müssen im Usenet eigentlich ständig Leute über Sachen posten, von
denen sie keine Ahnung haben.

> > davon kann man unter Linux auf einem modernen Rechner
> > echt viele machen.
> Hm. Sorry, aber das ist für mich ein Gates-Ansatz: Hey, wir haben doch
> schnellere Rechner, da braucht sich keiner um Optimierung zu kümmern.

Die Frage war, ob lseek ein Performance-Problem ist. Die Antwort ist:
nein. Mit Optimieren hat das nichts zu tun. Man optimiert auf geringe
Laufzeit, und wenn seek eine billige Operation ist, dann optimiert ist
dieses Wissen Grundlage für jede Optimierung. Mit Gates hat das nichts
zu tun. Warum kommst du nicht wieder, wenn du mal was programmiert
hast?

Felix von Leitner

unread,
Jan 22, 2002, 5:22:56 AM1/22/02
to
Thus spake Markus Lausser (lau...@sauron.forwiss.uni-passau.de):
> Wenn ich Dich richtig verstanden habe dann kann ich es mit einer der
> folgenden Moeglichkeiten machen (ich habe nur einen Prozess):
> * Datei pro Quelle oeffnen und zur richtigen Position springen,
> und dann pro quelle einfach subsequent schreiben
> * Datei einmal oeffnen, und jede Quelle seeked bei jeden Schreibvorgang
> immer zur richtigen Position
> * mmap fuer jede Quelle benutzen und in den Speicher schreiben

> Die Zieldatei kann uebrigens bis zu 1GB gross sein (oder sogar noch groesser,
> was aber selten der Fall ist)

Du willst also sowas wie edonkey implementieren, wenn ich das richtig
sehe. Das Problem mit mmap ist, daß auf 32-bit Prozessoren der
adressierbare Speicher limitiert ist, d.h. du kannst nicht zehn
1GB-Dateien mappen. Daher erspart dir auch mmap kein Haushalten.
Es macht auf jeden Fall Sinn, die Blöcke mindestens 16 KB groß zu halten
und Schreiboperationen zum Betriebssystem nur mit vollen Blöcken zu
machen. Ich kann mir aber in keinem Fall vorstellen, daß das
Betriebssystem-Interface am Ende die Performance dominieren wird, weil
das Netzwerk gewöhnlich mindestens eine Größenordnung langsamer ist als
der Rechner intern.

Wenn ich das implementieren müßte, würde ich mmap nehmen, und wenn die
Summe der zu mappenden Daten zu groß wird, würde ich auf eine
Buffer-Verwaltung mit 16k-Blöcken umsteigen und pwrite benutzen.

> Ich frage mich nun, warum Du mir oben mmap() empfiehlst, wenn die
> anderen beiden Loesungen genauso funktionieren.

Wenn du von Berlin nach Hamburg fährst, kannst du den Zug nehmen,
fliegen oder Autofahren. Welche davon für dich Sinn macht, mußt du
schon selber entscheiden.

Felix

Markus Lausser

unread,
Jan 22, 2002, 11:18:44 AM1/22/02
to
On Tue, 22 Jan 2002 10:22:56 GMT, Felix von Leitner wrote:
>
> Du willst also sowas wie edonkey implementieren, wenn ich das richtig
> sehe.

Ganz genau, nur ist das fuer das opennap protokoll.

> Das Problem mit mmap ist, daß auf 32-bit Prozessoren der
> adressierbare Speicher limitiert ist, d.h. du kannst nicht zehn
> 1GB-Dateien mappen.

Daran hatte ich auch nie gedacht. Im moment mappe ich fuer jede Quelle
einen 1MB Block und schreibe darin, wenn das ende eine Blocks erreicht ist,
dann wird er ge-unmapped und ein neuer gemapped.

> Daher erspart dir auch mmap kein Haushalten.
> Es macht auf jeden Fall Sinn, die Blöcke mindestens 16 KB groß zu halten
> und Schreiboperationen zum Betriebssystem nur mit vollen Blöcken zu
> machen. Ich kann mir aber in keinem Fall vorstellen, daß das
> Betriebssystem-Interface am Ende die Performance dominieren wird, weil
> das Netzwerk gewöhnlich mindestens eine Größenordnung langsamer ist als
> der Rechner intern.
>
> Wenn ich das implementieren müßte, würde ich mmap nehmen, und wenn die
> Summe der zu mappenden Daten zu groß wird, würde ich auf eine
> Buffer-Verwaltung mit 16k-Blöcken umsteigen und pwrite benutzen.

Wie gesagt, 1MB pro block, macht 10MB bei 10 quellen, macht 100MB bei 10
dateien, die ich downloade (aber wer downloaded schon von 100 quellen?).

Was passiert eingentlich bei nem crash mit den Daten, die ich in den
map-speicher geschrieben habe? Die manpage sagt, dass bei ner programm
termination ge-unmapped wird, heisst das: sobald ich in den speicher
geschrieben habe, kann ich davon ausgehen, dass die Daten auch in der
Datei sein werden (wenn ich nicht grade die Datei schliesse, ohne zu
unmappen..)

Markus.

Ingo Oeser

unread,
Jan 22, 2002, 11:52:04 AM1/22/02
to
Markus Lausser <lau...@sauron.forwiss.uni-passau.de> wrote:
> Was passiert eingentlich bei nem crash mit den Daten, die ich in den
> map-speicher geschrieben habe? Die manpage sagt, dass bei ner programm
> termination ge-unmapped wird, heisst das: sobald ich in den speicher
> geschrieben habe, kann ich davon ausgehen, dass die Daten auch in der
> Datei sein werden (wenn ich nicht grade die Datei schliesse, ohne zu
> unmappen..)

Davon ausgehen kannst du bei einem msync(..,O_SYNC,..). Sonst
kannst du maximal davon ausgehen, das einmal in diesen Bereich
geschriebene Daten auf jeden Fall mal auf der Platte landen
werden, wenn dein Prozess vor Absturz/Ausschalten des Rechners
beendet wird. Sogar bei SIGKILL kannst du das noch.

MAP_SHARED hast du ja angegeben, also brauch ich jetzt darauf
nicht eingehen.

Grusz
Ingo
--
Science is what we can tell a computer. Art is everything else. --- D.E.Knuth
>>> 4. Chemnitzer Linux-Tag - 09.+10. Maerz 2002 <<<
http://www.tu-chemnitz.de/linux/tag/

Oliver Blasnik

unread,
Jan 23, 2002, 6:02:51 AM1/23/02
to
*lol*

Der Felix meinte:

> > Ohne jetzt die exakte Implementation zu kennen behaupte ich ungesehen, dass
> > ein seek nach einem write (spätestens jedoch vor dem nächsten write) eventuell
> > vorhandene Buffer flushed.

> Behaupten kannst du alles mögliche, aber es ist sinnvoll, dich auf
> Sachen zu beschränken, bei denen du dich auskennst. Betriebssysteme
> gehören offensichtlich nicht dazu.

[ ] Du kennst mich

> Was denkst du denn, wie der kernel read() und write() implementiert?
> Der mappt natürlich auch das File in den Speicher und fummelt dann
> darin herum!

Das würde voraussetzen, dass der _Kernel_ fuer jedes File ein Read-Ahead
der internen Blockgrösse durchführt. Und natürlich auch unsinnigerweise
bei auch nur EINEM Byte Änderung den kompletten Block wieder zurück-
schreiben müsste. Nun gibt es auch Filesysteme, bei denen das nicht
wirklich Sinn macht. Einen Kernel, der das ohne meinen Willen tut, be-
zeichne ich mal als "kaputt". Merke: es gibt mehr als nur Blockdevices.

Oder verwechselst Du jetzt Kernel und libc?

Und: WENN gepuffert wird (wo&auf welche Art auch immer) und der *seek
geht über die Buf-Grenze hinaus, _muss_ dieser Geschrieben werden
beim nächsten write. Da führt kein Weg dran vorbei. Und nichts
anderes war meine obige Aussage.

Woher nimmst Du Deine obige Aussage?

> lseek ist das Setzen einer Variablen im Kernel Space.

Hier ging es nirgends um lseek:

> > > > Eigentlich interessiert mich, ist es recourcesaufwenig fseek() ein paar
> > > > tausend mal pro sekunde aufzurufen?
> > > Nein. Bei einer intelligenten libc kostet libc gar nichts, weil es lazy
> > > evaluiert werden kann.
> > Ich tippe mal drauf, dass das letztere "libc" ein "fseek" sein sollte?

> Nein. fseek ist in der libc, lseek ist ein Syscall.

| NAME
| lseek - reposition read/write file offset
|
| LIBRARY
| Standard C Library (libc, -lc)

Hu? Wie auch immer es implementiert ist, sowohl lseek als auch fseek be-
finden sich bei mir in der libc. Deine Aussage ist also flasch.

Achso: "lseek?" -> s.o. ;)

> Warum müssen im Usenet eigentlich ständig Leute über Sachen posten, von
> denen sie keine Ahnung haben.

Warum müssen im Usenet immer leute auf Artikel antworten, die sie nicht
mal gelesen haben?

> Die Frage war, ob lseek ein Performance-Problem ist. Die Antwort ist:

Nein, die Frage war, ob fseek ein... ;)

> Warum kommst du nicht wieder, wenn du mal was programmiert hast?

[ ] Du kennst mich wirklich

Cu, Olli, verwundert.


Tipp: Auf deiner Homepage, "Dinge, die ich mag", Punkt 3 und 4

Rainer Weikusat

unread,
Jan 23, 2002, 6:45:33 AM1/23/02
to
"Oliver Blasnik" <r...@taunus-biker.de> writes:
> > Was denkst du denn, wie der kernel read() und write() implementiert?
> > Der mappt natürlich auch das File in den Speicher und fummelt dann
> > darin herum!
>
> Das würde voraussetzen, dass der _Kernel_ fuer jedes File ein Read-Ahead
> der internen Blockgrösse durchführt.

Wie kommst Du auf das schmale Brett?

>
> > Nein. fseek ist in der libc, lseek ist ein Syscall.
>
> | NAME
> | lseek - reposition read/write file offset
> |
> | LIBRARY
> | Standard C Library (libc, -lc)
>
> Hu? Wie auch immer es implementiert ist, sowohl lseek als auch fseek be-
> finden sich bei mir in der libc.

[rw@winter]:~/software/linux/build/2.4/mm $man lseek | head
Reformatting lseek(2), please wait...

LSEEK(2) System calls LSEEK(2)


NAME
lseek - reposition read/write file offset


--
hoffentlich ist es beton

Oliver Blasnik

unread,
Jan 23, 2002, 7:14:14 AM1/23/02
to
Hi,

Rainer meinte:

[Felix: kernel-read/write ist mmap-basiert]

> > Das würde voraussetzen, dass der _Kernel_ fuer jedes File ein Read-Ahead
> > der internen Blockgrösse durchführt.

> Wie kommst Du auf das schmale Brett?

Wenn etwas _in_den_Speicher gemappt wird, muss natürlich erst einmal der
Speicher mit dem (partiellen) Inhalt des Files gefüllt werden. Daher ist
ein Read in der Grösse des entsprechenden Blocks notwendig. Sonst bräuchte
man auch kein mmap...

Tatsaechlich "sieht" man im Speicher ja nicht das File, sondern eine (in
einer RAM-Page erstellte) Kopie des entsprechenden FS-Blocks. Diese
Page (nenne man es "Fenster") wandert bei Zugriffen ausserhalb auf die
neue Location des Files, vorher muss natürlich der Inhalt zurückgeschrieben
werden, falls es eine Invalidierung hab. Üblicherweise handelt es sich
(bei x86) um x 4kB-grosse Speicherblöcke, die jeweils optimal verwendet
werden (erst mal noch valide, ungenutzte Blöcke moven).

> > > Nein. fseek ist in der libc, lseek ist ein Syscall.

> > | lseek - reposition read/write file offset

> > | Standard C Library (libc, -lc)
> > Hu? Wie auch immer es implementiert ist, sowohl lseek als auch fseek be-
> > finden sich bei mir in der libc.
>
> [rw@winter]:~/software/linux/build/2.4/mm $man lseek | head

> LSEEK(2) System calls LSEEK(2)

Tja, und da wir uns hier in .os.UNIX. befinden, ist die Aussage von Felix
falsch. Dann soll er doch bitte in .linux. schreiben, DORT wäre seine
Aussage wahrscheinlich korrekt. Mir war schon klar, dass er sich _nur_ auf
Linux bezieht.

Cu, Olli

PS: Mein 'man lseek' wurde übrigens auf einem FreeBSD4 ausgeführt...

Gunnar Ritter

unread,
Jan 23, 2002, 7:40:30 AM1/23/02
to
Oliver Blasnik <r...@taunus-biker.de> wrote:

> Der Felix meinte:


>> Behaupten kannst du alles mögliche, aber es ist sinnvoll, dich auf
>> Sachen zu beschränken, bei denen du dich auskennst. Betriebssysteme
>> gehören offensichtlich nicht dazu.
>
> [ ] Du kennst mich

[x] Du schreibst Müll
[x] Man kann das lesen
[ ] Man müßte Dich dafür kennen

>> Was denkst du denn, wie der kernel read() und write() implementiert?
>> Der mappt natürlich auch das File in den Speicher und fummelt dann
>> darin herum!
>
> Das würde voraussetzen, dass der _Kernel_ fuer jedes File ein Read-Ahead
> der internen Blockgrösse durchführt.

Du wirst es kaum glauben, aber der Kernel liest nicht nur
Blöcke, sondern normalerweise gleich ganze Pages und mit
Read-Ahead u.U. sogar mehrere davon.

> Und: WENN gepuffert wird (wo&auf welche Art auch immer) und der *seek
> geht über die Buf-Grenze hinaus, _muss_ dieser Geschrieben werden
> beim nächsten write.

Bitte? Der Kernel hält doch nicht nur eine Page pro Device im
Speicher!

> Woher nimmst Du Deine obige Aussage?

Ich empfehle z.B. die Lektüre von

Uresh Vahalia: UNIX Internals. Upper Saddle River, New Jersey
1996. p. 460-463.

linux/mm/filemap.c

Berny Goodheart, James Cox: The Magic Garden Explained. The
Internals of UNIX System V Release 4. Sydney 1994. p. 297-298.
Kostprobe:

| · read() - when a read system call is issued, the following
| actions are carried out: [...]
| · The ufs_read() function is called to read in data from the
| file. [...] The call to uiomove() [...] copies data from the
| kernel virtual address where the page of the file was mapped,
| into buffers in user-space [...] At the lowest level,
| uiomove() copies data between the kernel page and the user
| page. The first time the kernel page is accessed, there will
| be a page fault causing the data to be read in.

> Hu? Wie auch immer es implementiert ist, sowohl lseek als auch fseek be-
> finden sich bei mir in der libc. Deine Aussage ist also flasch.

Witzbold. Viele Syscalls haben Stubs in der libc. Wenn Du mal einen
dezenten Blick in linux/fs/read_write.c wirfst und nach lseek suchst,
siehst Du den Kernel-Part. Du kannst auch die Quellen irgendeines
anderen Unix-Kernels nehmen, Linux ist nur ein Beispiel.

Und jetzt setz Deinen Schnuller wieder ein, krabbel in Deinen
Laufstall zurück und verschwende nicht länger unsere Zeit und
aller Leute Bandbreite mit Deinem unsäglich inkompetenten
Geplappere.

Grüße,
Gunnar

Rainer Weikusat

unread,
Jan 23, 2002, 7:43:31 AM1/23/02
to
"Oliver Blasnik" <r...@taunus-biker.de> writes:
> Rainer meinte:
> [Felix: kernel-read/write ist mmap-basiert]
> > > Das würde voraussetzen, dass der _Kernel_ fuer jedes File ein Read-Ahead
> > > der internen Blockgrösse durchführt.
>
> > Wie kommst Du auf das schmale Brett?
>
> Wenn etwas _in_den_Speicher gemappt wird, muss natürlich erst einmal der
> Speicher mit dem (partiellen) Inhalt des Files gefüllt werden.

Es ist ziemlich wurscht, was Du hier so daherfaselst. Felix hat Recht
und Du irrst Dich und hast genau keine Ausrede, nicht selber
nachzuschauen.

> > [rw@winter]:~/software/linux/build/2.4/mm $man lseek | head
> > LSEEK(2) System calls LSEEK(2)
>
> Tja, und da wir uns hier in .os.UNIX. befinden,

Gehst Du jetzt nach intro(2) und bleibst eine Weile da.

F'up2 poster

Rainer Weikusat

unread,
Jan 23, 2002, 7:48:34 AM1/23/02
to
"Oliver Blasnik" <r...@taunus-biker.de> writes:
> Tja, und da wir uns hier in .os.UNIX. befinden,

gehst Du jetzt nach intro(2) und bleibst eine Weile da.

F'up2 poster

--
hoffentlich ist es beton

Gunnar Ritter

unread,
Jan 23, 2002, 7:50:59 AM1/23/02
to
Oliver Blasnik <r...@taunus-biker.de> wrote:

> Tatsaechlich "sieht" man im Speicher ja nicht das File, sondern eine (in
> einer RAM-Page erstellte) Kopie des entsprechenden FS-Blocks. Diese
> Page (nenne man es "Fenster") wandert bei Zugriffen ausserhalb auf die
> neue Location des Files,

ROTFL.

>> > > Nein. fseek ist in der libc, lseek ist ein Syscall.
>> > | lseek - reposition read/write file offset
>> > | Standard C Library (libc, -lc)
>> > Hu? Wie auch immer es implementiert ist, sowohl lseek als auch fseek be-
>> > finden sich bei mir in der libc.
>>
>> [rw@winter]:~/software/linux/build/2.4/mm $man lseek | head
>> LSEEK(2) System calls LSEEK(2)
>
> Tja, und da wir uns hier in .os.UNIX. befinden, ist die Aussage von Felix
> falsch. Dann soll er doch bitte in .linux. schreiben, DORT wäre seine
> Aussage wahrscheinlich korrekt. Mir war schon klar, dass er sich _nur_ auf

> Linux bezieht. [...]


> PS: Mein 'man lseek' wurde übrigens auf einem FreeBSD4 ausgeführt...

<http://www.freebsd.org/cgi/cvsweb.cgi/src/sys/kern/vfs_syscalls.c?rev=1.219&content-type=text/x-cvsweb-markup>

Geh sterben. Schnell.

Grüße,
Gunnar

Oliver Blasnik

unread,
Jan 23, 2002, 8:41:42 AM1/23/02
to
Nochmal Gunnar,

> [x] Du schreibst Müll
> [x] Man kann das lesen
> [ ] Man müßte Dich dafür kennen

Fast ;)

> Du wirst es kaum glauben, aber der Kernel liest nicht nur
> Blöcke, sondern normalerweise gleich ganze Pages und mit
> Read-Ahead u.U. sogar mehrere davon.

Was ich auch in <a2m9dv$uuf$04$1...@news.t-online.com> schrieb.

> Kostprobe:
[ufs]

Stimmt. Ich war eine ebene Tiefer, bei den Devices. An ufs (bzw. andere
Filesysteme) habe ich in dem Augenblick nicht gedacht. My fault.

> Und jetzt setz Deinen Schnuller wieder ein, krabbel in Deinen
> Laufstall zurück und verschwende nicht länger unsere Zeit und
> aller Leute Bandbreite mit Deinem unsäglich inkompetenten
> Geplappere.

Im Gegensatz zu anderen Postern lasse ich mich gerne aufklären. Das
geht natürlich mit Schnuller & Laufstall recht schlecht, daher erlaube
ich mir, weiterhin am Rechner zu bleiben. Was mein Arbeitgeber sehr
wahrscheinlich auch begrüsst ;)

> Grüße,
> Gunnar

Cu, Olli

Oliver Blasnik

unread,
Jan 23, 2002, 8:33:30 AM1/23/02
to
Gunnar,

> > Tatsaechlich "sieht" man im Speicher ja nicht das File, sondern eine (in
> > einer RAM-Page erstellte) Kopie des entsprechenden FS-Blocks. Diese
> > Page (nenne man es "Fenster") wandert bei Zugriffen ausserhalb auf die
> > neue Location des Files,
>
> ROTFL.

Gut, die "Erklärung-fuer-nicht-Dummies" wäre wohl eher gewesen:
Bei einem Zugriffsversuch auf einen nicht gemappten Teil des Files wird
eine Exception ausgelöst, die eben diesen Teil in eine (optimalerweise nicht
invalidierte) Page lädt und sie auf diesem Speicherbereich abbildet.
VM sei Dank.

Besser? ;)

> >> > Hu? Wie auch immer es implementiert ist, sowohl lseek als auch fseek be-
> >> > finden sich bei mir in der libc.

> <http://www.freebsd.org/cgi/cvsweb.cgi/src/sys/kern/vfs_syscalls.c[...]

Und dieser Link sagt nichts aus. Natürlich ist der Seek IM Kernel implementiert,
die _Funktion_ lseek() ist jedoch in der libc. Habe ich _jemals_ etwas anderes
gesagt? (src/lib/libc/sys/lseek.c).

Und wenn Felix meint:


| Nein. fseek ist in der libc, lseek ist ein Syscall

ist das flasch, denn korrekterweise wäre es:
"Nein. lseek ist ein Syscall, fseek nicht.".

> Geh sterben. Schnell.

Hab ich noch nicht vor *eg* Hier gefällts mir gerade so gut...

> Grüße,
> Gunnar

Ist es eigentlich üblich, derart falsch verstanden zu werden?

Cu, Olli

Stefan Reuther

unread,
Jan 21, 2002, 9:15:56 AM1/21/02
to
Hallo,

Markus Lausser <lau...@sauron.forwiss.uni-passau.de> wrote:
> Wie loest man das am besten?
> Kann man fuer jede Quelle die Datei oeffen und schreiben?
> Im moment oeffne ich die Datei nur einmal und seeke bei jedem
> schreibvorgang an die richtige stellen, allerdings scheint etwas ineffizient
> zu sein.
> Oder sollte ich am besten die Daten puffern und dann in groesseren Paketen
> schreiben, damit ich fseek() nicht so oft brauche.

Ich würde zuallererst mal nicht fseek/fwrite verwenden, sondern
lseek/write. fseek/fwrite sind gepuffert, was in dem Fall eher
hinderlich ist.

Ansonsten sollte es eigentlich keine Probleme machen, per
`open' die Datei 10x zu öffnen, dann hast du 10 verschiedene
file descriptoren, die alle einen unabhängigen file pointer
haben. Damit kannst du in die Dateien schreiben, ohne ständig
seeken zu müssen.

> Eigentlich interessiert mich, ist es recourcesaufwenig fseek() ein paar
> tausend mal pro sekunde aufzurufen?

fseek ja (wegen der Pufferung), lseek vermutlich eher nicht.


Stefan

Rainer Weikusat

unread,
Jan 23, 2002, 9:23:18 AM1/23/02
to
"Oliver Blasnik" <r...@taunus-biker.de> writes:
> > > Tatsaechlich "sieht" man im Speicher ja nicht das File, sondern eine (in
> > > einer RAM-Page erstellte) Kopie des entsprechenden FS-Blocks. Diese
> > > Page (nenne man es "Fenster") wandert bei Zugriffen ausserhalb auf die
> > > neue Location des Files,
>
> Gut, die "Erklärung-fuer-nicht-Dummies" wäre wohl eher gewesen:
> Bei einem Zugriffsversuch auf einen nicht gemappten Teil des Files wird
> eine Exception ausgelöst,

Das ändert an der Tatsache, daß intern 'mmap' verwendet wird,
nichts. Das kann man _nachlesen_.

> Besser? ;)

Ein Punkt für überflüssige Erklärungen, die jeder schon kannte.

> > <http://www.freebsd.org/cgi/cvsweb.cgi/src/sys/kern/vfs_syscalls.c[...]
>
> Und dieser Link sagt nichts aus. Natürlich ist der Seek IM Kernel implementiert,
> die _Funktion_ lseek() ist jedoch in der libc. Habe ich _jemals_ etwas anderes
> gesagt? (src/lib/libc/sys/lseek.c).

libc

----------------
/*
* This function provides 64-bit offset padding that
* is not supplied by GCC 1.X but is supplied by GCC 2.X.
*/
off_t
lseek(fd, offset, whence)
int fd;
off_t offset;
int whence;
{
return(__syscall((quad_t)SYS_lseek, fd, 0, offset, whence));
}
----------------

Doll, doll ...

Glibc:

----------------
/* Seek to OFFSET on FD, starting from WHENCE. */
loff_t
__llseek (int fd, loff_t offset, int whence)
{
loff_t result;

return (loff_t) (INLINE_SYSCALL (_llseek, 5, fd, (off_t) (offset >> 32),
(off_t) (offset & 0xffffffff),
&result, whence) ?: result);
}
-----------------

> Und wenn Felix meint:
> | Nein. fseek ist in der libc, lseek ist ein Syscall

> ist das falsch,

Wie oben demonstriert, irrst Du Dich und auch dein lahmer Versuch,
hier mit BSD<->Linux-Trolling aufzuschlagen entbehrt jeglicher
Grundlage. Inbesondere ist obiger Code bzgl 'Performanceüberlegungen'
mit Sicherheit irrelevant :->.

Oliver Blasnik

unread,
Jan 23, 2002, 9:59:45 AM1/23/02
to
Hmmmm,

Rainer schrieb noch:

[Erklärung Paging / Memory-Mapping von Files]


> Das ändert an der Tatsache, daß intern 'mmap' verwendet wird,
> nichts. Das kann man _nachlesen_.

*gruebel*

Was hat das eine nu mit dem anderen zu tun?

"intern" wird mmap (=Art, etwas zu realisieren, nicht die Funktion)
des VM-Systems verwendet. Und ich beschrieb, wie Paging realisiert
ist. Ja und?

Der Thread ging:
Du: kernel-read/write verwendet mmap
Ich: das würde voraussetzen, dass der Kernel read-ahead in der blockgroesse macht
Du: Wie kommst Du auf das schmale Brett?
Ich: erkläre kurz die Funktion von mmapping und dass mindestens getpagesize()
Bytes gelesen werden müssen
(Ich: sehe in einer anderen Reference ein, dass ich vom Device und nicht vom
Filesystem geredet habe, das also Blödsinn war.)

Ja wie nu? ;)

> Ein Punkt für überflüssige Erklärungen, die jeder schon kannte.

Ich glaube nicht, dass "jeder" weiss, wie VM funktioniert.
[Vorlage zum Quoten: -> "Stimmt. Du nicht." *g* ]

[lseek() ist in der libc]


> Wie oben demonstriert, irrst Du Dich

Ich fass es nicht. Du quotest sogar diesen Teil und sprichst das
Gegenteil aus ;) lseek() ist in der libc, ob es nun "nur" ein Stub
ist oder nicht.

> und auch dein lahmer Versuch, her mit BSD<->Linux-Trolling
> aufzuschlagen entbehrt jeglicher Grundlage.

Das war kein Versuch und auch keine Absicht. Ich kenne nur die
Linux-Manpages und weiss, dass dort idR keinerlei Informationen
darüber sind, in welcher Lib die entsprechende Funktion zu finden
ist.

> Inbesondere ist obiger Code bzgl 'Performanceüberlegungen'
> mit Sicherheit irrelevant :->.

Agree (obwohl er auch inline/Macro sein könnte, das spart wieder ein
paar Zyklen... ;-P )

Cu, Olli

Sven Mascheck

unread,
Jan 23, 2002, 11:22:24 AM1/23/02
to
Oliver Blasnik <r...@taunus-biker.de> wrote:

> lseek() ist in der libc, ob es nun "nur" ein Stub ist oder nicht.

...hattest früher zur Entgegnung, daß es ein syscall sei,
genau folgendes geschrieben:

| NAME


| lseek - reposition read/write file offset

| LIBRARY


| Standard C Library (libc, -lc)

aber das folgende (eine Zeile vorher) absichtlich weggelassen:

| LSEEK(2) FreeBSD System Calls Manual LSEEK(2)


Muß sich erst die ganze Leserschaft hier äußern, daß Du lernresistent trollst?
Bitte, laß es endlich gut sein und schalte einen Gang runter.

[fup2 poster]

Gunnar Ritter

unread,
Jan 23, 2002, 11:49:19 AM1/23/02
to
Oliver Blasnik <r...@taunus-biker.de> wrote:

>> Du wirst es kaum glauben, aber der Kernel liest nicht nur
>> Blöcke, sondern normalerweise gleich ganze Pages und mit
>> Read-Ahead u.U. sogar mehrere davon.
>
> Was ich auch in <a2m9dv$uuf$04$1...@news.t-online.com> schrieb.

Tolle Taktik, zwei gegensätzliche Aussagen zu posten und sich
dann bei Widerspruch auf die jeweils andere zu berufen.

Dummerweise bist Du da an die falsche Adresse geraten. Mein
Interesse an Sophistereien liegt ziemlich genau bei Null,
und fachlich hast Du offensichtlich nichts zu melden:
*plonk*

Grüße,
Gunnar

Oliver Blasnik

unread,
Jan 23, 2002, 1:44:22 PM1/23/02
to
[fup2poster ignoriert, da letztes Posting von mir in dem Thread]

Sven meinte:

> aber das folgende (eine Zeile vorher) absichtlich weggelassen:
> | LSEEK(2) FreeBSD System Calls Manual LSEEK(2)

Cool, und böses unterstellt ("absichtlich") wird hier auch noch.
Nett... (Nein, ich habe nur auf das "libc" geachtet, denn darum
ging es ja eigentlich).

> Muß sich erst die ganze Leserschaft hier äußern, daß Du lernresistent
> trollst?
> Bitte, laß es endlich gut sein und schalte einen Gang runter.

Genau das werde ich jetzt auch tun. Ich werde _nicht_ lernen, dass
lseek() _nicht_ in der libc vorhanden ist. Da nehm ich auch gern
das "lernresistent" als passend an. Danke ;)


Olli, der ebenso nicht vergisst, einen Medienkonverter zu erwähnen,
wenns von TP auf Fiber geht (aber eigentlich ist das ja unwichtig, oder?).

Felix von Leitner

unread,
Jan 24, 2002, 6:25:08 PM1/24/02
to
Thus spake Markus Lausser (lau...@sauron.forwiss.uni-passau.de):
> > Du willst also sowas wie edonkey implementieren, wenn ich das richtig
> > sehe.
> Ganz genau, nur ist das fuer das opennap protokoll.

Und saugst du da immer sequentiell? Ich kenne das Protokoll nicht, aber
bei edonkey ist es so, daß du von beliebigen Quellen beliebige Blöcke
holen kannst, auch überlappend.

> > Das Problem mit mmap ist, daß auf 32-bit Prozessoren der
> > adressierbare Speicher limitiert ist, d.h. du kannst nicht zehn
> > 1GB-Dateien mappen.
> Daran hatte ich auch nie gedacht. Im moment mappe ich fuer jede Quelle
> einen 1MB Block und schreibe darin, wenn das ende eine Blocks erreicht ist,
> dann wird er ge-unmapped und ein neuer gemapped.

Ja, so macht das Sinn. Nur meistens, wenn man mmap einsetzt,
will man einmal die gesamte Datei mappen und danach nicht mehr drüber
nachdenken. Das macht ja gerade die Attraktivität von mmap über read
aus. Wenn du da mit Buffern hantierst, könntest du ja auch gleich
pread/pwrite nehmen (auch wenn das etwas uneffizienter wäre).

> > Wenn ich das implementieren müßte, würde ich mmap nehmen, und wenn die
> > Summe der zu mappenden Daten zu groß wird, würde ich auf eine
> > Buffer-Verwaltung mit 16k-Blöcken umsteigen und pwrite benutzen.
> Wie gesagt, 1MB pro block, macht 10MB bei 10 quellen, macht 100MB bei 10
> dateien, die ich downloade (aber wer downloaded schon von 100 quellen?).

Warum 1MB pro Block und nicht 128K? Oder 64K?

> Was passiert eingentlich bei nem crash mit den Daten, die ich in den
> map-speicher geschrieben habe? Die manpage sagt, dass bei ner programm
> termination ge-unmapped wird, heisst das: sobald ich in den speicher
> geschrieben habe, kann ich davon ausgehen, dass die Daten auch in der
> Datei sein werden (wenn ich nicht grade die Datei schliesse, ohne zu
> unmappen..)

mmap und der Öffnungs-Zustand der Datei sind unabhängig. Du kannst eine
Datei öffnen, mmap benutzen, die schließen (, sogar löschen) und
trotzdem in dem gemappten Bereich herumlesen und -schreiben.

Wenn dein Programm abraucht, werden die Änderungen übernommen. Wann sie
genau physikalische auf der Platte landen ist eine andere Frage.

Felix

Gunnar Ritter

unread,
Jan 24, 2002, 7:13:37 PM1/24/02
to
Felix von Leitner <usenet-...@fefe.de> wrote:

> Das macht ja gerade die Attraktivität von mmap über read
> aus. Wenn du da mit Buffern hantierst, könntest du ja auch gleich
> pread/pwrite nehmen (auch wenn das etwas uneffizienter wäre).

Das ist nicht mal gesagt. Wenn man eine Datei mmap()t und dann
liest, gibt es u.U. so viel mehr separate Pagefaults, daß das
die Performance schwächt. Zumindest, solange man das nicht mit
madvise() kontrolliert.

Grüße,
Gunnar

Felix von Leitner

unread,
Jan 24, 2002, 7:25:17 PM1/24/02
to
Thus spake Gunnar Ritter (g...@bigfoot.de):

> > Das macht ja gerade die Attraktivität von mmap über read
> > aus. Wenn du da mit Buffern hantierst, könntest du ja auch gleich
> > pread/pwrite nehmen (auch wenn das etwas uneffizienter wäre).
> Das ist nicht mal gesagt. Wenn man eine Datei mmap()t und dann
> liest, gibt es u.U. so viel mehr separate Pagefaults, daß das
> die Performance schwächt. Zumindest, solange man das nicht mit
> madvise() kontrolliert.

Ich meinte eher die Speicherverschwendung als die Laufzeit.
Aber du hast Recht.

Felix

0 new messages