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

mmap() halb so schnell wie read()!

4 views
Skip to first unread message

Helmut Schellong

unread,
Sep 14, 2003, 2:02:57 AM9/14/03
to
Hallo,

char Buf[32*1024];
char *bufptr= Buf;
nr= read(fildes, bufptr, 32*1024);
found_ptr= SucheStr(bufptr, len);

char *mapptr;
mapptr= mmap(0, 32*1024, PROT_READ, MAP_PRIVATE, fildes, 0);
found_ptr= SucheStr(mapptr, len);


Im zweiten Fall mit mmap() benötigt die Funktion SucheStr()
doppelt soviel Zeit wie mit read(), obwohl auf dem jeweiligen
Pointer exakt die gleichen Daten liegen, bei gleicher len.

Man kann sagen, SucheStr() liest von mapptr halb so schnell
wie von bufptr.

Ich habe etwa 10 Varianten ausprobiert - nie ein Unterschied zu vorher!
Ich fasse das nicht!
Kann mir das mal jemand begründen?
(FreeBSD 4.8)

grep --mmap läuft auf dem gleichen System mit der gleichen Testdatei
etwa doppelt so schnell wie ohne --mmap.
Im grep-Quellcode wird aber auch nix anders gemacht
als ich es mit den 10 Varianten durchprobierte!

Ist meine SucheStr() vielleicht zu schnell?


--
Mit freundlichen Grüßen
Helmut Schellong po...@schellong.de po...@schellong.com
www.schellong.de www.schellong.biz sche...@t-online.de
http://www.schellong.de/c.htm

Patrick Schaaf

unread,
Sep 14, 2003, 4:56:12 AM9/14/03
to
Helmut Schellong <sche...@t-online.de> writes:

>char Buf[32*1024];
>char *bufptr= Buf;
>nr= read(fildes, bufptr, 32*1024);
>found_ptr= SucheStr(bufptr, len);

>char *mapptr;
>mapptr= mmap(0, 32*1024, PROT_READ, MAP_PRIVATE, fildes, 0);
>found_ptr= SucheStr(mapptr, len);

>Im zweiten Fall mit mmap() benötigt die Funktion SucheStr()
>doppelt soviel Zeit wie mit read(), obwohl auf dem jeweiligen
>Pointer exakt die gleichen Daten liegen, bei gleicher len.

Sicher. Beim ersten Zugriff. Weil page fuer page (8 mal bei 4k pages
und 32k buffer/filesize) ein major oder minor fault in den Kern
springt, read dagegen alles in einem syscall erledigt.

>Ist meine SucheStr() vielleicht zu schnell?

Nein. Deine Testanwendung ist zu trivial, die Datenmengen zu klein.

mmap bringt gegenueber read dann etwas Substantielles, wenn es um
Datenmengen geht, die man nicht mehr zweimal im RAM haben moechte
(einmal im Kernel-Plattencache, einmal in Kopie im Userlevel).

Nehmen wir mal an, Du hast eine Maschine mit 512MB RAM, und eine
256MB-Datei. Probier dann mal read(ineinemstueck) gegenueber
mmap aus.

Ebenso bringt mmap etwas, wenn nicht sequentiell/sonstwie die gesamten
Daten verarbeitet werden muessen, sondern nur ein kleiner Teil, und wenn
vorher nicht bekannt ist, welcher. mmap holt dann nur die pages wirklich
rein, die gerade benoetigt werden; wenn Du das mit read nachzustellen
versuchst, also in zB. 4k-Bloecken lesend die interessanten Stellen
holst, dann machst Du Dich mit den Grenzfaellen in Sachen Codecomplexitaet
kaputt.

Gruss
Patrick

Rainer Weikusat

unread,
Sep 14, 2003, 5:57:18 AM9/14/03
to
mailer...@bof.de (Patrick Schaaf) writes:
> mmap bringt gegenueber read dann etwas Substantielles, wenn es um
> Datenmengen geht, die man nicht mehr zweimal im RAM haben moechte
> (einmal im Kernel-Plattencache, einmal in Kopie im Userlevel).

void add_to_sentry_conf_file(char const *path)
{
int fd;
ssize_t rc;
off_t fsize;
void *data;
sigset_t block, old;

fd = open(path, O_RDONLY, 0);
fd != -1 || sys_die("add_to_sentry_config_file", "open", errno);

fsize = lseek(fd, 0, SEEK_END);
fsize != -1 || sys_die("add_to_sentry_config_file", "lseek", errno);

data = mmap(NULL, fsize, PROT_READ, MAP_SHARED, fd, 0);
data || sys_die("add_to_sentry_config_file", "mmap", errno);

rc = do_write(config_fd, data, fsize);
rc != -1 || sys_die("add_to_sentry_config_file", "write", errno);
add_to_sentry_string_list(&filenames, path);

munmap(data, fsize); /* ? */
close(fd);
}

Das ist mir eigentlich substantiell genug, denn ich brauche nicht
auch noch eine Schleife, die das kaputte Signal-handling von
LinuxThreads beim Lesen berücksichtigt (und ich weiß auch selber, das
es nicht race-frei ist. Es verwendet ein wahrscheinlichkeitsbasiertes
Synchronisationsmodell [ich muß unbedingt auch mal ein paar Begriffe
erfinden], dh es ist unwahrscheinlich, daß dieselbe Person
gleichzeitig das file ändert und den Prozeß neustartet :->>).
Es eignet sich auch wunderbar zum parsen von Textfiles, weil das
paging-Subsystem im Kernel dann die Speicherverwaltung macht, dh
minimal benötigt das für eine beliebig große Datei genau eine
Speicherseite und die wird 'nach Bedarf' vor mir hergeschoben.

Helmut Schellong

unread,
Sep 14, 2003, 11:41:35 AM9/14/03
to
Patrick Schaaf wrote:
> Helmut Schellong <sche...@t-online.de> writes:
>
>
>>char Buf[32*1024];
>>char *bufptr= Buf;
>>nr= read(fildes, bufptr, 32*1024);
>>found_ptr= SucheStr(bufptr, len);
>
>
>>char *mapptr;
>>mapptr= mmap(0, 32*1024, PROT_READ, MAP_PRIVATE, fildes, 0);
>>found_ptr= SucheStr(mapptr, len);
>
>
>>Im zweiten Fall mit mmap() benötigt die Funktion SucheStr()
>>doppelt soviel Zeit wie mit read(), obwohl auf dem jeweiligen
>>Pointer exakt die gleichen Daten liegen, bei gleicher len.
>
>
> Sicher. Beim ersten Zugriff. Weil page fuer page (8 mal bei 4k pages
> und 32k buffer/filesize) ein major oder minor fault in den Kern
> springt, read dagegen alles in einem syscall erledigt.
>
>
>>Ist meine SucheStr() vielleicht zu schnell?
>
>
> Nein. Deine Testanwendung ist zu trivial, die Datenmengen zu klein.
>
> mmap bringt gegenueber read dann etwas Substantielles, wenn es um
> Datenmengen geht, die man nicht mehr zweimal im RAM haben moechte
> (einmal im Kernel-Plattencache, einmal in Kopie im Userlevel).
>
> Nehmen wir mal an, Du hast eine Maschine mit 512MB RAM, und eine
> 256MB-Datei. Probier dann mal read(ineinemstueck) gegenueber
> mmap aus.

Das habe ich unter anderem auch!
Ich habe doch etwa 10 Varianten ausprobiert, nachdem ich sah, daß mmap()
stets langsamer war.
Die Testdatei hat 126 MB.
Ich habe mit mmap() alles auf einen Schlag gemapt, je 1 MB gemapt,
je 32 KB gemapt - immer gleicher Zeitbedarf!
[PIII/700, 768 MB RAM; 460 MB free (danach)]
Ich habe Flags durchprobiert, auch MAP_FIXED, auch
madvise() mit diversen Flags - immer gleicher Zeitbedarf!

------------------------------------------------------
???] /usr/bin/time bgrep -c iso /usr/z.iso
16
5.43 real ?.?? user ?.?? sys //1. Aufruf
------------------------------------------------------
104] /usr/bin/time fgrep -c --mmap iso /usr/z.iso
16
9.53 real 0.94 user 0.29 sys //1. Aufruf
------------------------------------------------------
105] /usr/bin/time fgrep -c --mmap iso /usr/z.iso
16
1.12 real 0.95 user 0.12 sys
106] /usr/bin/time fgrep -c iso /usr/z.iso
16
1.92 real 1.38 user 0.48 sys
107] /usr/bin/time bgrep -c iso /usr/z.iso
16
0.97 real 0.43 user 0.40 sys
108] /usr/bin/time bgrep -cM iso /usr/z.iso //-M == --mmap
16
1.13 real 1.01 user 0.07 sys
------------------------------------------------------
bgrep (binary grep) ist mein Testprogramm, das ich mittels
mmap() noch schneller machen wollte - aber denkste.
Mit mmap kommt immer die letzte Zeile heraus, egal wie ich variiere.

Verstehst Du das?

Patrick Schaaf

unread,
Sep 14, 2003, 12:46:21 PM9/14/03
to
Helmut Schellong <sche...@t-online.de> writes:

>Die Testdatei hat 126 MB.

>[PIII/700, 768 MB RAM; 460 MB free (danach)]

Das reicht noch nicht. 2*126MB sind 252MB, die Testdatei passt
also sehr luftig auch zweimal in den verfuegbaren Speicher.

Wobei ich bezweifle, dass ein fgrep die gesamte Datei
mit read() einliest. Der wird das stueckweise machen.

Mach die Datei mal 500MB gross.

und achte darauf (vmstat 1),
was so waehrend dem Testlauf passiert.

Gruss
Patrick

Rainer Weikusat

unread,
Sep 14, 2003, 12:54:54 PM9/14/03
to
Helmut Schellong <sche...@t-online.de> writes:
>>>char *mapptr;
>>>mapptr= mmap(0, 32*1024, PROT_READ, MAP_PRIVATE, fildes, 0);
>>>found_ptr= SucheStr(mapptr, len);
>>
>>>Im zweiten Fall mit mmap() benötigt die Funktion SucheStr()
>>>doppelt soviel Zeit wie mit read(), obwohl auf dem jeweiligen
>>>Pointer exakt die gleichen Daten liegen, bei gleicher len.
>> Sicher. Beim ersten Zugriff. Weil page fuer page (8 mal bei 4k pages
>> und 32k buffer/filesize) ein major oder minor fault in den Kern
>> springt, read dagegen alles in einem syscall erledigt.
>>
>>>Ist meine SucheStr() vielleicht zu schnell?
>> Nein. Deine Testanwendung ist zu trivial, die Datenmengen zu klein.
>> mmap bringt gegenueber read dann etwas Substantielles, wenn es um
>> Datenmengen geht, die man nicht mehr zweimal im RAM haben moechte
>> (einmal im Kernel-Plattencache, einmal in Kopie im Userlevel).
>> Nehmen wir mal an, Du hast eine Maschine mit 512MB RAM, und eine
>> 256MB-Datei. Probier dann mal read(ineinemstueck) gegenueber
>> mmap aus.
>
> Das habe ich unter anderem auch!
> Ich habe doch etwa 10 Varianten ausprobiert, nachdem ich sah, daß mmap()
> stets langsamer war.
> Die Testdatei hat 126 MB.
> Ich habe mit mmap() alles auf einen Schlag gemapt, je 1 MB gemapt,
> je 32 KB gemapt - immer gleicher Zeitbedarf!

Falls Patrick recht hat, ist das vollkommen egal.


[...]

> 107] /usr/bin/time bgrep -c iso /usr/z.iso
> 16
> 0.97 real 0.43 user 0.40 sys
> 108] /usr/bin/time bgrep -cM iso /usr/z.iso //-M == --mmap
> 16
> 1.13 real 1.01 user 0.07 sys

Allerdings sieht das nicht danach aus, denn Du hast erheblich weniger
Aktivität im Kernel als vorher. Dafür brauchst Du im userspace doppelt
solange.

> bgrep (binary grep) ist mein Testprogramm, das ich mittels
> mmap() noch schneller machen wollte - aber denkste.
> Mit mmap kommt immer die letzte Zeile heraus, egal wie ich variiere.
>
> Verstehst Du das?

Ohne Code? Wie?

Patrick Schaaf

unread,
Sep 14, 2003, 12:56:12 PM9/14/03
to
mailer...@bof.de (Patrick Schaaf) writes:

>Wobei ich bezweifle, dass ein fgrep die gesamte Datei
>mit read() einliest. Der wird das stueckweise machen.

Ich sollte oefter schauen, und nicht so oft zweifeln.
fgrep auf Debian woody macht, mit strace beobachtet,
irgendwie sehr lustige Sachen:

open("bullshit", O_RDONLY|O_LARGEFILE) = 3
brk(0x8062000) = 0x8062000
fstat64(3, {st_mode=S_IFREG|0644, st_size=134217728, ...}) = 0
read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 32768) = 32768
old_mmap(NULL, 172032, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x40135000
read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 131072) = 131072
mremap(0x40135000, 172032, 1318912, MREMAP_MAYMOVE) = 0x40135000
read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1048576) = 1048576
mremap(0x40135000, 1318912, 10493952, MREMAP_MAYMOVE) = 0x40135000
read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 8388608) = 8388608
mremap(0x40135000, 10493952, 83894272, MREMAP_MAYMOVE) = 0x40135000
read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 67108864) = 67108864
mremap(0x40135000, 83894272, 134225920, MREMAP_MAYMOVE) = 0x40135000
read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 57507840) = 57507840
read(3, "", 0) = 0
close(3) = 0

Stueckchen, aber in jedem Schritt 8 mal groesser? Ob das jemals aufhoert?
Versteht das jemand?

Gruss
Patrick

Helmut Schellong

unread,
Sep 14, 2003, 1:59:39 PM9/14/03
to
Rainer Weikusat wrote:
> Helmut Schellong <sche...@t-online.de> writes:

>>107] /usr/bin/time bgrep -c iso /usr/z.iso
>>16
>> 0.97 real 0.43 user 0.40 sys
>>108] /usr/bin/time bgrep -cM iso /usr/z.iso //-M == --mmap
>>16
>> 1.13 real 1.01 user 0.07 sys
>
>
> Allerdings sieht das nicht danach aus, denn Du hast erheblich weniger
> Aktivität im Kernel als vorher. Dafür brauchst Du im userspace doppelt
> solange.

Ja, genau, diese Zeit wird praktisch zu 100% in
SucheStr(bufptr bzw. mapptr, len); verbraucht.

> Ohne Code? Wie?

Der Code in meinem ersten Posting reicht eigentlich aus.
Es ist wirklich nur eine klassische Schleife: solange nr>0
bzw. solange filerest>0.

Es ist wirklich so, daß SucheStr() halb so schnell von
mapptr liest.

Peter J. Holzer

unread,
Sep 14, 2003, 3:15:31 PM9/14/03
to
On 2003-09-14 16:56, Patrick Schaaf <mailer...@bof.de> wrote:
> fgrep auf Debian woody macht, mit strace beobachtet,
> irgendwie sehr lustige Sachen:
>
> open("bullshit", O_RDONLY|O_LARGEFILE) = 3
> brk(0x8062000) = 0x8062000
> fstat64(3, {st_mode=S_IFREG|0644, st_size=134217728, ...}) = 0
> read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 32768) = 32768
> old_mmap(NULL, 172032, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x40135000
> read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 131072) = 131072
> mremap(0x40135000, 172032, 1318912, MREMAP_MAYMOVE) = 0x40135000
> read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1048576) = 1048576
[...]

> close(3) = 0
>
> Stueckchen, aber in jedem Schritt 8 mal groesser? Ob das jemals aufhoert?
> Versteht das jemand?

Ja, ich, wenn ich meine Glaskugel bemühe:

Du liest von einem File, das nur NUL-Bytes enthält, und somit nur eine
einzige Zeile enthält. Fgrep liest das File zeilenweise ein und
vergrößert den Zeilenbuffer jedesmal, wenn er zu klein wird, mittels
realloc, wobei das neue Stück jedesmal um den Faktor 8 wächst.

Wenn Du ein File mit mehreren Zeilen liest, hört es auf, sobald der
Zeilenbuffer groß genug für die längste Zeile ist.

hp

--
_ | Peter J. Holzer | > Wie sagt ihr zu der Mehrzahl von Mozilla?
|_|_) | Sysadmin WSR | Jurassic Park.
| | | h...@hjp.at | -- Alexander Skwar und Ruediger Lahl
__/ | http://www.hjp.at/ | in dcsmm.

Patrick Schaaf

unread,
Sep 14, 2003, 4:21:58 PM9/14/03
to
hjp-u...@hjp.at (Peter J. Holzer) writes:

>> Stueckchen, aber in jedem Schritt 8 mal groesser? Ob das jemals aufhoert?
>> Versteht das jemand?

>Ja, ich, wenn ich meine Glaskugel bemühe:
>Du liest von einem File, das nur NUL-Bytes enthält,

Gute Kristallkugel.

Verstehe das Verhalten trotzdem nicht. Auf der einen Seite soll fgrep ja
eine matching line ausgeben. Also macht es Sinn, auch bei nicht-finden
die aktuelle Zeile im Speicher zu halten. Das hat der fgrep in meinem
Beispiel aber offenbar schon aufgegeben, jeder read ueberlagert die
vorherigen Ergebnisse. Welchen Sinn macht also das Wachsen des Lesefensters?
Oder sagt sich da eine Heuristik "wen schert's, sind doch eh alles Nullen"?

Ich weiss, ich sollte in die Quellen schauen. So zu raten ist aber
viel Lustiger :)

Gruss
Patrick

Thomas Ogrisegg

unread,
Sep 14, 2003, 6:16:36 PM9/14/03
to
Patrick Schaaf <mailer...@bof.de> wrote on 2003-09-14:

> Helmut Schellong <sche...@t-online.de> writes:
>>Pointer exakt die gleichen Daten liegen, bei gleicher len.
> Sicher. Beim ersten Zugriff. Weil page fuer page (8 mal bei 4k pages
> und 32k buffer/filesize) ein major oder minor fault in den Kern
> springt, read dagegen alles in einem syscall erledigt.

ACK. Ich hatte da mal die groteske Situation dass 'mmap' + 'memcpy
des gemappten Buffers auf den Stack' deutlich schneller war als
entweder gleich den mmap-buffer zu nehmen bzw. 'read' zu verwenden.

Ich vermute das liegt daran dass die Load/Store Unit der CPU relativ
schnell mal 4 Kilobyte ausliest und dass durch die ganzen Instruction-
und Datacachemisses nach dem Pagefault, daher die Performance derartig
den Bach runtergeht.

>>Ist meine SucheStr() vielleicht zu schnell?

ROTFL.

> Nein. Deine Testanwendung ist zu trivial, die Datenmengen zu klein.

Das ist aber auch nicht wirklich das Problem. Ich vermute wenn
man ganz am Anfang alle Pages "touched" (d.h. einen Ladezugriff
ausfuehrt) muesste sich die Performance eigentlich deutlich
verbessern (basiernd auf obiger Theorie).

--
Fernab jeder hormonellen Verblendung faellt eine frappierende Aehnlichkeit
in Koerperbau, Haltung, Mimik, Feingefuehl und technischem Sachverstand
zwischen Frau und Tyrannosaurus Rex unmittelbar ins Auge.
-- Juergen Ernst Guenther

Peter J. Holzer

unread,
Sep 14, 2003, 7:59:45 PM9/14/03
to
On 2003-09-14 20:21, Patrick Schaaf <mailer...@bof.de> wrote:
> Verstehe das Verhalten trotzdem nicht. Auf der einen Seite soll fgrep ja
> eine matching line ausgeben. Also macht es Sinn, auch bei nicht-finden
> die aktuelle Zeile im Speicher zu halten. Das hat der fgrep in meinem
> Beispiel aber offenbar schon aufgegeben, jeder read ueberlagert die
> vorherigen Ergebnisse.

Das sieht man zwar im strace nicht direkt, aber ich bezweifle das. Er
alloziert immer etwas mehr als er für das bereits gelesene und den
folgenden Block braucht:


| read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 32768) = 32768
| old_mmap(NULL, 172032, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x40135000

^^^^^^ > 32768 + 131072 = 163840


| read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 131072) = 131072
| mremap(0x40135000, 172032, 1318912, MREMAP_MAYMOVE) = 0x40135000

^^^^^^^ > 163840 + 1048576 = 1212416


| read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1048576) = 1048576

| mremap(0x40135000, 1318912, 10493952, MREMAP_MAYMOVE) = 0x40135000

^^^^^^^^ > 1212416 + 8388608 = 9601024


| read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 8388608) = 8388608
| mremap(0x40135000, 10493952, 83894272, MREMAP_MAYMOVE) = 0x40135000

^^^^^^^^ > 9601024 + 67108864 = 76709888


| read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 67108864) = 67108864
| mremap(0x40135000, 83894272, 134225920, MREMAP_MAYMOVE) = 0x40135000

^^^^^^^^^ > 76709888 + 57507840 = 134217728
| read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 57507840) = 57507840

Daraus schließe ich, dass er immer brav hinten anhängt. Wie er auf genau
diese Größen kommt, kann ich aber auch nicht erraten. Dazu müsste ich in
den Source-Code schauen, und dafür ist es schon zu spät :-)

Helmut Schellong

unread,
Sep 14, 2003, 10:04:51 PM9/14/03
to
Thomas Ogrisegg wrote:

> ACK. Ich hatte da mal die groteske Situation dass 'mmap' + 'memcpy
> des gemappten Buffers auf den Stack' deutlich schneller war als
> entweder gleich den mmap-buffer zu nehmen bzw. 'read' zu verwenden.

> Ich vermute das liegt daran dass die Load/Store Unit der CPU relativ
> schnell mal 4 Kilobyte ausliest und dass durch die ganzen Instruction-
> und Datacachemisses nach dem Pagefault, daher die Performance derartig
> den Bach runtergeht.

> Das ist aber auch nicht wirklich das Problem. Ich vermute wenn


> man ganz am Anfang alle Pages "touched" (d.h. einen Ladezugriff
> ausfuehrt) muesste sich die Performance eigentlich deutlich
> verbessern (basiernd auf obiger Theorie).

Findest Du nicht, daß es ziemlich 'bekloppt' ist, wenn man mit
mmap so umgehen muß, damit mmap nicht mehr nur halb so schnell ist
wie read?

Patrick Schaaf

unread,
Sep 15, 2003, 1:56:49 AM9/15/03
to
Helmut Schellong <sche...@t-online.de> writes:

>Findest Du nicht, daß es ziemlich 'bekloppt' ist, wenn man mit
>mmap so umgehen muß, damit mmap nicht mehr nur halb so schnell ist
>wie read?

Findest Du es bekloppt, dass man zum erfolgreichen Haemmern den Hammer
am Stiel halten sollte, statt ihn einfach irgendwo anzupacken? Und dass
das bei einer Reisszwecke auch ohne Hammer und einfacher geht?

mmap ist ein Werkzeug fuer bestimmte Zwecke. Der Zweck ist nicht,
immer und ueberall read zu ersetzen. Waere das so, gaebe es read
schon lange nicht mehr, bzw. es waere eine Library-Funktion geworden.

Gruss
Patrick

Patrick Schaaf

unread,
Sep 15, 2003, 2:00:06 AM9/15/03
to
hjp-u...@hjp.at (Peter J. Holzer) writes:

>On 2003-09-14 20:21, Patrick Schaaf <mailer...@bof.de> wrote:
>> Verstehe das Verhalten trotzdem nicht. Auf der einen Seite soll fgrep ja
>> eine matching line ausgeben. Also macht es Sinn, auch bei nicht-finden
>> die aktuelle Zeile im Speicher zu halten. Das hat der fgrep in meinem
>> Beispiel aber offenbar schon aufgegeben, jeder read ueberlagert die
>> vorherigen Ergebnisse.

>Das sieht man zwar im strace nicht direkt, aber ich bezweifle das. Er
>alloziert immer etwas mehr als er für das bereits gelesene und den
>folgenden Block braucht:

>| old_mmap(NULL, 172032, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x40135000


> ^^^^^^ > 32768 + 131072 = 163840

>| mremap(0x40135000, 172032, 1318912, MREMAP_MAYMOVE) = 0x40135000
> ^^^^^^^ > 163840 + 1048576 = 1212416

>| mremap(0x40135000, 1318912, 10493952, MREMAP_MAYMOVE) = 0x40135000
> ^^^^^^^^ > 1212416 + 8388608 = 9601024

Jetzt habe ich auch nachgeschaut / verstanden, was mremap genau tut.
Weg ist meine Verwirrung. Danke fuer's Insistieren :)

Gruss
Patrick

Helmut Leitner

unread,
Sep 15, 2003, 3:30:57 AM9/15/03
to

Patrick Schaaf wrote:
>
> Helmut Schellong <sche...@t-online.de> writes:
>
> >Findest Du nicht, daß es ziemlich 'bekloppt' ist, wenn man mit
> >mmap so umgehen muß, damit mmap nicht mehr nur halb so schnell ist
> >wie read?
>
> Findest Du es bekloppt, dass man zum erfolgreichen Haemmern den Hammer
> am Stiel halten sollte, statt ihn einfach irgendwo anzupacken? Und dass
> das bei einer Reisszwecke auch ohne Hammer und einfacher geht?

Das mag richtig sein...



> mmap ist ein Werkzeug fuer bestimmte Zwecke. Der Zweck ist nicht,
> immer und ueberall read zu ersetzen. Waere das so, gaebe es read
> schon lange nicht mehr, bzw. es waere eine Library-Funktion geworden.

aber es scheint, dass niemand so recht weiß, wo dieses Werkzeug anzugreifen
ist und wie es zuschlägt. Seinen sinnvollen Einsatz davon abhängig zu machen,
wie Filegröße und System-RAM-Größe zusammenhängen, könnte ja nur bedeuten,
dass man für ein optimales Tool immer beide Strategien implementieren muss
und zusätzlich die Erkennung der Auswahlkriterien. Schließlich wird man ja
nicht für eine zufällige Konfiguration programmieren.

D. h. eigentlich müsste mmap ein mmap_makes_sense(filesize) bedingen,
das alle relevanten Systemparameter einbezieht und eine Prognose abgibt.
Wenn das nicht mitgeliefert wird, ist mmap eine Falle oder der Zwang das Rad
neu zu erfinden.

Ganz kann ich dem 'bekloppt' von HS nicht widersprechen.

--
Helmut Leitner lei...@hls.via.at
Graz, Austria www.hls-software.com

Patrick Schaaf

unread,
Sep 15, 2003, 3:44:13 AM9/15/03
to
Helmut Leitner <lei...@hls.via.at> writes:

>aber es scheint, dass niemand so recht weiß, wo dieses Werkzeug anzugreifen
>ist und wie es zuschlägt.

Nicht? Ich bilde mir ein, zwei solche Szenarien geschildert zu haben,
und Rainer erzaehle von einem Dritten.

Meine Analogie mal etwas drastischer:

Es kann auch kaum jemand richtig mit einem Schweissgeraet umgehen.
Loetkolben sind da schon sozialvertraeglicher. Aber das macht
Schweissgeraete nicht entbehrlich.

Ich fasse so ein Ding nicht an!

>Seinen sinnvollen Einsatz davon abhängig zu machen,
>wie Filegröße und System-RAM-Größe zusammenhängen, könnte ja nur bedeuten,
>dass man für ein optimales Tool immer beide Strategien implementieren muss
>und zusätzlich die Erkennung der Auswahlkriterien. Schließlich wird man ja
>nicht für eine zufällige Konfiguration programmieren.

Das kann es moeglicherweise bedeuten, ja. Es kann aber auch gut sein,
dass fuer die gegebene Anwendung mmap genau das Richtige ist. Ich erwaehnte
dazu zwei Szenarien, Rainer ein Drittes.

>Ganz kann ich dem 'bekloppt' von HS nicht widersprechen.

Fasst einfach mmap nicht an.

Gruss
Patrick

Michael van Elst

unread,
Sep 15, 2003, 4:30:21 AM9/15/03
to
Rainer Weikusat <weik...@students.uni-mainz.de> writes:

>Was ist daran 'grotesk'? Durch das memcpy bewegst Du das File effektiv
>in Deinen Adressraum und danach kannst Du schneller darauf
>zugreifen.

In "deinem Adressraum" ist es schon vorher, aber nicht im Cache.

Wenn die Suchroutine langsam ist, dann kann es sein, dass das vorherige
Kopieren und anschliessende Suchen im Cache schneller ist als das direkte
Suchen.

Allerdings wird der Effekt meistens sehr klein sein, weil heutige CPUs
viel schneller suchen koennen als die Platte Daten liefern kann.

Der Unterschied zwischen read() und mmap() liegt dann eher daran, dass
read() normalerweise ein read-ahead im Filesystem ausloest, waehrend
mmap() das nicht macht. Je nach Platte und Controller kann das durchaus
einen Faktor 2 ausmachen.

Eventuell hilft ein passender madvise()-Aufruf, mit dem man dem VM-System
mitteilt, ob man sequentiell auf den Speicher (und damit die Datei)
zugreifen will.


--
--
Michael van Elst
Internet: mle...@serpens.de
"A potential Snark may lurk in every tree."

Bernd Petrovitsch

unread,
Sep 15, 2003, 4:50:41 AM9/15/03
to
On Mon, 15 Sep 2003 09:30:57 +0200, Helmut Leitner wrote:
[...]

> aber es scheint, dass niemand so recht weiß, wo dieses Werkzeug anzugreifen
> ist und wie es zuschlägt. Seinen sinnvollen Einsatz davon abhängig zu machen,
> wie Filegröße und System-RAM-Größe zusammenhängen, könnte ja nur bedeuten,

Nicht greifen auf den Inhalt eines Files sequentiell genau einmal von
vorne nach hinten zu - manche brauchen abwechselnd verschiedene Stellen
eines (großen) Files und verändern dort was.
Viel Spaß mit
---- snip ----
lseek(offset);
read(buf, size);
* do and change sth on buf*
lseek(offset);
write(buf, size);
---- snip ----
Obiges ist Pseudo-C und soll den Algorithmus bzw dessen Struktur andeuten.
Was fehlt sind etliche Parameter, Fehlerabfragen, und v.a. die Schleifen
um read() und write(), damit auch sicher alles gelesen bzw. geschrieben
wird.

> dass man für ein optimales Tool immer beide Strategien implementieren muss

Normalerweise sieht man es am Problem bzw. Algorithmus, welche Strategie
die wohl sinnvollere ist.

> und zusätzlich die Erkennung der Auswahlkriterien. Schließlich wird man ja
> nicht für eine zufällige Konfiguration programmieren.

Die übliche Antwort: Du machst es so, daß es funktiniert. Wenn es zu
langsame ist *und* dort der Flaschenhals ist, überlegt man sich was
anderes.

Bernd
--
Bernd Petrovitsch Email : be...@bofh.at
"For I was talking aloud to myself. A habit of the old: they choose
the wisest person present to speak to; the long explanations needed
by the young are wearying." --- Gandalf, the White

Rainer Weikusat

unread,
Sep 15, 2003, 5:18:44 AM9/15/03
to
Helmut Schellong <sche...@t-online.de> writes:
> Rainer Weikusat wrote:
>> Helmut Schellong <sche...@t-online.de> writes:
>>>107] /usr/bin/time bgrep -c iso /usr/z.iso
>>>16
>>> 0.97 real 0.43 user 0.40 sys
>>>108] /usr/bin/time bgrep -cM iso /usr/z.iso //-M == --mmap
>>>16
>>> 1.13 real 1.01 user 0.07 sys
>> Allerdings sieht das nicht danach aus, denn Du hast erheblich weniger
>> Aktivität im Kernel als vorher. Dafür brauchst Du im userspace doppelt
>> solange.
>
> Ja, genau, diese Zeit wird praktisch zu 100% in
> SucheStr(bufptr bzw. mapptr, len); verbraucht.
>
>> Ohne Code? Wie?
>
> Der Code in meinem ersten Posting reicht eigentlich aus.

Nein.

> Es ist wirklich so, daß SucheStr() halb so schnell von
> mapptr liest.

Falls man sowas nimmt:

---------
#define _GNU_SOURCE

#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <memory.h>
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/mman.h>

void scan_a(int fd, off_t size)
{
char *p, *e;

size = lseek(fd, 0, SEEK_END);
p = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
e = p + size - sizeof("winter") + 1;
while (1) {
p = memmem(p, e - p, "winter", sizeof("winter") - 1);
if (!p) break;
p += sizeof("winter") - 1;
if (p >= e) break;
}
}

void scan_b(int fd, off_t size)
{
char *p, *e;

p = malloc(size);
e = p + size - sizeof("winter") + 1;
read(fd, p, size);
while (1) {
p = memmem(p, e - p, "winter", sizeof("winter") - 1);
if (!p) break;
p += sizeof("winter") - 1;
if (p >= e) break;
}
}

int main(void)
{
int fd;
clock_t c0;
off_t size;

fd = open("sll", O_RDONLY, 0);
size = lseek(fd, 0, SEEK_END);
lseek(fd, 0, SEEK_SET);

scan_b(fd, size);
// scan_a(fd, size);

return 0;
}
-------------

kann man dem entnehmen, daß das Problem wahrscheinlicht an nicht mmap
liegt. Für 156M Eingabedaten sieht das einmal so aus:

[rw@winter]:/tmp $/usr/bin/time -f "wall %e user %U system %S %% cpu: %P major: %F minor: %R" ./a.out
wall 15.58 user 3.45 system 1.35 % cpu: 30% major: 73 minor: 39414
[rw@winter]:/tmp $/usr/bin/time -f "wall %e user %U system %S %% cpu: %P major: %F minor: %R" ./a.out
wall 16.13 user 3.43 system 1.14 % cpu: 28% major: 71 minor: 39060
[rw@winter]:/tmp $/usr/bin/time -f "wall %e user %U system %S %% cpu: %P major: %F minor: %R" ./a.out
wall 17.27 user 3.44 system 1.27 % cpu: 27% major: 71 minor: 39060

und einmal so:

[rw@winter]:/tmp $/usr/bin/time -f "wall %e user %U system %S %% cpu: %P major: %F minor: %R" ./a.out
wall 12.45 user 2.43 system 0.14 % cpu: 20% major: 39118 minor: 7
[rw@winter]:/tmp $/usr/bin/time -f "wall %e user %U system %S %% cpu: %P major: %F minor: %R" ./a.out
wall 3.53 user 3.45 system 0.08 % cpu: 99% major: 39118 minor: 7
[rw@winter]:/tmp $/usr/bin/time -f "wall %e user %U system %S %% cpu: %P major: %F minor: %R" ./a.out
wall 3.53 user 3.47 system 0.07 % cpu: 100% major: 39118 minor: 7

Rainer Weikusat

unread,
Sep 15, 2003, 6:11:58 AM9/15/03
to
mle...@serpens.de (Michael van Elst) writes:
> Rainer Weikusat <weik...@students.uni-mainz.de> writes:
>>Was ist daran 'grotesk'? Durch das memcpy bewegst Du das File effektiv
>>in Deinen Adressraum und danach kannst Du schneller darauf
>>zugreifen.
>
> In "deinem Adressraum" ist es schon vorher,

Nein, das ist es nicht. Das sind ein Haufen page frames und für die
kann man sogar noch lazy allocation machen.

> Wenn die Suchroutine langsam ist, dann kann es sein, dass das vorherige
> Kopieren und anschliessende Suchen im Cache schneller ist als das direkte
> Suchen.

Ich habe die langsamst mögliche Suchroutine für beides implementiert
und gepostet. Fazit: Das war es nicht.

> Der Unterschied zwischen read() und mmap() liegt dann eher daran, dass
> read() normalerweise ein read-ahead im Filesystem ausloest, waehrend
> mmap() das nicht macht.

Das ist Humbug. Da liegt ein cache dazwischen.

> Eventuell hilft ein passender madvise()-Aufruf, mit dem man dem VM-System
> mitteilt, ob man sequentiell auf den Speicher (und damit die Datei)
> zugreifen will.

Er macht exakt keinen Unterschied.

Michael van Elst

unread,
Sep 15, 2003, 7:54:15 AM9/15/03
to
Rainer Weikusat <weik...@students.uni-mainz.de> writes:

>> In "deinem Adressraum" ist es schon vorher,

>Nein, das ist es nicht. Das sind ein Haufen page frames und für die
>kann man sogar noch lazy allocation machen.

Adressraum == die fuer dich allokierten Adressen, wenn du darauf zugreifst
bekommst du keinen segfault oder bus error. Ob und welche reale Pages dahinter
stehen ist irrelevant.


>> Wenn die Suchroutine langsam ist, dann kann es sein, dass das vorherige
>> Kopieren und anschliessende Suchen im Cache schneller ist als das direkte
>> Suchen.

>Ich habe die langsamst mögliche Suchroutine für beides implementiert
>und gepostet. Fazit: Das war es nicht.

Den Widerspruch seh ich nicht. Es kommt darauf an, ob das Kopieren den
Cache schneller fuellt als die Suchroutine und ob das nachtraegliche
Suchen im Cache das nicht wieder aufwiegt.


>> Der Unterschied zwischen read() und mmap() liegt dann eher daran, dass
>> read() normalerweise ein read-ahead im Filesystem ausloest, waehrend
>> mmap() das nicht macht.

>Das ist Humbug. Da liegt ein cache dazwischen.

wall 15.58 user 3.45 system 1.35 % cpu: 30% major: 73 minor: 39414


wall 16.13 user 3.43 system 1.14 % cpu: 28% major: 71 minor: 39060

wall 17.27 user 3.44 system 1.27 % cpu: 27% major: 71 minor: 39060

Das sieht nicht sehr nach Cache aus.

wall 12.45 user 2.43 system 0.14 % cpu: 20% major: 39118 minor: 7

wall 3.53 user 3.45 system 0.08 % cpu: 99% major: 39118 minor: 7

wall 3.53 user 3.47 system 0.07 % cpu: 100% major: 39118 minor: 7

Dies hingegen schon. Ich rate mal, dass erstes mmap() ist, zweiteres
read(). Soll das auch ein FreeBSD4.8-System sein ?

Rainer Weikusat

unread,
Sep 15, 2003, 9:10:02 AM9/15/03
to
mle...@serpens.de (Michael van Elst) writes:
> Rainer Weikusat <weik...@students.uni-mainz.de> writes:
>>> In "deinem Adressraum" ist es schon vorher,
>
>>Nein, das ist es nicht. Das sind ein Haufen page frames und für die
>>kann man sogar noch lazy allocation machen.
>
> Adressraum == die fuer dich allokierten Adressen,

Ja. Und direkt nach dem mmap befindet sich dort höchstwahrscheinlich
nichts, auch wenn diese Adressen vielleicht schon in einem pagedirectory
stehen.

> wenn du darauf zugreifst bekommst du keinen segfault oder bus
> error. Ob und welche reale Pages dahinter stehen ist irrelevant.

Es ist insofern relevant, als das das file immer noch gelesen werden
muß und mir auch noch tatsächlich physisch vorhandener Hauptspeicher
zugewiesen werden muß.

>>> Wenn die Suchroutine langsam ist, dann kann es sein, dass das vorherige
>>> Kopieren und anschliessende Suchen im Cache schneller ist als das direkte
>>> Suchen.
>
>>Ich habe die langsamst mögliche Suchroutine für beides implementiert
>>und gepostet. Fazit: Das war es nicht.
>
> Den Widerspruch seh ich nicht. Es kommt darauf an, ob das Kopieren den
> Cache schneller fuellt als die Suchroutine und ob das nachtraegliche
> Suchen im Cache das nicht wieder aufwiegt.

Bei großen Dateien sicher nicht. Dann habe ich am Ende das
Kopiervorganges das gecachet, was ich erst als allerletztes brauche,
falls ich nicht rückwärts suche.

>>> Der Unterschied zwischen read() und mmap() liegt dann eher daran, dass
>>> read() normalerweise ein read-ahead im Filesystem ausloest, waehrend
>>> mmap() das nicht macht.
>

> wall 15.58 user 3.45 system 1.35 % cpu: 30% major: 73 minor: 39414
> wall 16.13 user 3.43 system 1.14 % cpu: 28% major: 71 minor: 39060
> wall 17.27 user 3.44 system 1.27 % cpu: 27% major: 71 minor: 39060
>
> Das sieht nicht sehr nach Cache aus.

Es illustriert den von Patrick erwähnten Effekt bei einer Kopie einer
ausreichend großen Datei (in diesem Fall groß genug, daß es hörbare
und eine Weile andauernde paging-Aktivität gab).

> wall 12.45 user 2.43 system 0.14 % cpu: 20% major: 39118 minor: 7
> wall 3.53 user 3.45 system 0.08 % cpu: 99% major: 39118 minor: 7
> wall 3.53 user 3.47 system 0.07 % cpu: 100% major: 39118 minor: 7
>
> Dies hingegen schon. Ich rate mal, dass erstes mmap() ist, zweiteres
> read().

Umgekehrt. Man sieht das auch schön dann denn fault-Zahlen oben und
unten: Im zweiten Fall werden fast nur 'frische' Seiten gemappt, im
ersten bouncen sie ständig zwischen Prozeß und Kernel hin- und
her. Das wird noch viel lustiger, falls man zwei davon laufen läßt.

Helmut Schellong

unread,
Sep 15, 2003, 9:10:38 AM9/15/03
to
Michael van Elst wrote:
> Rainer Weikusat <weik...@students.uni-mainz.de> writes:

> Der Unterschied zwischen read() und mmap() liegt dann eher daran, dass
> read() normalerweise ein read-ahead im Filesystem ausloest, waehrend
> mmap() das nicht macht. Je nach Platte und Controller kann das durchaus
> einen Faktor 2 ausmachen.
>
> Eventuell hilft ein passender madvise()-Aufruf, mit dem man dem VM-System
> mitteilt, ob man sequentiell auf den Speicher (und damit die Datei)
> zugreifen will.

Zur Erinnerung:
---------------


Ich habe mit mmap() alles auf einen Schlag gemapt, je 1 MB gemapt,
je 32 KB gemapt - immer gleicher Zeitbedarf!

[PIII/700, 768 MB RAM; 460 MB free (danach)]

Ich habe Flags durchprobiert, auch MAP_FIXED, auch

*madvise()* mit diversen Flags - immer gleicher Zeitbedarf!
------------------------------------------------------------------
105] /usr/bin/time bgrep -c iso /usr/z.iso
17
5.44 real 0.47 user 0.50 sys //1. Aufruf

104] /usr/bin/time fgrep -c --mmap iso /usr/z.iso
16
9.53 real 0.94 user 0.29 sys //1. Aufruf

------------------------------------------------------------------
Es gab stets vor den Messungen einen 1. Aufruf.

Helmut Schellong

unread,
Sep 15, 2003, 9:34:09 AM9/15/03
to
Helmut Leitner wrote:
>
> Patrick Schaaf wrote:
>
>>Helmut Schellong <sche...@t-online.de> writes:
>>
>>
>>>Findest Du nicht, daß es ziemlich 'bekloppt' ist, wenn man mit
>>>mmap so umgehen muß, damit mmap nicht mehr nur halb so schnell ist
>>>wie read?
>>
>>Findest Du es bekloppt, dass man zum erfolgreichen Haemmern den Hammer
>>am Stiel halten sollte, statt ihn einfach irgendwo anzupacken? Und dass
>>das bei einer Reisszwecke auch ohne Hammer und einfacher geht?
>
>
> Das mag richtig sein...

Übrigens, Reiszwecke mit dem Daumen kann schrecklich enden, wenn sich
beim Drücken der Stift vom Blechteller löst.

> aber es scheint, dass niemand so recht weiß, wo dieses Werkzeug anzugreifen
> ist und wie es zuschlägt. Seinen sinnvollen Einsatz davon abhängig zu machen,
> wie Filegröße und System-RAM-Größe zusammenhängen, könnte ja nur bedeuten,
> dass man für ein optimales Tool immer beide Strategien implementieren muss
> und zusätzlich die Erkennung der Auswahlkriterien. Schließlich wird man ja
> nicht für eine zufällige Konfiguration programmieren.
>
> D. h. eigentlich müsste mmap ein mmap_makes_sense(filesize) bedingen,
> das alle relevanten Systemparameter einbezieht und eine Prognose abgibt.
> Wenn das nicht mitgeliefert wird, ist mmap eine Falle oder der Zwang das Rad
> neu zu erfinden.
>
> Ganz kann ich dem 'bekloppt' von HS nicht widersprechen.

Ich finde es auf jeden Fall 'bekloppt', wenn man alle gemapten Pages
vorher anlesen muß, damit das anschließende Ganzlesen schneller ist.
(s.u. madvise)

Ich finde es 'unproduktiv', daß mmap nicht nur keinen Gewinn bringt, sondern
sogar nur halb so schnell ist.

Ich finde es unbefriedigend, wenn madvise( MADV_WILLNEED MADV_SEQUENTIAL
absolut keinen Effekt haben, auch wenn die Arbeitslage dazu paßt.
Im Quelltext zu grep steht sogar, daß dies manchmal 30% Speedsenkung
bringt. Das finde ich alles zusammen - reichlich 'witzig'.

Michael van Elst

unread,
Sep 15, 2003, 10:23:49 AM9/15/03
to
Helmut Schellong <sche...@t-online.de> writes:

>Michael van Elst wrote:
>> Eventuell hilft ein passender madvise()-Aufruf, mit dem man dem VM-System
>> mitteilt, ob man sequentiell auf den Speicher (und damit die Datei)
>> zugreifen will.

>Zur Erinnerung:
>---------------
>Ich habe mit mmap() alles auf einen Schlag gemapt, je 1 MB gemapt,
>je 32 KB gemapt - immer gleicher Zeitbedarf!
>[PIII/700, 768 MB RAM; 460 MB free (danach)]
>Ich habe Flags durchprobiert, auch MAP_FIXED, auch
>*madvise()* mit diversen Flags - immer gleicher Zeitbedarf!

Sorry, das Posting kam hier erst spaeter an. Wenn keine physikalische I/O
stattfindet, sind read-ahead und madvise() natuerlich bedeutungslos.

Michael van Elst

unread,
Sep 15, 2003, 10:19:00 AM9/15/03
to
Rainer Weikusat <weik...@students.uni-mainz.de> writes:

>Es ist insofern relevant, als das das file immer noch gelesen werden
>muß und mir auch noch tatsächlich physisch vorhandener Hauptspeicher
>zugewiesen werden muß.

Aussage: Kopieren von gemmapten Daten auf Stack beschleunigt die Suche.
Behauptung: Das liegt daran, dass die Daten nach dem Kopieren in
deinem (Prozess-)Adressraum liegen.

Die Daten liegen bereits im Adressraum (denn das ist rein die Illusion,
die dir das VM-System vorspiegelt).

Ob mit oder ohne Kopie, die Daten muessen in jedem Fall gelesen werden
und auch der Hauptspeicher muss zugewiesen werden. Ob das bei der Kopie
passiert oder waehrend der Suche macht keinen Unterschied, beides geschieht
fuer jede Page einzeln, der Overhead ist derselbe.


>>>> Wenn die Suchroutine langsam ist, dann kann es sein, dass das vorherige
>>>> Kopieren und anschliessende Suchen im Cache schneller ist als das direkte
>>>> Suchen.
>>
>>>Ich habe die langsamst mögliche Suchroutine für beides implementiert
>>>und gepostet. Fazit: Das war es nicht.
>>
>> Den Widerspruch seh ich nicht. Es kommt darauf an, ob das Kopieren den
>> Cache schneller fuellt als die Suchroutine und ob das nachtraegliche
>> Suchen im Cache das nicht wieder aufwiegt.

>Bei großen Dateien sicher nicht. Dann habe ich am Ende das
>Kopiervorganges das gecachet, was ich erst als allerletztes brauche,
>falls ich nicht rückwärts suche.

Schon wahr, aber von der Groesse der Dateien wurde gar nicht geredet
und die ist auch nicht relevant im Gegensatz zur Buffergroesse.
Und das einzige "Kopieren auf den Stack" findet sich auch nur in dem
Code-Beispiel, das einen 32kB-Buffer liest.


>>>> Der Unterschied zwischen read() und mmap() liegt dann eher daran, dass
>>>> read() normalerweise ein read-ahead im Filesystem ausloest, waehrend
>>>> mmap() das nicht macht.
>>
>> wall 15.58 user 3.45 system 1.35 % cpu: 30% major: 73 minor: 39414
>> wall 16.13 user 3.43 system 1.14 % cpu: 28% major: 71 minor: 39060
>> wall 17.27 user 3.44 system 1.27 % cpu: 27% major: 71 minor: 39060
>>
>> Das sieht nicht sehr nach Cache aus.

>Es illustriert den von Patrick erwähnten Effekt bei einer Kopie einer
>ausreichend großen Datei (in diesem Fall groß genug, daß es hörbare
>und eine Weile andauernde paging-Aktivität gab).

Dann hat dieser Test nichts mit dem Problem zu tun. In einem Fall hast du
dann heftiges Thrashing und im anderen Fall hat der Speicher fuer die eine
Kopie der 150+-MB-Datei gerade ausgereicht.


Als ich mein erstes Posting schrieb ging ich von _grossen Dateien_
aus die stueckweise gelesen werden, so wie man das eben normalerweise
macht, wenn man keine worst-case-Untersuchungen anstrebt. Ein
grep --mmap macht das auch nicht anders.

Die vom OP gemessenen Zeiten sagen allerdings, dass die Datei klein
genug war um komplett im Cache zu liegen und es findet auch kein
Thrashing statt.

Damit bleibt als Erklaerung in erster Linie der Einfluss des
(Speicher-)Caches obwohl es seltsam ist, dass die Buffergroessen
darauf keinen Einfluss gehabt haben sollen. Allerdings kennen wir
ja auch das Originalprogramm nicht, vielleicht steckt da einfach
ein dummer Fehler drin.

Helmut Schellong

unread,
Sep 15, 2003, 10:43:23 AM9/15/03
to
Michael van Elst wrote:

>>Zur Erinnerung:
>>---------------
>>Ich habe mit mmap() alles auf einen Schlag gemapt, je 1 MB gemapt,
>>je 32 KB gemapt - immer gleicher Zeitbedarf!
>>[PIII/700, 768 MB RAM; 460 MB free (danach)]
>>Ich habe Flags durchprobiert, auch MAP_FIXED, auch
>>*madvise()* mit diversen Flags - immer gleicher Zeitbedarf!
>
>
> Sorry, das Posting kam hier erst spaeter an. Wenn keine physikalische I/O
> stattfindet, sind read-ahead und madvise() natuerlich bedeutungslos.

Nicht nur das; ich schrieb ja, daß ich etwa 10 Varianten probierte:
ich habe auch mal alle gemapten Pages angelesen vor dem Ganzlesen.
Keinerlei Effekt!
GAR NICHTS hat irgendeinen Effekt! mmap bleibt stets halb so schnell!
Dies sogar bei "1. Aufruf"!

Rainer Weikusat

unread,
Sep 15, 2003, 11:58:15 AM9/15/03
to
mle...@serpens.de (Michael van Elst) writes:
> Rainer Weikusat <weik...@students.uni-mainz.de> writes:
>>Es ist insofern relevant, als das das file immer noch gelesen werden
>>muß und mir auch noch tatsächlich physisch vorhandener Hauptspeicher
>>zugewiesen werden muß.
>
> Aussage: Kopieren von gemmapten Daten auf Stack beschleunigt die Suche.
> Behauptung: Das liegt daran, dass die Daten nach dem Kopieren in
> deinem (Prozess-)Adressraum liegen.
>
> Die Daten liegen bereits im Adressraum

Da liegt überhaupt nichts. 'Irgendetwas' liegt *möglicherweise* in
einer page table und verweist von dort buchstäblich ins Nichts. Alles
weitere findet später statt. Auf diesem Niveau brauchen wir das auch
nicht zu diskutieren. Bis demnächst irgendwann vielleicht.

Rainer Weikusat

unread,
Sep 15, 2003, 11:59:19 AM9/15/03
to
mle...@serpens.de (Michael van Elst) writes:
> Rainer Weikusat <weik...@students.uni-mainz.de> writes:
>>Es ist insofern relevant, als das das file immer noch gelesen werden
>>muß und mir auch noch tatsächlich physisch vorhandener Hauptspeicher
>>zugewiesen werden muß.
>
> Aussage: Kopieren von gemmapten Daten auf Stack beschleunigt die Suche.
> Behauptung: Das liegt daran, dass die Daten nach dem Kopieren in
> deinem (Prozess-)Adressraum liegen.
>
> Die Daten liegen bereits im Adressraum

Da liegt überhaupt nichts. 'Irgendetwas' liegt *möglicherweise* in

Michael van Elst

unread,
Sep 15, 2003, 1:20:35 PM9/15/03
to
Rainer Weikusat <weik...@students.uni-mainz.de> writes:

> Auf diesem Niveau brauchen wir das auch
>nicht zu diskutieren.

Ts.ts. Erst alles Humbug nennen, dann was erzaehlen, was zwar nicht
falsch ist aber mit dem Thema nichts zu tun hat und dann noch
Niveau verlangen.

Ich hoffe du wirst auch noch mal so alt wie ich mich gerade fuehle.

Helmut Schellong

unread,
Sep 15, 2003, 11:25:29 PM9/15/03
to
Michael van Elst wrote:
> Helmut Schellong <sche...@t-online.de> writes:
>
>
>>Michael van Elst wrote:
>>
>>>Eventuell hilft ein passender madvise()-Aufruf, mit dem man dem VM-System
>>>mitteilt, ob man sequentiell auf den Speicher (und damit die Datei)
>>>zugreifen will.
>
>
>>Zur Erinnerung:
>>---------------
>>Ich habe mit mmap() alles auf einen Schlag gemapt, je 1 MB gemapt,
>>je 32 KB gemapt - immer gleicher Zeitbedarf!
>>[PIII/700, 768 MB RAM; 460 MB free (danach)]
>>Ich habe Flags durchprobiert, auch MAP_FIXED, auch
>>*madvise()* mit diversen Flags - immer gleicher Zeitbedarf!
>
>
> Sorry, das Posting kam hier erst spaeter an. Wenn keine physikalische I/O
> stattfindet, sind read-ahead und madvise() natuerlich bedeutungslos.


Ich habe die mmap-Testfunktion doch mal hier:
(basiert auf der mit read):
------------------------------------------------------------------------------
static int FindM(off_t fsz)
{
# define FILL (32*1024)
register char *bp;
const char *fp;
register int nr, fl;
int nf, pgsz, o;
ulong fnd=0;
off_t nd;
pgsz= getpagesize();

for (Nr=0,o=nr=0,bp=0; (nd=Nmax-Nr, nd>0)&&(
(void)(bp?munmap(bp,nr):0),
nr= nd>=FILL?FILL:(int)nd,
bp= mmap(0, nr, PROT_READ, MAP_PRIVATE, FDi, Nr),
bp!=MAP_FAILED); )
{
Nr+=nr; nf=nr-o;
do {
fp= FindS(bp+o, nf, Str, lStr);
if (!fp) { o=0; break; }
if (fl=(bp+o+nf)-fp, fl<lStr) {
if (o=0, Nmax-Nr>0&&Nr>=pgsz) Nr-=pgsz, o=pgsz-fl;
break;
}
if (++fnd, !(O1|Ol|Oc)) {
;
}
if (!(fl-=lStr)) { o=0; break; }
o=(fp-bp)+lStr; nf=fl;
}
while (1);
}
;
return (int)fnd;
}
------------------------------------------------------------------------------
Ich sehe da nix, was mmap 'stören' könnte.


Mit icc kompiliert:
------------------------------------------------------
151] /usr/bin/time bgrep -c iso /usr/z.iso
17
0.84 real 0.40 user 0.40 sys
------------------------------------
170] /usr/bin/time bgrep -cM iso /usr/z.iso
17
1.04 real 0.91 user 0.07 sys
------------------------------------------------------

Patrick Schaaf

unread,
Sep 16, 2003, 2:37:32 AM9/16/03
to
Helmut Schellong <sche...@t-online.de> writes:

>Ich sehe da nix, was mmap 'stören' könnte.

Ich sehe da nix kaputtes, muss aber zugeben, dass Augen und Gehirn
nach dem mmap()-Aufruf irgendwie einen Nothalt durchgefuehrt haben,
und den weiteren Code nicht wahrnehmen wollen. Weiss nicht, warum.

Hast Du mittlerweile mal mit 'filegroesse >> 1/2 RAM' getestet? Und?

Gruss
Patrick

Michael van Elst

unread,
Sep 16, 2003, 3:10:07 AM9/16/03
to
Helmut Schellong <sche...@t-online.de> writes:

>Ich habe die mmap-Testfunktion doch mal hier:

Ein bisschen obfuscated und nicht vollstaendig.

Das hier:

> if (o=0, Nmax-Nr>0&&Nr>=pgsz) Nr-=pgsz, o=pgsz-fl;

sieht nicht so gut aus. Ob es zuschlaegt haengt natuerlich von
den Daten und dem Suchstring ab.

Patrick Schaaf

unread,
Sep 16, 2003, 3:28:22 AM9/16/03
to
Hallo Helmut,

mein Kleinhirn war vom Notaus nicht betroffen, und moechte Dies mitteilen:

># define FILL (32*1024)


> for (Nr=0,o=nr=0,bp=0; (nd=Nmax-Nr, nd>0)&&(

> nr= nd>=FILL?FILL:(int)nd,
> bp= mmap(0, nr, PROT_READ, MAP_PRIVATE, FDi, Nr),
> bp!=MAP_FAILED); )
> {
> Nr+=nr;

Was genau ist Nmax? Ich nehme an, es handelt sich um eine globale Variable,
die die Groesse der Input-Datei in Byte angibt.

Wie man der Verwendung von FILL ansieht, mmappst Du IMMER hoechsten 32kB.
Auch wenn Dein Testfile 128MB gross ist. Dann machst Du 4096 mal mmap und
munmap. Statt einmal mmap von 128MB am Stueck, wovon vorher IMHO immer die
Rede war.

Du testest also nicht die Vorteile von mmap, sondern den syscall-overhead
fuer munmap/mmap auf unsinnig kleinen Speicherbereichen. Die genaue Suche
dazwischen kannst Du Dir vermutlich komplett sparen, ohne am Ergebnis viel
zu aendern. (ggf. jede cacheline oder zumindest jede page einmal touchen)

Ich haette etwas wie Unten erwartet. Teste mal damit.

Gruss
Patrick

unsigned find_string_in_file_using_mmap(int fd, char *nadel)
{
struct stat sb;
unsigned l = strlen(nadel), n = ~0;
if ((0 == fstat(fd, &sb)) && (0 < sb.st_size)) {
char *heuhaufen =
mmap(0, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
if (heuhaufen) {
for (n = 0; n < sb.st_size; n++) {
if (0 == strncmp(heuhaufen+n, nadel, l))
break;
/* put progressive intelligence here */
}
munmap(heuhaufen, sb.st_size);
}
}
return n < sb.st_size ? n : ~0;
}

Uwe Ohse

unread,
Sep 16, 2003, 6:08:50 AM9/16/03
to
Hallo Patrick,

> char *heuhaufen =
> mmap(0, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
> if (heuhaufen) {

heuhaufen!=-1 oder heuhufen!=MAP_FAILED

btw: es mag sinnvoll sein, nicht gleich die ganze Datei zu mmappen.
Gigabytes in den Adressraum aufzunehmen ist nicht unproblematisch.


> if (0 == strncmp(heuhaufen+n, nadel, l))

if (heuhaufen[n]==nadel[0] && strncmp(...+1,+...+1,l-1)

> return n < sb.st_size ? n : ~0;

ich finde es durchaus nicht elegant, die Fälle "Suchbegriff nicht
gefunden" und "das System kann das mmap()ing nicht durchführen" als
identisch zu betrachten.

Allerdings könnte das dem Schellongschen Codebeispiel angemessen bzw.
ihm weit überlegen sein.

Gruß, Uwe

Patrick Schaaf

unread,
Sep 16, 2003, 6:51:43 AM9/16/03
to
u...@ohse.de (Uwe Ohse) writes:

>Hallo Patrick,

>> char *heuhaufen =
>> mmap(0, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
>> if (heuhaufen) {

>heuhaufen!=-1 oder heuhaufen!=MAP_FAILED

Das ist in der Tat ein unverzeihlicher Fehler.

Wollte ich die Tage sogar bei Beispielcode von Anderen in diesem Thread
anmaekeln, hatte es mir da aber gespart - wahrscheinlich habe ich den
Fehler genau deshalb dann selbst gemacht :)

>btw: es mag sinnvoll sein, nicht gleich die ganze Datei zu mmappen.
>Gigabytes in den Adressraum aufzunehmen ist nicht unproblematisch.

Da stellt sich halt die Frage, wo man die Grenze setzt. Aber darum
ging es bisher nicht. Die Frage stellt sich genauso fuer den Einsatz
von read(), wie gross soll da der Lesebuffer sein?

>> if (0 == strncmp(heuhaufen+n, nadel, l))

> if (heuhaufen[n]==nadel[0] && strncmp(...+1,+...+1,l-1)

Mikrooptimierung, macht Beispielkot nur schwerer leslich.

>> return n < sb.st_size ? n : ~0;

>ich finde es durchaus nicht elegant, die Fälle "Suchbegriff nicht
>gefunden" und "das System kann das mmap()ing nicht durchführen" als
>identisch zu betrachten.

Ein berechtigter Kritikpunkt. Aber um API-Schoenheit ging es mir nicht.

Gruss
Patrick

Helmut Schellong

unread,
Sep 16, 2003, 11:09:19 AM9/16/03
to
Michael van Elst wrote:
> Helmut Schellong <sche...@t-online.de> writes:
>
>
>>Ich habe die mmap-Testfunktion doch mal hier:
>
>
> Ein bisschen obfuscated und nicht vollstaendig.

printf-Code hab ich weggelassen.

Daß bei -c "17" ausgegeben wird, kann man sich denken.

> Das hier:
>
>
>> if (o=0, Nmax-Nr>0&&Nr>=pgsz) Nr-=pgsz, o=pgsz-fl;
>
>
> sieht nicht so gut aus. Ob es zuschlaegt haengt natuerlich von
> den Daten und dem Suchstring ab.

126 MB und 17mal 'iso' darin; kann man also zur Zeit vernachlässigen.

Achtung, ist eine TESTfunktion!

Helmut Schellong

unread,
Sep 16, 2003, 11:17:58 AM9/16/03
to
Patrick Schaaf wrote:
> Hallo Helmut,
>
> mein Kleinhirn war vom Notaus nicht betroffen, und moechte Dies mitteilen:
>
>
>># define FILL (32*1024)
>> for (Nr=0,o=nr=0,bp=0; (nd=Nmax-Nr, nd>0)&&(
>> nr= nd>=FILL?FILL:(int)nd,
>> bp= mmap(0, nr, PROT_READ, MAP_PRIVATE, FDi, Nr),
>> bp!=MAP_FAILED); )
>> {
>> Nr+=nr;
>
>
> Was genau ist Nmax? Ich nehme an, es handelt sich um eine globale Variable,
> die die Groesse der Input-Datei in Byte angibt.

Das Programm hat eine Option -n nmax

> Wie man der Verwendung von FILL ansieht, mmappst Du IMMER hoechsten 32kB.
> Auch wenn Dein Testfile 128MB gross ist. Dann machst Du 4096 mal mmap und
> munmap. Statt einmal mmap von 128MB am Stueck, wovon vorher IMHO immer die
> Rede war.

Hab ich doch alles getan!: Full, 1 MB, 128KB, 32KB, 8KB...
Nie ein Unterschied!
(Unterhalb 32KB kam natürlich etwas mehr time)

> Du testest also nicht die Vorteile von mmap, sondern den syscall-overhead
> fuer munmap/mmap auf unsinnig kleinen Speicherbereichen. Die genaue Suche
> dazwischen kannst Du Dir vermutlich komplett sparen, ohne am Ergebnis viel
> zu aendern. (ggf. jede cacheline oder zumindest jede page einmal touchen)

Dieser Overhead ist im Vergleich zu FindS() fast Null!

Ich habe auch jede Page einmal getoucht - Kein Unterschied!

Helmut Schellong

unread,
Sep 16, 2003, 11:21:46 AM9/16/03
to
Uwe Ohse wrote:
> Hallo Patrick,

> ich finde es durchaus nicht elegant, die Fälle "Suchbegriff nicht
> gefunden" und "das System kann das mmap()ing nicht durchführen" als
> identisch zu betrachten.
>
> Allerdings könnte das dem Schellongschen Codebeispiel angemessen bzw.
> ihm weit überlegen sein.

Woher weißt Du das? Speed gemessen?

Helmut Schellong

unread,
Sep 16, 2003, 11:24:14 AM9/16/03
to
Patrick Schaaf wrote:

>>btw: es mag sinnvoll sein, nicht gleich die ganze Datei zu mmappen.
>>Gigabytes in den Adressraum aufzunehmen ist nicht unproblematisch.
>
>
> Da stellt sich halt die Frage, wo man die Grenze setzt. Aber darum
> ging es bisher nicht. Die Frage stellt sich genauso fuer den Einsatz
> von read(), wie gross soll da der Lesebuffer sein?

16..24 KB.
Darunter und darüber wirds langsamer!

Helmut Schellong

unread,
Sep 16, 2003, 11:46:51 AM9/16/03
to

cd /usr
touch zz
repeat 9 cat z.iso >>zz

------------------------------------------------------
110] /usr/bin/time bgrep -c iso /usr/zz 1. Aufruf
153
43.18 real 4.23 user 4.56 sys

111] /usr/bin/time bgrep -c iso /usr/zz
153
44.63 real 4.47 user 4.33 sys

112] /usr/bin/time bgrep -cM iso /usr/zz 32 KB FILL
153
30.42 real 8.31 user 1.95 sys

116] /usr/bin/time bgrep -cM iso /usr/zz 2 MB FILL
153
29.81 real 8.48 user 1.44 sys
------------------------------------------------------

mmap() lohnt sich insgesamt also nicht (FBSD) bei sequentiellem
Lesen, da nur bei Mammutdateien ein Vorteil vorhanden ist,
ansonsten stets halb so schnell wie mit read().

Patrick Schaaf

unread,
Sep 16, 2003, 1:02:58 PM9/16/03
to
Helmut Schellong <sche...@t-online.de> writes:

>> Hast Du mittlerweile mal mit 'filegroesse >> 1/2 RAM' getestet? Und?

>cd /usr
>touch zz
>repeat 9 cat z.iso >>zz

>------------------------------------------------------
>110] /usr/bin/time bgrep -c iso /usr/zz 1. Aufruf
>153
> 43.18 real 4.23 user 4.56 sys

>111] /usr/bin/time bgrep -c iso /usr/zz
>153
> 44.63 real 4.47 user 4.33 sys

>112] /usr/bin/time bgrep -cM iso /usr/zz 32 KB FILL
>153
> 30.42 real 8.31 user 1.95 sys

>116] /usr/bin/time bgrep -cM iso /usr/zz 2 MB FILL
>153
> 29.81 real 8.48 user 1.44 sys
>------------------------------------------------------

>mmap() lohnt sich insgesamt also nicht (FBSD) bei sequentiellem
>Lesen, da nur bei Mammutdateien ein Vorteil vorhanden ist,

30 Sekunden "real" statt 44 Sekunden "real". "nur". Wer Mammutdateien zu
verarbeiten hat, wird das zu schaetzen wissen. Mehr habe ich bisher nicht
zu sagen versucht. Danke, dass Du es Dir einmal demonstriert hast.

>ansonsten stets halb so schnell wie mit read().

Das ist sicher nicht so zu verallgemeinern. Wenn mir langweilig wird,
versuche ich mal zu verstehen, was Du da genau fuer ein Phaenomen hast.
Habe aber leider nur ein freeBSD zur Hand, und ausserdem ist mir gerade
nicht langweilig.

Gruss
Patrick

Helmut Schellong

unread,
Sep 16, 2003, 1:43:32 PM9/16/03
to
Patrick Schaaf wrote:
> Helmut Schellong <sche...@t-online.de> writes:
...

>>mmap() lohnt sich insgesamt also nicht (FBSD) bei sequentiellem
>>Lesen, da nur bei Mammutdateien ein Vorteil vorhanden ist,
>
>
> 30 Sekunden "real" statt 44 Sekunden "real". "nur". Wer Mammutdateien zu
> verarbeiten hat, wird das zu schaetzen wissen. Mehr habe ich bisher nicht
> zu sagen versucht. Danke, dass Du es Dir einmal demonstriert hast.

Du redest ziemlich mutig daher;
in wieviel % aller Fälle hat man es mit solchen Mammutdateien zu tun?!
Desweiteren ist mmap eingeschränkt portabel.

>>ansonsten stets halb so schnell wie mit read().
>
>
> Das ist sicher nicht so zu verallgemeinern. Wenn mir langweilig wird,
> versuche ich mal zu verstehen, was Du da genau fuer ein Phaenomen hast.

Für mich ist nach wie vor das Phänomenon, daß FindS() von *mapptr
halb so schnell liest wie von *bufptr (read).

Patrick Schaaf

unread,
Sep 16, 2003, 2:07:37 PM9/16/03
to
Helmut Schellong <sche...@t-online.de> writes:

>in wieviel % aller Fälle hat man es mit solchen Mammutdateien zu tun?!

Bin ich Soziologe? Keine Ahnung. Ich habe sie oefter.

>Desweiteren ist mmap eingeschränkt portabel.

Alles ist eingeschraenkt portabel. mmap ist eingeschraenkter portabel als read.
Wenn der Compiler kotzt, bekommt die Quelle '#if 0 || whatever'. Life goes on.

Gruss
Patrick

Helmut Schellong

unread,
Sep 16, 2003, 2:18:14 PM9/16/03
to
Patrick Schaaf wrote:
> Helmut Schellong <sche...@t-online.de> writes:

> Alles ist eingeschraenkt portabel. mmap ist eingeschraenkter portabel als read.
> Wenn der Compiler kotzt, bekommt die Quelle '#if 0 || whatever'. Life goes on.

Ich rede allerdings stets respektvoll mit meinem Compiler;
obwohl auch der beste von denen letztlich saudumm ist.

Uwe Ohse

unread,
Sep 17, 2003, 1:50:39 AM9/17/03
to
Hallo Helmut,

>> Allerdings könnte das dem Schellongschen Codebeispiel angemessen bzw.
>> ihm weit überlegen sein.
>
>Woher weißt Du das? Speed gemessen?

das ist nicht nötig, um die Codequalität zu beurteilen.

Gruß, Uwe

Helmut Schellong

unread,
Sep 17, 2003, 10:57:03 AM9/17/03
to

Komisch, Speed ist bei Code, der dem offenbaren Zweck dient,
das absolut größte Programm-Qualitätsmerkmal.

Du hast die Postings als Reaktion auf den Code (nicht mein Code)
gelesen?

Was genau ist denn an meiner TESTfunktion qualitativ schlecht?

Rainer Weikusat

unread,
Sep 17, 2003, 4:20:37 PM9/17/03
to
Helmut Schellong <sche...@t-online.de> writes:

> Uwe Ohse wrote:
>>>>Allerdings könnte das dem Schellongschen Codebeispiel angemessen bzw.
>>>>ihm weit überlegen sein.
>>>
>>>Woher weißt Du das? Speed gemessen?
>> das ist nicht nötig, um die Codequalität zu beurteilen.
>
> Komisch, Speed ist bei Code, der dem offenbaren Zweck dient,
> das absolut größte Programm-Qualitätsmerkmal.

Nein, Funktionstüchtigkeit ist das. Dazu gehört unter anderem 'so
schnell, wie nötig', aber nicht 'so schnell, wie möglich'.

Helmut Schellong

unread,
Sep 17, 2003, 6:19:01 PM9/17/03
to

Das ist ja wohl logisch, braucht man gar nicht erwähnen.
Ein nicht funktionierendes Programm ist nichts wert.

Rudolf Polzer

unread,
Sep 17, 2003, 8:01:11 PM9/17/03
to
Scripsit illa aut ille »Helmut Schellong« <sche...@t-online.de>:

> Rainer Weikusat wrote:
> > Helmut Schellong <sche...@t-online.de> writes:
> >>Uwe Ohse wrote:
> >>
> >>>>>Allerdings könnte das dem Schellongschen Codebeispiel angemessen bzw.
> >>>>>ihm weit überlegen sein.
> >>>>
> >>>>Woher weißt Du das? Speed gemessen?
> >>>
> >>>das ist nicht nötig, um die Codequalität zu beurteilen.
> >>
> >>Komisch, Speed ist bei Code, der dem offenbaren Zweck dient,
> >>das absolut größte Programm-Qualitätsmerkmal.
> >
> > Nein, Funktionstüchtigkeit ist das. Dazu gehört unter anderem 'so
> > schnell, wie nötig', aber nicht 'so schnell, wie möglich'.
>
> Das ist ja wohl logisch, braucht man gar nicht erwähnen.
> Ein nicht funktionierendes Programm ist nichts wert.

Ein nicht wartbares ist ebenfalls nichts wert.


--
The only thing that Babelfish is good at is proving that Vogons are
great poets.
Josef 'Jupp' Schugt in japan.anime.evangelion

Helmut Schellong

unread,
Sep 18, 2003, 2:08:40 AM9/18/03
to
Rudolf Polzer wrote:
> Scripsit illa aut ille »Helmut Schellong« <sche...@t-online.de>:
>
>>Rainer Weikusat wrote:
>>
>>>Helmut Schellong <sche...@t-online.de> writes:
>>>
>>>>Uwe Ohse wrote:
>>>>
>>>>
>>>>>>>Allerdings könnte das dem Schellongschen Codebeispiel angemessen bzw.
>>>>>>>ihm weit überlegen sein.
>>>>>>
>>>>>>Woher weißt Du das? Speed gemessen?
>>>>>
>>>>>das ist nicht nötig, um die Codequalität zu beurteilen.
>>>>
>>>>Komisch, Speed ist bei Code, der dem offenbaren Zweck dient,
>>>>das absolut größte Programm-Qualitätsmerkmal.
>>>
>>>Nein, Funktionstüchtigkeit ist das. Dazu gehört unter anderem 'so
>>>schnell, wie nötig', aber nicht 'so schnell, wie möglich'.
>>
>>Das ist ja wohl logisch, braucht man gar nicht erwähnen.
>>Ein nicht funktionierendes Programm ist nichts wert.
>
>
> Ein nicht wartbares ist ebenfalls nichts wert.

Doch. Wenn es fertig ist und gut ist und nix zu warten ist
und man nicht lange warten muß.

Worauf beziehen sich eigentlich diese ganzen Bemerkungen?
Etwa auf meine lächerlichen paar Zeilen Testcode, die ich
postete?
Falls ja, muß ich mal verstärkt über Geisteskrankheiten nachdenken.

Rainer Weikusat

unread,
Sep 18, 2003, 7:27:48 AM9/18/03
to
Helmut Schellong <sche...@t-online.de> writes:
> Rainer Weikusat wrote:
>> Helmut Schellong <sche...@t-online.de> writes:
>>>Uwe Ohse wrote:
>>>>>>Allerdings könnte das dem Schellongschen Codebeispiel angemessen bzw.
>>>>>>ihm weit überlegen sein.
>>>>>
>>>>>Woher weißt Du das? Speed gemessen?
>>>>
>>>>das ist nicht nötig, um die Codequalität zu beurteilen.
>>>
>>>Komisch, Speed ist bei Code, der dem offenbaren Zweck dient,
>>>das absolut größte Programm-Qualitätsmerkmal.
>> Nein, Funktionstüchtigkeit ist das. Dazu gehört unter anderem 'so
>> schnell, wie nötig', aber nicht 'so schnell, wie möglich'.
>
> Das ist ja wohl logisch, braucht man gar nicht erwähnen.
> Ein nicht funktionierendes Programm ist nichts wert.

Darauf wollte ich nicht hinaus. Es mag ganz amüsant sein, aus jedem
Code das letzte bißchen Geschwindigkeit herauszuprügeln, aber solange
diese Geschwindigkeit gar nicht gebraucht wird, ist es genau das: Ganz
amüsant. Der Code wird dadurch nicht schlechter (typischerweise eher
verständlicher, falls er halbwegs 'sane' strukturiert ist), aber eben
auch nicht besser.

ZB habe ich mal gemessen, wie lange mein Rechner braucht, um eine
lineare Liste mit 2^16 Elementen nach einem bestimmten (ein
Integer-Vergleich) abszusuchen: 4*10^-3 Sekunden. Falls man also nicht
einen guten Grund hat (zB Skalierbarkeit) lohnt sich die Verwendung
komplizierter Suchalgorithem heuzutage einfach nicht mehr. Dafür gibt
es dann andere Probleme, die zu lösen sind.

Markus Brueckner

unread,
Sep 18, 2003, 8:56:59 AM9/18/03
to
Helmut Schellong <sche...@t-online.de> wrote:

> Doch. Wenn es fertig ist und gut ist und nix zu warten ist
> und man nicht lange warten muß.

Es gibt keine fertige Software. Und selbst wenn: die Einstellung macht
einem Reviewer das Überprüfen deines Codes unsinnig schwer, wenn nicht
unmöglich. Aber ich nehme mal an, daß du es nicht nötig hast, jemanden
über deinen Code "drüberschauen" zu lassen...

Markus

--
Das Gateway ist einfach nur ein Gateway, und keine "Firewall". Dazu
muesste ich den Rechner in ein 19" Rack stecken und ihn bunt anmalen.
- Urs Traenkner in dcsf

Helmut Schellong

unread,
Sep 18, 2003, 11:15:18 AM9/18/03
to
Markus Brueckner wrote:
> Helmut Schellong <sche...@t-online.de> wrote:
>
>
>>Doch. Wenn es fertig ist und gut ist und nix zu warten ist
>>und man nicht lange warten muß.
>
>
> Es gibt keine fertige Software. Und selbst wenn: die Einstellung macht
> einem Reviewer das Überprüfen deines Codes unsinnig schwer, wenn nicht
> unmöglich. Aber ich nehme mal an, daß du es nicht nötig hast, jemanden
> über deinen Code "drüberschauen" zu lassen...

/* bgrep.c sc/19.01.97 */
#if !defined(OS)
# define OS 0
#endif

Damals geschrieben, hatte auf Anhieb funktioniert, damals im Vergleich
zu fgrep unter SCO ~6-fach schneller.
Seitdem nie wieder angefaßt.

Jetzt lediglich Find() zu FindM() kopiert und auf mmap angepaßt.
Und mit mmap unerwartete Speed-Einbrüche festgestellt.

Jens Schweikhardt

unread,
Sep 18, 2003, 11:29:20 AM9/18/03
to
Helmut Schellong <sche...@t-online.de> wrote
in <bkci66$jqu$06$1...@news.t-online.com>:
[Beweis durch Beispiel entsorgt (Wartung von Software)]

Die Kategorisierung weiterer argumentative Schnitzer findest Du
unter http://www.datanation.com/fallacies/index.htm


Regards,

Jens
--
Jens Schweikhardt http://www.schweikhardt.net/
SIGSIG -- signature too long (core dumped)

Andreas Krennmair

unread,
Sep 18, 2003, 1:56:21 PM9/18/03
to
* Helmut Schellong <sche...@t-online.de> [de.comp.os.unix.programming]:

> >>Ein nicht funktionierendes Programm ist nichts wert.
> >
> > Ein nicht wartbares ist ebenfalls nichts wert.
>
> Doch. Wenn es fertig ist und gut ist und nix zu warten ist
> und man nicht lange warten muß.

Ah, der Herr hat offensichtlich das Phaenomen des "bit rot" noch nicht
miterlebt. :-)

> Worauf beziehen sich eigentlich diese ganzen Bemerkungen?
> Etwa auf meine lächerlichen paar Zeilen Testcode, die ich
> postete?

Wenn du schon kurzen Testcode so schrecklich schreibst, wie sehen dann
etwas umfangreichere Programme von dir aus?

nichts fuer ungut,
mfg, ak

Patrick Schaaf

unread,
Sep 18, 2003, 3:02:47 PM9/18/03
to
Andreas Krennmair <net...@synflood.at> writes:

>* Helmut Schellong <sche...@t-online.de> [de.comp.os.unix.programming]:
>> >>Ein nicht funktionierendes Programm ist nichts wert.
>> >
>> > Ein nicht wartbares ist ebenfalls nichts wert.
>>
>> Doch. Wenn es fertig ist und gut ist und nix zu warten ist
>> und man nicht lange warten muß.

>Ah, der Herr hat offensichtlich das Phaenomen des "bit rot" noch nicht
>miterlebt. :-)

Wer sich darauf beschraenkt, die eigene Software zu betrachten,
in einem Vakuum, der wird nie "bit rot" erleben.

Gruss
Patrick

--
Ich bin KEIN Programmierer, den Sie anstellen moechten.
Ich habe EINMAL den Code anderer Leute gepflegt.
Das ist schon LANGE her.
Signaturen sollten nicht laenger als VIER Zeilen sein.

Andreas Krennmair

unread,
Sep 18, 2003, 3:13:24 PM9/18/03
to
* Patrick Schaaf <mailer...@bof.de> [de.comp.os.unix.programming]:

> Wer sich darauf beschraenkt, die eigene Software zu betrachten,
> in einem Vakuum, der wird nie "bit rot" erleben.

Dann darf aber auch nie Betriebssystem, Libraries, etc. upgraden.

mfg, ak

Helmut Schellong

unread,
Sep 18, 2003, 7:41:04 PM9/18/03
to
Andreas Krennmair wrote:

>>>Ein nicht wartbares ist ebenfalls nichts wert.
>>
>>
>> Doch. Wenn es fertig ist und gut ist und nix zu warten ist
>> und man nicht lange warten muß.
>
>
> Ah, der Herr hat offensichtlich das Phaenomen des "bit rot" noch nicht
> miterlebt. :-)

Doch, nicht selten. Allerdings noch nicht bei Privat-Code.

>> Worauf beziehen sich eigentlich diese ganzen Bemerkungen?
>> Etwa auf meine lächerlichen paar Zeilen Testcode, die ich
>> postete?
>
>
> Wenn du schon kurzen Testcode so schrecklich schreibst, wie sehen dann
> etwas umfangreichere Programme von dir aus?

Irgendwie habt ihr wenig Ahnung von der Praxis:
Ich habe diesen Testcode nicht *geschrieben*, sondern *kopiert*
und dann *schnell zurechtgestutzt* auf die neuen Verhältnisse.

Rainer Weikusat

unread,
Sep 19, 2003, 8:13:24 AM9/19/03
to
Markus Brueckner <mb1...@gmx.de> writes:
> Helmut Schellong <sche...@t-online.de> wrote:
>> Doch. Wenn es fertig ist und gut ist und nix zu warten ist
>> und man nicht lange warten muß.
>
> Es gibt keine fertige Software.

Es gibt in jedem Fall ziemlich 'fertige' Routinen. Sogar, falls man
nicht gegen $bibliotheksmonster linkt. Das ist eine notwendige
Voraussetzung für 'wartbare Software', denn es bedeutet nämlich, daß
man 'sicher' Teile austauschen kann, falls man das möchte, solange man
dasselbe Interface beibehält.

> Und selbst wenn: die Einstellung macht einem Reviewer das Überprüfen
> deines Codes unsinnig schwer, wenn nicht unmöglich.

Wie bereits in dclc gepostet: Leute, die C nicht fließend lesen können
können C nicht fließend lesen. Was machen die bitte im Inneren von
C-Programmen? Man kann das übrigens auch lernen.

int main(int argc, char **argv)
{
int exit_code;

init_sentry_abort();
if (!*argv || !*++argv) usage();

setup_sentry_playground();
start_sentry_conf_file();
argv = parse_arguments(argv);
ops_parse_opsec_args(argv);

exit_code = 0;
run(get_id);
if (id_valid) run(grab);
else exit_code = 1;
remove_sentry_playground();

return exit_code;
}

Das, was eine Funktion tut, erkennt an dem Kontext, in dem sie
aufgerufen wird und *genau da* gehört auch ein erläuternder Kommentar
hin, falls einer gebraucht wird. Was meistens nicht der Fall ist, wenn
die Dinge ein Baumstruktur haben, bei der auf den unteren Ebenen nur
explizit an sie weitergereichte Informationen bekannt sind
(DAG). Falls man das ändern muß, kann man sich zu jedem Zeitpunkt auf
den aktuellen subtree und seine Nachbarknoten beschränken. Das bringt
viel mehr, als sich auf 'einfache Aussagesätze' zu beschränken.

0 new messages