Lowlevel

Lowlevel => OS-Design => Thema gestartet von: rizor am 18. May 2011, 21:52

Titel: SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: rizor am 18. May 2011, 21:52
Nabend zusammen,

ich habe jetzt einen fertigen SLAB-Allocator, der stark auf parallelen Zugriff durch feingranulares Locking optimiert ist. Nun wollte ich mir kmalloc schreiben und habe mir ueberlegt, ob es nicht sinnvoll waere kmalloc nur als eine Art Wrapper zu verwenden, der anhand der Groessen entscheidet aus welchem SLAB der Speicher geholt werden soll. Macht sowas sinn? Das erhoeht natuerlich den Verwaltungsoverhead, da ich mehrere Slabs fuer ein kmalloc brauche. Ausserdem erlaubt mein Kernel Speicherallokationen aus bestimmten bereichen (low- oder highmem). Ausserdem wird noch zwischen normalem und boot Speicher unterschieden. Nach dem Bootvorgang wird der gesamte boot Speicher freigegeben, damit der Kernel so wenig Speicher wie moeglich verschwendet. Somit muesste ich auf jeden Fall drei SLABS anlegen, wobei das noch nicht reichen duerfte. Ansonsten muss jeder SLAB grosse Bloecke verteilen, die zu einen starken inneren Fragmentierung fuehren. Also brauchte ich 3 * x SLABS.
Ist das noch praktikabel?

Habe auch lockless Allokation-Algorithmen gefunden, die sind aber vermutlich nicht viel optimaler.

Gruss,
rizor
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: FlashBurn am 18. May 2011, 22:07
Also erstmal wird das so z.B. im Linux-Kernel gemacht (die haben aber inzwischen en SLUB-Allocator).

Ich weiß nicht wie dein Kernel-Konzept aussieht, aber brauchst du unbedint ein kmalloc? Ich komme z.B. komplett ohne aus und habe nur den SLAB-Allocator.
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: rizor am 18. May 2011, 22:10
Da hast du dann aber auch verschiedene Slabs fuer die verschiedenen Groessen, oder?
Welche verwendest du denn?
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: FlashBurn am 18. May 2011, 22:15
Entweder ich verstehe deine Frage nicht richtig oder du hast das Prinzip/den Vorteil vom SLAB-Allocator nicht verstanden.

kmalloc brauchst du für Sachen wo du entweder die Größe zur Compilezeit nicht kennst oder es so viele unterschiedlichen Größen sind, das sich der SLAB-Allocator nicht lohnt.
Der SLAB-Allocator ist für Objekte gedacht z.B. ne Thread-Struktur. Du erstellst also nen Object-Cache der Slabs der Objektgröße einer Thread-Struktur enthält.

Wenn du also nicht alzu viele verschiedene Objekte hast brauchst du kein kmalloc.
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: Jidder am 18. May 2011, 23:08
ich habe jetzt einen fertigen SLAB-Allocator, der stark auf parallelen Zugriff durch feingranulares Locking optimiert ist. Nun wollte ich mir kmalloc schreiben und habe mir ueberlegt, ob es nicht sinnvoll waere kmalloc nur als eine Art Wrapper zu verwenden, der anhand der Groessen entscheidet aus welchem SLAB der Speicher geholt werden soll. Macht sowas sinn?
Ja, das macht Sinn. Hast du eigentlich die Papers von Bonwick gelesen?

Ausserdem erlaubt mein Kernel Speicherallokationen aus bestimmten bereichen (low- oder highmem).
Der SLAB sollte virtuellen Speicher verwalten. Ich denke nicht, dass dort die Unterscheidung wo es im physischen Speicher landet, sinnvoll ist.
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: FlashBurn am 18. May 2011, 23:37
Zitat von: PorkChicken
Der SLAB sollte virtuellen Speicher verwalten. Ich denke nicht, dass dort die Unterscheidung wo es im physischen Speicher landet, sinnvoll ist.
Ich habe zwar bis heute nicht das Konzept von highmem in Linux verstanden, aber der SLAB-Allocator sollte schon wissen wo der Speicher herkommen soll (und das muss er dem virtuellen Speichermanager sagen).
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: Jidder am 18. May 2011, 23:40
Warum muss er das wissen?
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: FlashBurn am 18. May 2011, 23:43
Na wenn du normalerweise nen kmalloc(size,wo_speicher_herkommen) machst und das gegen nen slab Aufruf ersetzen willst, sollte der Speicher wieder dort herkommen und dazu muss der SLAB-Allocator das wissen.
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: Jidder am 18. May 2011, 23:50
Also ich finde kalloc ist nicht die richtige Schnittstelle, um Speicher aus einem bestimmten physischen Speicherbereich anzufordern. Aber auch in dem Fall trifft nicht der Slab Allocator die Entscheidung wo der Speicher herkommt, sondern immer noch kmalloc.

Ein Slab Allocator verwaltet Objekte (structs und so weiter) im virtuellen Speicher. Wenn Anforderungen an die Platzierung im physischen Speicher gestellt werden, will man meistens keine Objekte verwalten, sondern z.B. Puffer. An diese Puffer werden auch strengere Anforderungen als an allgemeine Objekte gestellt (z.B. Alignment, physische Durchgängigkeit, kein Kreuzen von 64 KB Grenzen). Es liegt deswegen ganz im Sinne des Slab Allocators dafür einen anderen Allocator zu verwenden. Zum Beispiel den, der unterhalb des Slab Allocators liegt.
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: rizor am 19. May 2011, 08:13
Entweder ich verstehe deine Frage nicht richtig oder du hast das Prinzip/den Vorteil vom SLAB-Allocator nicht verstanden.

kmalloc brauchst du für Sachen wo du entweder die Größe zur Compilezeit nicht kennst oder es so viele unterschiedlichen Größen sind, das sich der SLAB-Allocator nicht lohnt.
Der SLAB-Allocator ist für Objekte gedacht z.B. ne Thread-Struktur. Du erstellst also nen Object-Cache der Slabs der Objektgröße einer Thread-Struktur enthält.

Wenn du also nicht alzu viele verschiedene Objekte hast brauchst du kein kmalloc.
Das macht soweit ja alles Sinn. Das Problem ist, dass ich nicht für jedes Struct einen eigenen Cache aufbauen möchte, da das absolute Verschwendung ist. Also brauche ich einen Cache, der für allgemeinen Speicher zuständig ist. Das ist momentan mein Problem.


Zitat von: PorkChicken
Der SLAB sollte virtuellen Speicher verwalten. Ich denke nicht, dass dort die Unterscheidung wo es im physischen Speicher landet, sinnvoll ist.
Ich habe zwar bis heute nicht das Konzept von highmem in Linux verstanden, aber der SLAB-Allocator sollte schon wissen wo der Speicher herkommen soll (und das muss er dem virtuellen Speichermanager sagen).
Das sind Überbleibsel aus vergangenen X86-Zeiten. Es gibt/gab Hardware, die nur Speicher unterhalb der 1GB-Grenze ansprechen konnte. Dafür wurde das Konzept eingeführt, damit die Treiber richtigen SPeicher anfordern können. Außerdem war der Zugriff auch mal auf Speicher oberhalb der 1GB-Grenze langsamer als auf den unter dieser Grenze. Damit hat der Kernel seine Datenstrukturen, die er seltener benötigt, in den Highmem-SPeicher gelegt (und prinzipiell den Speicher der Anwendungen) und alles andere in Lowmem.


Warum muss er das wissen?

Der Slab-Allocator fordert SLABS an, die aus bestimmten Speicherbereichen kommen müssen. Er bittet den virtuellen Verwallter um Speicher mit der Anforderung an die Speicherregion, da dieser sich Speicher vom physischen Verwalter holt.
Natürlich kann ich am SLAB vorbei arbeiten, aber ich hätte ihn ganz gerne als zentrale Instanz, damit ich bei OOM-Problemen dem Kernel schnell Speicher klauen kann, damit der Fehler unter Umständen vermieden werden kann.
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: FlashBurn am 19. May 2011, 09:12
Zitat von: rizor
Das Problem ist, dass ich nicht für jedes Struct einen eigenen Cache aufbauen möchte, da das absolute Verschwendung ist.
Dann hast du den Vorteil und eigentlichen Grund für den SLAB-Allocator nicht verstanden ;)

Er wurde gerade für die vielen Objekte gleicher Größe entworfen, weil du so weniger Verschnitt produzieren kannst und der Allocator auch schneller ist.
Ich lege für jede Struct einen Cache an.

Wenn du eigentlich eh immer kmalloc() nutzt, dann würde ich dir einen anderen malloc() Algo empfehlen (z.B. dmalloc oder sowas, musst du mal gucken, da gibt es auch welche für Multithreading), aber nen SLAB-Allocator da drunter zu verwenden, das ist Verschwendung!

Zitat von: PorkChicken
An diese Puffer werden auch strengere Anforderungen als an allgemeine Objekte gestellt (z.B. Alignment, physische Durchgängigkeit, kein Kreuzen von 64 KB Grenzen).
Ich weiß nicht wie es beim "originalen" SLAB-Allocator aussieht, aber meiner beachtet das Alignment, das gefordert wird. Zumal Puffer so eine Sache ist, jedes Struct ist doch im Endeffekt ein Puffer ;)

So kann ich den SLAB-Allocator z.B. auch für die FPU-Structs nutzen (weil die ja nen spezielles Alignment fordern, obwohl das Aufgrund ihrer Größe schon kein Problem ist).
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: rizor am 19. May 2011, 09:39
Das Problem, das ich da sehe ist, dass ich einen großen Verwaltungsaufwand habe und viel Speicher für die Verwaltung verwende, wenn ich das so machen würde. Da stellt sich mir die Frage nach der Effektivität. Ich habe aber auch schon Lösungen gesehen, die SLAB als Basis für malloc verwenden und dann halt 16-, 64- und 512-byte-Blöcke als Caches.
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: erik.vikinger am 19. May 2011, 09:43
Hallo,


Für die Frage nach der sinnvollen Verwendung eines SALB-Allocators ist noch relevant ob es sich um einen Micro-Kernel oder um einen Monolithen handelt. Bei ersterem würde ich auch sagen das es keines kmalloc bedarf einfach weil es nur ganz wenige verschiedene Objekt-Größen gibt und deren Größe auch immer zur Compile-Zeit bekannt ist. Des weiteren wird ein Micro-Kernel kaum Speicher mit bestimmten physischen Eigenschaften anfordern, das machen eher die Treiber (im User-Mode) die dafür einen speziellen Syscall bemühen müssen welcher dann direkt bei der physischen Speicherverwaltung anfragt. Bei einem Monolithen hingegen wird man um eine ordentliche kmalloc Implementierung für beliebige Objekt-Größen kaum rum kommen und wenn man beliebige Objekt-Größen mit SLAB-Allocatoren managen will wird man entweder recht viele SLAB-Größen benötigen oder eine enorme Speicherverschwendung in kauf nehmen müssen (oder man baut einen Hybriden der bestimmte Objekt-Größen an den SLAB-Allocator weiter reicht und den Rest klassisch managed).

Das der SLAB-Allocator sich für die physischen Eigenschaften seiner SLABs interessiert halte ich persönlich auch eher für ungeschickt, Objekte bei denen das eine Rolle spielt sollten direkt von der physischen Speicherverwaltung geholt werden. Außerdem gibt es in normalen PCs keine Gründe den Speicher mit bestimmten physischen Eigenschaften zu verwalten, das einzigste Device was mir da einfällt ist der Floppy-Controller und für den muss man eh noch ein paar weitere Extra-Würste aufs Feuer legen so das es IMHO nichts ausmacht wenn es im Start-Code des Kernel ein paar Zeilen Code gibt die speziell für den Floppy-Controller während der Einrichtung der physischen Speicherverwaltung mal spezielle 512 kBytes zur Seite schaffen die dann später der Floppy-Treiber exklusiv benutzen darf.


In meinem Micro-Kernel möchte ich auch kein kmalloc haben sondern direkt immer das richtige SLAB_alloc aufrufen (ich gebe also nicht die gewünschte Objekt-Größe als Parameter mit sondern rufe direkt die passende Funktion auf, das selbe auch beim SLAB_free da ich ja immer weiß was ich für ein Objekt frei geben möchte so das ich mir sparen kann aus dem Objekt-Pointer auf die Objekt-Größe schließen zu müssen was bei einer generischen malloc/free-nach-SLAB-Umsetzung durchaus knifflig sein kann), da ich wohl mit 5 bis 7 Objekt-Größen aus komme sehe ich in der kleinen Code-Vervielfachung auch keine Probleme (soll auch alles aus der selben Vorlage compiliert werden, nur jeweils mit den passenden SLAB-Defines als Compiler-Parameter für die entsprechende Objekt-Größe).


Grüße
Erik
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: erik.vikinger am 19. May 2011, 09:54
Hallo,


Ich habe aber auch schon Lösungen gesehen, die SLAB als Basis für malloc verwenden und dann halt 16-, 64- und 512-byte-Blöcke als Caches.
Das ist aber eine enorme Verschwendung wenn Du ne Menge Objekte mit 20 Byte Größe benötigst. Also gröber als in Wurzel-2-Schritten (16, 24, 32, 48, 64, 92, 128, 184, 256, 364 ....., für eine 64Bit-Plattform auch immer auf das nächste Vielfache von 8 und nicht blos 4 aufgerundet) würde ich für eine generische malloc-Implementierung auf SLAB-Basis nicht machen, ansonsten bekommt man eine ziemliche interne Fragmentierung.

Aber ich finde ja Du solltest erst mal Deine Anforderungen genauer spezifizieren, vielleicht kommst Du ja auch mit wenigen fest vorgegebenen Objekt-Größen aus.


Grüße
Erik
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: rizor am 19. May 2011, 10:13
Hallo,


Für die Frage nach der sinnvollen Verwendung eines SALB-Allocators ist noch relevant ob es sich um einen Micro-Kernel oder um einen Monolithen handelt. Bei ersterem würde ich auch sagen das es keines kmalloc bedarf einfach weil es nur ganz wenige verschiedene Objekt-Größen gibt und deren Größe auch immer zur Compile-Zeit bekannt ist. Des weiteren wird ein Micro-Kernel kaum Speicher mit bestimmten physischen Eigenschaften anfordern, das machen eher die Treiber (im User-Mode) die dafür einen speziellen Syscall bemühen müssen welcher dann direkt bei der physischen Speicherverwaltung anfragt. Bei einem Monolithen hingegen wird man um eine ordentliche kmalloc Implementierung für beliebige Objekt-Größen kaum rum kommen und wenn man beliebige Objekt-Größen mit SLAB-Allocatoren managen will wird man entweder recht viele SLAB-Größen benötigen oder eine enorme Speicherverschwendung in kauf nehmen müssen (oder man baut einen Hybriden der bestimmte Objekt-Größen an den SLAB-Allocator weiter reicht und den Rest klassisch managed).

Es soll ein Hybrid werden.
Somit möchte ich den Treibern sowohl ein kmalloc bieten und auch das normale SLAB-Interface.



Gibt es Benchmarks zu den Größen
Hallo,


Ich habe aber auch schon Lösungen gesehen, die SLAB als Basis für malloc verwenden und dann halt 16-, 64- und 512-byte-Blöcke als Caches.
Das ist aber eine enorme Verschwendung wenn Du ne Menge Objekte mit 20 Byte Größe benötigst. Also gröber als in Wurzel-2-Schritten (16, 24, 32, 48, 64, 92, 128, 184, 256, 364 ....., für eine 64Bit-Plattform auch immer auf das nächste Vielfache von 8 und nicht blos 4 aufgerundet) würde ich für eine generische malloc-Implementierung auf SLAB-Basis nicht machen, ansonsten bekommt man eine ziemliche interne Fragmentierung.

Aber ich finde ja Du solltest erst mal Deine Anforderungen genauer spezifizieren, vielleicht kommst Du ja auch mit wenigen fest vorgegebenen Objekt-Größen aus.


Grüße
Erik
Gibt es Benchmarks zu den optimalen Größen? Habe leider nichts gefunden. Deine 4- bzw. 8-byte Variante klingt einleuchtend.
WOher hast du die Werte? Selbst ermittelt?
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: erik.vikinger am 19. May 2011, 10:26
Hallo,


Es soll ein Hybrid werden.
Somit möchte ich den Treibern sowohl ein kmalloc bieten und auch das normale SLAB-Interface.
Okay, das ist dann natürlich was anderes. Ich kenne die SLAB-Implementierung des Linux-Kernel nur sehr oberflächlich aber vielleicht kannst Du Dir dort die nötigen Inspirationen holen. Ich denke die dortigen Konzepte wurden vor der Umsetzung auch lang und breit auf den einschlägigen Mailing-Lists diskutiert, bestimmt lohnt es sich da mal nen Tag in alten Threads zu stöbern (wenn Du was interessantes findest würden sich hier bestimmt einige über ein paar Links freuen).

Gibt es Benchmarks zu den optimalen Größen? Habe leider nichts gefunden. Deine 4- bzw. 8-byte Variante klingt einleuchtend.
WOher hast du die Werte? Selbst ermittelt?
Die Werte habe ich vorhin einfach mit dem Taschenrechner ermittelt aber das geht auch mit ner simplen Formel zur Laufzeit (oder Du baust ne feste Tabelle o.ä.). Das Aufrunden auf die native Größe der betreffenden Plattform ist wohl logisch. "Benchmarks" kenne ich dazu nicht aber die potentielle Platzverschwendung in Prozent kann man sich auch so ausrechnen (der Verwaltungsoverhead durch die SLABs selber sollte bei geschickter Wahl der Block-Größe eher gering bleiben).


Grüße
Erik
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: FlashBurn am 19. May 2011, 10:30
Zitat von: erik
Bei ersterem würde ich auch sagen das es keines kmalloc bedarf einfach weil es nur ganz wenige verschiedene Objekt-Größen gibt und deren Größe auch immer zur Compile-Zeit bekannt ist.
Das (Objekt-Größe zur Compilezeit bekannt) kommt ganz darauf an was für nen SLAB-Allocator du verwendest. Denn ich verwende z.B. den SLAB-Allocator auch für die Objekte die er selber benötigt um verschiedene Objekte zu managen. Das hat den Hintergrund das ich zur Compilezeit halt nicht weiß wieviele CPUs der Computer, wo der Code mal drauf laufen wird, hat und ich wollte es halt nicht so wie es bei den meisten (vllt sogar alle?) OS ist, dass schon zur Compilezeit festgelegt wird was die maximale CPU Anzahl ist und vorallem ist das dann ja auch Speicherverschwendung wenn du deine Datenstrukturen immer auf z.B. 32 CPUs ausrichtest, aber eigentlich nur 2 hast.
So ist die größe bestimmter Datenstrukturen erst zur Laufzeit bekannt und dazu gehören vorallem die zum Managen der verschiedenen Objekte. Da ich die Variante vom SLAB-Allocator verwende, wo man pro CPU ne Art Stack hat und die Objekte immer von diesem Stack holt (so lange dort welche drin sind). Dieses Design skaliert besser mit mehreren CPUs.
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: erik.vikinger am 19. May 2011, 10:38
Hallo,


.....
So ist die größe bestimmter Datenstrukturen erst zur Laufzeit bekannt und dazu gehören vorallem die zum Managen der verschiedenen Objekte. Da ich die Variante vom SLAB-Allocator verwende, wo man pro CPU ne Art Stack hat und die Objekte immer von diesem Stack holt (so lange dort welche drin sind). Dieses Design skaliert besser mit mehreren CPUs.
Diese Datenstrukturen möchte ich nicht vom SLAB-Allocator holen (da hätte ich ja auch wieder ein Henne-Ei-Problem) sondern die will ich beim Vorbereiten des Kernels (also zur Boot-Zeit) direkt der physischen Speicherverwaltung entnehmen. Diese Strukturen ändern ihre Größe ja zur Laufzeit nicht mehr und werden auch nie freigegeben so das die ruhig zum Basisverbrauch des Kernels gehören können.


Grüße
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: FlashBurn am 19. May 2011, 10:50
Naja, wenn ich mal davon ausgehe, dass ich 256 CPUs unterstützen möchte und dann ja immer für diese maximale Grenze meine Datenstrukturen auslegen müsste. Dann wäre das eine Verschwendung von ca. 8kb pro Objekt-Typ (wenn nur eine CPU genutzt wird) und das finde ich dann schon nicht mehr so wenig.

Das Henne-Ei-Problem war ganz einfach zu lösen und zwar in dem man den ersten SLAB (also den der für die SLAB Datenstruktur zuständig ist) von Hand konstruiert (zur Laufzeit).

Das mit der Größe nicht ändern (zur Laufzeit) trifft doch eh auf alle Objekte zu, die du per SLAB-Allocator holst.
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: rizor am 19. May 2011, 14:12
Ich hatte mir überlegt das Ganze so zu lösen.
Aber wie löst du das Problem, dass wenn du ein Objekt brauchst, es aber ein neuer SLAB aufgebaut werden muss, da du keinen freien hast. Dann rufst den Cache für die SLABS auf, oder?
Was passiert, wenn dieser wiederum einen neuen SLAB aufbauen muss, da der keinen freien hat?
Für mich klingt das stark nach einer unendlichen Rekursion, falls du nicht gerade Extra-Funktionen für diese Caches hast.
Wie hast du das Problem gelöst?
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: FlashBurn am 19. May 2011, 14:26
Nope!

Also ich habe ein Objekt vom Typ SlabDesc (wo die ganzen Infos zum Slab drin stehen, z.B. wie groß ein Objekt ist, welches Alignment usw. und auch die Listen für die Objectcaches) und dieses Objekt brauchst du ja im Endeffekt nur einmal und zwar wenn du den Slab-Descriptor erzeugst und der wird vom Slab-Allocator geholt (deswegen gibt es da auch kein Henne-Ei-Problem, nur bei dem SlabDesc der die Objekte vom Typ SlabDesc beschreibt, aber den kann ich von Hand erstellen).

Wenn ein neuer Objectcache erstellt werden muss, muss man ja einfach nur ein paar Pages (die Info steht im SlabDesc) vom VMM geholt werden und die einzelnen Objekte müssen konstruiert werden (falls du das verwendest) und schon habe ich neue Objekte die ich dann rausgeben kann.

Dann gibt es da noch das Problem das man ja feststellen muss zu welchen Objectcache ein Object gehört (es sei denn du machst es wie einige einfache malloc() Implementationen und speicherst nen Pointer auf den Objectcache 4byte vor dem Object, aber dann müssen alle deine Objecte 4byte größer sein) und da habe ich mir was von Linux abgeguckt. Dort werden zu jeder physikalischen Page einige Infos gespeichert und ich speichere da unter anderem zu welchem Objectcache eine Page gehört. So muss man nur in einem Array nachgucken und bekommt nen Pointer auf den Objectcache (was O(1) ist). Vorher hatte ich das in Bäumen gespeichert (da bin ich dann den Baum nach der Adresse des Objects durchgegangen und ob die innerhalb eines Objectcaches liegt), aber das war mir zu Zeit-, Speicher- und Rechenaufwändig.
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: erik.vikinger am 19. May 2011, 16:28
Hallo,


Warum so unendlich kompliziert?
Die SLABs können sich doch auch selber verwalten. Ich hab mir gedacht das in jeden Block (ich fordere für die SLABs immer Blöcke zu 512 kB an) vorne ein kleiner Header drin ist der Infos über die Anzahl der freien Objekte in diesem Block und einen Pointer auf das erste freie Objekt (soll dann nach LIFO-Prinzip arbeiten), dazu kommen dann noch ein Next-/Prev-Pointer-Pärchen damit die Blöcke als doppelt verkette Liste verwaltet werden können (die Liste soll nach der Anzahl an freien Objekten sortiert werden damit ich immer möglichst aus den vollsten Blöcken zuerst neue Objekte nehme). Es gibt dann also für jede Objekt-Größe eine solche SLAB-Block-Verkettung und jeweils einen Pointer (als statische Variable) der auf den SLAB-Block zeigt welcher am vollsten aber noch nicht ganz voll ist (damit das Allozieren neuer Objekte möglichst schnell geht). Dazu gibt es dann pro Objekt-Größe (als statische Variable) noch jeweils die Gesamt-Anzahl an SLAB-Blöcken und die Anzahl aller freien Objekte (wenn dieser Wert eine kritische Grenze unterschreitet wird ein neuer Block von der physischen Speicherverwaltung angefordert, diese Grenze muss aber so bemessen sein das die physische Speicherverwaltung selber noch problemlos arbeiten kann da diese ja auch kleine Objekte benötigt).

Von dem Objekt-Pointer auf dessen Größe schließen zu müssen empfinde ich als unnötig, da kann man auch kfree mit einen zweiten Parameter ausstatten das die Objekt-Größe angibt. Man weiß doch schließlich was man frei gibt! Und wenn die SLAB-Blöcke immer eine definierte Größe (Zweierpotenz) und ein passendes Alignment haben kommt man vom Objekt-Pointer immer sofort auf den Header des betreffenden SLAB-Blocks mit einer simplen AND-Operation.

Einen Typ "SlabDesc" möchte ich gar nicht haben da ich ja nur eine sehr überschaubare Anzahl an Objekt-Größen habe (die alle zur Compile-Zeit bekannt sind) und die entsprechenden SLAB-Parameter jeweils händisch bestimmen kann (welche dann als Konstanten in den Code kommen was dafür kleineren und schnelleren Code ergibt weil ja Speicherzugriffe fehlen).

Die CPU-lokalen Caches sind da eine zusätzliche Ebene drüber (auf die ich der Einfachheit halber im ersten Anlauf verzichten möchte) und dafür sollten die SLAB-Funktionen so aufgebaut werden das sie immer gleich 16 (oder ne andere Anzahl) Objekte auf einmal allozieren oder freigeben. Ich seh da jedenfalls kein Problem sowas später drüber zu stülpen um ordentliche Performance zu bekommen. Der komplette Speicherbedarf für diese Funktionalität ist zur gesamten Laufzeit konstant (es wird hierfür also kein malloc/free benötigt) und hängt nur von einer Information ab die man nicht zur Compile-Zeit hat: der Anzahl der CPUs.


Grüße
Erik
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: FlashBurn am 19. May 2011, 17:09
Zitat von: erik
Warum so unendlich kompliziert?
Also erstmal wurde der originale Slab-Allocator ja für monolithische Kernel entwickelt und da gelten ein paar andere Bedingungen und dann kommt noch hinzu das sich jeder andere Ziele für sein OS setzt. Zumal ich meine Variante nicht sondernlich kompliziert finde.

Was mich an deinem Konzept stören würde (aber das hat was mit den Zielen die wir erreichen wollen zu tun), ist das du immer Objectcaches von 512kb hast, ist mir viel zu groß. Dann hast du den Header vorne drin, ich würde ihn ja nach hinten packen. Denn dann kannst du ein besseres Alignment umsetzen (da du immer mit einem Alignment von 512kb anfängst), aber das hat auch den Nachteil, das du unter Umständen ganz schön verschnitt hast (obwohl das bei dieser Größe=512kb nicht das Problem sein sollte).
Dann kommt noch das Sortieren der Liste hinzu, das könnte ein Problem sein, aber theoretisch würdest du einen Objectcache max 1 Element nach hinten oder vorne schieben (?).

Dein Vorschlag kfree einen zweiten Parameter mit der größe mitzugeben, halte ich mal "dagegen", warum macht man das dann nicht schon seit Anfang an?

Ich habe diese SlabDescs auch nur deswegen dynamisch, weil ich halt die CPU Anzahl (und bei bestimmten Datenstrukturen die Größe) nicht zur Compilezeit kenne. Ansonsten hätte ich das auch so gemacht, alleine schon deswegen, weil man so weniger Speicher benötigt.

Das du immer gleich 16 (als Bsp.) Objekte mit einmal rausgeben willst, ist erstmal eine gute Idee, aber was machst du wenn die Anzahl an Objekten die in einem Objectcache ist, kein vielfaches von 16 ist? Dann hättest du ja nochmal Verschnitt.

Als letztes wäre noch meine Frage, wie du dann eine Datenstruktur haben willst, deren Größe erst zur Laufzeit bekannt ist (was ja auf die per CPU Caches zutrifft)?
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: erik.vikinger am 20. May 2011, 09:10
Hallo,


Also erstmal wurde der originale Slab-Allocator ja für monolithische Kernel entwickelt und da gelten ein paar andere Bedingungen
Ja, da hast Du Recht, aber Du wolltest doch wimre einen Micro-Kernel und ich finde da sollte man sich schon mal die Mühe machen auch das Konzept passend umzuarbeiten.

Natürlich hat jeder andere Ziele für sein OS, wäre ja schlimm wenn es anders wäre, aber für die Bedürfnisse eines Micro-Kernels empfinde ich persönlich das Du etwas zu viel Komplexität da drin hast.

Das ich immer gleich 512 kB nehme hat bei mir einen einfachen Grund: die Descriptor-Tabellen sind auch 512 kB groß und in der 64 Bit-Version meiner CPU möchte ich eventuell 512 kB als kleinste Page-Größe benutzen (für ein 3-stufiges Paging, wenn ich kleinere Pages (z.B. 64 kB) möchte dann benötige ich auf jeden Fall ein 4-stufiges Paging). Diese 512 KB tauchen bei meiner CPU-Architektur auch noch an anderen Stellen auf und als so verschwenderisch empfinde ich die 512 kB auch nicht. Das Windows XP an dem ich gerade sitze sagt das im Moment 63 Prozesse mit 700 Threads zusammen knapp 800 MB Speicher verbrauchen, wenn auf mein System irgendwann einmal eine ähnliche Last kommt denke ich das mein Kernel deutlich weniger eigenen Verwaltungsspeicher verbraucht als Windows XP oder andere OSe (schon weil ich nicht für jeden Prozess ein eigenes Paging-Directory benötige) trotz den großzügigen 512 kB SLAB-Blöcken.

Ob der Header vorne oder hinten ist hat IMHO auf den Verschnitt keine Auswirkungen (der Header bleibt ja immer gleich groß) aber das Argument mit dem Alignment für die eigentlichen Objekte muss ich mir auf jeden Fall noch mal durch den Kopf gehen lassen, Danke für den Hinweis.

Dann kommt noch das Sortieren der Liste hinzu, das könnte ein Problem sein, aber theoretisch würdest du einen Objectcache max 1 Element nach hinten oder vorne schieben (?).
Ich kann nicht nachvollziehen worin Du beim Sortieren der SLAB-Block-Kette ein Problem siehst. Klar kostet das ab und an mal etwas Rechenleistung aber dafür hab ich beim Allozieren den Vorteil das ich bevorzugt die Blöcke benutze die eh schon recht voll sind und sobald diese ganz voll sind fallen sie aus der Suche nach freien Objekten ganz raus. Wenn Speicher immer nach dem LIFO-Prinzip alloziert und freigegeben werden würde würde sich das von ganz allein so ergeben aber in der Realität ist das eben nicht so, von daher möchte ich dem etwas nachhelfen. Ich erhoffe mir durch diese Sortierung dafür zu sorgen das immer nur möglichst wenige dieser Blöcke nur teilweise belegt sind. Falls das so in der Realität nicht funktioniert muss ich mir dann was anderes überlegen aber erst einmal möchte ich das so umsetzen.

Dein Vorschlag kfree einen zweiten Parameter mit der größe mitzugeben, halte ich mal "dagegen", warum macht man das dann nicht schon seit Anfang an?
Das ist doch kein Argument, selbst wenn ich der einzigste in diesem Universum wäre der das so macht. Warum soll ich es dem free unnötig kompliziert machen? Gerade in einem überschaubaren Micro-Kernel weiß ich doch immer was ich freigebe also kann ich diese Information auch gleich dem free mitgeben und ihm so die Mühe sparen das selber heraus finden zu müssen. Du hattest Dein Konzept dazu ja mal beschrieben und ich muss ehrlich sagen das mir persönlich das viel zu viel Speicher und CPU-Leistung kosten würde. Vor allem da ein zweites Parameter für free ja quasi gratis ist.

Für meine User-Mode-Heap-Umsetzung möchte ich ja ein zum SLAB ähnliches Konzept benutzen aber da ich dort immer FAR-Pointer habe sehe ich dem Pointer durch den Selector-Teil immer an was er für ein Objekt beschreibt. Mein Aufwand ist also ein einzelner simpler Tabellenzugriff.

Ich habe diese SlabDescs auch nur deswegen dynamisch, weil ich halt die CPU Anzahl (und bei bestimmten Datenstrukturen die Größe) nicht zur Compilezeit kenne.
Aber zur Boot-Zeit kennst Du doch die Anzahl der CPUs und ab da ist diese konstant. Oder möchtest Du das Hinzufügen und Entfernen von CPUs zur Laufzeit unterstützen?

Ansonsten hätte ich das auch so gemacht, alleine schon deswegen, weil man so weniger Speicher benötigt.
Dann mach es doch einfach so. Ich denke das die Einsparung an Speicher (bei Daten und Code) sicher nennenswert ist.

Das du immer gleich 16 (als Bsp.) Objekte mit einmal rausgeben willst, ist erstmal eine gute Idee, aber was machst du wenn die Anzahl an Objekten die in einem Objectcache ist, kein vielfaches von 16 ist? Dann hättest du ja nochmal Verschnitt.
Die 16 war ja auch nur so ein Vorschlag, ich könnte in den CPU-lokalen Cache auch immer 8 Objekte auf einmal vom SLAB-Allocator holen bzw. zurückgeben. Ich bin aber der Meinung das man den SLAB-Allocator dann schon so umbauen sollte das er mehrere Objekte mit einem Aufruf alloziert bzw. freigibt um eben die Kosten von mehreren Funktionsaufrufen zu sparen. Da die eigentlichen Benutzer von kmalloc/kfree ja dann nur noch den CPU-lokalen Cache benutzen benötigt der eigentliche SLAB-Allocator dann kein Interface mehr das einzelne Objekte behandeln kann. Ich kann mir sogar vorstellen das man diese CPU-lokalen Caches per define zur Compile-Zeit zuschaltbar macht ohne das man am restlichen Code etwas ändern müsste, so könnte man mal belastbare Messergebnisse liefern um zu sehen wie viel Performance diese Caches wirklich bringen.

Als letztes wäre noch meine Frage, wie du dann eine Datenstruktur haben willst, deren Größe erst zur Laufzeit bekannt ist (was ja auf die per CPU Caches zutrifft)?
Ich habe keine solchen Strukturen und mir fällt auch absolut keine Situation ein wo ich das brauchen könnte. Auch die Größe der CPU-lokalen Objekt-Caches ist bei mir schon zur Compile-Zeit bekannt (ich sehe da nichts dynamisches, der besteht doch aus X Pointern und ein paar Verwaltungsdaten) nur die Anzahl weiß ich eben erst wenn das OS gestartet wird. Ich möchte diese Objekt-Caches dann einfach beim Booten hinten an die Data-Sektion des Kernels ran hängen, so das ich zur Laufzeit auch immer möglichst einfach den richtigen Pointer ausrechnen kann (aus CPU-Nummer und Objekt-Typ).


Grüße
Erik
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: rizor am 20. May 2011, 11:52
Hallo,


Also erstmal wurde der originale Slab-Allocator ja für monolithische Kernel entwickelt und da gelten ein paar andere Bedingungen
Ja, da hast Du Recht, aber Du wolltest doch wimre einen Micro-Kernel und ich finde da sollte man sich schon mal die Mühe machen auch das Konzept passend umzuarbeiten.

Natürlich hat jeder andere Ziele für sein OS, wäre ja schlimm wenn es anders wäre, aber für die Bedürfnisse eines Micro-Kernels empfinde ich persönlich das Du etwas zu viel Komplexität da drin hast.

Das ich immer gleich 512 kB nehme hat bei mir einen einfachen Grund: die Descriptor-Tabellen sind auch 512 kB groß und in der 64 Bit-Version meiner CPU möchte ich eventuell 512 kB als kleinste Page-Größe benutzen (für ein 3-stufiges Paging, wenn ich kleinere Pages (z.B. 64 kB) möchte dann benötige ich auf jeden Fall ein 4-stufiges Paging). Diese 512 KB tauchen bei meiner CPU-Architektur auch noch an anderen Stellen auf und als so verschwenderisch empfinde ich die 512 kB auch nicht. Das Windows XP an dem ich gerade sitze sagt das im Moment 63 Prozesse mit 700 Threads zusammen knapp 800 MB Speicher verbrauchen, wenn auf mein System irgendwann einmal eine ähnliche Last kommt denke ich das mein Kernel deutlich weniger eigenen Verwaltungsspeicher verbraucht als Windows XP oder andere OSe (schon weil ich nicht für jeden Prozess ein eigenes Paging-Directory benötige) trotz den großzügigen 512 kB SLAB-Blöcken.

Ich nehme selten Windows in Schutz, aber in diesem Fall sagen deine 800 MB nichts über die wirklich notwendige Menge an belegten MBs aus. Das das Ding so viel verwendet, hat den einfachen Grund, dass moderne OSes freien Speicher als Verschwendung ansehen. Windows arbeitet in diesen Fällen genau so wie Linux. "Nimm dir jeden freien SPeicher, den du finden kannst und gib ihn frei, falls jemand anders den Speicher benötigt." Das hat den einfachen Grund, dass die Dinger alles Chachen, was sie vermuten demnächst zu brauchen. Also sagen die 800 MB für den Kernel nur aus, dass deine Prozesse nicht viel Speicher benötigen und Windows somit mehr für sich nimmt.

So will ich es ja auch machen und dafür verwende ich den SLAB-Allocator. Ich möchte da auch so eine Art Defragmentierung des Speichers einbauen, dass bei SPeicherknappheit der Speicher umgelegt werden soll. Macht das System in manchen Situationen natürlich langsamer, aber das ist kurz vor einem OOM egal. Lieber warte ich etwas, bis mein System wieder flüssig läuft, bevor es einen OOM ausgibt.


Dein Vorschlag kfree einen zweiten Parameter mit der größe mitzugeben, halte ich mal "dagegen", warum macht man das dann nicht schon seit Anfang an?
Das ist doch kein Argument, selbst wenn ich der einzigste in diesem Universum wäre der das so macht. Warum soll ich es dem free unnötig kompliziert machen? Gerade in einem überschaubaren Micro-Kernel weiß ich doch immer was ich freigebe also kann ich diese Information auch gleich dem free mitgeben und ihm so die Mühe sparen das selber heraus finden zu müssen. Du hattest Dein Konzept dazu ja mal beschrieben und ich muss ehrlich sagen das mir persönlich das viel zu viel Speicher und CPU-Leistung kosten würde. Vor allem da ein zweites Parameter für free ja quasi gratis ist.
Compile-Zeit zuschaltbar macht ohne das man am restlichen Code etwas ändern müsste, so könnte man mal belastbare Messergebnisse liefern um zu sehen wie viel Performance diese Caches wirklich bringen.

Die Variante dürfte vermutlich auch schneller sein, da du dir so unnötiges nachschauen im Speicher schenken kannst. Das macht natürlich nichts, wenn der Speicher im Cache liegt, aber tut er das nicht, verbrätst du Takte, die du mit einem zweiten Parameter verhinderst. Außerdem ist es so gut wie sicher, dass der zweite Parameter im CPU Cache liegt.

Als letztes wäre noch meine Frage, wie du dann eine Datenstruktur haben willst, deren Größe erst zur Laufzeit bekannt ist (was ja auf die per CPU Caches zutrifft)?
Ich habe keine solchen Strukturen und mir fällt auch absolut keine Situation ein wo ich das brauchen könnte. Auch die Größe der CPU-lokalen Objekt-Caches ist bei mir schon zur Compile-Zeit bekannt (ich sehe da nichts dynamisches, der besteht doch aus X Pointern und ein paar Verwaltungsdaten) nur die Anzahl weiß ich eben erst wenn das OS gestartet wird. Ich möchte diese Objekt-Caches dann einfach beim Booten hinten an die Data-Sektion des Kernels ran hängen, so das ich zur Laufzeit auch immer möglichst einfach den richtigen Pointer ausrechnen kann (aus CPU-Nummer und Objekt-Typ).


Grüße
Erik

Naja, sobald du CPU-Hotplugin unterstützen möchtest, ist die ganze Geschichte dynamisch. Habe ich momentan auch noch nicht drin, soll aber irgendwann mal kommen. Dürfte aber eine riesige Baustelle für sich selbst werden, da da ja sehr viel mehr dran hängt.
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: FlashBurn am 20. May 2011, 14:21
Zitat von: erik
Klar kostet das ab und an mal etwas Rechenleistung aber dafür hab ich beim Allozieren den Vorteil das ich bevorzugt die Blöcke benutze die eh schon recht voll sind und sobald diese ganz voll sind fallen sie aus der Suche nach freien Objekten ganz raus.
Mir gefällt die Idee auch immer besser ;) Das Sortieren sollte eigentlich nicht wirklich Rechenzeit kosten, weil du ja einen Objectcache max eine Postion nach vorne schiebst (es wird was alloziert) oder nach hinten (es wird was freigegeben). Da ich ja dann eh von der Objektadresse auf die Adresse von der Slab-Struktur komme brauche ich die vollen Objecktcaches auch nicht in einer extra Liste speichern (zu Debugging Zwecken wäre das natürlich trotzdem sinnvoll).

Zitat von: erik
Das ist doch kein Argument, selbst wenn ich der einzigste in diesem Universum wäre der das so macht.
Das war übrigens ne ernst gemeinte Frage ;) Ich denke mal das hat mal "damals" nicht so gemacht, weil man dann in jedem Objekt hätte speichern müssen wie groß es ist und (das wird viel wichtiger sein), malloc liefert nicht immer einen Block zurück der genauso groß sit wie angefordert, sondern der kann auch größer sein und dann nützt dir die Angabe bei free() nämlich nichts!

Zitat von: erik
Aber zur Boot-Zeit kennst Du doch die Anzahl der CPUs und ab da ist diese konstant. Oder möchtest Du das Hinzufügen und Entfernen von CPUs zur Laufzeit unterstützen?
Also ich will kein Hotplugging von CPUs unterstützen. Allerdings hilft es mir auch nicht wenn ich zur Boot-Zeit weiß wie viele CPUs ich habe.
Mein SlabDesc sieht ungefähr so aus:
struct SlabDesc {
 //alle möglichen Sachen und Listen die man halt so braucht
 void* CPUCaches[][4][2];
};
Das heißt ich habe pro CPU 2*4 Objekte. Einmal 4 Objekte die ich rausgeben kann (allozieren) und einmal 4 Objekte die ich freigeben kann (free).
Wie willst du es hinbekommen das der SlabDesc immer erst zur Bootzeit erstellt wird und wo willst du das hinpacken? Zumal ich dann entweder alle SlabDesc Symbole erst zur Boot-Zeit auflösen kann (und dann das Problem habe, wie bekomme ich meine Konstanten Daten da rein, ohne das ich das als extra Code habe) oder ich speichere die Pointer (so wie jetzt auch schon) in Variablen ab (wo ich mir dann auch erstmal die Symbole holen müsste).

Zitat von: erik
Die 16 war ja auch nur so ein Vorschlag, ich könnte in den CPU-lokalen Cache auch immer 8 Objekte auf einmal vom SLAB-Allocator holen bzw. zurückgeben.
Auf was ich hinaus will ist, was passiert, wenn du ne ungerade Anzahl von Objekten in deinen 512kb hast?
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: Svenska am 20. May 2011, 16:32
Hallo,

ein free(pointer, size) ist nicht unbedingt sinnvoll. Denn malloc() darf mehr rausgeben als gewünscht und realloc() darf dynamisch die Größe ändern. Das kann unter Umständen im Programm sehr aufwändig werden, da den Überblick bis zum free() vollständig zu behalten.

Ansonsten könnt ihr immer RAM-Verbrauch durch Rechenzeit ersetzen.

Ich sehe kein Problem darin, für ein SMP-fähiges Betriebssystem ein paar Kilobyte für CPU-Verwaltungsstrukturen zu opfern, welche dann mangels realer CPUs nicht genutzt werden. Jeder heute übliche Rechner hat RAM-Größen im Gigabytebereich und ob dein Kernel nun ein MB mehr oder weniger für elementare Dinge (!) verbraucht oder nicht, spielt keine Rolle. Wenn mein Firefox sich ein paar hundert MB greift, dann fallen die paar KB mehr oder weniger freier Speicher nicht ins Gewicht.

Gruß,
Svenska
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: FlashBurn am 20. May 2011, 17:23
Sorry, wenn ich das mal wieder so sage, aber was du (Svenska) schreibst ist doch der Grund warum die Programme soviel Speicher verbrauchen! Alle denken ja, wir hams ja und keiner macht sich mehr nen Kopf darüber.

Zumal du besser sagen solltest besonders die x86 Architektur ist mit viel RAM "gesegnet" (obwohl ich das eher negativ sehe). Wenn du dann mal zu ARM guckst (auch wenn die RAM mäßig tierisch am Aufholen sind) sieht es wieder anders aus. Wenn ich mir noch überlege wie es "damals" war, als 128MB noch als viel galten und auch ausreichen war, selbst für Spiele.

Ich weiß das viele die Auto vergleiche hassen, aber das kennt nun mal jeder. Wenn das Öl nicht so teuer (und knapp) wäre, dann würden wir heute immernoch (?) mit Autos fahren die 20l und mehr fressen.

Und was den Speicherverbrauch von einem OS angeht, wie gesagt jeder setzt sich halt andere Ziele und ich möchte kein OS schreiben welches schon nur für ne einfach Konsole 16MB und mehr braucht.

Das die paar KB nicht ins Gewicht fallen mag ja für nen Mikrokernel stimmen, aber ab nem Hybriden kann das schon echt viel werden. Hätte denn jemand mal eine Zahl zur Hand wie viele verschiedene Objekttypen (die den Slab-Allocator nutzen) der Linux-Kernel hat und dann wäre (auch wenn es Off-Topic ist) die max CPU Anzahl auch mal interessant.

So und um nun auch mal eure Einstellung/Meinung ein wenig zu überspitzen. Ihr sagt also die meisten Sachen sollte man statisch machen. Na wenn ich meine ganzen Datenstrukturen statisch mache, die von der CPU Anzahl abhängen, dann bin ich wahrscheinlich irgendwo im MB bereich. Dann kommen bei mir noch die Datenstrukturen für die IRQs dazu, weil da kann ich ja auch nicht wissen wie viele es sind (obwohl es zu >99% wohl 24 oder weniger sein werden) und das geht noch weiter so ;)
Weil wir haben ja genug RAM ;)

Das Problem was ich einfach damit habe, ist die Einstellung, die ich auch in der Uni feststellen muss. Man hat ja genug Speicher, da können wir den auch verschwenden, fällt ja nicht auf oder bis irgendein Programm mal fertig ist, hat sich die durchschnittliche RAM-Menge ja eh wieder vergrößert.

Zitat von: Svenska
Ansonsten könnt ihr immer RAM-Verbrauch durch Rechenzeit ersetzen.
Sicher das du bei dieser These mit dieser Wortwahl bleiben möchtest ;)
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: rizor am 20. May 2011, 17:55
So und um nun auch mal eure Einstellung/Meinung ein wenig zu überspitzen. Ihr sagt also die meisten Sachen sollte man statisch machen. Na wenn ich meine ganzen Datenstrukturen statisch mache, die von der CPU Anzahl abhängen, dann bin ich wahrscheinlich irgendwo im MB bereich. Dann kommen bei mir noch die Datenstrukturen für die IRQs dazu, weil da kann ich ja auch nicht wissen wie viele es sind (obwohl es zu >99% wohl 24 oder weniger sein werden) und das geht noch weiter so ;)
Weil wir haben ja genug RAM ;)

Hier möchte ich dir widersprechen. Den Rest empfinde ich genau so.
Wenn man das statisch macht, kannst du Speicher sparen, da du davon ausgehst, dass derjenige, der den Kernel baut, weiß wie viel Kerne er verwendet. Du kannst dem Compiler ja sagen, dass dein System auf zwei CPUs gebaut werden soll. Wenn es nicht stimmt, ist der User des Kernels selber schuld. Im Prinzip genau so, wie es Linux macht. Natürlich hast du einen größeren Speicherverbrauch wenn du mehr Kerne angibst, aber warum solltest du das tun?
Okay, große Linux-Distros machen das so (Deren Config nimmt 256 CPUs als Basis (Standard vom Kernel)), aber Gentoo z.B. baut ja keine Kernel. Das muss der Gentoo-User selber machen (in meinen Augen der gigantische Vorteil von Gentoo). Und jemand, der das macht, kennt auch die Anzahl an CPUs.
Also hat statisch definitiv seine Vorteile (außer beim CPU-Hotplugin)
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: FlashBurn am 20. May 2011, 18:02
@rizor

Da wären wir dann wieder bei dem Thema, was man mit seinem OS erreichen möchte. Ganz ehrlich das was du beschreibst ist genau der Punkt warum Linux Windows nie ersetzen kann.

Es kann, meiner Meinung nach, nicht das Ziel sein, jedes Mal wenn ich mein OS auf nem anderen Rechner laufen lassen, neu kompilieren zu müssen.

Das wäre wie, das man erst Windows installieren müsste um dann Linux zu kompilieren und dann nutzen zu können und ich denke mal das will keiner ;)

Auch diese Einstellung kann ich überspitzt so darstellen, dass ich dann sage, sowas wie PIC/IOAPIC oder PIT/APIC mache ich auch statisch und der jenige der mein OS nutzen will, muss halt wissen was für Hardware er dann vorsich hat um mein OS nutzen zu können.
Das nächste ist die Hemmschwelle, wenn ich ein OS erst kompilieren muss (und bei größeren OS dauert das schonmal ewig und ist meistens mit einigem Aufwand verbunden), dann will ich es auch nicht mehr ausprobieren!
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: rizor am 20. May 2011, 18:08
Okay, das ist ein Argument.
Ich weiß nicht, wie Windows das intern handhabt, aber die machen bestimmt auch nicht alles dynamisch.
Natürlich ist das der Grund warum Linux den Nerd-Status nie verlieren wird, aber man kann das ganze ja auch noch etwas einfacher machen.
Für den OS-Installer könnte man ja einen Kernel verwenden, der alles erkennen kann und automatisch die Config anpasst und dann den passenden Kernel baut. Natürlich kannst du jetzt sagen, dass das ganze dann trotzdem nur auf einem System läuft, aber da gibt es ja auch Mittel und Wege. Man könnte z.B. Beim booten analysieren,ob noch alles passt. Wenn das nicht so ist, wird im Hintergrund ein Kernel gebaut, der sich anpasst und dann das System neu gestartet werden muss.
Ist halt alles eine Frage des Aufwands.
Aber die ganzen der zur Compiler-Zeit zu kennen hat in meinen Augen den riesigen Vorteil, dass du das gesamte System kennst und der Compiler den Kernel optimal bauen kann. Das dürfte dann zum Teil schneller sein, als deine zur Laufzeit aufgebauten Datenstrukturen.
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: FlashBurn am 20. May 2011, 18:25
Es ist auch möglich, mit einigem Aufwand, das ich die Sache "emulieren" könnte. In dem Sinne, das ich meine Datenstrukturen, die dynamisch sind, kennen muss und mein Bootloader die dann zur Laufzeit erzeugt und hinten an das Datensegment ranhängt und dann die ganzen Symbole auflöst. Das sollte genauso wenig Speicher verbrauchen.

Also ich möchte kein System nutzen wollen, wo während eines Starts rebootet wird, weil der Kernel neu kompiliert werden muss. Zumal es sowas in der Art bzw. von der Idee her besser, schon gibt. TCC kompiliert doch den Kernel erst zur Bootzeit. Allerdings steigt damit natürlich die Bootzeit enorm an.

Ein anderes Problem was ich sehe, der Source-Code benötigt auch ne Menge Speicher (was wieder vorraussetzt das du deinen Source-Code mitliefern möchtest) und den müsstest du dann auch immer auf dem Bootmedium haben, wo wir dann wieder dabei wären, wir haben ja riesige Festplatten, wozu also mit dem Speicher geizen (und da regen sich die meisten immer auf, wieviel Speicher Windows immer auf der Festplatte belegt).

Dazu kommt das man das ja auch auf Anwendungen ummünzen könnte und ganz ehrlich, ich möchte die meisten Sachen einfach benutzen und nicht noch kompilieren müssen.

Wenn deine Zielgruppe, für dein OS, natürlich absolute Nerds sind ist das natürlich möglich, aber bedenke das sich dann nicht viele finden lassen werden die dein OS mal testen oder ausprobieren würden!

Ich muss auch ganz ehrlich sein, ich würde kein OS testen wollen, was ich erst noch kompilieren muss. Wäre mir der Aufwand viel zu groß für.
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: Svenska am 20. May 2011, 19:43
Hallo,

Alle denken ja, wir hams ja und keiner macht sich mehr nen Kopf darüber.
Beachte bitte die Relationen. Es ging um statische(!) Datenstrukturen, in einer Größenordnung von weniger als einem Mega(!)byte und um Rechnersysteme, die sehr viel mehr RAM haben (weil SMP).

Außerdem ist es problemlos möglich, die Anzahl der Einträge zur Compilezeit begrenzen (oder nachträglich durch ein Relinken anzupassen). So funktionierten alte UNIX-Systeme.

Ihr sagt also die meisten Sachen sollte man statisch machen. Na wenn ich meine ganzen Datenstrukturen statisch mache, die von der CPU Anzahl abhängen, dann bin ich wahrscheinlich irgendwo im MB bereich.
Ja. Dafür verbrauchst du weniger Rechenzeit, weil du für den Zugriff auf die Strukturen nicht durch ewig viele Indirektionen gehen musst, außerdem sparst du Codegröße, weil die Zugriffsmuster viel einfacher sind.

Wenn du einen SMP-fähigen Kernel auf einem Uniprozessorsystem betreibst, dann führst du oft mehr Code aus als nötig (z.B. für Locking etc.). Dieser Code nimmt Platz weg. Ältere Prozessoren haben weniger CPU-Cache, also reduzierst du durch "mehr nutzloser Code" ohnehin die Leistung.

Willst du einen Kernel schreiben, der optimal auf einem 386er mit 4 MB RAM optimal performt, dann wird er auf einem Dual-Hexacore-System mit 64 GB RAM nur suboptimal laufen. Andersrum gilt das genauso. Du musst dir bewusst sein, dass du immer Kompromisslösungen benutzt.

Weil wir haben ja genug RAM ;)
Ja, haben wir. Auf meinem System sind von 2 GB RAM mehr als die Hälfte für Plattencache eingeteilt. Eben weil wir genug RAM haben, können wir performancesteigernden Maßnahmen, wie z.B. aggressives Caching, sinnvoll einsetzen. Ich rede nicht von großflächiger Verschwendung.

Wenn der Compiler (für eine sinnvolle Verarbeitungszeit) nur 8 MB RAM hat, dann kann er nunmal nicht alle Optimierungen ausschöpfen. Hat er dagegen ein paar GB verfügbar, geht das plötzlich viel besser. Und wenn wir den Compiler in nur 64K quetschen müssen, dann ist das Ergebnis sogar grausam dagegen. Aber es gibt solche Compiler.

Das Problem was ich einfach damit habe, ist die Einstellung, die ich auch in der Uni feststellen muss. Man hat ja genug Speicher, da können wir den auch verschwenden, fällt ja nicht auf oder bis irgendein Programm mal fertig ist, hat sich die durchschnittliche RAM-Menge ja eh wieder vergrößert.
In der freien Wirtschaft zählt die Größe "Realzeit zwischen Idee und Vermarktung". Da ist für Qualität nur wenig Platz. In der Uni zählt "lässt sich theoretisch Beweisen", da spielt die Umsetzbarkeit nur eine untergeordnete Rolle.

Zitat von: Svenska
Ansonsten könnt ihr immer RAM-Verbrauch durch Rechenzeit ersetzen.
Sicher das du bei dieser These mit dieser Wortwahl bleiben möchtest ;)
Ich ersetze das Wort "immer" durch "fast immer". Und ja, bei der These bleibe ich; ich bin mir aber durchaus bewusst, dass es sowohl nach oben als auch nach unten praktische Grenzen gibt, ab der es sich nicht lohnt.

Gruß,
Svenska
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: FlashBurn am 20. May 2011, 20:02
Zitat von: Svenksa
Außerdem ist es problemlos möglich, die Anzahl der Einträge zur Compilezeit begrenzen (oder nachträglich durch ein Relinken anzupassen).
Da müsstest du mal genauer werden. Ich verstehe nicht ganz wie das mit dem relinken funktionieren soll bzw. was das machen soll.

Zitat von: Svenska
Wenn du einen SMP-fähigen Kernel auf einem Uniprozessorsystem betreibst, dann führst du oft mehr Code aus als nötig (z.B. für Locking etc.). Dieser Code nimmt Platz weg. Ältere Prozessoren haben weniger CPU-Cache, also reduzierst du durch "mehr nutzloser Code" ohnehin die Leistung.
Da hast du absolut recht!

Aber wie gesagt, zum Thema Usability finde ich es sehr schlecht wenn man ein Programm immer bzw. immer wenn man auf nem anderen Rechner ist (was auch portable Programme unmöglich macht bzw. unpraktikabel) neu kompilieren muss.

Zitat von: Svenska
Willst du einen Kernel schreiben, der optimal auf einem 386er mit 4 MB RAM optimal performt, dann wird er auf einem Dual-Hexacore-System mit 64 GB RAM nur suboptimal laufen. Andersrum gilt das genauso. Du musst dir bewusst sein, dass du immer Kompromisslösungen benutzt.
Ich gehe dahin, das ich auf jeden Fall alte Systeme unterstützen will, aber SMP Systeme bevorzuge. Ansonsten sehe ich zu das meine Datenstrukturen und Algos in beiden Extremen halbwegs gleich effizient sind.

Zumal du mir doch wohl zustimmen musst, das es eigentlich nicht sein kann, dass ein OS welches nur eine Konsole zur Verfügung stellt schon 16MB und mehr braucht, oder?

Ich sags mal so, mit der Einstellung würde Linux aber nicht auf Routern oder anderen kleinen Geräten laufen und Handies wären noch langsamer!

Zitat von: Svenska
In der freien Wirtschaft zählt die Größe "Realzeit zwischen Idee und Vermarktung". Da ist für Qualität nur wenig Platz. In der Uni zählt "lässt sich theoretisch Beweisen", da spielt die Umsetzbarkeit nur eine untergeordnete Rolle.
Da stimme ich dir nicht ganz zu. Ich habe allerdings noch keinerlei Erfahrung aus der freien Wirtschaft, aber wenn du ein Programm schreibst, dann musst du dich ja für irgend einen Algo und irgendeine Datenstruktur entscheiden, d.h. du denkst darüber nach und genau da kann man ansetzen. Denn seien wir ehrlich es wird sich oft nur für irgendeine Datenstruktur entschieden weil man keine besseren kennt (weil man sich nicht auf dem laufenden hält und/oder keine Ahnung hat) und sich sagt, Speicher ist ja genug da, was die anderen Programme dann machen ist ja egal.

Zitat von: Svenska
Und ja, bei der These bleibe ich; ich bin mir aber durchaus bewusst, dass es sowohl nach oben als auch nach unten praktische Grenzen gibt, ab der es sich nicht lohnt.
Naja, um nur mal ein Bsp. zu nennen. Ich habe eine zeitlang für alle Sachen die über eine ID haben, einen AVL-Baum benutzt um die IDs zu verwalten und auf die Datenstrukturen zuzugreifen.
Jetzt verwende ich statt dessen ein Array und das verbraucht immer (da nur Pages gemappt werden wo auch Daten drin sind) weniger oder gleich viel (was nur zutrifft, wenn eine Page in Benutzung ist) Speicher ist aber um Welten schneller.

Es kommt nämlich durchaus auf das Problem an, ob man sagen kann das weniger Speicherverbrauch mehr Rechenzeit heißt.

Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: kevin am 20. May 2011, 20:05
Wenn man das statisch macht, kannst du Speicher sparen, da du davon ausgehst, dass derjenige, der den Kernel baut, weiß wie viel Kerne er verwendet. Du kannst dem Compiler ja sagen, dass dein System auf zwei CPUs gebaut werden soll. Wenn es nicht stimmt, ist der User des Kernels selber schuld. Im Prinzip genau so, wie es Linux macht. Natürlich hast du einen größeren Speicherverbrauch wenn du mehr Kerne angibst, aber warum solltest du das tun?
Ist das immer noch so? Ich meine, in Erinnerung zu haben, dass das zu ändern schon vor zwei, drei Jahren im Gespräch war. Du kannst auf jeden Fall davon ausgehen, dass das nicht so ist, weil es toll wäre, sondern eher weil es so schön einfach zu implementieren war. Auf kurz oder lang wird das also dynamisch werden.
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: erik.vikinger am 20. May 2011, 20:47
Hallo,


Mir gefällt die Idee auch immer besser ;) Das Sortieren sollte eigentlich nicht wirklich Rechenzeit kosten, weil du ja einen Objectcache max eine Postion nach vorne schiebst (es wird was alloziert) oder nach hinten (es wird was freigegeben).
Ja, meine Ideen wissen oft zu gefallen. :-D

Da ich ja dann eh von der Objektadresse auf die Adresse von der Slab-Struktur komme brauche ich die vollen Objecktcaches auch nicht in einer extra Liste speichern (zu Debugging Zwecken wäre das natürlich trotzdem sinnvoll).
Wozu Du die komplett vollen SLAB-Blöcke in einer extra Liste speichern möchtest verstehe ich nicht, ich möchte das als eine einzige doppelt verkettete Liste lassen und den statischen Pointer (quasi den Einsprungspunkt in diese Liste) will ich auf den vollsten nicht ganz vollen SLAB-Block zeigen lassen (von diesem Punkt aus kann man sich also oft in beide Richtungen durch die Liste bewegen). Zusätzlich möchte ich noch einen Pointer auf den leersten SLAB-Block haben um das Freigeben von diesen zu vereinfachen.

Das war übrigens ne ernst gemeinte Frage ;) Ich denke mal das hat mal "damals" nicht so gemacht, weil man dann in jedem Objekt hätte speichern müssen wie groß es ist und (das wird viel wichtiger sein)
Mir ist klar das Deine Frage ernst gemeint ist aber ich Denke wir reden hier trotzdem von 2 verschiedenen Standpunkten. Ich rede von einem kleinen überschaubaren Micro-Kernel (gerade die dynamischen Speicherbedürfnisse eines Micro-Kernels sind IMHO sehr gut überschaubar weil man ja nur eine eng begrenzte und wohl bekannte Menge an unterschiedlichen Objekten benötigt) und nicht von einer generischen Heap-Implementierung (wie sie z.B. in einer libc drin ist, auch die User-Mode-libc zu meinem OS wird ein normales free implementieren, schon allein weil ich im User-Mode FAR-Pointer hab und die gewünschte Information ja daher auch gratis bekomme).

malloc liefert nicht immer einen Block zurück der genauso groß sit wie angefordert, sondern der kann auch größer sein und dann nützt dir die Angabe bei free() nämlich nichts!
Klar kann malloc auch größere Objekte liefern, solange free den selben Algorithmus benutzt um an die genormte Objektgröße zu kommen ist das doch auch in Ordnung.

Also ich will kein Hotplugging von CPUs unterstützen.
Das ist IMHO auch ganz gut, ansonsten holt man sich damit doch eine enorme Komplexität ins OS von der wohl kaum einer von uns tatsächlich profitieren könnte. Aber selbst wenn dann kann man ja auch einfach beim booten die Anzahl der Sockel bestimmen und so die maximal mögliche Anzahl an CPUs ausrechnen.

Allerdings hilft es mir auch nicht wenn ich zur Boot-Zeit weiß wie viele CPUs ich habe.
Warum nicht? Vor allem was geht besser wenn Du das erst noch später ermittelst? Wann genau ermittelt Dein OS denn die Anzahl der vorhandenen CPUs?

Ich möchte zur Verwaltung der SLABs folgende Struktur verwenden (für jede Objektgröße eine eigene) :
struct t_SlabMng
{
  ulong  NumFreeObj;     //Anzahl an freien Objekten (kann bei ungeordneter Freigabe auch deutlich mehr als die Anzahl der Objekte in einem SLAB-Block sein)
  ulong  NumSlabBlocks;  //Anzahl der SLAB-Blöcke insgesamt
  void*  SlabList;       //Pointer auf den vollsten nicht ganz vollen SLAB-Block
  void*  SlabListLast;   //Pointer auf den leersten SLAB-Block (Ende der Liste)
  char   Lock;           //Lock-Variable für alle malloc/mfree für diese Objektgröße
  char   BlockAddActiv;  //wird auf 1 gesetzt solange eine Block-Add-Aktion aktiv ist
                         //(in der Zeit müssen alle anderen Anforderungen die nicht vom VMM kommen warten)
  void*  LocalCaches[];  //Pointer auf ein Array mit allen CPU-lokalen Caches
                         //(die Größe dieser Objekte ist zur Compile-Zeit bekannt und die Anzahl wird beim booten ermittelt,
                         // die CPU-Anzahl steht in einer globalen Variable)
};
Ich denke das ich damit komplett hin komme, alles andere sind ja Konstanten die bereits zur Compile-Zeit bekannt sind. Den Speicher für die CPU-lokalen Caches möchte ich dem physischen Speicher entnehmen (genauso wie den jeweils ersten SLAB-Block auch) bevor ich den VMM mit dem dann noch freien Speicher initialisiere, das Freigeben dieser Strukturen ist ja nicht nötig also geht das problemlos als statischer Speicherverbrauch durch. Zugegriffen wird auf die CPU-lokalen Caches mit LocalCaches[currentCpuNum].* da sehe ich keine Probleme.

Auf was ich hinaus will ist, was passiert, wenn du ne ungerade Anzahl von Objekten in deinen 512kb hast?
Ah, jetzt hab ich verstanden auf was Deine Frage abzielt. Dann muss eben bevor die Bündelanforderung erfüllt werden kann noch ein neuer SLAB-Block per VMM alloziert werden, ob das nötig ist ergibt bei mir folgender Vergleich: if (slab.NumFreeObj <= (Anforderungsmenge + ObjektReserve)) { vmalloc(); }. Eine Bündelanforderung muss ja nicht alle Objekte aus einem SLAB nehmen sondern soll auch beim vollsten nicht ganz vollen SLAB-Block anfangen, theoretisch wäre es möglich das alle neuen Objekte aus unterschiedlichen SLAB-Blöcken kommen (und danach auch X Blöcke zusätzlich komplett voll sind).


Also sagen die 800 MB für den Kernel nur aus, dass deine Prozesse nicht viel Speicher benötigen und Windows somit mehr für sich nimmt.
Nein, die 800 MB sind der Verbrauch der 63 Prozesse selber, was der Kernel tatsächlich für sich verbraucht (ohne Caches und ohne Treiber usw.) sagt der Taskmanager nicht so deutlich.

Ich möchte da auch so eine Art Defragmentierung des Speichers einbauen, dass bei SPeicherknappheit der Speicher umgelegt werden soll.
Du willst in einem Flat-Memory-System den Speicher defragmentieren? Da bin ich jetzt aber mal neugierig, wie?

Außerdem ist es so gut wie sicher, dass der zweite Parameter im CPU Cache liegt.
Dieser zweite Parameter für mein kfree ist eine Konstante die ich als Programmierer in den Quell-Code tippen kann da ich ja immer genau weiß was für ein Objekt ich da freigeben will. Zumindest in meinem Kernel kostet die gar nichts.

soll aber irgendwann mal kommen.
Was echt, Du willst CPU-Hotplugging unterstützen? Und ich dachte immer mein Projekt ist schon ziemlich ambitioniert. Auf was für einen Rechner möchtest Du das denn entwickeln/testen?

Dürfte aber eine riesige Baustelle für sich selbst werden, da da ja sehr viel mehr dran hängt.
Oh ja, das dürfte wirklich eine recht große und komplexe Baustelle werden.


Ansonsten könnt ihr immer RAM-Verbrauch durch Rechenzeit ersetzen.
Grundsätzlich kann ich dieser These zustimmen. Aber es gibt manchmal auch Lösungen die an beiden Seiten einen Vorteil bringen, z.B. das zweite Parameter für free bei einem SLAB-Allocator bringt mehr Performance weil man nicht erst aufwendig die Objekt-Größe ermitteln muss und spart Speicher weil eben einige Verwaltungsinformationen weg fallen (ja ich weiß das ich das auf einen exotischen Sonderfall (meinen Micro-Kernel) beziehe aber es gibt diese Fälle eben doch ab und an mal).

Wenn mein Firefox sich ein paar hundert MB greift, dann fallen die paar KB mehr oder weniger freier Speicher nicht ins Gewicht.
Grundsätzlich kann ich auch hier zustimmen aber möchte schon anmerken das man sich zumindest bemühen sollte mit den verfügbaren Ressourcen sparsam umzugehen. Zumindest hab ich kein großes Problem damit wenn man mit ein klein wenig Speicherverschwendung einiges an Performance rausholen kann, wenn aber der Performancegewinn nur marginal oder der zusätzliche Speicherverbrauch riesig wäre würde ich das wohl nicht machen, ist eben immer ein Kompromiss.


In der freien Wirtschaft zählt die Größe "Realzeit zwischen Idee und Vermarktung". Da ist für Qualität nur wenig Platz.
So ist es! Leider!


Das Neucompilieren eines OS (oder eines anderen Programms) würde ich als User auch nur dann in Betracht ziehen wenn ich dadurch einen echten Vorteil bekomme, z.B. eine spürbar höhere Performance oder einen spürbar niedrigeren Speicherverbrauch. Das Aufsetzen einer geeigneten Build-Umgebung ist meistens mit erheblichen Aufwand verbunden für den es schon einer ordentlichen Begründung bedarf. Prinzipiell möchte ich mit einem frisch ausgepackten OS/Programm zumindest überhaupt etwas anfangen können (auch wenn es da ein paar Aspekte gibt die nicht ganz optimal auf meinen konkreten PC abgestimmt sind).


Zumal du mir doch wohl zustimmen musst, das es eigentlich nicht sein kann, dass ein OS welches nur eine Konsole zur Verfügung stellt schon 16MB und mehr braucht, oder?
Das kommt auf die Qualitäten der Konsole an. ;)
Der Punkt ist das hier viele eine möglichst hochperformante Speicherverwaltung realisieren wollen und da hat man oft einen gewissen Basisverbrauch (z.B. bei meinen riesigen SLAB-Blöcken) der sich erst mit steigender Systemauslastung wieder relativiert aber eben die Minimalanforderungen sehr hoch ausfallen lässt. In das Zeitalter wo es noch hieß "640 kB sind genug für alles" möchte ich aber definitiv auch nicht mehr zurück.


Grüße
Erik
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: FlashBurn am 20. May 2011, 21:16
Zitat von: erik
Wozu Du die komplett vollen SLAB-Blöcke in einer extra Liste speichern möchtest verstehe ich nicht, ich möchte das als eine einzige doppelt verkettete Liste lassen und den statischen Pointer (quasi den Einsprungspunkt in diese Liste) will ich auf den vollsten nicht ganz vollen SLAB-Block zeigen lassen (von diesem Punkt aus kann man sich also oft in beide Richtungen durch die Liste bewegen). Zusätzlich möchte ich noch einen Pointer auf den leersten SLAB-Block haben um das Freigeben von diesen zu vereinfachen.
Ich sags mal so, ob du nun alles in einer Liste hast, die sortiert ist und dir trotzdem den Anfang der vollen Elemente, den Anfang der Elemente mit mind. einem freien Objekt und den Anfang der komplett freien Element merkst oder ob du 3 Listen hast, sollte nun wirklich egal sein.
Was mir aber gefällt (im Hinblick auf den Speicherverbrauch) ist, dass die Liste der Anzahl der freien Objekte nach sortiert ist.

Zitat von: erik
Klar kann malloc auch größere Objekte liefern, solange free den selben Algorithmus benutzt um an die genormte Objektgröße zu kommen ist das doch auch in Ordnung.
Mal was anderes, du sprichst zwar ständig von malloc/free, aber wenn ich dein Konzept richtig verstanden habe, dann hast du die doch gar nicht, sondern nur nen Slab-Allocator, wo du auch noch für jedes Objekt ne andere Funktion aufrufst.

Was mir auch nicht ganz klar ist, was du eigentlich immer mit der Objektgröße holen meinst. Wann brauchst du die denn? Nur wenn du einen neuen Objektcache erstellst und da wird bei dir einfach ne Instruktion sein, die die Größe in ein Register läd und bei mir wird sie von ner Stack-Variablen geladen. Da sollte Performance technisch nun wirklich kein Unterschied sein! Dafür ist mein Code dann kompakter.

Zitat von: erik
Warum nicht? Vor allem was geht besser wenn Du das erst noch später ermittelst? Wann genau ermittelt Dein OS denn die Anzahl der vorhandenen CPUs?
Damit wollte ich eigentlich nur ausdrücken, da ich ja die Objektgröße für SlabDesc dynamisch beim Initialisieren festlege, ändert auch die Tatsache, das ich die CPU Anzahl zur Bootzeit kenne, nichts daran.

Was man vllt auch nochmal betonen sollte, du hast ja deine Segment und damit eine Art malloc/free und ich habe das gar nicht und kann nicht mal eben einen Block einer beliebigen Größe allozieren um den als Puffer für die per CPU Caches zu nehmen. Wobei wir da dann auch wieder wären, das du nen Pointer hast um auf deine CPU Caches zuzugreifen und ich habe auch einen Pointer dafür. Ist also im Endeffekt das gleiche, nur anders gelöst.

Zitat von: erik
Eine Bündelanforderung muss ja nicht alle Objekte aus einem SLAB nehmen sondern soll auch beim vollsten nicht ganz vollen SLAB-Block anfangen, theoretisch wäre es möglich das alle neuen Objekte aus unterschiedlichen SLAB-Blöcken kommen (und danach auch X Blöcke zusätzlich komplett voll sind).
Jetzt wird es nämlich interessant. Wie gibst du die dann zuück? Machst du aus den Objekten eine Liste? Wie löst du es, dass du ja auch jedes Mal nachgucken musst, ob überhaupt noch ein freies Objekt in dem Cache ist?

Ich habe das (leider eher unperformant) so gelöst das halt 4x die Funktion aufgerufen werden muss, die immer ein Objekt aus nem Cache holt. Macht die Sache erstens einfacher und zweitens behalte ich mir so die Option vor (und nutze sie auch intensiv), dass ich Fälle habe, wo ich den per CPU Cache nicht nutzen will oder kann.

Zitat von: erik
In das Zeitalter wo es noch hieß "640 kB sind genug für alles" möchte ich aber definitiv auch nicht mehr zurück.
Schon alleine wegen der Herausforderung würde ich das gerne machen bzw. habe mich ja auch vor fast 10 Jahren noch damit befasst.

Edit::

Jetzt sind mir meine Bedenken bezüglich der sortierten Liste doch wieder eingefallen.

Stell dir vor du hast eine List mit 100 Objectcaches und alle haben nur zwei Objekte rausgegeben und jetzt gibst du genau beim ersten Objectcache der List ein Objekt frei und musst jetzt 99 Listeneinträge durchgehen nur um die Liste sortiert zu halten.

Um das Problem zu umgehen würde ich insgesamt 4 Pointer für Objectcaches nutzen, 2 um eine doppelt verkettete Liste für alle Objectcaches mit der gleichen Anzahl freier Objekte zu machen und zwei um diese Listen miteinander zu verbinden.
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: Svenska am 20. May 2011, 21:35
Hallo,

Zitat von: Svenksa
Außerdem ist es problemlos möglich, die Anzahl der Einträge zur Compilezeit begrenzen (oder nachträglich durch ein Relinken anzupassen).
Da müsstest du mal genauer werden. Ich verstehe nicht ganz wie das mit dem relinken funktionieren soll bzw. was das machen soll.
Wie das technisch genau umgesetzt wurde, weiß ich nicht. Konkret hatte ich bei nem alten Xenix die Möglichkeit, durch ein Konfigurationsprogramm die Limits im Kernel zu ändern (also max. Anzahl serieller Terminals / gleichzeitig aktiver Prozesse / gleichzeitig geöffneter Dateien usw.); anschließend wurde der Kernel aus den Objectfiles neu gelinkt. Die Sourcen waren also nicht verfügbar, aber die Objectfiles. Ich vermute, dass dort die Offsets geändert wurden und im Kernel dann Freiräume eingebaut wurden, in denen dann die Datenstrukturen lagen.

Aber wie gesagt, zum Thema Usability finde ich es sehr schlecht wenn man ein Programm immer bzw. immer wenn man auf nem anderen Rechner ist (was auch portable Programme unmöglich macht bzw. unpraktikabel) neu kompilieren muss.
Davon redet auch keiner. Du redest von müssen, ich rede von können. Wenn es dir also zufällig auf das letzte Byte im Kernel ankommen sollte, hast du durchaus die Möglichkeit, den Speicherverbrauch zu reduzieren. Du musst es aber nicht tun.

Guck dir doch die üblichen Linux-Distributionen an. Die sind nicht auf Speicher sparen ausgelegt.

Zumal du mir doch wohl zustimmen musst, das es eigentlich nicht sein kann, dass ein OS welches nur eine Konsole zur Verfügung stellt schon 16MB und mehr braucht, oder?
Ein Größenvergleich: Boote ich mein Netbook (i686) mit "init=/bin/sh", lande ich bei 4.6 MB (6 MB inkl. Plattencache). Boote ich mit "single", lande ich bei 12 MB (27 MB inkl. Plattencache). Starte ich ein vollwertiges System ohne X11 (Runlevel 2), verbraucht mein System schon 29 MB (60 MB inkl. Plattencache). In allen Fällen habe ich "nur" eine Shell. Aber, wie dir auffallen sollte, ist die Größe des Kernels gegenüber den Anwendungen vernachlässigbar klein.

Oder andersrum: Wenn jede Anwendung einen Speicherverbrauch von mindestens 64 MB RAM hat, dann ist es total egal, ob der Microkernel nun 1 MB oder 2 MB verbraucht.

Würde man bei deinem Auto-Beispiel so konsequent argumentieren wie du, dann hätten wir keine Autobahnen aus Straßen, sondern aus Schienen und würden ausschließlich elektrisch angetriebene Mobilität haben. Die Kosten dafür (Bau, Instandhaltung, Inflexibilität) machen es aber nicht sinnvoll. Also nehmen wir absichtlich einen höheren Benzin-/Dieselverbrauch in Kauf.

Ich sags mal so, mit der Einstellung würde Linux aber nicht auf Routern oder anderen kleinen Geräten laufen und Handies wären noch langsamer!
Guck dir mal in einem modernen Kernel an, was alles durch CONFIG_EMBEDDED abschaltbar oder änderbar wird. Dann siehst du vielleicht auch den Grund, warum Linux auf Routern mit 16 MB einigermaßen vernünftig läuft. Ein normaler Distributionskernel für x86_64 ist da jedenfalls nicht mehr gebrauchbar.

Du vergleichst Äpfel mit Birnen.

Ich habe allerdings noch keinerlei Erfahrung aus der freien Wirtschaft, aber wenn du ein Programm schreibst, dann musst du dich ja für irgend einen Algo und irgendeine Datenstruktur entscheiden, d.h. du denkst darüber nach und genau da kann man ansetzen.
Kann man nicht. Da wird sich nicht für einen Algorithmus und eine Datenstruktur entschieden, sondern da wird nach der erstbesten Bibliothek gesucht, die man anwenden kann und die die Aufgabe erledigt.

Da ist es schon zu spät, auf Effizienz zu achten. Oder andersrum: Es wird durchaus hochgradig optimiert, aber auf die Zeit bis zur Marktreife, nicht auf Effizienz des Ergebnisses.

Denn seien wir ehrlich es wird sich oft nur für irgendeine Datenstruktur entschieden weil man keine besseren kennt (weil man sich nicht auf dem laufenden hält und/oder keine Ahnung hat) und sich sagt, Speicher ist ja genug da, was die anderen Programme dann machen ist ja egal.
Nein. Wenn ich alle Daten vorrätig habe, dann habe ich weniger Arbeit. Also verbrauche ich Speicher, um mir damit später Arbeit zu vereinfachen (oder die Programmierzeit zu verkürzen).

Zitat von: Svenska
Und ja, bei der These bleibe ich; ich bin mir aber durchaus bewusst, dass es sowohl nach oben als auch nach unten praktische Grenzen gibt, ab der es sich nicht lohnt.
Naja, um nur mal ein Bsp. zu nennen. Ich habe eine zeitlang für alle Sachen die über eine ID haben, einen AVL-Baum benutzt um die IDs zu verwalten und auf die Datenstrukturen zuzugreifen.
Wenn du noch mehr Speicher sparen möchtest, dann verwaltest du die IDs garnicht zentral, sparst dir also die Datenstruktur komplett, und iterierst bei jeder ID-Anfrage durch sämtliche vorhandenen Objekte. Das ist wesentlich langsamer, kostet aber garkeinen Speicher.

Es kommt nämlich durchaus auf das Problem an, ob man sagen kann das weniger Speicherverbrauch mehr Rechenzeit heißt.
Es gibt immer noch mehr Möglichkeiten, den Speicherverbrauch oder die Rechenzeit zu minimieren. Ab einem gewissen Punkt lohnt es sich jedoch nicht mehr, weil die geringste Ersparnis zu enormen Performanceverlust führt oder umgekehrt.

Wenn du dein Betriebssystem auf 640K optimierst, dann wird es auf großen Maschinen nicht optimal laufen. Das solltest du bedenken - hat dein Ziel viel RAM, solltest du ihn auch nutzen.

Gruß,
Svenska
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: FlashBurn am 20. May 2011, 21:51
Zitat von: Svenska
Du redest von müssen, ich rede von können. Wenn es dir also zufällig auf das letzte Byte im Kernel ankommen sollte, hast du durchaus die Möglichkeit, den Speicherverbrauch zu reduzieren. Du musst es aber nicht tun.
Naja, wenn ein Programm mit einem bestimmten Prozessorfeature kompiliert wurde (weil halt hochgradig optimeirt), dann muss ich das Programm auf nem Rechner wo die CPU dieses Feature nicht bietet neu kompilieren.
Baue ich mein Programm so auf, das ich sagen, entweder ich optimiere hochgradig (durch irgendwelche Flags eventuell auch im Code) oder ich mache es allgemein und packe alle Features rein, würde ich sagen macht es die Sache nur unnötig kompliziert und verlängert die Programmentwicklung. Besser ist es sich für eine Sache zu entscheiden (in meinem Fall also, alle Features rein und zur Laufzeit wird entschieden welches Feature genutzt wird).

Zitat von: Svenska
Oder andersrum: Wenn jede Anwendung einen Speicherverbrauch von mindestens 64 MB RAM hat, dann ist es total egal, ob der Microkernel nun 1 MB oder 2 MB verbraucht.
Ich meinte das mit dem Speicherverbrauch eigentlich auch allgemein und nicht nur auf den Kernel bezogen.

Zitat von: Svenska
Würde man bei deinem Auto-Beispiel so konsequent argumentieren wie du, dann hätten wir keine Autobahnen aus Straßen, sondern aus Schienen und würden ausschließlich elektrisch angetriebene Mobilität haben. Die Kosten dafür (Bau, Instandhaltung, Inflexibilität) machen es aber nicht sinnvoll. Also nehmen wir absichtlich einen höheren Benzin-/Dieselverbrauch in Kauf.
Da kann ich dir nicht ganz folgen. Zumal es mir darum ging, wenn wir (und das gilt wahrscheinlich für fast alle Probleme) keinen Zwang zu Effizienzverbesserungen bekommen, dann belassen wir es dabei.

Zitat von: Svenska
Da wird sich nicht für einen Algorithmus und eine Datenstruktur entschieden, sondern da wird nach der erstbesten Bibliothek gesucht, die man anwenden kann und die die Aufgabe erledigt.
Ich kann da wie gesagt leider nicht aus Erfahrung sprechen, aber ich kann mich auch dann immer noch zw. verschiedenen Datenstrukturen entscheiden, auch wenn ich eine schon fertige Implementierung der Datenstruktur nehme.

Zitat von: Svenska
Wenn du noch mehr Speicher sparen möchtest, dann verwaltest du die IDs garnicht zentral, sparst dir also die Datenstruktur komplett, und iterierst bei jeder ID-Anfrage durch sämtliche vorhandenen Objekte. Das ist wesentlich langsamer, kostet aber garkeinen Speicher.
Ich will ja nicht so wenig Speicher wie nur äußerst möglich verbrauchen, sondern so wenig wie mit der Leistung zu vereinbaren und da ist viel möglich, wenn man die richtigen Algos nutzt. Außerdem kann ein Algo der weniger Speicher verbraucht durchaus schneller sein, alleine schon weil man wahrscheinlich weniger Cachemisses hat und die sind richtig teuer.

Zitat von: Svenska
Wenn du dein Betriebssystem auf 640K optimierst, dann wird es auf großen Maschinen nicht optimal laufen. Das solltest du bedenken - hat dein Ziel viel RAM, solltest du ihn auch nutzen.
Eher umgedreht in meinem Fall. Ich möchte das mein OS auch mit wenig Speicher läuft, aber mit mehr Speicher wird es definitiv bei vielen Sachen schneller/besser laufen, weil dann z.B. weniger ausgelagert werden muss und sowas. Ich will dahin, das es läuft und zwar auf beiden extremen und das sollte machbar sein. Die Cachegröße an die vorhandene RAM-Größe anzupassen sollte kein Problem sein und muss sowieso gemacht werden.

Edit::

Auch die freie Wirtschaft wird irgendwann lernen, dass alles immer schnell nichts bringt. Ganz aktuell, siehe Sony ;)

Der Schaden ist oft höher wenn man etwas zu schnell veröffentlich als wenn man gründlich arbeitet!
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: Svenska am 20. May 2011, 22:12
Hallo,

Naja, wenn ein Programm mit einem bestimmten Prozessorfeature kompiliert wurde (weil halt hochgradig optimeirt), dann muss ich das Programm auf nem Rechner wo die CPU dieses Feature nicht bietet neu kompilieren.
Darum ging es doch nicht. Konkret ging es um die paar KB, die du verschwendest, wenn du die per-CPU-Strukturen statisch einbindest. Um die paar KB einzusparen, machst du dir eine Menge Aufwand und meine Argumentation war "wozu eigentlich, dafür ist genug RAM da".

Optimierung auf CPU-Basis ist noch eine ganz andere Baustelle, siehe "int 0x80", "SYSENTER", "SYSCALL".

Besser ist es sich für eine Sache zu entscheiden (in meinem Fall also, alle Features rein und zur Laufzeit wird entschieden welches Feature genutzt wird).
Oder, dass halt der PIT verwendet wird und nicht der HPET. :-)

Zitat von: Svenska
Würde man bei deinem Auto-Beispiel so konsequent argumentieren wie du, dann hätten wir keine Autobahnen aus Straßen, sondern aus Schienen (...)
Da kann ich dir nicht ganz folgen. Zumal es mir darum ging, wenn wir (und das gilt wahrscheinlich für fast alle Probleme) keinen Zwang zu Effizienzverbesserungen bekommen, dann belassen wir es dabei.
Schienen haben wesentlich weniger Gleitreibung und sind daher effizienter für den Transport. Dennoch wird Transport im großen Stil auf der Straße durchgeführt.

Zitat von: Svenska
Wenn du noch mehr Speicher sparen möchtest, dann verwaltest du die IDs garnicht zentral, sparst dir also die Datenstruktur komplett, und iterierst bei jeder ID-Anfrage durch sämtliche vorhandenen Objekte. Das ist wesentlich langsamer, kostet aber garkeinen Speicher.
Ich will ja nicht so wenig Speicher wie nur äußerst möglich verbrauchen, sondern so wenig wie mit der Leistung zu vereinbaren und da ist viel möglich, wenn man die richtigen Algos nutzt.
Merkste was? Das ist eine Kompromisslösung. Du kannst den Speicherverbrauch noch weiter auf Kosten der Performance reduzieren. Das ergibt sich aus meiner These: Du kannst beide gegeneinander eintauschen. Vom Verhältnis ist keine Rede.

Außerdem kann ein Algo der weniger Speicher verbraucht durchaus schneller sein, alleine schon weil man wahrscheinlich weniger Cachemisses hat und die sind richtig teuer.
Kann, muss aber nicht, das hängt konkret von der Umgebung ab. Wäre dir das wichtig, würdest du immer den langsameren, speichersparenden Algorithmus nehmen, denn so ein 486er hat nur 16K Cache... Die Aussage ist in jedem Fall nicht allgemeingültig, sonst würde man keine aufwändigeren Algorithmen verwenden.

Ich möchte das mein OS auch mit wenig Speicher läuft, [...] weil dann z.B. weniger ausgelagert werden muss und sowas.
Also doch Windows 95 bei 4 MB RAM. Es geht, ist aber nicht benutzbar.

Gruß,
Svenska
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: rizor am 20. May 2011, 23:01
Ach du grosser Gott... Das wird ja eine riesige Diskussion, bei der man nicht mal ein paar Stunden fehlen kann, da man ansonsten den Ueberblick verliert xD

Also sagen die 800 MB für den Kernel nur aus, dass deine Prozesse nicht viel Speicher benötigen und Windows somit mehr für sich nimmt.
Nein, die 800 MB sind der Verbrauch der 63 Prozesse selber, was der Kernel tatsächlich für sich verbraucht (ohne Caches und ohne Treiber usw.) sagt der Taskmanager nicht so deutlich.

Achso, dann habe ich dich falsch verstanden. Nicht so deutlich? Windows verheimlicht das doch komplett, oder? Mein NT Kernel (Win7) soll momentan angeblich nur 84kB verbrauchen, was ich aber fuer ein verdammt grosses Geruecht halte.
Das ist ja auch bekannt, dass Microsoft da die Werte etwas schoent.

Wenn man das statisch macht, kannst du Speicher sparen, da du davon ausgehst, dass derjenige, der den Kernel baut, weiß wie viel Kerne er verwendet. Du kannst dem Compiler ja sagen, dass dein System auf zwei CPUs gebaut werden soll. Wenn es nicht stimmt, ist der User des Kernels selber schuld. Im Prinzip genau so, wie es Linux macht. Natürlich hast du einen größeren Speicherverbrauch wenn du mehr Kerne angibst, aber warum solltest du das tun?
Ist das immer noch so? Ich meine, in Erinnerung zu haben, dass das zu ändern schon vor zwei, drei Jahren im Gespräch war. Du kannst auf jeden Fall davon ausgehen, dass das nicht so ist, weil es toll wäre, sondern eher weil es so schön einfach zu implementieren war. Auf kurz oder lang wird das also dynamisch werden.
Das kommt vermutlich auf das Subsystem an. Ich weiss, dass der Scheduler damit nicht mehr arbeitet. Die Funktionen des Schedulers fuer das Hotplugging sind mir schon haeufig genug auf die Fuesse gefallen.
Aber mir ist so, als wenn der Kernel das in manchen Systemen noch macht.

Ich möchte da auch so eine Art Defragmentierung des Speichers einbauen, dass bei SPeicherknappheit der Speicher umgelegt werden soll.
Du willst in einem Flat-Memory-System den Speicher defragmentieren? Da bin ich jetzt aber mal neugierig, wie?
Das habe ich noch nicht bis ins letzte Detail durchdacht, aber jeder Cache soll eine Funktion bieten, die defrag heisst und die der SLAB-Allocator aufrufen kann, sobald er vom OOM-Detector gerufen wird. Das Ganze soll dann so ablaufen, dass jeder Cache analysiert wird und geschaut wird, ob eine Defragmentierung (also die Erstellung komplett leerer Slabs) moeglich ist. Falls ihm ein Szenario einfaellt, ruft er defrag auf. Als Uebergabe ist es einmal das Objekt, das bewegt werden soll und dann die neue Position des Objekts. Nun versucht Defrag das zu organisieren (kennt die dahinter liegende Datenstruktur bereits). Falls die Datenstruktur eine Verknuepfung zu anderen hat, muss natuerlich die Gueltigkeit der Daten gewaehrleistet sein. Es kann auch sein, dass Defrag sagt, dass das nicht moeglich ist, dann hat der SLAB-Allocator pech gehabt.
Da es sich aber um den Kernel handelt, sollten alle teilnehmenden Komponenten ja durchaus kooperativ sein.
Also meine Defragmentierung zwingt niemanden, sondern bittet hoeflich.
Frei nach dem Motto: "Lieber SLAB-User, bitte versuche mal den Inhalt des Objekts in ein anderes Objekt zu legen und melde mir das Resultat." Wenn das geklappt hat, kann der SLAB-Allocator frei gewordene SLABs sofort an die virtuelle und damit an die physische Speicherverwaltung weiterreichen. Das soll natuerlich der letzte Ausweg sein. So eine Art alles oder nichts. Wenn der SLAB-Allocator die Defrag-Methoden aufruft, ist die Wahrscheinlichkeit sehr hoch, dass es bei fehlgeschlagenen Defragmentierungen zu einem OOM kommt.

Und ja, irgendwann mal moechte ich CPU-Hotplugging unterstuetzen. Ist aber sehr weit hinten. Bis dahin koennen das die x86 mit Sicherheit auch, falls sie es nciht sogar schon koennen. Linux unterstuetzt das zumindest unter den x86ern.

Zitat von: Svenska
Wenn du dein Betriebssystem auf 640K optimierst, dann wird es auf großen Maschinen nicht optimal laufen. Das solltest du bedenken - hat dein Ziel viel RAM, solltest du ihn auch nutzen.
Auf den ersten Blick hast du natuerlich recht, aber was bringt dir ein Kernel der viel Speicher BRAUCHT und nicht mit weniger umgehen kann. Das bringt dir nichts, sobald du Anwendungen hast, die viel Speicher brauchen (berechtigter Weise).
Ich bin der Meinung, dass ein Kernel jedes freie Byte verwenden sollte, aber nur wenn es kein anderer braucht. Das macht ein modernes OS aus. Ich will meinen Kernel auch so schreiben, dass er so viel wie moeglich an Daten Cached, diese aber auch in "Rekordzeit" wegwerfen kann, damit Anwendungen den Speicher bekommen koennen. Also im Prinzip eine Art Weak-Malloc im Kernel.
Ich bin mir nur noch nicht sicher, ob es wirklich sinnvoll ist ein Weak-Malloc zu implementieren oder ob man nicht lieber die Subsysteme um Speicher bitten soll.
Natuerlich braucht ein OS ein Mindestmass an Speicher (keine Frage), aber das sollte in meinen Augen im kB-Bereich (max. 64 oder so) liegen. Dadurch wird das gesamte System natuerlich extrem langsam, aber es ist immer noch besser als ein OOM-Fehler, weil der Kernel meint, dass er auf kein Byte Speicher verzichten kann, das er sich reserviert hat.
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: rizor am 20. May 2011, 23:11
Da der Quote-Button nicht mehr wollte, gibt es jetzt halt einen Doppel-Post...

Hallo,

Zitat von: Svenska
Würde man bei deinem Auto-Beispiel so konsequent argumentieren wie du, dann hätten wir keine Autobahnen aus Straßen, sondern aus Schienen (...)
Da kann ich dir nicht ganz folgen. Zumal es mir darum ging, wenn wir (und das gilt wahrscheinlich für fast alle Probleme) keinen Zwang zu Effizienzverbesserungen bekommen, dann belassen wir es dabei.
Schienen haben wesentlich weniger Gleitreibung und sind daher effizienter für den Transport. Dennoch wird Transport im großen Stil auf der Straße durchgeführt.

Das erinnert mich irgendwie an die Aepfel und die Birnen...
Ein alter Lehrer meinte mal: Nicht alles was hinkt, ist ein Vergleich.

Zitat von: Svenska
Wenn du noch mehr Speicher sparen möchtest, dann verwaltest du die IDs garnicht zentral, sparst dir also die Datenstruktur komplett, und iterierst bei jeder ID-Anfrage durch sämtliche vorhandenen Objekte. Das ist wesentlich langsamer, kostet aber garkeinen Speicher.
Ich will ja nicht so wenig Speicher wie nur äußerst möglich verbrauchen, sondern so wenig wie mit der Leistung zu vereinbaren und da ist viel möglich, wenn man die richtigen Algos nutzt.
Merkste was? Das ist eine Kompromisslösung. Du kannst den Speicherverbrauch noch weiter auf Kosten der Performance reduzieren. Das ergibt sich aus meiner These: Du kannst beide gegeneinander eintauschen. Vom Verhältnis ist keine Rede.
Das hat doch auch nie jemand bestritten, oder?
Natuerlich musst du immer einen Komprimiss finden, aber ich finde es auch nicht sinnvoll, wenn du 10 % mehr Speicher brauchst, damit du 1-2 % mehr Performance erreichst. Das ist mir der Zeitgewinn nicht wert, da mein Kernel auch auf Systemen mit wenig Speicher irgendwann mal laufen soll (z.B. MIPS und die ganzen Konsorten)

Ich möchte das mein OS auch mit wenig Speicher läuft, [...] weil dann z.B. weniger ausgelagert werden muss und sowas.
Also doch Windows 95 bei 4 MB RAM. Es geht, ist aber nicht benutzbar.

Gruß,
Svenska
Gewagte These. Wer bei Win95 von einem modernen OS (nach heutigen Massstaeben) spricht, gehoert gesteinigt ;).
Es kommt ganz klar auf das Einsatzgebiet des OSes an. Daran wird Microsoft mit Sicherheit hart gearbeitet haben oder es noch tun, da sie ja mit Win8 auch ARM unterstuetzen wollen. Wenn sie da dann mit mindestens einem GB RAM ankommen, erhalten sie eher Mitleid oder Spott als wirkliche Partner.
Wenn du einen Kernel nur auf x86 und Nachfolger laufen lassen willst, kannst du natuerlich mit Speicher um dich schmeissen, da es bestimmt niemanden mehr gibt, der weniger als ein oder zwei GB Speicher verwendet.
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: Svenska am 21. May 2011, 00:00
Von einem "modernen" OS war nicht die Rede. Und man kann auch das "OS" noch diskutieren, tu ich aber nicht. :-)

Du kannst auch ein normales Windows extrem klein konfigurieren, siehe beispielsweise Windows XP embedded. Jedes bessere Android-Gerät hat inzwischen 512 MB RAM verbaut (gut, meins hat nur 256 MB - dafür hat es 64 MB Swap im internen Flash). Ein Netbook mit Windows 8 und ARM wird mindestens 1 GB RAM verbaut haben, vielleicht sogar 2 GB; der Einsatzzweck ist ein anderer. Ich bezweifle, dass es Häme hagelt, wenn Win8 sinnvoll nur ab 1 GB aufwärts läuft (aber auf der Verpackung 512 MB steht).

Auf den ersten Blick hast du natuerlich recht, aber was bringt dir ein Kernel der viel Speicher BRAUCHT und nicht mit weniger umgehen kann. Das bringt dir nichts, sobald du Anwendungen hast, die viel Speicher brauchen (berechtigter Weise).
Wenn die Anwendungen trotzdem genug Speicher haben, interessiert es mich nicht weiter (geht). Brauchen die Anwendungen dagegen richtig viel Speicher, interessiert es mich auch nicht mehr (dann geht es ohnehin nicht). Der Bereich dazwischen ist relativ klein (und kann teilweise mit Swap abgefangen werden).

Wenn der Kernel viel Speicher braucht, kannst du eh nichts dagegen machen. Interessant ist die Frage, wieviel Speicher der Kernel nicht braucht, aber gerne hat (Caches mal ausgenommen). Wenn der Kernel inklusive alles 10 MB braucht und 20 MB nimmt, dann kann das angemessen sein, das hängt vom Kernel ab. Ein paar KB interessieren da nicht.

Der meiste RAM geht in den Hardwaretreibern und Anwendungen verloren, nicht im Kernel. Also sehe ich das Optimierungspotential eher dort - auch, wenn das OS-Dever nicht hören wollen. :-)

Ich will meinen Kernel auch so schreiben, dass er so viel wie moeglich an Daten Cached, diese aber auch in "Rekordzeit" wegwerfen kann, damit Anwendungen den Speicher bekommen koennen. Also im Prinzip eine Art Weak-Malloc im Kernel.
Ähnlich wie Plattencache. Finde ich sinnvoll.

Natuerlich braucht ein OS ein Mindestmass an Speicher (keine Frage), aber das sollte in meinen Augen im kB-Bereich (max. 64 oder so) liegen. Dadurch wird das gesamte System natuerlich extrem langsam, aber es ist immer noch besser als ein OOM-Fehler, weil der Kernel meint, dass er auf kein Byte Speicher verzichten kann, das er sich reserviert hat.
Dann riskierst du durch amoklaufende Prozesse einen Denial-of-Service, statt einen kontrollierten Absturz. Es ist in meinen Augen nicht sinnvoll, für jeden potentiellen Fehler eine Fallbacklösung zu haben; ein Ende mit Schrecken ist in meinen Augen sinnvoller.
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: erik.vikinger am 21. May 2011, 09:51
Hallo,


Ich sags mal so, ob du nun alles in einer Liste hast, die sortiert ist und dir trotzdem den Anfang der vollen Elemente, den Anfang der Elemente mit mind. einem freien Objekt und den Anfang der komplett freien Element merkst oder ob du 3 Listen hast, sollte nun wirklich egal sein.
Ich habe aber nur 2 Pointer in die eine Liste, für die ganz vollen Blöcke benötige ich keinen Pointer (wenn eines der Objekte dort freigegeben werden soll dann hat free ja einen passenden Pointer und ansonsten muss ich die vollen SLAB-Blöcke doch nicht anfassen).

Was mir aber gefällt (im Hinblick auf den Speicherverbrauch) ist, dass die Liste der Anzahl der freien Objekte nach sortiert ist.
Der Hintergedanke dazu ist nicht primär der Speicherverbrauch sondern eher das ich damit versuchen will möglichst wenige nicht ganz volle Blöcke zu haben um insgesamt möglichst wenige SLAB-Blöcke pro Objektgröße zu benötigen. Klar hat das auch positive Auswirkungen auf den Gesamtspeicherverbrauch (weil ich versuche den Verschnitt zu minimieren) aber es geht mir dabei auch um Effizienz beim Allozieren (deswegen möchte ich diese Kette sortiert haben).

Mal was anderes, du sprichst zwar ständig von malloc/free, aber wenn ich dein Konzept richtig verstanden habe, dann hast du die doch gar nicht, sondern nur nen Slab-Allocator, wo du auch noch für jedes Objekt ne andere Funktion aufrufst.
Sehr gut beobachtet. Ja ich will in meinem Micro-Kernel nur einen SLAB-Allocator haben und das sein Interface kmalloc/kmfree heißt ist eher eine nostalgische Entscheidung als rational begründet. Zumindest liefert mir dieses System den Kernel-Heap. Ob ich bei beiden Funktionen ein Parameter hab das mir den Gewünschten Objekttyp angibt (ist kein Integer mit der Größe sondern ein enum mit dem Typ, das enum lässt sich effizienter mit einem switch verarbeiten) oder ob ich dieses Funktionspärchen gleich mehrfach habe (für jeden Objekttyp eines) und dafür immer ein Parameter spare hab ich noch nicht endgültig entschieden aber ich tendiere momentan schon eher zur zweiten Lösung. Die zweite Lösung produziert zwar insgesamt etwas mehr Code weil ja einiges mehrfach vorhanden ist aber dafür sind die Funktionen an sich deutlich kleiner und schneller weil die SLAB-Parameter als Konstanten direkt in den Befehlen mit drin sind und nicht erst aus dem Speicher geholt werden müssen.

Damit wollte ich eigentlich nur ausdrücken, da ich ja die Objektgröße für SlabDesc dynamisch beim Initialisieren festlege, ändert auch die Tatsache, das ich die CPU Anzahl zur Bootzeit kenne, nichts daran.
Ah, jetzt begreife ich was Du meinst. Du möchtest also alle SLAB-Parameter (wie z.B. auch die Größe der SLAB-Blöcke und damit der Anzahl an Objekten pro Block) erst beim booten festlegen damit Du da möglichst ein Optimum aus verfügbaren RAM und bestmöglicher Performance raus holen kannst? Hm, ist eine interessante Idee aber wäre mir persönlich viel zu Aufwendig, für Systeme mit weniger als 2 GB RAM muss ich mein OS sowieso nicht planen von daher habe ich mich bei den 512 kB SLAB-Block-Größe an anderen Kriterien orientiert.

Was man vllt auch nochmal betonen sollte, du hast ja deine Segment
Nein, nicht im Kernel, der arbeitet direkt und flach auf dem physischen Speicher. Segmente habe ich eigentlich nur im User-Mode aber der Kernel hat auch die Möglichkeit über Segmente (und damit optional auch mit Paging) auf Speicher zuzugreifen.

kann nicht mal eben einen Block einer beliebigen Größe allozieren
Mein VMM kann auch nur mit Pages als kleinste Einheit umgehen, diese kleinen Datenstrukturen soll bei mir der Boot-Code direkt hinter dem Kernel "allozieren" und die dann ermittelte Endadresse auf die nächste Page-Grenze aufrunden und das als Anfangswert des linearen Speichers dem VMM geben so das der dann den restlichen Speicher verwaltet. Objekte mit beliebiger Größe kann mein Kernel auch nicht zur Laufzeit allozieren sondern nur während des Bootens (also während die Lebendgeburt vorbereitet wird). Ich denke das ich damit genug Freiheiten hab, da ich ja während der Laufzeit keinen Bedarf mehr an beliebigen Objektgrößen habe.

Jetzt wird es nämlich interessant. Wie gibst du die dann zuück? Machst du aus den Objekten eine Liste? Wie löst du es, dass du ja auch jedes Mal nachgucken musst, ob überhaupt noch ein freies Objekt in dem Cache ist?
Wie ich das im Deteil lösen möchte hab ich mir noch nicht überlegt, das wird sich dann beim programmieren ergeben, aber ich könnte mir vorstellen da ich ja immer ganze Magazine befüllen/leeren muss das ich einfach die Adresse eines Magazins als Parameter mitgebe und die Funktion intern das mit ner Schleife abarbeitet (ein Magazin ist ja nur ein simples Array mit bekannter Anzahl an Pointern). Dieses Interne Interface, zwischen den CPU-lokalen Magazin-Mechanismen und dem eigentlichen SLAB-Allocator, ist dann auch nicht mehr öffentlich für den restlichen Code des Kernels. Der Kernel sieht immer noch nur das kmalloc/kmfree-Pärchen (das auch immer noch die selbe API und ABI bietet) und ist glücklich. Eine Möglichkeit an den CPU-lokalen Caches dran vorbei zu arbeiten möchte ich nicht schaffen aber wahrscheinlich werde ich diesen Mechanismus nicht für alle Objektgrößen aktivieren. Für das Erstellen von Threads möchte ich ja einen eigenen Cache-Mechanismus haben in dem dann nicht nur der Thread-Descriptor (der vom SLAB-Allocator kommt) sondern auch immer ein zugehöriges Stack-Segment (das vom VMM kommt) gemeinsam verwalten möchte, das Erstellen/Löschen von Threads ist ja für die Performance meines IPC-Systems von entscheidender Bedeutung. Für die Prozess-Descriptoren werde ich wohl auch keine CPU-lokalen Caches benötigen da das nicht ganz so oft vorkommt.

Zitat von: erik
In das Zeitalter wo es noch hieß "640 kB sind genug für alles" möchte ich aber definitiv auch nicht mehr zurück.
Schon alleine wegen der Herausforderung würde ich das gerne machen bzw. habe mich ja auch vor fast 10 Jahren noch damit befasst.
Hm, nein Danke, ich denke das meine derzeitige Herausforderung anspruchsvoll genug ist.

Stell dir vor du hast eine List mit 100 Objectcaches und alle haben nur zwei Objekte rausgegeben und jetzt gibst du genau beim ersten Objectcache der List ein Objekt frei und musst jetzt 99 Listeneinträge durchgehen nur um die Liste sortiert zu halten.
So eine Situation ist zwar äußerst unperformant aber auch extrem unwahrscheinlich. Das müsste man schon mit viel Aufwand absichtlich so hintricksen und da mein Kernel nur von mir programmiert wird kann ich da ja aufpassen. Dieses Szenario ist in etwa so praxisrelevant wie das mit nur jeder zweiten Pages belegt, ist zwar theoretisch möglich aber dürfte in der Realität faktisch nie auftreten.

Um das Problem zu umgehen würde ich insgesamt 4 Pointer für Objectcaches nutzen, 2 um eine doppelt verkettete Liste für alle Objectcaches mit der gleichen Anzahl freier Objekte zu machen und zwei um diese Listen miteinander zu verbinden.
Und was ist wenn von den 100 SLAB-Blöcken 20 zu 1/4 belegt, 20 zu 2/4 belegt, 20 zu 3/4 belegt und 40 ganz voll sind? Das Auslagern von Blöcken mit identischem Füllgrad in extra Listen halte ich für keine gute Idee. Ist IMHO viel zu Aufwändig, kostet ne Menge extra Pointer und dürfte in der Praxis einfach fast nie auftreten. Eben um solchen Situationen vorzubeugen möchte ich die Kette ja sortiert halten und das Allozieren immer bei den möglichst vollen SLAB-Blöcken beginnen.


Auch die freie Wirtschaft wird irgendwann lernen, dass alles immer schnell nichts bringt. Ganz aktuell, siehe Sony ;)
Der Schaden ist oft höher wenn man etwas zu schnell veröffentlich als wenn man gründlich arbeitet!
Das möchte man annehmen, ja, aber die vergangenen Jahrzehnte zeigen uns das der (Image-)Schaden durch ein fehlerhaftes Produkt durchaus nicht allzu hoch ist. Redet heute noch jemand über den FDIV-Bug des Pentium? Klar hat der Intel etwas Geld (Rückrufaktion) und Ansehen (bei den professionellen/wissenschaftlichen Kunden) gekostet aber insgesamt hat Intel das ziemlich gut weggesteckt. In der freien Wirtschaft läuft das wie bei einer Rinderherde: es knallt irgendwo, alle Viecher gucken sich kurz um und dann wird munter weiter gegrast.


Ach du grosser Gott... Das wird ja eine riesige Diskussion, bei der man nicht mal ein paar Stunden fehlen kann, da man ansonsten den Ueberblick verliert xD
Wie wahr!

Frei nach dem Motto: "Lieber SLAB-User, bitte versuche mal den Inhalt des Objekts in ein anderes Objekt zu legen und melde mir das Resultat." Wenn das geklappt hat, kann der SLAB-Allocator frei gewordene SLABs sofort an die virtuelle und damit an die physische Speicherverwaltung weiterreichen. Das soll natuerlich der letzte Ausweg sein. So eine Art alles oder nichts. Wenn der SLAB-Allocator die Defrag-Methoden aufruft, ist die Wahrscheinlichkeit sehr hoch, dass es bei fehlgeschlagenen Defragmentierungen zu einem OOM kommt.
Na ob das was wird? Dafür müsstest Du bei allen Clients Deines SLAB-Allocators ja extra Code einbauen, mal von dem zusätzlichen Bug-Potential abgesehen wird das wohl schon mehr Speicher fressen als das freigeben von ein oder zwei SLAB-Blöcken bringen kann. Sorry, aber diese Idee halte ich nicht für zielführend.

Und ja, irgendwann mal moechte ich CPU-Hotplugging unterstuetzen. Ist aber sehr weit hinten. Bis dahin koennen das die x86 mit Sicherheit auch, falls sie es nciht sogar schon koennen. Linux unterstuetzt das zumindest unter den x86ern.
x86 kann CPU-Hotplugging schon seit vielen Jahren, wimre gab es sogar mal PentiumPro-Systeme die das können aber sowas hat für gewöhnlich nicht Otto-Normalverbraucher unter/auf seinem Schreibtisch zu stehen. CPU-Hotplugging gibt es eigentlich nur bei fetten und teuren Servern für Mission-Critical-Applicationen.


Ich bezweifle, dass es Häme hagelt, wenn Win8 sinnvoll nur ab 1 GB aufwärts läuft (aber auf der Verpackung 512 MB steht).
Sehe ich ganz genauso. Speicher ist heute so billig (und auch sparsam) das man davon problemlos zu viel einbauen kann damit er auch immer reicht. Ich denke bei ARM wird man momentan mit Hochdruck daran arbeiten endlich den Anschluss an die 64Bit-Welt zu schaffen (in der Hinsicht ist ARM der letzte Nachzügler) um noch mehr Speicher benutzen zu können. Ich vermute die Vielfalt bei den ARM-Befehlssätzen wird damit noch größer werden weil man ja vom kleinsten Embedded-Mikrocontroller bis zum fetten Server-Prozi alles unterstützen möchte (gerade das fette Ende fehlt ARM derzeit ja noch in der Produktpalette).


Grüße
Erik
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: FlashBurn am 21. May 2011, 10:37
Zitat von: Svenska
Merkste was? Das ist eine Kompromisslösung. Du kannst den Speicherverbrauch noch weiter auf Kosten der Performance reduzieren. Das ergibt sich aus meiner These: Du kannst beide gegeneinander eintauschen. Vom Verhältnis ist keine Rede.
Mir gefällt an deiner These nicht (was leider die meisten so sehen und auch lernen), das sie irgendwo sagt, das ein Algo der weniger Speicher verbraucht als ein anderer auch langsamer sein muss und das ist halt nicht der Fall.
Dass deine Theorie an den beiden Extremen korrekt ist, möchte ich nicht mal bezweifeln, aber in der Mitte ist es halt auch oft genug nicht so.

Zitat von: Svenska
Also doch Windows 95 bei 4 MB RAM. Es geht, ist aber nicht benutzbar.
Stimmt wohl, war aber eigentlich auch mit 8MB noch unbenutzbar, aber so 16MB waren schon ganz gut damals. Was dazu ganz gut passt, gab es jemals eine Linux-Distribution die da mithalten konnte (soll jetzt nichts gegen Linux werden)? Denn ich erinnere mich noch recht gut, das KDE damals ganz schön Speicher wollte, damit man halbwegs damit arbeiten konnte.

Zitat von: Svenska
Der meiste RAM geht in den Hardwaretreibern und Anwendungen verloren, nicht im Kernel. Also sehe ich das Optimierungspotential eher dort - auch, wenn das OS-Dever nicht hören wollen.
Das ändert aber nichts daran, das man auch im Kernel nicht verschwenderisch sein muss ;) Aber ansonsten kann ich dir nur zustimmen. Allerdings beweisen die Konsolen immer das es auch anders gehen kann, da müssen die Programmierer zwar mal ihren Kopf benutzen, aber immerhin.

Zitat von: erik
Du möchtest also alle SLAB-Parameter (wie z.B. auch die Größe der SLAB-Blöcke und damit der Anzahl an Objekten pro Block) erst beim booten festlegen damit Du da möglichst ein Optimum aus verfügbaren RAM und bestmöglicher Performance raus holen kannst? Hm, ist eine interessante Idee aber wäre mir persönlich viel zu Aufwendig
Naja, was heißt schon aufwendig ;) Ich meine du hast ja auch ne Art Formel wie du die Anzahl der Objekte pro SLAB berechnest. Du lässt das deinen Compiler machen und ich berechne das einmal zur Laufzeit. Bekomme aber weniger Verschnitt bzw. die Speicherauslastung dürfte bei mir geringer sein.

Zitat von: erik
Mein VMM kann auch nur mit Pages als kleinste Einheit umgehen, diese kleinen Datenstrukturen soll bei mir der Boot-Code direkt hinter dem Kernel "allozieren" und die dann ermittelte Endadresse auf die nächste Page-Grenze aufrunden und das als Anfangswert des linearen Speichers dem VMM geben so das der dann den restlichen Speicher verwaltet. Objekte mit beliebiger Größe kann mein Kernel auch nicht zur Laufzeit allozieren sondern nur während des Bootens (also während die Lebendgeburt vorbereitet wird).
Genau dieses "Verfahren" wende ich auch bei einiges Sachen an, aber für die Slabs wäre mir das einfach zu aufwendig ;)

Zitat von: erik
So eine Situation ist zwar äußerst unperformant aber auch extrem unwahrscheinlich. Das müsste man schon mit viel Aufwand absichtlich so hintricksen und da mein Kernel nur von mir programmiert wird kann ich da ja aufpassen.
Also ich behaupte mal das du da als Programmierer nicht wirklich Einfluss drauf hast. Das hängt ja z.B. davon ab wann die Programme gestartet und wann sie beendet werden und das ist ja mehr oder weniger zufällig.
Es gibt da so ein Bsp, wo genau dieser worst-case nicht so toll ist, ich sag nur DoS. Wimre wurden die IP-Adressen (?) unter Linux eine zeitlang in einem normalen Baum gespeichert und da war ein DoS ziemlich einfach, aber inzwischen speichern sie sowas in nem Red-Black-Tree (oder schon wieder was neues?) und dadurch wurde der DoS schwieriger.

Ich weiß gar nicht mehr was es damals unter Windows war, was mich immer geärgert hatte, ein Programm hat praktisch den ganzen Computer unbenutzbar gemacht.

Zitat von: erik
Und was ist wenn von den 100 SLAB-Blöcken 20 zu 1/4 belegt, 20 zu 2/4 belegt, 20 zu 3/4 belegt und 40 ganz voll sind?
Ich sehe da gerade kein Problem. Zumal ich sowas schon woanders einsetze, weil es weniger Speicher verbraucht und schneller ist. Nämlich für meinen VMM, der alle freien Bereiche, einmal nach der Adresse sortiert und einmal nach der Größe und da fasse ich auch alle Bereiche mit der gleichen Größe zusammen und habe so nur einen Eintrag in meinem Baum.

Mir fällt spontan QNX als gutes Bsp für ein OS ein, welches wenig Speicher braucht und trotzdem benutzbar ist bzw. in bestimmten Bereichen sogar bevorzugt wird.
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: erik.vikinger am 21. May 2011, 14:00
Hallo,


Naja, was heißt schon aufwendig ;) Ich meine du hast ja auch ne Art Formel wie du die Anzahl der Objekte pro SLAB berechnest. Du lässt das deinen Compiler machen und ich berechne das einmal zur Laufzeit. Bekomme aber weniger Verschnitt bzw. die Speicherauslastung dürfte bei mir geringer sein.
Ich wollte dieses ausrechnen eigentlich in meinem Kopf machen und damit dann ein paar Defines füttern aber das dem Compiler zu überlassen ist natürlich auch ne gute Idee. Wie Du mit der selben Formel (die Du nur zu einem anderen Zeitpunkt rechnest) auf weniger Verschnitt kommen möchtest verstehe ich aber nicht. Der wesentliche Unterschied zwischen unseren Konzepten dürfte sein das ich mit 512 kB ziemlich große SLAB-Blöcke benutze und Du wohl eher kleinere Stücke nehmen möchtest um den anfänglichen Speicherverbrauch klein zu halten. Dafür wirst Du öfters die kostspielige Aktion des Hinzufügens eines weiteren SLAB-Block durchführen müssen als ich. Wenn wir beide von einem Objekttyp erst mal ein paar hunderttausend Stück alloziert haben dürfte sich der resultierenden Gesamtspeicherverbrauch (also inklusive Verschnitt durch die SLAB-Verwaltung usw.) kaum noch wesentlich unterschieden (außer das bei Deinen kleineren SLAB-Blöcken eventuell ein minimal größerer prozentualer Verschnitt ist). Und genau da kommen wir wieder zur eigentlichen Zielstellung für das OS. Ich möchte das mein OS auf einem System mit deutlich mehr als 1 GB Speicher und dicken Work-Loads ordentlich performt und Du möchtest eben das Dein OS auch auf Systemen mit wenig Speicher überhaupt angemessen benutzbar ist. Zwischen unseren Zielvorstellungen liegen mindestens 2 Zehnerpotenzen und demzufolge unterscheiden sich auch unsere Konzepte.

Mal eine andere Frage: wie möchtest Du eigentlich das Freigeben von komplett unbenutzten SLAB-Blöcken managen? Willst Du die sofort freigeben oder möchtest Du damit lieber etwas warten? Wenn Du sofort frei gibst kann es sehr schnell passieren das Du kurz darauf wieder einen SLAB-Block vom VMM holen musst da es ja möglich ist das der Speicherverbrauch nur kurzzeitig so niedrig war.
Ich schätze ich werde erst frei geben wenn mindestens 2 SLAB-Blöcke komplett leer sind oder mindestens noch mal die Anzahl an Objekten die in einen SLAB-Block passt über mehrere andere SLAB-Blöcke frei ist. Auch wenn ich pro Objektgröße nur mit einem einzigen SLAB-Block starte so denke ich das ich zur Laufzeit nie unter 3 SLAB-Blöcke kommen möchte (also bei nur noch 3 SLAB-Blöcken wird keiner mehr an den VMM zurück gegeben egal wie leer die auch sind). Der Grund dafür ist das bei mir das Initialisieren eines neuen SLAB-Blocks recht aufwendig ist, ich möchte das jeder SLAB-Block seine eigenen freien Objekte als Stack verwaltet und dazu muss ich in jedes Objekt einmal schreibend Zugreifen um eben eine einfach verkette Liste aufzusetzen. Ich denke das ich hier auf jeden Fall bereit bin etwas Speicherverschwendung in Kauf zu nehmen um dafür den Heap zu beschleunigen. Eventuell könnte man dieses Verhalten auch an die Menge des freien physischen Speichers ankoppeln. Wenn noch viel RAM frei ist warum sollte der Heap dann seine SLAB-Blöcke überhaupt zurück geben?

Genau dieses "Verfahren" wende ich auch bei einiges Sachen an, aber für die Slabs wäre mir das einfach zu aufwendig ;)
Ich wende dieses Verfahren bei sehr vielen Dingen an, ich muss ne Menge an Speicher für den Kernel reservieren was ich nicht zur Compile-Zeit bestimmen kann. Auf meiner Architektur benötigt man für jede CPU einen individuellen Kernel-Stack (da mein Kernel ja prinzipiell nicht unterbrechbar ist reicht auch einer pro CPU), dazu kommen dann z.B. die Verwaltungsstrukturen für die HW-IRQs (was der IRQ-Controller maximal kann sehe ich ja auch erst beim booten) und eben auch die SLAB-Verwaltungsstrukturen. Den jeweils ersten SLAB-Block pro Objektgröße muss ich auch auf diese Weise "allozieren" da ja der VMM ohne den Heap nicht arbeiten kann (er soll ja für das Allozieren seiner Verwaltungsstrukturen kmalloc benutzen). Wenn die Speicherverwaltung dann soweit vorbereitet ist, das sie nun auch funktioniert, kann ich die normalen Funktionen des Kernels zum Anlegen der ersten 3 Prozesse benutzen (da z.B. auch der Scheduler den Heap benötigt um damit die Liste der runnable Threads aufzubauen).

Das hängt ja z.B. davon ab wann die Programme gestartet und wann sie beendet werden und das ist ja mehr oder weniger zufällig.
Klar ist das zufällig aber deswegen sortiere ich ja die SLAB-Blöcke um da ein möglichst günstiges Verhalten im Kernel zu haben. Und spätestens mit den CPU-lokalen Caches wird das System so stark entkoppelt das sich solche Situationen kaum noch herbeiführen lassen.

der alle freien Bereiche, einmal nach der Adresse sortiert und einmal nach der Größe und da fasse ich auch alle Bereiche mit der gleichen Größe zusammen und habe so nur einen Eintrag in meinem Baum.
Für den VMM ist das tatsächliche eine gute Idee, das muss ich mir auf jeden Fall notieren.

Mir fällt spontan QNX als gutes Bsp für ein OS ein, welches wenig Speicher braucht und trotzdem benutzbar ist bzw. in bestimmten Bereichen sogar bevorzugt wird.
QNX unterschiedet bei Syscall nach 2 Kategorien: die mit deterministischen Zeitverbrauch und die mit nicht vorhersehbaren Zeitverbrauch. Das Memory-Management fällt meines Wissens nach in die zweite Kategorie weswegen man üblicherweise versucht den gesamten Speicherbedarf einer Applikation beim Booten/Initialisieren zu allozieren und während der eigentlichen Laufzeit auf malloc/free möglichst verzichtet. Diese Strategie wird wimre in nahezu allen harten Real-Time-Applikationen benutzt. Auch unsere Memory-Management-Konzepte würden nicht wirklich für harte Echtzeit taugen. Eine generische Speicherverwaltung die immer O(1) arbeitet stelle ich mir persönlich unmöglich vor.


Grüße
Erik
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: FlashBurn am 21. May 2011, 14:39
Zitat von: erik
Wie Du mit der selben Formel (die Du nur zu einem anderen Zeitpunkt rechnest) auf weniger Verschnitt kommen möchtest verstehe ich aber nicht.
Da habe ich mich total falsch ausgedrückt, aber du hast es dann schon richtig verstanden. Ich werde bis zu einem gewissen Punkt weniger Speicher als du verbrauchen und ab dem dann mehr. Verschnitt könnte bei mir auch größer sein, aber nur wenn die Objekte nicht genau in einen Slab reinpassen.

Zitat von: erik
wie möchtest Du eigentlich das Freigeben von komplett unbenutzten SLAB-Blöcken managen? Willst Du die sofort freigeben oder möchtest Du damit lieber etwas warten?
Das ist so ein Problem. Ich habe mir noch nichts konkretes überlegt, aber implementiert ist die Variante von Linux (ich denke doch mal das ich gelesen hatte, dass Linux das so macht) und zwar gibst du von dir (der Slab-Allocator) nie den Speicher wieder frei, sondern das wird immer von außen angestoßen. Sprich man müsste einen Thread laufen lassen, der immer mal wieder den Speicherstand kontrolliert und wenn er eine bestimmte Schwelle unterschreitet rufst du ne Funktion auf, wo durch alle Objekttypen gegangen wird und die freien Slabs freigegeben werden. Diese Strategie kann man sicherlich noch verfeinern und hier ist leider auch ein monolith klar im Vorteil. Denn das kann meiner Meinung nach nur im Kernel funktionieren oder würde es Sinn machen das ein Programm ne Art Callback beim Kernel registriert und der kann dann aufgerufen werden um Speicher zu bekommen?
Ansonsten wäre auch meine Idee gewesen, nur Slabs freizugeben, wenn eine bestimmte Anzahl freier Slabs vorhanden ist (das wird man wohl durch probieren rausfinden müssen, was sich dort anbietet).

Zitat von: erik
Eine generische Speicherverwaltung die immer O(1) arbeitet stelle ich mir persönlich unmöglich vor.
Ich habe mir angewöhnt mit dem immer und dem nie eher vorsichtig umzugehen. Die Geschichte sollte uns da eines besseren belehren ;) Die Menschen waren immer zu 100% überzeugt das gewisse Dinge unmöglichen sind und heute sind sie möglich.
Aber mit den momentan bekannten Algos hast du recht. Obwohl ich mir vorstellen könnte das es möglich ist, aber das wäre dann wohl ein sehr gutes Bsp. den ganzen Leuten mal zu zeigen das ein O(1) Algo langsamer sein kann als z.B. ein O(n) Algo (auf nem Computer mit endlichen Ressourcen).
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: Svenska am 21. May 2011, 16:05
Zitat von: Svenska
Merkste was? Das ist eine Kompromisslösung. Du kannst den Speicherverbrauch noch weiter auf Kosten der Performance reduzieren. Das ergibt sich aus meiner These: Du kannst beide gegeneinander eintauschen. Vom Verhältnis ist keine Rede.
Mir gefällt an deiner These nicht (was leider die meisten so sehen und auch lernen), das sie irgendwo sagt, das ein Algo der weniger Speicher verbraucht als ein anderer auch langsamer sein muss und das ist halt nicht der Fall.
Das stimmt nicht: Da steht nicht, dass kleinere Algorithmen langsamer sein müssen. Da steht was von können. Und davon, dass es potentiell immer noch andere Möglichkeiten gibt - du kannst ja die Grundidee ändern, dann werden die Algorithmen vielleicht sogar komplett überflüssig. Also "thinking outside the box".

Das ändert aber nichts daran, das man auch im Kernel nicht verschwenderisch sein muss ;)
Definiere "verschwenderisch". In einem Serverbetriebssystem opfert man lieber 10% des RAMs für 2% der Performance, auf einem eingebetteten System macht man es eher umgekehrt. Es gibt halt keine Größe, die überall funktioniert.

Ich kenne einen Fall, da wurden in einen chronisch überlasteten Datenbankserver einfach 16 GB RAM nachgesteckt. Plötzlich lief fast die gesamte Datenbank aus dem RAM und das System war schnell. In der Größenordnung spielen selbst 64 MB Verschwendung im Kernel keine Rolle mehr.

Aber ansonsten kann ich dir nur zustimmen. Allerdings beweisen die Konsolen immer das es auch anders gehen kann, da müssen die Programmierer zwar mal ihren Kopf benutzen, aber immerhin.
Auf Konsolen gelten andere Gesetze, weil du nämlich eine Plattform hast, wo du jegliche Hardware kennst und damit optimal zuschneiden kannst. Das geht auf dem PC prinzipiell nicht. Wenn die Konsole 256 MB RAM hat, dann brauchst du keine Kompromisse suchen, damit es bei weniger RAM gerade noch so und bei mehr RAM noch viel besser geht.

Mir fällt spontan QNX als gutes Bsp für ein OS ein, welches wenig Speicher braucht und trotzdem benutzbar ist bzw. in bestimmten Bereichen sogar bevorzugt wird.
Mit QNX kenne ich mich nicht aus, aber in jeder Nische hast du ein gutes System, welches dort optimal läuft, woanders aber versagt.

Zitat von: erik
Eine generische Speicherverwaltung die immer O(1) arbeitet stelle ich mir persönlich unmöglich vor.
Ich habe mir angewöhnt mit dem immer und dem nie eher vorsichtig umzugehen. Die Geschichte sollte uns da eines besseren belehren ;) Die Menschen waren immer zu 100% überzeugt das gewisse Dinge unmöglichen sind und heute sind sie möglich.
Naja, du musst zwischen "unmöglich" und "unrealistisch" unterscheiden. Ich stimme Erik insofern zu, dass eine Speicherverwaltung, wie sie von heutigen Systemen benötigt wird, nicht in O(1) machbar ist.

mal zu zeigen das ein O(1) Algo langsamer sein kann als z.B. ein O(n) Algo (auf nem Computer mit endlichen Ressourcen).
Das eine ist Geschwindigkeit, das andere ist Skalierbarkeit. Du kannst wieder das eine gegen das andere eintauschen. Inzwischen bevorzugt man lieber skalierende und langsamerere Algorithmen als umgekehrt, sofern die Grundeinbuße nicht zu hoch ist.

Gruß,
Svenska
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: FlashBurn am 21. May 2011, 16:26
Zitat von: Svenska
Definiere "verschwenderisch". In einem Serverbetriebssystem opfert man lieber 10% des RAMs für 2% der Performance, auf einem eingebetteten System macht man es eher umgekehrt. Es gibt halt keine Größe, die überall funktioniert.
Also ja es ist richtig das es (leider?) keine Größe gibt die überall funktioniert. Allerdings ist das wahrscheinlich auch ein gutes Bsp. das man sich keinen Kopf macht, weil man keinen Zwang hat (bzw. ist es billiger mehr RAM zu kaufen als zu "denken"). Denn wäre es nicht möglich den RAM so stark zu vergrößern, würde man bestimmt versuchen nen anderen Algo/Datenstruktur zu nutzen und würde wahrscheinlich effizienter arbeiten, aber so erweitert man einfach den RAM und das Problem wird halt wieder in die Zukunft verschoben (woher kenne ich das nur ;)).

Zitat von: Svenska
Auf Konsolen gelten andere Gesetze, weil du nämlich eine Plattform hast, wo du jegliche Hardware kennst und damit optimal zuschneiden kannst. Das geht auf dem PC prinzipiell nicht.
Naja, aber man könnte ja einen mind. RAM vorgeben (so wie es auch schon gemacht wird) und das ganz so gestalten das es nach oben hin (also mehr RAM) skaliert, aber das es auch mit dem mind. RAM gut funktioniert. Z.B. so dass man mit etwas mehr als dem Konsolen RAM arbeiten kann (weil das OS und sowas ja auch RAM braucht), aber wenn mehr RAM zur Verfügung steht kann man den nutzen. Allerdings sieht es ja anscheinend so aus, dass man auf dem PC immer von deutlich mehr RAM ausgeht und daher nicht so clever arbeiten muss.

Im Endeffekt kann man daraus ne philosophische Aussage drauß machen, ohne Zwang kein (oder besser kaum) Fortschritt!
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: erik.vikinger am 21. May 2011, 19:15
Hallo,


Ich werde bis zu einem gewissen Punkt weniger Speicher als du verbrauchen und ab dem dann mehr.
Ganz genau. Du wirst aber für gewöhnlich auch den dickeren Prozessor haben als ich. Wenn ich mit meiner CPU alles richtig mache werde ich etwa das Niveau der untersten Pentiums erreichen und wenn ich mir richtig Mühe gebe vielleicht sogar das Niveau eines mittleren Pentium und wenn ich mir noch mehr Mühe gebe (und auch etwas Glück dazu kommt) eventuell das Niveau eines unteren PentiumPro. Dafür werde ich mit Sicherheit immer mindestens 2 GB RAM haben und dieser RAM wird auf meinem eigenen FPGA-Board etwa 400MHz-DDR2 mit mindestens 128Bit-Datenbusbreite sein, das heißt ich habe deutlich mehr RAM und auch deutlich schnelleren RAM (sowohl mehr Speicherbandbreite als auch kürzere Latenzzeiten) als ein typisches Pentium- oder PentiumPro-System zur Verfügung und genau deswegen werde ich diesen RAM auch einsetzen wenn ich dafür mehr Performance erreichen kann. Ist eben alles eine Frage der Rahmenbedingungen und Zielsetzungen.

Verschnitt könnte bei mir auch größer sein, aber nur wenn die Objekte nicht genau in einen Slab reinpassen.
Selbst wenn die Objekte genau in den SLAB-Block passen wirst Du mehr Verschnitt haben da Du ja mehr SLAB-Blöcke brauchst und jeder Block seinen Header hat.

und zwar gibst du von dir (der Slab-Allocator) nie den Speicher wieder frei, sondern das wird immer von außen angestoßen.
Hm, auch ne Variante. Solange noch genug physischer Speicher frei ist sehe ich für den Kernel-Heap auch keine Notwendigkeit da etwas her zu geben. Auf der anderen Seite geht dieser Speicher damit eventuell dem VFS-Cache o.ä. verloren. Ich hab zwar eine komfortable Möglichkeit in meinem Kernel mit der ich in regelmäßigen Abständen mal prüfen kann ob es sich lohnt ein paar SLAB-Blöcke frei zu geben aber von der Idee bin ich nicht so sehr angetan. Ich denke auch das dieses Konzept eher für einen Monolithen geeignet ist als für einen Micro-Kernel, das ist aber auch nur so ein Bauchgefühl und keine fundierte Analyse. Wenn Du also mal beides ausprobieren und uns dann das Ergebnis berichten möchtest wären wir alle sicher sehr Dankbar. ;)

Ansonsten wäre auch meine Idee gewesen, nur Slabs freizugeben, wenn eine bestimmte Anzahl freier Slabs vorhanden ist (das wird man wohl durch probieren rausfinden müssen, was sich dort anbietet).
Diese Lösung ist IMHO auch recht billig zu bekommen, da man ja eh am Ende von free den Freie-Objekte-Zähler inkrementieren muss kann man den auch gleich mit einer Konstanten vergleichen um zu prüfen ob es sich überhaupt lohnt mal nachzusehen ob man etwas frei geben könnte. Diese Konstante sollte etwa das Doppelte von der Anzahl an Objekten pro SLAB-Block sein, würde ich jetzt mal so sagen aber genauer (falls das überhaupt genauer geht) wird man das auch nur mit Versuchen und Benchmarks ermitteln können.

Ich habe mir angewöhnt mit dem immer und dem nie eher vorsichtig umzugehen.
Deswegen hab ich ja "stelle .... vor" geschrieben. Wenn mir jemand einen Speicherverwaltungsalgorithmus zeigen kann der in O(1) arbeitet und die 1 auch wirklich konkurrenzfähig klein ist dann bin ich sofort überzeugt.
Natürlich passieren solche Quantensprünge immer mal wieder aber die sind trotzdem ziemlich selten. In der täglichen Praxis muss man eben meistens Kompromisse schließen, der Trade-Off aus Rechenleistung und Speicherverbrauch ist da nur ein Beispiel von vielen.


In einem Serverbetriebssystem opfert man lieber 10% des RAMs für 2% der Performance, auf einem eingebetteten System macht man es eher umgekehrt.
Wenn ich einem Vorgesetzten so eine Art von Problem erklärt hab hab ich auch schon oft die Gegenfrage "was kostet eigentlich der nächst größere Chip" bekommen. Man kann nicht nur Speicherverbrauch und CPU-Verbrauch gegeneinander eintauschen sondern auch beides gegen Geld. Und da auch die Man-Stunde des Programmierers Geld kostet (wenn er sich Mühe geben muss den Kompromiss aus Speicherverbrauch und CPU-Verbrauch in eine gute Balance zu bekommen) kann es eben sein das ein ökonomisch denkender Manager auch einfach mal die kosteneffizienteste Lösung nimmt.


Denn wäre es nicht möglich den RAM so stark zu vergrößern, würde man bestimmt versuchen nen anderen Algo/Datenstruktur zu nutzen und würde wahrscheinlich effizienter arbeiten, aber so erweitert man einfach den RAM und das Problem wird halt wieder in die Zukunft verschoben (woher kenne ich das nur ;)).
Wenn das Deine ehrliche Einstellung ist dann empfehle ich Dir einen C64. Der ist gut Dokumentiert und es gibt selbst heute noch eine treue Entwicklergemeinde die immer fähige Hände sucht. Ich hab auf dem C64 schon Dinge gesehen für die ein PC locker die hundertfache Rechenleistung des C64 brauchen würde wenn ich das implementieren müsste. Ich habe da noch ein paar Kontakte also wenn Du wirklich eine Herausforderung suchst dann bin ich Dir da gerne behilflich.

Naja, aber man könnte ja einen mind. RAM vorgeben (so wie es auch schon gemacht wird) und das ganz so gestalten das es nach oben hin (also mehr RAM) skaliert, aber das es auch mit dem mind. RAM gut funktioniert.
Das wird nur selten funktionieren. Die Fähigkeit zum Skalieren kostet etwas und dieser Preis kann dann wenn diese Fähigkeit nicht nutzbar ist (also bei der Standardausstattung) schon zu hoch sein.

Im Endeffekt kann man daraus ne philosophische Aussage drauß machen, ohne Zwang kein (oder besser kaum) Fortschritt!
Das kann ich ruhigen Gewissens unterschreiben.
Nicht umsonst heißt es "Not macht erfinderisch".


Grüße
Erik
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: FlashBurn am 21. May 2011, 19:35
Zitat von: erik
Du wirst aber für gewöhnlich auch den dickeren Prozessor haben als ich. Wenn ich mit meiner CPU alles richtig mache werde ich etwa das Niveau der untersten Pentiums erreichen
Ich kann den zwar durchaus haben, aber mein Ziel sind genau die Pentiums (und bei einigen Sachen brauche ich dann doch neuere Computer, wie z.B. den HPET) und davon habe ich auch einfach genug zum Testen.

Zitat von: erik
Wenn das Deine ehrliche Einstellung ist dann empfehle ich Dir einen C64.
Auf der einen Seite sehr verlockend, aber auf der anderen muss ich sagen, wenn ich nur halb so viel Können hätte wie solche Demo-Programmierer, würde ich jetzt nicht noch immer studieren ;)

Ich bin immer wieder hin und weg, wenn ich sehe was solche Leute aus der Hardware rausholen, aber dafür fehlt mir leider die nötige Kreativität und mein Mathe ist inzwischen so schlecht, das ich nicht mal mehr das Abitur schaffen würde :(

Zitat von: erik
Das wird nur selten funktionieren. Die Fähigkeit zum Skalieren kostet etwas und dieser Preis kann dann wenn diese Fähigkeit nicht nutzbar ist (also bei der Standardausstattung) schon zu hoch sein.
Diese Aussage ist insofern interessant, da dass ich auch implezieren würde, das ein Spiel immer den gleichen Speicher belegt (wenn die gleichen Rahmenbedingungen geltern, außer dem RAM)?! Sprich in dem Sinne wäre es also das gleiche wie auf einer Konsole.
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: erik.vikinger am 22. May 2011, 08:04
Hallo,


davon habe ich auch einfach genug zum Testen.
Aha, hast Du zufällig auch einen mehrfach PentiumPro in Deiner Sammlung?

Auf der einen Seite sehr verlockend, aber auf der anderen muss ich sagen, wenn ich nur halb so viel Können hätte wie solche Demo-Programmierer, würde ich jetzt nicht noch immer studieren ;)
Ja, das ist sehr verlockend aber auch einigermaßen zeitintensiv. Vor über 10 Jahren hab ich an sowas mitprogrammiert aber meistens nur irgendwelche Low-Level-Sachen wie die Dekompressoren da die Demos ja oft mit 64 kB o.ä. aus kommen mussten (als Dateigröße, nicht als RAM-Belegung). Heute sind die Tage dieser Demos vorbei, einfach weil es gute 3D-Grafikkarten gibt. In heutigen Demos geht es nur noch darum die 3D-Daten für Direct-X oder OpenGL passend vorzubereiten und dann alles laufen zu lassen, für mich persönlich hat dieses Thema damit seinen Reiz verloren. Ich kenne übrigens einen der hat extra lange studiert eben weil er das kann, um dafür genügend Freizeit zu haben was neben einem Job nicht mehr so gut funktioniert.

Ich bin immer wieder hin und weg, wenn ich sehe was solche Leute aus der Hardware rausholen, aber dafür fehlt mir leider die nötige Kreativität
Das die Hardware oft mehr kann als die Konstrukteure sich bewusst sind gibt es nicht nur beim C64, als ich das erste mal auf meinem eigenen PC (damals ein 486 mit 80 MHz und einer ISA-GraKa mit 512 kB) 3D-Graphik in Echtfarben (die ISA-GraKa kann definitiv nur palettenbasierte Darstellung) gesehen hab war ich echt platt, wenn ich das nicht mit eigenen Augen gesehen hätte hätte ich es nicht geglaubt. Ich weiß bis heute nicht genau wie dieser Trick funktioniert.

und mein Mathe ist inzwischen so schlecht, das ich nicht mal mehr das Abitur schaffen würde :(
Also wenn Du Dein Mathe als so schlecht einstufst dann wirst Du auch im Job ernste Schwierigkeiten bekommen. Gerade in technischen Berufen (ich gehe jetzt mal davon aus das Du etwas mit Programmieren o.ä. machen möchtest) muss man in Mathe immer fit sein. Da ich selber nicht mal Abi hab musste ich in den vergangenen 10 Jahren immer mal wieder etwas für mich neues lernen und das geht zwar dank des Internets einigermaßen gut aber toll ist das auch nicht.

Diese Aussage ist insofern interessant, da dass ich auch implezieren würde, das ein Spiel immer den gleichen Speicher belegt (wenn die gleichen Rahmenbedingungen geltern, außer dem RAM)?! Sprich in dem Sinne wäre es also das gleiche wie auf einer Konsole.
Wenn Du die Compilerschalter mit in die Rahmenbedingungen einbeziehst könnte das tatsächlich zutreffen. Aber in den Spielen die für mehrere Plattformen parallel raus kommen werden sicher auch jeweils passende Versionen der 3D-Engine eingesetzt. Wimre gibt es die großen 3D-Engines in verschiedenen Ausführungen die zwar nach oben hin immer das selbe API haben aber intern an die entsprechende Plattform ganz genau angepasst sind. Also der zugrunde liegende Source-Code insgesamt (unter Einbeziehung aller Librarys) für ein und das selbe Spiel dürfte sich doch von Plattform zu Plattform erheblich unterscheiden. Auch an den Daten (Texturen usw.) wird es sicher erhebliche Unterschiede geben, während für die Konsolen 2 Auflösungen (TV + HDTV) reichen muss in der PC-Version sehr viel mehr drin sein (zuzüglich der erforderlichen Flexibilität im Code).


@rizor:
Wenn Du wirklich einen SLAB-Allocator als generische Heap-Implementierung benutzen möchtest (also alles was malloc liefert aus nem SLAB kommen soll) dann würde ich mir an Deiner Stelle noch mal die Größenstaffelung überlegen. Selbst eine Wurzel-2-Staffelung erzeugt immer noch einen enormen Verschnitt (bis zu 50%), wenigstens 16 Abstufungen pro Zweierpotenz (mit logarithmischen Abständen) würde ich schon machen. Auch solltest Du die Größe der Objekte die tatsächlich aus einem SLAB kommen sollen beschränken, einen 16MB-Puffer aus einem SLAB zu holen ist IMHO Quatsch. Wimre holt der Hoard Memory Allocator (eine Heap-Implementierung für den User-Space) für Objekte größer 256 kB auch direkt virtuellen Speicher vom OS.


Grüße
Erik
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: FlashBurn am 22. May 2011, 09:03
Zitat von: erik
Aha, hast Du zufällig auch einen mehrfach PentiumPro in Deiner Sammlung?
Jap, konnte auf dem bisher leider noch nicht testen (aber der läuft), da das eines der Boards ist, was bei meinen Eltern ist und da komme ich in letzter Zeit so selten hin.

Zitat von: erik
Also wenn Du Dein Mathe als so schlecht einstufst dann wirst Du auch im Job ernste Schwierigkeiten bekommen.
Ich denke mal da wäre es sinnvoller nen neuen Thread im Off-Topic Forum aufzumachen. Was mich immer wundert ist, das ich genug Kommiltonen kenne, die zwar Mathe gut können, aber von Programmieren keine Ahnung haben bzw. kein "Gespür" dafür.

Zitat von: erik
Wenn Du die Compilerschalter mit in die Rahmenbedingungen einbeziehst könnte das tatsächlich zutreffen.
Das überrascht mich dann doch ein wenig. Allerdings denke ich mal das man die Engines so programmiert, dass sie einen bestimmten Speicher benötigen und als mindest Angabe an RAM macht man dann soviel dass das OS nicht zuviel swappen muss.
Obwohl das eigentlich auch logisch ist, ich meine auf der Konsole musst du dich selbst drum kümmern, das nachgeladen werden muss und auf nem PC macht dass das OS für dich (das Swappen).

@rizor

Die Frage die ich mir stellen würde, warum brauchst du ein allgemeines malloc() in einem Mikrokernel (du schreibst doch einen?)?
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: erik.vikinger am 22. May 2011, 10:51
Hallo,


Jap, konnte auf dem bisher leider noch nicht testen (aber der läuft), da das eines der Boards ist, was bei meinen Eltern ist und da komme ich in letzter Zeit so selten hin.
Ahh, wie viele CPUs mit welchem Takt und welcher L2-Cache-Größe und wie viel RAM von welchem Typ und Geschwindigkeit stecken denn da drin? Ich suche ja immer noch eine adäquate Herausforderung für meine CPU-Entwicklung, ich hab zwar hier nen K6 (der ja auch Out-of-Order-Execution usw. kann) denn ich auf eine passende Taktfrequenz runtertakten könnte aber der ist eben alleine auf seinem Board. Und ein aktueller Core-irgendwas oder Athlon wäre einfach kein fairer Vergleich.

Was mich immer wundert ist, das ich genug Kommiltonen kenne, die zwar Mathe gut können, aber von Programmieren keine Ahnung haben bzw. kein "Gespür" dafür.
Gerade dieses "Gespür" hat eben nichts mit mathematischer Intelligenz o.ä. zu tun. Ich persönlich betrachte es nicht als verwunderlich das viele Mathematiker und auch Physiker keine guten Programmierer sind, für die wurden ja extra Programmiersprachen wie Fortran erschaffen (nur leider lernt man damit auch nicht wirklich programmieren). Aber wenn dann sollten wir das wohl wirklich in einem extra Thead näher diskutieren.

Allerdings denke ich mal das man die Engines so programmiert ....
Auf einer Konsole wird eine komplett andere Implementierung der Engine eingesetzt als auf dem PC, nur das Interface zum eigentlichen Spiel ist identisch. Und auch im Spiel selber werden sicher einige Features bzw. Einstellmöglichkeiten per Compilerschalter abgeschalten bzw. beschnitten. Ich vermute mal das die Entwickler erst mal das Spiel generisch mit maximalen Features entwickeln und das dann das Ergebnis für die jeweilige Zielplattform zurechtgestutzt wird. Für den PC wird dieses Zurechtstutzen wohl sehr knapp ausfallen aber für die verschiedenen Konsolen wird wohl mindestens das Auswechseln der drunter liegenden Engine und das Ausdünnen der Textur-Daten anfallen (Dinge die sicher zum Großteil komplett automatisiert ablaufen, als Teil des Build-Prozesses).


Grüße
Erik
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: FlashBurn am 22. May 2011, 11:32
Zitat von: erik
Ahh, wie viele CPUs mit welchem Takt und welcher L2-Cache-Größe und wie viel RAM von welchem Typ und Geschwindigkeit stecken denn da drin?
Also aus dem Kopf kann ich dir sagen, das es (leider nur) ein Dual-Board ist mit 200MHz 512kbL2 und noch PS/2-RAM verwendet. Ich habe auch ein Board für eine PPro CPU mit SD-RAM, aber das habe ich noch nicht zum Laufen bekommen. Allerdings habe ich einige Dual-Pentium Boards und auch Pentium 2 Boards (auch die ersten, die mit 233-300MHz liefen). Wo dann schon SD-RAM eingesetzt wurde.

Das kann man dann ja immernoch sehen, ich ziehe bald um und da könnte ich eigentlich mal anfangen alles zu katalogisieren, weil ich inzwischen doch den Überblick verloren habe.
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: FlashBurn am 25. May 2011, 16:37
So ich benutze jetzt mal den Thread für mein Problem.

Der Linux Slab-Allocator unterstützt ja das Konstruieren und Destruieren von Objekten. Das habe ich auch schon drin, allerdings noch nicht an der richtigen Stelle. Ich mache das im Moment erst wenn das Objekt rausgegeben wird oder wenn es wieder freigegeben wird.
Richtig wäre es aber, wenn man das Objekt konstruiert wenn ein einer Objectcache erstellt wird. Hier habe ich nun das Problem das ja beim Konstruieren ein Fehler auftreten könnte, aber was macht man in dem Moment?

Der Sinn ist es, dass man z.B. einen Konstruktor übergeben kann und wenn ein Objectcache erstellt wird, kann z.B. bei Threads, gleich ne Thread-ID geholt werden und der Kernel-Stack (weil das ja Dinge sind die sich nicht verändern). Damit wird das über die gesamte Lebenszeit (solange also der Obejctcache besteht) nur einmal gemacht und man kann z.B. schneller Threads erstellen (was ja bei mir und erik wichtig ist).
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: erik.vikinger am 25. May 2011, 18:55
Hallo,


Richtig wäre es aber, wenn man das Objekt konstruiert wenn ein einer Objectcache erstellt wird. Hier habe ich nun das Problem das ja beim Konstruieren ein Fehler auftreten könnte, aber was macht man in dem Moment?
Warum ist dieses Vorgehen Richtig? Ich bin mir jetzt nicht ganz sicher aber wimre sichert der C++-Standard zu das der Konstruktor dann aufgerufen wird nachdem das new erfolgreich Speicher geholt hat oder wenn das Objekt anfängt gültig zu sein und der Destruktor dann wenn das Objekt nicht mehr gültig ist oder als erstes beim delete. Davon abzuweichen birgt IMHO zu viele Risiken, eines davon hast Du ja gerade gefunden. Meiner Meinung nach hast Du dann etwa folgende Optionen: (1) Du gibst beim ersten Problem den gesamten SLAB-Block wieder frei (also löscht auch alle bereits erfolgreich konstruierten Objekte), (2) Du markierst die fehlerhaft konstruierten Objekte speziell damit sie später nicht rausgegeben werden (falls gar keines der Objekte erfolgreich erstellt werden kann könnte man auch wieder den gesamten SLAB-Block freigeben), (3) so wie 1 oder 2 nur das Du im Fehlerfall dem aktuellen Speicheranfrager NULL zurück gibst, (4) Du machst diesen Vorgang grundsätzlich in einem extra Kontext in dem Du solche Fehler auch anständig behandeln kannst. Ich bin ja der Meinung das alle Varianten erhebliche Nachteile haben und würde daher grundsätzlich davon abraten. Das Problem ist IMHO das die möglichen Fehler zu komplex sind und man sie auch nicht einfach ignorieren kann. Ich persönlich würde ja zu (3) tendieren weil dort immer noch der konsistenteste End-Zustand (inklusive in den CPU-lokalen Magazinen usw.) bei raus kommt (bei Erfolgreich aber auch bei Fehler). Eine weitere Möglichkeit wäre es den Konstruktionsvorgang auf 2 Phasen aufzuteilen, der erste Konstruktor (welcher beim SLAB-Block initialisieren aufgerufen wird) darf nur weiteren Speicher (z.B. Deinen Kernel-Mode-Stack bei Threads) anfordern und der zweite Konstruktor (der dann aufgerufen wird wenn das Objekt tatsächlich rausgegeben wird) macht dann den Rest (z.B. IDs holen). Auf diese Weise wären die Fehler bei der SLAB-Block-Erstellung wenigstens immer nur reine Out-of-Memory-Fehler so das der Rückgabewert NULL insgesamt auch konsistent ist (auch wenn das Objekt das Du jetzt eigentlich raus geben möchtest ja fertig vorhanden ist) und es ist IMHO auch ein guter Kompromiss aus Performance und geringer Komplexität.


Grüße
Erik
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: FlashBurn am 25. May 2011, 19:08
Der Vorteil dieses Vorgehens ist doch, das du nicht jedes Mal ein Objekt konstruieren musst, wenn du Speicher allozierst und wieder destruieren musst, wenn du den Speicher wieder freigibst. Sondern dass das Objekt immer einen genau definierten Zustand hat, wenn du es bekommst und du es in dem Zustand auch wieder freigibst. So sparst du dir zusätzliche Arbeit (was auch ein Grund für den Slab-Allocator war).
Und genau dieser Thread-Pool ist wie gemacht dafür.
Im Endeffekt sind das Allozieren von Stack und ID beides nur OOM-Fehler (weil du ne neue ID nur nicht bekommen kannst, wenn kein Speicher mehr da ist um das Array zu erweitern).
Ich werde dann wohl Variante 1 implementieren, weil das die sinnvollste ist (mMn).

Da hast du dann mit deinen großen Slabs wieder Vorteile, weil bei dir schnell viele Threads erzeugt werden können, ohne das irgendwas nachgeladen werden muss. Allerdings den Nachteil (je nach dem was für Ziele man hat), dass ich (weil du ja nur einen Kernelstack pro CPU hast) dann auch zuviele Kernelstacks hätte und das frisst dann auch ganz schön (MB Bereich).
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: erik.vikinger am 25. May 2011, 19:26
Hallo,


Der Vorteil dieses Vorgehens ist doch, das du nicht jedes Mal ein Objekt konstruieren musst, wenn du Speicher allozierst und wieder destruieren musst, wenn du den Speicher wieder freigibst. Sondern dass das Objekt immer einen genau definierten Zustand hat, wenn du es bekommst und du es in dem Zustand auch wieder freigibst. So sparst du dir zusätzliche Arbeit (was auch ein Grund für den Slab-Allocator war).
Ich kann mir nicht helfen aber das erscheint mir doch sehr suspekt. In meinem Konzept hab ich sowas jedenfalls nicht vorgesehen, ich möchte die Objekte erst befüllen nachdem sie rausgegeben wurden.

Im Endeffekt sind das Allozieren von Stack und ID beides nur OOM-Fehler (weil du ne neue ID nur nicht bekommen kannst, wenn kein Speicher mehr da ist um das Array zu erweitern).
Wenn Du das so zusichern kannst ist das natürlich auch Okay. Aber kannst Du das auch bei den anderen Objekt-Typen zu 100% zusichern?

Ich werde dann wohl Variante 1 implementieren, weil das die sinnvollste ist (mMn).
Was ist mit Variante 3? Ich meine wenn Du ein Magazin von dem CPU-lokalen Cache neu befüllen möchtest weil es die State-Maschine der Magazinverwaltung so vorsieht und Du das aber nicht machst, könnte es dann nicht sein das Deine Magazinverwaltung in einem ungültigen (bzw. normal nicht erreichbaren) Zustand wäre? Ich kenne ja nicht Dein System aber dieser Aspekt lässt mich da insgesamt etwas abschrecken.

Vor allem sehe ich in diesem Vorgehen insgesamt keinen so großen Vorteil, was in das Objekt rein soll weiß man doch zum Großteil erst wenn man es wirklich benötigt. Der Thread-Cache ist da sicher eine Ausnahme aber gerade hierfür wollte ich einen speziellen CPU-lokalen Cache bauen (der im wesentlichen auf dem selben Magazinverwaltungsmechanismus basiert) und nicht nur den Thread-Descriptor sondern auch einen zugehörigen User-Mode-Stack und eventuell eine ID enthält (wobei ich persönlich IDs nur ungern so kurzfristig recyceln würde).

Da hast du dann mit deinen großen Slabs wieder Vorteile, weil bei dir schnell viele Threads erzeugt werden können, ohne das irgendwas nachgeladen werden muss. Allerdings den Nachteil (je nach dem was für Ziele man hat), dass ich (weil du ja nur einen Kernelstack pro CPU hast) dann auch zuviele Kernelstacks hätte und das frisst dann auch ganz schön (MB Bereich).
Mit einem nichtunterbrechbaren Kernel würdest Du auch nur einen Kernel-Mode-Stack pro CPU benötigen. ;)


Grüße
Erik
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: FlashBurn am 25. May 2011, 19:52
Zitat von: erik
Aber kannst Du das auch bei den anderen Objekt-Typen zu 100% zusichern?
Ich kann das, aber um sicher zu gehen, würde ich das in die Anforderungen an den Slab-Allocator mit aufnehmen. Zumal mir auch nichts anderes einfällt außer OOM, was da in einem Konstruktor schief gehen könnte (im Kernel)!?

Zitat von: erik
Ich meine wenn Du ein Magazin von dem CPU-lokalen Cache neu befüllen möchtest weil es die State-Maschine der Magazinverwaltung so vorsieht und Du das aber nicht machst, könnte es dann nicht sein das Deine Magazinverwaltung in einem ungültigen (bzw. normal nicht erreichbaren) Zustand wäre? Ich kenne ja nicht Dein System aber dieser Aspekt lässt mich da insgesamt etwas abschrecken.
Naja, das mit der Magazinverwaltung ist nicht das Problem, weil mein Slab-Allocator erstmal nur einzelne Objekte rausgibt und d.h. die werden auch dort, wenn ein neuer Slab erstellt wird, konstruiert. Ich brauche das, da ich ein oder zwei Objekte habe die den Magazinlayer nicht benutzen sollen (zwecks Verschwendung). Alle anderen Objekttypen rufen dann die Funktionen auf, die den Magazinlayer benutzen und da der eigentliche Slab-Allocator keine Magazine kennt, gibt es auch keine Probleme mit halbvollen Magazinen oder solchen Späßen.

Zitat von: erik
wobei ich persönlich IDs nur ungern so kurzfristig recyceln würde
Damit wäre man dann auch nicht POSIX-kompatibel, aber das kann ich lösen, indem ich immer beim Freigeben hinten an die freie Liste ranhänge und beim Allozieren immer vom Anfang wegnehme (wenn nur ein Objekt in dem Slab ist, funktioniert das natürlich auch nicht).
Aber ich sehe da erstmal nicht so das Problem (kann aber gut sein, das es da welche gibt, dann immer her damit), zumal du eh irgendwann anfangen musst die IDs zu recyceln.

Zitat von: erik
Vor allem sehe ich in diesem Vorgehen insgesamt keinen so großen Vorteil, was in das Objekt rein soll weiß man doch zum Großteil erst wenn man es wirklich benötigt.
Naja, sowas wie IDs (und im Falle von Threads der Stack) muss ich doch nicht jedes Mal neu machen (vorallem wenn es relativ teuer ist), wenn es auch anders geht.

Zitat von: erik
Mit einem nichtunterbrechbaren Kernel würdest Du auch nur einen Kernel-Mode-Stack pro CPU benötigen.
Naja, da würde ich dann mal Messungen machen müssen (wenn der Kernel soweit steht), was bestimmte Syscalls oder Exceptions an Zeit kosten und wenn das in Ordnung ist. Dann kann ich das auch so machen, aber dann muss ich meine Thread-Struktur vergrößern, weil da ja dann alle Register mit drin gespeichert werden müssen und was viel schwieriger sein wird, ich müsste zusehen, dass ich so ziemlich alle Spinlocks wegbekomme.
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: erik.vikinger am 25. May 2011, 21:41
Hallo,


aber um sicher zu gehen, würde ich das in die Anforderungen an den Slab-Allocator mit aufnehmen.
Jo, besser is das.

Zumal mir auch nichts anderes einfällt außer OOM, was da in einem Konstruktor schief gehen könnte (im Kernel)!?
Hm, stimmt auch wieder, zumindest in einem Micro-Kernel.

Naja, das mit der Magazinverwaltung ist nicht das Problem, weil mein Slab-Allocator erstmal nur einzelne Objekte rausgibt
Aber was ist wenn Deine Magazinverwaltung ein neues Magazin voll machen möchte und von den X SLAB-Allocator-Aufrufen 2 Aufrufe schief gingen? Dann ist ja das Magazin gar nicht voll, wie gehst Du damit um?

da ich ein oder zwei Objekte habe die den Magazinlayer nicht benutzen sollen (zwecks Verschwendung).
Ja, ich wollte den Thread-Descriptor (wegen einem extra Cache-Mechanismus für komplette Threads) und den Process-Descriptor (wird zu selten benötigt) nicht über so einen Magazinlayer laufen lassen, alles andere wohl schon (wenn ich denn mal sowas einbaue).

Aber ich sehe da erstmal nicht so das Problem (kann aber gut sein, das es da welche gibt, dann immer her damit), zumal du eh irgendwann anfangen musst die IDs zu recyceln.
Bei guter SW sollte es überhaupt keine Probleme machen wenn IDs schnell recycelt werden aber da kann man sich ja nie ganz drauf verlassen, weswegen ich IDs lieber global in eine sortierte Kette packen möchte (also immer vorne weg nehmen und hinten dran hängen). Bei den Thread-IDs könnte man es ja so machen das immer beim Auffüllen des CPU-lokalen Cache-Mechanismus gleich X IDs auf einmal geholt werden welche dann beim tatsächlichen Ausliefern der Threads der Reihe nach benutzt werden und auch beim Abgeben von Threads werden immer erst X IDs gesammelt bevor diese dann gebündelt in den ID-Pool zurück kommen, das macht zumindest die zugehörigen Aufrufe seltener und reduziert damit die Kosten (ich hoffe einfach mal dass das reicht).

aber dann muss ich meine Thread-Struktur vergrößern, weil da ja dann alle Register mit drin gespeichert werden müssen
Was bei x86 ja so enorm viel ist, da hast Du echt mein vollstes Mitleid. Was soll ich da erst mit meinen 64 Registern (von denen ich 8 Stück noch aus speziellen Schattenregistern holen muss weil die CPU die beim Wechsel vom User-Mode in den System-Mode einfach nur schnell ausblendet) + 16 Segmentregistern sagen? Das ist einer der Gründe warum ich beim synchronen IPC direkt vom Aufrufenden Thread in den PopUp-Thread wechseln möchte, da brauch ich dann vom aufrufenden Thread nur die Callee-Saves in dessen Thread-Descriptor zu packen bzw. beim Ende vom PopUp-Thread wiederherstellen um dann da das IRET zu machen. Für den PopUp-Thread muss ich fast gar nichts vorbereiten (außer dafür sorgen das keine Register vom Caller oder vom Kernel für den PopUp-Thread sichtbar sind) so das wenn der PopUp-Thread noch innerhalb der Zeitscheibe des Caller-Threads fertig wird und er nicht geschedult werden muss gar keine Register überhaupt in dessen Thread-Descriptor landen. Eben weil der PopUp-Thread ja u.a. einen leeren Kontext bekommt ist dessen Thread-Erstellung ja so billig.

und was viel schwieriger sein wird, ich müsste zusehen, dass ich so ziemlich alle Spinlocks wegbekomme.
Ja, da muss man halt von Anfang an entsprechend aufpassen. ;)


Grüße
Erik
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: FlashBurn am 25. May 2011, 21:56
Zitat von: erik
Aber was ist wenn Deine Magazinverwaltung ein neues Magazin voll machen möchte und von den X SLAB-Allocator-Aufrufen 2 Aufrufe schief gingen? Dann ist ja das Magazin gar nicht voll, wie gehst Du damit um?
Gegenfrage, wie gehst du mit nem nicht ganz vollem Magazin um? Ich benutze es einfach, bis es leer ist ;)

Bei mir gibt es nicht so richtig Magazine wie es im Slab-Allocator Design vorgesehen ist. Bei mir ist ein Magazin einfach nur ein kleiner Stack (im Mom von 4 Objekten) und wenn das Magazin (bzw. in meinem Fall beide) leer ist, wird es halt wieder aufgefüllt. Wenn das Auffüllen nicht klappt (womit ich ja rechnen muss) ist das nicht weiter wild, es sei denn es konnte gar kein Objekt aufgefüllt werden.

Zitat von: erik
Bei guter SW sollte es überhaupt keine Probleme machen wenn IDs schnell recycelt werden aber da kann man sich ja nie ganz drauf verlassen
Naja, das ich als OS Programmierer um Hardwarefehler drumrum programmieren muss, ok das sehe ich noch ein, aber das ich um Softwarefehler drumrum programmieren muss, sehe ich nicht ein.

Was die Spinlocks betrifft, sind die nicht das eigentliche Problem, sondern das ich Spinlocks immer mit Algos verbinde die nicht skalieren und wenn man dann einen nicht unterbrechbaren Kernel hat, kann das schonmal in Zeiten ausarten wo es anfängt mit wehtun.
Auf der anderen Seite, würde das die Performance auf Single-CPU System (vorallem auf alten, wo cli/sti richtig teuer sind) doch ganz schön verbessern.
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: erik.vikinger am 26. May 2011, 12:16
Hallo,


Gegenfrage, wie gehst du mit nem nicht ganz vollem Magazin um?
Gute Frage, hab ich noch nicht allzu gründlich drüber nachgedacht.
Ich schätze ich werde mich für Variante 3 entscheiden, da ich ja Bündelanfragen an den SLAB-Allocator geben möchte wird dieser eh entweder ein Magazin komplett befüllen (wenn er genug Objekte hat bzw. einen neuen SLAB-Block vom VMM bekommen kann) oder er wird nichts tun (wenn er keinen weiteren SLAB-Block vom VMM bekommt) und einen Fehler zurück melden. Ich schätze ich werde daher wohl nicht mit nur halb befüllten Magazinen umgehen müssen.

Wobei ich immer noch nicht erkennen kann worin Du den Vorteil der direkten Konstruktor-Aufrufe durch den SLAB-Allocator siehst. Ich bin eher der Meinung das Du Dir damit vor allem zusätzliche Probleme in die Speicherverwaltung holst.

Naja, das ich als OS Programmierer um Hardwarefehler drumrum programmieren muss, ok das sehe ich noch ein, aber das ich um Softwarefehler drumrum programmieren muss, sehe ich nicht ein.
lol    (das mit der Hardware siehst Du ja auch nur so weil Du die Hardware nicht ändern kannst)

Wenn Du die IDs nicht so schnell recycelst hat das OS weniger potentielle Angriffsfläche weil (absichtlich) fehlerhafte Syscall dann eher ins Leere laufen weil die IDs ja ungültig sind. Etwas "Security by Obscurity" ist auf jeden Fall besser als gar nichts.

Was schätzt Du denn wie viele IDs insgesamt (also alles inklusive Prozess-IDs, Thread-IDs, Port-IDs ....) Du so überhaupt pro Tag Laufzeit mit ordentlicher Last benötigen wirst?

und wenn man dann einen nicht unterbrechbaren Kernel hat, kann das schonmal in Zeiten ausarten wo es anfängt mit wehtun.
Das einztigste was mir in einem Micro-Kernel einfällt was auch mal erheblich Zeit kosten kann ist die Speicherverwaltung aber da davon ja wieder fast alles abhängig ist sind wohl auch fast alle Syscalls betroffen. Ich denke hier sollte man die Speicherverwaltung so gut bauen das die in den meisten Fällen schnell arbeitet und eben nur möglichst selten mal ein langsamer Fall eintritt. Wenn man das gut genug hinbekommt sollte es sich wieder rechnen.


Grüße
Erik
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: FlashBurn am 26. May 2011, 12:37
Zitat von: erik
Wobei ich immer noch nicht erkennen kann worin Du den Vorteil der direkten Konstruktor-Aufrufe durch den SLAB-Allocator siehst.
Die Anzahl der Konstruktor Aufrufe ist bei meinem Design wesentlich geringer als bei dir.

Bei mir wird ein neue Objectcache erstellt und alle Objekte werden gleich konstruiert (wo ich dann wirklich so Sachen wie ID und im Falle von Threads noch den Kernel-Stack machen will).
Bei dir muss jedes Mal wenn ein Objekt rausgegeben wird, erst ne ID geholt und der Stack geholt werden. Wenn du dein Objekt wieder freigibst, gibst du also auch die ID und den Stack wieder frei.
Bei mir werden ID und Stack erst wieder freigegeben, wenn der Objectcache freigegeben wird.

Zitat von: erik
das mit der Hardware siehst Du ja auch nur so weil Du die Hardware nicht ändern kannst
Jein, weil man solche Hardwarefehler im Allgemeinen nur durch neue Hardware und nicht durch ein Softwareupdate beheben kann.

Um es mal überspitzt zu sagen, du hast nen Programm wo du eine bestimmte Funktion nutzen willst. Diese Funktion kannst du aber immer nur nutzen kurz nachdem du das Programm gestartet hast, sprich jedes Mal wenn du diese Funktion nutzen willst, musst du das Programm beenden und dann wieder neustarten um dann schnell die Funktion zu nutzen.
Das ist für mich ganz klar ein Bug/Softwarefehler und um sowas programmieren oder "nutze" ich nicht herum. Das kann man durch nen Update beheben.
Ich meine stell dir mal vor, nur weil irgendein Programm nen Bug hat, muss der Kernel geändert werden, damit das Programm läuft?!

Zitat von: erik
Was schätzt Du denn wie viele IDs insgesamt (also alles inklusive Prozess-IDs, Thread-IDs, Port-IDs ....) Du so überhaupt pro Tag Laufzeit mit ordentlicher Last benötigen wirst?
Ich habe keine Ahnung, aber bei mir ist das durch meinen Algo schon nicht einfach oder praktikabel die IDs nicht schnell oder gleich wiederzuverwenden. ID Recycling ist ohnehin nicht so einfach, wenn man dann auch noch möchte das die IDs erst nach nem Überlauf wiederverwendet werden (das sollte unter POSIX so sein glaub ich).

Zitat von: erik
Das einztigste was mir in einem Micro-Kernel einfällt was auch mal erheblich Zeit kosten kann ist die Speicherverwaltung aber da davon ja wieder fast alles abhängig ist sind wohl auch fast alle Syscalls betroffen.
Richtig, deswegen muss das auch am meisten optimiert werden und ich denke mal meine Speicherverwaltung ist noch nicht so die Bombe.
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: Svenska am 26. May 2011, 15:03
Zitat von: erik
Das einztigste was mir in einem Micro-Kernel einfällt was auch mal erheblich Zeit kosten kann ist die Speicherverwaltung aber da davon ja wieder fast alles abhängig ist sind wohl auch fast alle Syscalls betroffen.
Richtig, deswegen muss das auch am meisten optimiert werden und ich denke mal meine Speicherverwaltung ist noch nicht so die Bombe.
Das ist richtig, allerdings bin ich erstmal lieber für eine langsame, aber zuverlässige Speicherverwaltung. Dann kann man anderes, für ein OS wichtigeres Zeug drauf implementieren (z.B. Userspace) und schauen, wie es im realen Leben performt.

Optimieren kann man später immernoch, wenn es zu langsam ist.
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: FlashBurn am 26. May 2011, 15:53
Das Problem mit der späteren Optimierung ist, dass ich bestimmte Design Entscheidung treffen muss/will und dazu muss ich dann woanders auch wieder Entscheidungen treffen und ganz konkret heißt dass, wenn ich meinen Kernel nicht unterbrechbar machen will, muss der worst-case bestimmten Anforderungen gerecht werden.
Erst später den Kernel nicht unterbrechbar zu machen, wäre dann doch ein wenig viel Arbeit, würde schon in die Richtung rewrite gehen ;) Das würde ich gerne vermeiden.
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: erik.vikinger am 26. May 2011, 17:24
Hallo,


Die Anzahl der Konstruktor Aufrufe ist bei meinem Design wesentlich geringer als bei dir.
Hä, ich hab gar keine Konstruktoren. Ich sehe darin auch keinen echten Sinn da sich der meiste Inhalt für ein neues Objekt IMHO erst dann ergibt wenn es wirklich konkret eingesetzt werden soll. Außerdem ist der Performance-Verlust durch das Schreiben weiterer Daten ziemlich klein wenn das Objekt eh schon im lokalen CPU-Cache ist, da Du ja auf jeden Fall zumindest etwas in das neue Objekt schreiben wirst muss es eh in den CPU-Cache geladen werden und von daher ist das kein großes Problem mehr ob da nun 70% oder 100% der Daten geschrieben werden. Dafür muss mein SLAB-Allocator gar nicht in die Objekte rein greifen.
Das nächste ist das ich einige der Objekt-Größen(Typen) für unterschiedliche Dinge einsetzen möchte so das der SLAB-Allocator gar nicht einen bestimmten Konstruktor aufrufen kann. Warum sollte ich auch für 2 unterschiedliche Objekt-Typen die aber die selbe Größe haben unterschiedliche SLABs einsetzen, macht doch gar keinen Sinn.

Der Fall mit den Thread-Descriptoren ist tatsächlich etwas anders aber da habe ich doch auch beschrieben das ich dafür einen extra Cache-Mechanismus bauen möchte der eben nicht nur den nackten Thread-Descriptor sondern auch noch den Stack und passende IDs vorrätig hält.

Ich meine stell dir mal vor, nur weil irgendein Programm nen Bug hat, muss der Kernel geändert werden, damit das Programm läuft?!
Das ist schon richtig, was ich meinte ist eher das Dein Kernel eine geringere Angriffsfläche hat wenn die IDs nicht so einfach vorhersehbar sind. Wenn Du für Threads immer wieder die selben IDs benutzt dann könnte es sein das für einen Thread eine Aktion ausgeführt wird die eigentlich für einen anderen Thread gedacht war aber dieser andere Thread sich kurz vorher beendet hat. Wenn man die IDs nicht sofort sondern erst später recycelt dann fallen solche Bugs eher auf und es ist auch schwieriger mit diesem Wissen einen Angriff auf andere Threads zu unternehmen.


Grüße
Erik
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: erik.vikinger am 29. May 2011, 09:57
Hallo,


Bei mir wird ein neue Objectcache erstellt und alle Objekte werden gleich konstruiert (wo ich dann wirklich so Sachen wie ID und im Falle von Threads noch den Kernel-Stack machen will).
Bei dir muss jedes Mal wenn ein Objekt rausgegeben wird, erst ne ID geholt und der Stack geholt werden. Wenn du dein Objekt wieder freigibst, gibst du also auch die ID und den Stack wieder frei.
Bei mir werden ID und Stack erst wieder freigegeben, wenn der Objectcache freigegeben wird.
Da fällt mir gerade noch ein Problem auf: wenn Du den Stack sofort recycelst dann sind da ja noch die Daten des vorherigen Threads drin und das könnte ein ernstes Sicherheitsrisiko sein. Aus diesem Grund möchte ich den Prozessen nur Speicher geben der vorher zu 100% mit 0x00 überschrieben wurde.
Effizientes Recyceln ist sicher ein wesentlicher Faktor zu hoher Performance aber das darf keine Sicherheitslöcher aufreißen.


Grüße
Erik
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: FlashBurn am 29. May 2011, 12:36
Zitat von: erik
Da fällt mir gerade noch ein Problem auf: wenn Du den Stack sofort recycelst dann sind da ja noch die Daten des vorherigen Threads drin und das könnte ein ernstes Sicherheitsrisiko sein.
Ich recycle sofort den KernelStack! Wieso sollte das ein Sicherheitsrisiko sein? Ich gehe doch mal davon aus, das wir unseren Kerneln vertrauen können ;)
Zumal kein Programm Zugrif auf diese Daten hat, sondern nur der Kernel.
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: erik.vikinger am 29. May 2011, 21:18
Hallo,


Ich recycle sofort den KernelStack!
Äh, stimmt. Hab ich doch glatt übersehen, sorry. Wie machst Du das eigentlich mit dem User-Mode-Stack? Ich gehe doch mal davon aus das die Mehrheit Deiner Threads dazu dient den User-Mode mit Leben zu füllen.

Ich möchte ja die User-Mode-Stacks cachen aber eben zwischen das Recyceln noch den Memory-Cleaner stellen. Wobei das alles natürlich auch ne ganz schöne Speicherverschwendung wird. Stell sich mal einer vor: 8 CPUs mit je 32 User-Mode-Stacks a 8 kB (oder auch mehr falls mal ein Stack vergrößert werden musste) auf Vorrat und dazu noch das was so im Memory-Cleaner und sonstwo gerade steckt, das macht locker mal 2 bis 3 MB Speicher und das alles nur für die Performance. Ich schätze unter 32 MB wird es mein OS erst gar nicht machen.


Grüße
Erik
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: FlashBurn am 29. May 2011, 21:24
Ich handhabe es so, wenn ein Prozess der Meinung ist das er so wichtige Daten hat, das andere Prozesse diese nicht sehen dürfen, dann muss er ein Flag setzen und alle Pages aus diesem Prozess werden genullt, aber für alle anderen Prozesse mache ich mir da keinen Kopf.

Was die UserMode Stacks angeht, wie stellst du dir das bei nem normalen System vor? Problem ist ja, das ich immer nur per Prozess cachen könnte (ist ne Möglichkeit, aber da verschwendest du dann richtig Speicher, weil stell dir vor ein Prozess braucht nur einen Thread und du cachest aber immer 8!).
Eine andere Möglichkeit (habe ich so bei Haiku gesehen) ist, dass man einfach alle Threads die beendet wurden in eine Art Cache an den Prozess heftet und wenn der Prozess mal wieder nen Thread braucht ist schon alles da. Das kostet allerdings auch Speicher, aber wäre wahrscheinlich sogar für Services sehr vorteilhaft.
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: erik.vikinger am 29. May 2011, 21:52
Hallo,


Ich handhabe es so, wenn ein Prozess der Meinung ist das er so wichtige Daten hat, das andere Prozesse diese nicht sehen dürfen, dann muss er ein Flag setzen ....
Is ne Variante aber damit rechnet wohl kaum ein Programm. Wimre sichert Windows zu das neuer Speicher immer genullt ist, wie das unter Linux läuft weiß ich jetzt nicht aber ich vermute mal in etwa ähnlich. Das nächste ist das viele Programme ja gar nicht wissen ob sie wichtige Daten bearbeiten oder nicht (das Office-Paket kann ja nicht ahnen ob Du nur nen langweiligen Brief an Deine Oma schreibst (soll keine Abwertung Deiner Oma sein) oder wichtige Firmendaten oder gar Top-Secret-Forschungsergebnisse aufbereitest).
Wenn dann würde ich Sicherheit als Default-Vorgabe benutzen oder willst Du ein weiteres Windows bauen? ;)
Das einzigste wo ich das andersrum machen möchte ist das Swappen, per Default darf alles geswappt werden und nur dann wenn ein Prozess das für ein Segment verbietet wird dieses Segment eben nicht geswappt. So wird das wimre auch unter Windows und Linux gehandhabt (dort kann man gezielt einzelne Pages vom Swapping ausschließen).

Was die UserMode Stacks angeht, wie stellst du dir das bei nem normalen System vor?
Na der lineare Speicher wird einfach nicht freigegeben (bei Dir dann der physische Speicher) und bei Bedarf in den richtigen Prozess als neues Segment eingeblendet indem in dessen LDT ein passender Segment-Descriptor eingetragen wird (bei Dir in dem in das richtige Paging-Directory ein paar passende Einträge kommen). Ich kann da erstmal keine Probleme sehen.

Problem ist ja, das ich immer nur per Prozess cachen könnte
Warum? Wo siehst Du da das Problem?
Davon würde ich eben wegen der Speicherverschwendung abraten. Die Threads möchte ich auch pro CPU cachen um eben eine möglichst hohe Cache-Trefferquote zu bekommen.

aber wäre wahrscheinlich sogar für Services sehr vorteilhaft.
So eine Situation möchte ich bei meinen IPC-PopUp-Threads (für die Handler) benutzen. Wenn ein Handler fertig ist und sein Ergebnis dem Aufrufer mitteilen möchte dann schau ich kurz nach ob noch weitere Anfragen gequeued wurden und erstelle dann sofort einen neuen Thread (der aber nicht gleich los läuft sondern nur in die runnable-Liste kommt) für den ich auch den Stack direkt recyceln möchte, ich denke innerhalb des selben Prozesses ist das auch kein Sicherheitsrisiko.


Grüße
Erik
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: FlashBurn am 29. May 2011, 22:07
Zitat von: erik
Das nächste ist das viele Programme ja gar nicht wissen ob sie wichtige Daten bearbeiten oder nicht (das Office-Paket kann ja nicht ahnen ob Du nur nen langweiligen Brief an Deine Oma schreibst (soll keine Abwertung Deiner Oma sein) oder wichtige Firmendaten oder gar Top-Secret-Forschungsergebnisse aufbereitest).
Der Punkt geht an dich ;) Also doch alles nullen, aber das würde ich dann den PMM machen lassen.

Zitat von: erik
Warum? Wo siehst Du da das Problem?
Naja, wenn ich nen Stack alloziere, dann brauche ich dafür physischen Speicher (Pages) und auch virtuelle Adressen und bei mir geht es um die virtuellen (oder sind die physischen Pages vom Cache her wichtiger?) und das kann ich ja nur per Prozess cachen.
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: erik.vikinger am 29. May 2011, 22:29
Hallo,


aber das würde ich dann den PMM machen lassen.
Zum einen hab ich keinen PMM und zum anderen möchte ich das die Hardware machen lassen (lauter dumme Null-Bytes zu schreiben finde ich zu langweilig für ne wertvolle CPU die mit ihrer Zeit auch was besseres anfangen kann). Wäre ja cool wenn der klassische PC-DMA-Controller das könnte aber ich fürchte mal eher nicht.

Die virtuellen Adressen für den neuen Stack sollten sich doch recht schnell finden lassen, an die Position und Ausrichtung von Stack werden in einem Flat-Memory-OS doch üblicherweise bestimmte Kriterien gestellt. Zur Not könntest Du genau das ja dann in einer Prozess-spezifischen Struktur cachen, ich meine Du betrachtest einfach den physischen Speicher von den virtuellen Adressen getrennt und cachest beides unabhängig von einander.


Grüße
Erik
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: FlashBurn am 30. May 2011, 10:27
Zitat von: erik
Die virtuellen Adressen für den neuen Stack sollten sich doch recht schnell finden lassen, an die Position und Ausrichtung von Stack werden in einem Flat-Memory-OS doch üblicherweise bestimmte Kriterien gestellt.
Naja, üblicherweise heißt für mich immer klassische Unix-Architektur ;) Sprich der Stack wächst vom Ende des Adressraum nach unten und der Heap nach oben (vom Ende des Programms).

Erstens ist das seit sowas wie ALR nicht mehr drin und diese alte Architektur (wie Unix insgesamt da so seine "Probleme" hat) ist nicht gerade für Multithreading geeignet.

Von daher gibt es bei mir in dem Sinne gar keine Anforderungen an den Stack, nur das er wahrscheinlich eine festgelegte Größe haben wird (die man zur Erstellungszeit angeben kann), aber der nicht unbedingt größer werden kann.

Zitat von: erik
Zur Not könntest Du genau das ja dann in einer Prozess-spezifischen Struktur cachen, ich meine Du betrachtest einfach den physischen Speicher von den virtuellen Adressen getrennt und cachest beides unabhängig von einander.
Naja, den physischen Speicher zu cachen halte ich für überflüssig. Denn wenn man nen Stack für die freien Pages nimmt, ist das nicht wirklich ein Performanceproblem (kann zu einem werden, wenn zu viele auf einmal Pages haben wollen).

Noch was anderes zur Sicherheit, wo liegt eigentlich das Problem wenn noch die alten Daten in den Pages stehen? Ich meine woher will das Programm wissen ob das jetzt zufällige Daten sind, die in menschlich lesbarer Form zufällig Sinn ergeben oder ob das genau die Daten sind?
Treiber können ohnehin den ganzen Speicher auslesen, wenn sie denn wollen und von daher können ja nur Programme ein Sicherheitsrisiko sein.
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: erik.vikinger am 30. May 2011, 11:18
Hallo,


Das mit dem nicht mehr ganz so starren Stack ist auch wieder wahr. Dann würde ich eventuell doch den virtuellen Adressraum des Stacks (den wirst Du doch sicher immer gleich komplett allozieren und dann später nach Bedarf mit echten Pages hinterlegen) prozess-spezifisch cachen. Wenn Du in Deinen Prozessen einfach ein paar MB virtuellen Speicher für die potentielle Benutzung als Stack zur Seite legst sollte das mMn kein Problem darstellen, echten Speicher kostet das zumindest nicht (im Gegensatz zu all den anderen Beschleunigungsmaßnahmen).


Naja, den physischen Speicher zu cachen halte ich für überflüssig. Denn wenn man nen Stack für die freien Pages nimmt, ist das nicht wirklich ein Performanceproblem (kann zu einem werden, wenn zu viele auf einmal Pages haben wollen).
Okay, vom dem Problem der Gleichzeitigkeit mal abgesehen hast Du es da natürlich einfacher als ich. Ich muss User-Segmente (und eben auch Stack) immer vom Kernel-VMM (der bei mir den einen globalen linearen Adressraum managed) holen und das ist nicht ganz so schnell wie einfach eine beliebige Page vom Stapel zu nehmen (wobei Du das IMHO auch CPU-lokal cachen solltest). Deswegen ist bei mir das Cachen von Threads gerade auch das Cachen des zugehörigen User-Mode-Stacks.
Da fällt mir ein: was ist mit dem TLS-Speicher? Möchtest Du denn auch in irgendeiner Form cachen? (Falls der Prozess überhaupt TLS benutzt aber da das jetzt auch Bestandteil der offiziellen C/C++-Spezifikation ist/wird dürfte man das in Zukunft häufiger antreffen)

Das Ausnullen des physischen Speichers bevor er verwendet wird ist eher eine Art vorbeugende Vorsichtsmaßnahme. Klar könnte man sich jetzt die Frage stellen ob das in einem Hobby-OS überhaupt lohnt oder nicht eher nur eine unnütze Zusatzkomplexität darstellt (ich denke die überwiegende Mehrheit der OS-Dever hat sich für letzteres entschieden und einfach drauf verzichtet). Das Problem ist das Computer für gewöhnlich streng deterministische Systeme sind und sich daher aus solchen Lücken oft doch gut funktionierende Angriffe bauen lassen. Ich bin zwar der Meinung das sich das Ausnullen des Speichers beim Recyceln in den selben Prozess nicht lohnt aber theoretisch könnte ja in einem Service-Handler ein Bug sein der für den Aufrufer den Stack ausließt und so vielleicht die Daten eines anderen Service-Nutzers sichtbar macht (auch wenn die Daten so nicht manipulierbar sind aber selbst die Sichtbarkeit kann schon eine ernst Lücke sein). An dieser Stelle bin ich aber eben der Meinung das ich besser den Bug im Service fixen sollte anstatt da mit Hilfe des OS-Kernels etwas zu kaschieren.

In einem Micro-Kernel-OS sollten eigentlich auch Treiber nicht in der Lage sein beliebigen Speicher zu Lesen/Schreiben und mit einer anständigen IO-MMU (die nur vom Kernel selber bedient wird) sollte das noch nicht mal mit Hilfe von Hardware möglich sein.

Das Ausnullen ansich wollte ich mit einem kleinen Hintergrund-Mechanismus erledigen der für die HW eine einfach verkettete Liste aufbaut welche dann von der HW (im Chipsatz) abgearbeitet wird. Dieses Ausnullen wird dabei auch den Speicher aus allen CPU-Caches werfen so das es auch keine Rolle spielt in welchen CPU-lokalen Thread-Cache der dann kommt (nebst dessen das bei Stack auch eh aggressiver gecachet werden kann, also Dinge wie Write-Allocation usw. da immer voll genutzt werden). Auf dem PC kenne ich leider keine Standard-Komponente die das machen könnte so dass das eben in SW erledigt werden muss und damit auch etwas Performance kostet. Und wenn dann muss das in einem Flat-Memory-OS natürlich auch in den PMM.


Grüße
Erik
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: FlashBurn am 30. May 2011, 22:16
Das mit dem Stack und seiner Größe ist so ein Sache. Obwohl ich da der Meinung bin, das man als OS Dever ein paar Grenzwerte festlegen sollte (so dass wahrscheinlich die meisten Programme ohne Probleme laufen) und alles andere muss der Programmierer des Programms selber wissen und festlegen (er weiß am ehesten wieviel Threads laufen werden und wieviel Speicher ansonsten vom Heap benötigt wird).

Zitat von: erik
Da fällt mir ein: was ist mit dem TLS-Speicher?
Mit TLS habe ich mich länger nicht befasst. Mein Problem damit ist, das ich eigentlich immer dachte, das jeder Thread ne Art private Tabelle hat, wo er Adressen reinschreiben kann und da der Index für jeden Thread gleich ist, greift jeder Thread auf seine eigene Datenstruktur zu.
Allerdings kommt es mir so vor (und ich möchte meinen was darüber gelesen zu haben), dass es jetzt mehr so zu sein scheint, dass jeder Thread nen anderes PD hat, aber die gleichen Pages benutzt, bis auf den TLS Bereich, der ist für jeden Thread unterschiedlich. Das empfinde ich einfach nur als falsch. Gut man könnte jetzt argumentieren das es eh unwahrscheinlich ist, dass 2 Threads des selben Prozessen nacheinander laufen werden, so dass der TLB nicht gelöscht wird. Allerdings kann man dann auch gleich einfach mehrere Prozesse laufen lassen und über shared Memory miteinander arbeiten.

Zitat von: erik
In einem Micro-Kernel-OS sollten eigentlich auch Treiber nicht in der Lage sein beliebigen Speicher zu Lesen/Schreiben
Was (wie du schon richtig sagst) aber nur klappt wenn eine IO-MMU vorhanden ist und das trifft nur auf neuere PCs zu und dort auch nicht auf alle (das war doch sowas was nicht alle Intel CPUs haben?).
Ansonsten ist auch ein Treiber von nem MikroKernel sehr wohl in der Lage den gesamten Speicher auszulesen. Ich meine was hält ihn davon ab, einfach alle physikalischen Pages durchzugehen und zu senden?

Was mir noch zum ausnullen einfällt, ist das nicht der Cache-Trasher schlecht hin?
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: Svenska am 31. May 2011, 01:22
Hallo,

Zitat von: erik
In einem Micro-Kernel-OS sollten eigentlich auch Treiber nicht in der Lage sein beliebigen Speicher zu Lesen/Schreiben
Was (wie du schon richtig sagst) aber nur klappt wenn eine IO-MMU vorhanden ist und das trifft nur auf neuere PCs zu und dort auch nicht auf alle (das war doch sowas was nicht alle Intel CPUs haben?).
Das stimmt so einfach nicht. Eine IOMMU verhindert, dass ein Treiber den gesamten Speicher ausliest, indem er die Hardware anweist, per DMA von allen Adressen zu lesen und die gleichen Daten wieder per DMA oder PIO zurückzuschreiben. Performance ist was anderes, außerdem kann das nicht jede Hardware.

Ansonsten ist auch ein Treiber von nem MikroKernel sehr wohl in der Lage den gesamten Speicher auszulesen. Ich meine was hält ihn davon ab, einfach alle physikalischen Pages durchzugehen und zu senden?
Ein General Protection Fault? Wenn der Treiber auf Speicher oder Adressen zugreift, der ihm nicht gehört, dann gibt das nunmal eine Exception: In einem Mikrokernel sind Treiber auch "nur" (Ring3-)Tasks.

Gruß,
Svenska
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: FlashBurn am 31. May 2011, 10:22
Zitat von: Svenska
Das stimmt so einfach nicht. Eine IOMMU verhindert, dass ein Treiber den gesamten Speicher ausliest, indem er die Hardware anweist, per DMA von allen Adressen zu lesen und die gleichen Daten wieder per DMA oder PIO zurückzuschreiben.
Ist doch genau das was ich gesagt habe ;)

Zitat von: Svenska
Ein General Protection Fault? Wenn der Treiber auf Speicher oder Adressen zugreift, der ihm nicht gehört, dann gibt das nunmal eine Exception: In einem Mikrokernel sind Treiber auch "nur" (Ring3-)Tasks.
Davon abgesehen das wir das Thema schonmal diskutiert hatten, versteht ihr beide mich nicht ;) Der Treiber kann den gesamten Speicher auslesen, weil er halt Zugriff auf die Hardware hat und diese anweisen kann per DMA den gesamten Speicher auslesen. Das war das was ich meinte!
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: erik.vikinger am 31. May 2011, 10:31
Hallo,


Das mit dem Stack und seiner Größe ist so ein Sache.....
Ja, das stimmt. Das Problem bei Flat-Memory-System ist eben das all das aus einem einzigen Adressraum kommen muss und daher alles voneinander abhängig ist. Der typische Programmierer wird sich aber nur wenig Gedanken über die Bedürfnisse des von ihm getippten Codes machen so dass das OS mit nur sehr wenigen Informationen eine möglichst gute Automatik füttern muss. Ich persönlich bin auch ehrlich der Meinung das es nicht unbedingt Aufgabe des Programmierers ist sich darum zu kümmern wie das System dafür sorgt das sein Programm erwartungsgemäß läuft. Gerade dieser Denkansatz ist einer der wesentlichen Gründe dafür das ich mich für Segmentierung entschieden hab. Aber auch ich muss mit Grenzen kämpfen, z.B. mit der festen Größe der LDT welche die maximale Anzahl an Segmenten und damit auch an Stacks für Threads pro Prozess begrenzt. Mehr als knapp 15000 Threads kann ich pro Prozess nicht zulassen (es sind doppelt so viele wenn der Prozess kein TLS benutzt).

Mit TLS habe ich mich länger nicht befasst....
Die Idee mit einem extra Paging-Directory pro Thread wird extrem viel Speicher kosten (vor allem unnützen da ja eigentlich fast alles Redundant ist) und auch Performance wenn bei jeder Änderung im virtuellen Adressraum des Prozess X Paging-Directorys angefasst werden müssen (von den vielen TLB-Flushs mal ganz abgesehen). Auf x86 wird man für TLS eher ein Register opfern und zwar ein Segment-Register (meist wohl FS oder GS, die selbst im Long-Mode noch gerade so genug vorhanden sind damit man damit TLS realisieren kann). Auf den meisten anderen Plattformen wird man wohl ebenfalls eines der normalen Register opfern. Man könnte aber auch eine Funktion oder einen Syscall benutzen der die TLS-Adresse des aktuellen Threads aus einer Tabelle holt aber auch das ist nicht allzu performant. Für meine Plattform habe ich mich daher ebenfalls für das Opfern eines Segment-Registers entschieden aber da ich davon 16 Stück habe ist das nur ein sehr kleines Opfer.


Die IOMMU ist nicht Teil der CPU sondern des Chipsatzes bzw. des PCI-(Express-)Root-Controllers (okay das wird bei neueren Intel-CPUs doch wieder auf dem selben Silizium wie die CPU sein), aber es stimmt natürlich das sowas tolles nicht immer vorhanden ist.

Mit dem Auslesen des gesamten Speichers bei Treibern meinte ich eigentlich das direkte Auslesen durch Software, was ja eben eine Exception auslösen sollte, und nicht das Missbrauchen der Hardware (dagegen hilft eben nur eine IOMMU).


Was mir noch zum ausnullen einfällt, ist das nicht der Cache-Trasher schlecht hin?
Nein eigentlich nicht. Wenn Du das in SW machst dann ist diese Page komplett im Cache der aktuellen CPU und genau deswegen würde ich freie physische Pages auch CPU-lokal cachen. Auf meiner Plattform ist das Ausnullen aber tatsächlich ein echter Cache-Trasher und zwar für alle CPUs, die entsprechenden Cache-Lines werden in allen CPUs invalidiert ohne das sie zurückgeschrieben werden und der entsprechende Heimat-Speicher-Controller kennzeichnet diese Cache-Lines wieder als "nicht entliehen" und als "leer" (so das beim nächsten Zugriff erst gar nicht auf die Speicherchips zugegriffen wird sondern einfach nur eine Antwort die nur aus 0x00-Bytes besteht an die anfragende CPU geschickt wird, erst mit einem Schreibzugriff wird diese Cache-Line im Speicher-Controller wieder als "befüllt" gekennzeichnet). Aber gerade bei Stack macht das mit dem Cache-Trashing auch nichts (auf keiner CPU) da ja beim Stack üblicherweise nur die Daten gelesen werden die auch selber vor kurzem dort hin geschrieben wurden. Es erfolgt auf eine bestimmte Speicherstelle also zumeist erst ein Schreibzugriff und danach dann Lesezugriffe und die Schreibzugriffe können mit Write-Allocation ganz gut abgefangen werden ohne das der CPU-Kern für die Dauer der Speicher-Latenz blockiert werden muss.


Performance ist was anderes
Auch in einer IOMMU kann man einen TLB implementieren. Klar kostet eine IOMMU immer ein paar Nanosekunden zusätzliche Latenz (der Durchsatz sollte davon nicht betroffen sein) bei Hardware-Zugriffen auf den normalen RAM, aber so viel ist das nun auch wieder nicht und man bekommt dafür eben einiges an Sicherheit.


Grüße
Erik
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: FlashBurn am 31. May 2011, 11:11
Zitat von: erik
Der typische Programmierer wird sich aber nur wenig Gedanken über die Bedürfnisse des von ihm getippten Codes machen so dass das OS mit nur sehr wenigen Informationen eine möglichst gute Automatik füttern muss. Ich persönlich bin auch ehrlich der Meinung das es nicht unbedingt Aufgabe des Programmierers ist sich darum zu kümmern wie das System dafür sorgt das sein Programm erwartungsgemäß läuft.
Das mit dem Stack nimmt aber teilweise wirklich nicht mehr tragbare Ausmaße an. Wenn ich sehe das jemand versucht nen 16MB Array auf dem Stack zu allozieren (davon abgesehen, das der Compiler sowas gar nicht erst zulassen sollte) dann hört mein Verständnis dort auf.
Der Stack ist für Parameter und lokale (kleine) Variablen da und nicht dafür jeden Scheiß da drauf zu speichern (z.B. durch lokale Variablen in der Main-Funktion).
Wenn wir von einem Programm ausgehen, das nur einen Thread hat, sollte sich der Programmierer wirklich nicht darum kümmern müssen. Allerdings sollten ihm die OS Begrenzungen bekannt sein.
Geht es aber um ein Multithreading Programm sollte der Programmierer sich schon Gedanken machen wieviel Stack er wirklich braucht, alleine schon weil virtueller Speicher unter 32bit irgendwann knapp wird.

Zitat von: erik
Auf x86 wird man für TLS eher ein Register opfern und zwar ein Segment-Register (meist wohl FS oder GS, die selbst im Long-Mode noch gerade so genug vorhanden sind damit man damit TLS realisieren kann).
Genauso habe ich das bei mir umgesetzt. Problem ist jetzt noch die Art der Umsetzung, mache ich ein statisches Segment, wo also zum Ladezeitpunkt die Größe bekannt sein muss und man einfach nen neuen logischen Adressraum hat oder mache ich es so, dass das Programm auch zur Laufzeit die Größe ändern kann, was aber schwierig wird, zwecks virtueller Adressen.
Eine andere Variante (die ich irgendwo bevorzuge, aber die sich schlechter durch nen Compiler direkt umsetzen lässt) ist dass man jedem Thread (z.B.) 1024 Slots zur Verfügung stellt wo er Werte seiner Wahl drin speichern kann. Man würde dann z.B. sagen wenn man eine Freelist pro Thread hat, das man die Freelist im Slot 0 speichert und speicher die "0" in einer globalen Variable ab. Jeder Zugriff auf den Slot 0 würde dann den Thread lokalen Wert liefern.

Wesentlich schöner und einfacher für den Compiler/Programmierer ist natürlich ein abgetrennter Bereich wo das Segment dann hinzeigt. Da stellt sich mir dann aber die Frage wie man das umsetzt? Weil wo holt das OS den Speicher her um einen neuen Thread zu starten (er kann ja schlecht das malloc vom Programm nutzen) und was für Werte sollen da dann rein?

Zitat von: erik
Nein eigentlich nicht. Wenn Du das in SW machst dann ist diese Page komplett im Cache der aktuellen CPU und genau deswegen würde ich freie physische Pages auch CPU-lokal cachen.
Ich habe mich auch länger nicht mit den verschiedenen Caches der CPUs beschäftigt, aber gibt es nen separaten Cache zum Lesen und Schreiben? Weil ansonsten ist ja ne Cacheline (heutzutage) 64byte groß und wenn du dann eine ganze Page nullst, verdrängst du ja andere Cacheeinträge (und das meinte ich mit Cachetrashing).
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: erik.vikinger am 31. May 2011, 13:02
Hallo,


Wenn ich sehe das jemand versucht nen 16MB Array auf dem Stack zu allozieren (davon abgesehen, das der Compiler sowas gar nicht erst zulassen sollte) dann hört mein Verständnis dort auf.
Wo ist da Deiner Meinung nach das Problem? Wenn dieses Array nur innerhalb der Funktion benötigt wird dann ist der Stack IMHO genau der Ort wo es eben hingehört. Vor allem macht das die Funktion reentrant (im Gegensatz zu statischen Variablen) und schneller (kein Overhead für malloc/free).
Wo genau würdest Du die Grenze den ziehen? Und vor allem mit welcher Begründung? Etwa weil der VMM in Deinem OS nicht so gut mit flexiblen Stacks umgehen kann? Die Programmiersprache C macht den Stack nutzbar (bei z.B. Java ist das nicht so) und es ist meiner Meinung nach Aufgabe von Compiler und OS jedes valide C-Programm auch auszuführen, wenn Du das nicht möchtest dann benutze eben eine andere Programmiersprache.

Eine flexible TLS-Größe stelle ich mir in einem Flat-Memory-System auch schwierig vor, Du wirst auf jeden Fall die maximale Größe hart begrenzen müssen und immer gleich den gesamten virtuellen Adressraum allozieren (so wie beim Stack auch). Ich schätze mal den Hinweis das ich dieses Problem bei meinen Segmenten grundsätzlich nicht habe und mir sogar ne Art malloc/free für den TLS vorstellen kann kann ich mir doch jetzt sicher sparen, oder? ;)

Um für neue Threads neuen TLS-Speicher anzulegen kann man natürlich nicht das malloc vom Prozess nehmen sondern das ist Aufgabe des OS.

verdrängst du ja andere Cacheeinträge (und das meinte ich mit Cachetrashing).
Ah, jetzt verstehe ich. Ja das ist ein Problem wenn man das Ausnullen per SW macht, bei einer HW-Lösung ist das nicht so. Dem kann man aber entgegenwirken indem man passende Cache-Flush-Befehle oder Write-Through-Befehle benutzt, damit wird erreicht das diese Cache-Lines aus dem Cache raus fliegen und in den echten RAM zurückgeschrieben werden. Ich kann Dir da jetzt keine konkreten Befehle nennen aber die gehören wimre zur SSE2-Befehlserweiterung dazu, die Manuals Deines CPU-Herstellers sollten da entsprechend Auskunft geben können. Damit ist natürlich CPU-lokales cachen von freien physischen Pages nicht mehr so interessant, aber wimre wolltest Du das doch eh nicht machen.


Grüße
Erik
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: FlashBurn am 31. May 2011, 13:22
Zitat von: erik
Wo ist da Deiner Meinung nach das Problem? Wenn dieses Array nur innerhalb der Funktion benötigt wird dann ist der Stack IMHO genau der Ort wo es eben hingehört. Vor allem macht das die Funktion reentrant (im Gegensatz zu statischen Variablen) und schneller (kein Overhead für malloc/free).
Sorry, aber wer 16MB auf den Stack packt der hat eindeutig was falsch gemacht (ist natürlich meine eigene Meinung).

Wieso nicht das Array vom Heap holen und den Pointer in einer lokalen Variablen Speichern? Um mit 16MB zu arbeiten, braucht man eh ein wenig. Dann kommt noch hinzu das gerade solch eine Größe auf dem Stack liegend wesentlich langsamer sein wird als wenn man malloc/free benutzt! Denn erstmal sind die nicht aligned, dann kommt hinzu das unter den meisten OS die Pages per Pagefault gemappt und alloziert werden und das es auch oft Probleme gibt, wenn man mehr als eine Page über das momentane Ende des Stacks hinausschießt.
Nutzt man malloc/free wird der Allocator bestimmt sofort die 16MB an das OS weiterleiten ohne in den eigenen Freelists zu gucken und bei der Größe könnte man sogar davon gebrauch machen mal die Portabilität außer acht zu lassen (wenn man Performance braucht) und das OS selber aufrufen, wo man dann auch sagen könnte das der Speicher sofort gemappt werden soll.

Ein weiteres Problem was ich daran sehe solche Stacks zuzulassen, stell dir mal ne rekursive Endlosschleife vor und da soll dann erst bei 16MB abgebrochen werden?

Zitat von: erik
Um für neue Threads neuen TLS-Speicher anzulegen kann man natürlich nicht das malloc vom Prozess nehmen sondern das ist Aufgabe des OS.
Und genau damit habe ich jetzt ein Problem. Ich gehe jetzt mal davon aus das der TLS 256byte pro Thread ist und da ich ja nicht noch ein eigenes malloc/free für den UserSpace implementieren möchte muss ich da jedes Mal eine ganze Page für nehmen. Ich kann mir irgendwie nicht vorstellen dass das so gelöst wurde (obwohl ich es "denen" durchaus zu traue ;) ).

Zitat von: erik
Dem kann man aber entgegenwirken indem man passende Cache-Flush-Befehle oder Write-Through-Befehle benutzt, damit wird erreicht das diese Cache-Lines aus dem Cache raus fliegen und in den echten RAM zurückgeschrieben werden. Ich kann Dir da jetzt keine konkreten Befehle nennen aber die gehören wimre zur SSE2-Befehlserweiterung dazu
Wo dann also z.B. die guten alten Athlon XPs rausfliegen würden oder einen totalen Performance Einbruch (?) haben würden. Von daher gefällt mir das schon nicht.

Das ist jetzt zwar wieder so eine Sache mit den Zielen die man erreichen möchte, aber ich denke mal die meisten OS Dever (gerade in Europa) vergessen dass nicht alle so moderne Rechner haben wie wir (sicher wer probiert schon so ein Hobby OS aus oder nutzt es) und gerade die Athlon XPs sind doch noch sehr verbreitet.
Bei meinem Vater auf Arbeit wird z.B. noch ein P3 mit Win2k eingesetzt und der ist für seine Aufgabe auch vollkommen ausreichend.
Auch ist das wieder so ein Thema der Herausforderung, wenn man natürlich von der perfekten Hardware ausgeht kann man alles leicht implementieren. Man muss sich halt nur die nötigen "guten" Rahmenbedingungen schaffen. Das ist ein wenig wie in der Schulphysik, findet alles unter optimalen Bedingungen und unter Vernachlässigung vieler Dinge statt ;)
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: erik.vikinger am 31. May 2011, 14:03
Hallo,


Sorry, aber wer 16MB auf den Stack packt der hat eindeutig was falsch gemacht
Warum? Was?
Wenn mein Programm einen virtuellen Adressraum von 2 GB bekommt (und im PC genug RAM drin steckt) warum darf ich mich als Programmierer nicht dafür entscheiden diesen Speicher für den Stack zu benutzen? Ich empfinde es eben als doof wenn ich als Programmierer auf etwas Rücksicht nehmen muss (z.B. Flat-Memory) das eigentlich Compiler und OS vor mir verstecken sollten (laut C-Standard).
Speicher, der auf dem Stack am besten aufgehoben ist, vom Heap holen zu müssen kostet immer extra Performance. Der Stack ist eigentlich grundsätzlich schneller (wenn man im OS nichts falsch macht) als Heap. Auch auf dem Stack kann man (also der Compiler, wenn man das denn passend kommuniziert) Speicher passend ausrichten.

(ist natürlich meine eigene Meinung)
Die sei Dir auch absolut unbenommen, aber zumindest eine nachvollziehbare Begründung wäre schon nicht schlecht.

Ich freue mich jedenfalls schon darauf wenn VLA etwas mehr Verbreitung gefunden hat und dann viele erfrischend neue Probleme auftauchen. Falls ich bis dahin mit meinem Projekt was vorzeigbares auf die Füße bekommen hab kann ich dann immerhin sagen "mit der richtigen Speicherverwaltung wäre das nicht passiert". ;)

und das es auch oft Probleme gibt, wenn man mehr als eine Page über das momentane Ende des Stacks hinausschießt.
Also das wäre definitiv ein Bug im OS. Solange der Pagefault innerhalb des gültigen Stack des aktuellen Threads passiert muss das eigentlich auch ordentlich funktionieren.

Ich kann mir irgendwie nicht vorstellen dass das so gelöst wurde (obwohl ich es "denen" durchaus zu traue ;) ).
"denen" ist es völlig egal wie Du das in Deinem OS realisierst, solange das Ergebnis konform zum C-Standard ist. Natürlich haben "die" sich sicher auch mal überlegt wie das machbar ist, es ist wohl ziemlich unwahrscheinlich das "die" etwas standardisieren das sich auf üblichen Plattformen (Paging-basiertes Flat-Memory ist ja eben üblich) nicht ordentlich umsetzen lässt.

Das ist jetzt zwar wieder so eine Sache mit den Zielen die man erreichen möchte
Ganz recht. Wenn Du hohe Performance auch auf alten Systemen erreichen möchtest dann musst Du eben auf ein paar andere Features (wie z.B. das Ausnullen von Pages vor dem Recyceln) verzichten, wenn Du hingegen maximale Sicherheit auf aktuellen Systemen erreichen möchtest dann gehst Du da wieder anders ran. Eventuell kannst Du das ja hinter auswechselbaren Modulen verstecken.

Man muss sich halt nur die nötigen "guten" Rahmenbedingungen schaffen.
Darauf läuft es in der realen Praxis aber oft hinaus. Viele Probleme lassen sich mit vertretbaren Aufwand nicht korrekt lösen also muss man da ein paar Kompromisse eingehen und/oder Tricks anwenden. Du deklarierst doch auch eine maximale Stack-Größe um einen praktisch realisierbaren VMM zu erreichen.


Grüße
Erik
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: FlashBurn am 31. May 2011, 14:23
Um nochmal auf das 16MB Array auf dem Stack zurückzukommen. Folgende Situation, der Adressraum des Programms ist voll und du kannst deinen Stack nicht mehr weiter vergrößern und da kommst du jetzt mit den Array welches auf dem Stack anglegt wurde (und ich gehe jetzt mal davon aus, das der Compiler nichts eingebaut hat um zu überprüfen ob der Stack noch genügend Platz bietet) und fängst an das Array zu füllen (natürlich beim Index 0). Jetzt bist du aber nicht nur eine Page (und zwar die Guard-Page) über das Stackende hinaus gegangen sondern sogar 16MB und das kann dann auch das beste OS nicht mehr abfangen (dafür bräuchte man dann wieder Segmente ;) ) und du greifst auf Speicher zu auf den du das besser nicht machen solltest.

Zitat von: erik
Ich freue mich jedenfalls schon darauf wenn VLA etwas mehr Verbreitung gefunden hat und dann viele erfrischend neue Probleme auftauchen.
Ich würde da einfach ab einer bestimmten Grenze sagen, das man das auf dem Heap speichert. Das kann der Compiler ja so implementieren, da eh eine Funktion aufgerufen werden muss um Speicher vom Stack zu bekommen.

Was mir gerade noch einfällt, bei mir in der Uni hat man uns auch schön gezeigt, das es keine gute Idee ist VLAs auf dem Stack zu allozieren, weil das Programm da zeitiger flöten geht als wenn man den Heap benutzt. Im konkreten Fall ging es darum ob man VLAs benutzt oder einfach new.

Zitat von: erik
Also das wäre definitiv ein Bug im OS. Solange der Pagefault innerhalb des gültigen Stack des aktuellen Threads passiert muss das eigentlich auch ordentlich funktionieren.
Siehe oben, das man da ab einer Gewissen Situation nichts mehr gegen machen kann.

Zitat von: erik
Du deklarierst doch auch eine maximale Stack-Größe um einen praktisch realisierbaren VMM zu erreichen.
Meinen VMM interessiert das mit dem Stack erstmal gar nicht (der weiß nicht mal das es sowas gibt), sondern ich erstelle einen ausreichend großen (was auch immer das ist) Bereich in dem die Pages durch Pagefaults gemappt werden (außer der ersten) und noch eine Guardpage.

Das machen übrigens Windows und Linux so, bei beiden hat der Stack eine genau definierte Größe. Unter Windows kann man das glaube ich sogar im EXE-Header einstellen. Ob er bei beiden zur Laufzeit vergrößet werden kann weiß ich nicht.

Der Punkt bleibt einfach, das man nicht davon ausgehen kann das ein Stack immer 16MB groß ist oder Platz für solche Objekte bietet.

Habe mich gerade mal in TLS im ELF eingelesen und es ist unter POSIX und Windows wirklich so, dass man sich nen Slot holt (der dann für alle Threads des Prozesses als used gilt) und dort einen Wert (natürlich nen Pointer) speichern kann. Was nun C/C++ betrifft, wird ein Slot immer pro Modul genutzt um alle TLS Variablen des Moduls dort abzuspeichern. Es wird also malloc/free des Programms genommen. Eigentlich auch klar da es eine Sprachbezogene Implementierung ist und keine Allgemeine.

Ich würde das dann wahrscheinlich so lösen, das jeder Thread genau eine Variable für sich speichern darf und dort kommt dann der Vektor für die Slots rein (weil das Problem ist, das der Vektor "unendlich" groß sein muss :( ). Ich hätte es zwar gerne anders gelöst, aber da wird das mit der Größe des Vektors zu umständlich.
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: erik.vikinger am 31. May 2011, 16:08
Hallo,


Jetzt bist du aber nicht nur eine Page (und zwar die Guard-Page) über das Stackende hinaus gegangen sondern sogar 16MB und das kann dann auch das beste OS nicht mehr abfangen (dafür bräuchte man dann wieder Segmente ;) ) und du greifst auf Speicher zu auf den du das besser nicht machen solltest.
Genau diese Art Szenario hab ich auch als Begründung für Segmente in meinem aller ersten Thread hier (http://forum.lowlevel.eu/index.php?topic=2224.msg25456#msg25456) im Forum benutzt. Genau das ist die Sorte Fehler die sich mit Flat-Memory grundsätzlich nicht lösen lässt und da wird VLA sicher noch viel Freude bringen. Ich vermute mal das die Compiler wieder damit anfangen werden vor jedem Allozieren auf dem Stack erst zu prüfen ob auf dem Stack noch ausreichend Platz ist, also Performance ist was anderes.

Ich würde da einfach ab einer bestimmten Grenze sagen, das man das auf dem Heap speichert.
Also zusätzlicher Code.

da eh eine Funktion aufgerufen werden muss um Speicher vom Stack zu bekommen.
Für was muss eine Funktion aufgerufen werden um Speicher auf dem Stack zu allozieren oder wieder frei zu geben? Das läuft auf eine simple Addition/Subtraktion mit dem Stack-Pointer hinaus, also einem einzelnen Assembler-Befehl. Erst das Prüfen auf ausreichend Platz macht üblicherweise eine kleine Funktion, ich hab so eine mal für den Watcom-Compiler implementiert.

Was mir gerade noch einfällt, bei mir in der Uni hat man uns auch schön gezeigt, das es keine gute Idee ist VLAs auf dem Stack zu allozieren, weil das Programm da zeitiger flöten geht als wenn man den Heap benutzt. Im konkreten Fall ging es darum ob man VLAs benutzt oder einfach new.
Hast Du da nen Script o.ä.? Es würde mich mal sehr interessieren mit was für Argumenten und Szenarien da gearbeitet wurde.

Der Punkt bleibt einfach, das man nicht davon ausgehen kann das ein Stack immer 16MB groß ist oder Platz für solche Objekte bietet.
Ja leider, und das trotz dessen das in einem heutigen PCs locker mal ein paar GB Speicher stecken. Ich empfinde das als beschämend.

und es ist unter POSIX und Windows wirklich so, dass man sich nen Slot holt (der dann für alle Threads des Prozesses als used gilt) und dort einen Wert (natürlich nen Pointer) speichern kann....
Das erscheint mir irgendwie kompliziert und langsam, ein Haufen indirektes Zeug.
Ich möchte einfach alle TLS-Variablen in einer extra Sektion sammeln und der Linker macht dann daraus ein spezielles Segment das dann vom OS (zur Laufzeit) für jeden Thread der auf seinen TLS schreibend zugreift einmal geklont wird (COW). Damit kann ich TLS sogar aus simplen Assembler-Programmen benutzen ohne irgendwelche Verrenkungen und zusätzliche Befehle, ganz so wie alle anderen statischen Variablen auch. Ich dachte eigentlich dass das auf x86 ähnlich gemacht wird, schließlich hat man dort ja Segmente.


Grüße
Erik
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: kevin am 31. May 2011, 16:29
Eine flexible TLS-Größe stelle ich mir in einem Flat-Memory-System auch schwierig vor, Du wirst auf jeden Fall die maximale Größe hart begrenzen müssen und immer gleich den gesamten virtuellen Adressraum allozieren (so wie beim Stack auch). Ich schätze mal den Hinweis das ich dieses Problem bei meinen Segmenten grundsätzlich nicht habe und mir sogar ne Art malloc/free für den TLS vorstellen kann kann ich mir doch jetzt sicher sparen, oder? ;)
Dafür braucht man aber keine Segmente. Ein einziger Pointer als TLS reicht, um alles machen zu können, wenn man nicht die Threads voneinander abschotten will. Letztendlich ist ja in der Regel %fs auf x86_64 genau dieser eine Pointer und nicht mehr. Und in der Struktur, auf die er zeigt, kann man dann eine Freispeicherliste für das threadlokale malloc aufhängen, wenn man mag.
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: FlashBurn am 31. May 2011, 16:33
Zitat von: erik
Für was muss eine Funktion aufgerufen werden um Speicher auf dem Stack zu allozieren oder wieder frei zu geben? Das läuft auf eine simple Addition/Subtraktion mit dem Stack-Pointer hinaus, also einem einzelnen Assembler-Befehl. Erst das Prüfen auf ausreichend Platz macht üblicherweise eine kleine Funktion, ich hab so eine mal für den Watcom-Compiler implementiert.
Genau für das Prüfen ob genügend Platz ist. Dafür wird bei VLAs eine Funktion aufgerufen und da kann ich dann auch gleich malloc aufrufen (muss dann ntürlich am Ende der Funktion auch noch free aufrufen). Der Unterschied sollte, je nach Größe mal auf dem Stack und mal auf dem Heap schneller sein. Deswegen sollte sowas auch der Programmierer entscheiden, der weiß am besten wie groß die Arrays am meisten sind.

Zitat von: erik
Hast Du da nen Script o.ä.? Es würde mich mal sehr interessieren mit was für Argumenten und Szenarien da gearbeitet wurde.
Nope, das war innerhalb einer Übung, eigentlich wollte der Prof da gar nicht drauf eingehen (insbesondere da er nicht dachte das jemand versucht ein solches VLA auf dem Stack anzulegen, aber Studenten haben noch jede Dummheit mitgenommen ;) ), aber hat dann in der Übung schön zeigen können, das ab einer gewissen Arraygröße auf dem Stack das Programm beendet wird (zwecks nicht genug Stack) und wenn man new (also den Heap) nutzt funktioniert das bis zu wesentlich größeren Größen.

Zitat von: erik
Ja leider, und das trotz dessen das in einem heutigen PCs locker mal ein paar GB Speicher stecken. Ich empfinde das als beschämend.
Nicht wirklich (unter 64bit ja). Denn denk an ALR (oder wie das doch gleich hieß). Irgendwo musst du da bei der Stackgröße ne Grenze ziehen und wenn dann noch mehrere Threads dazu kommen eh!

Zitat von: erik
Das erscheint mir irgendwie kompliziert und langsam, ein Haufen indirektes Zeug.
Ich möchte einfach alle TLS-Variablen in einer extra Sektion sammeln und der Linker macht dann daraus ein spezielles Segment das dann vom OS (zur Laufzeit) für jeden Thread der auf seinen TLS schreibend zugreift einmal geklont wird (COW). Damit kann ich TLS sogar aus simplen Assembler-Programmen benutzen ohne irgendwelche Verrenkungen und zusätzliche Befehle, ganz so wie alle anderen statischen Variablen auch. Ich dachte eigentlich dass das auf x86 ähnlich gemacht wird, schließlich hat man dort ja Segmente.
Genauso hat man es dann auch gemacht in der ELF und C/C++ Implementierung. Da macht man sich das gs Register zu nutze und das beide Systeme es zulassen einen Wert zu speichern und den über "gs:0" anzusprechen. Es gibt da allerdings noch ein paar Sachen die mir nicht ganz einleuchten in dem "Werk", aber das kann ich dann lösen wenn ich das mal portiere.

Im Endeffekt ist es allgemein (weil es ja Platformübergreifend sein soll) so, das man ne Funktion aufruft (sowas wie tls_get_data(size_t mid, size_t offset)) und die Daten bekommt (oder die Adresse, bin mir da gerade nicht sicher), aber auf x86 wird das alles vereinfacht und kein call zu dieser Funktion gemacht, sondern mit dem gs Register gearbeitet.

Kannst du dir ja bei Gelegenheit mal angucken.

Zitat von: taljeth
Dafür braucht man aber keine Segmente.
Und was ist deiner Meinung nach das fs Register ;)
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: Svenska am 31. May 2011, 17:18
Der Treiber kann den gesamten Speicher auslesen, weil er halt Zugriff auf die Hardware hat und diese anweisen kann per DMA den gesamten Speicher auslesen. Das war das was ich meinte!
Und das ist so nicht richtig: Nicht jede Hardware kann DMA und nicht jede Hardware kann die gerade per DMA gelesenen Daten auch wieder zurückschieben. Auch kann nicht jede Hardware so einen Durchsatz garantieren, den du für unbemerktes Memdumping möchtest, zumal währenddessen die Hardware wahrscheinlich ausgelastet ist. Außerdem ist der Treiber dann garantiert hardwarespezifisch - und ein gutes OS lässt nicht zwei Treiber auf die gleiche Hardware zugreifen, d.h. man müsste den schon vorhandenen Treiber manipulieren, statt einfach einen beliebigen Treiber zu injizieren.

Ein paar Treiber werden in der Lage sein, den Speicher halbwegs schnell mit Hilfe der Hardware zu dumpen, aber davor kannst du dich ohne IOMMU nicht schützen. Dennoch sollte ein Treiber nicht auf den gesamten Speicher zugreifen können; versucht er es dennoch, gibt es halt einen GPF.

Performance ist was anderes
Auch in einer IOMMU kann man einen TLB implementieren. [...]
Das bezog sich darauf, dass man, wenn man mit einer Hardware den Speicher ohne IOMMU auslesen möchte, die Daten halt zweimal mit DMA (oder DMA+PIO) durch langsame Subsysteme transportieren muss. Das ist nicht besonders performant.

Gruß,
Svenska
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: FlashBurn am 31. May 2011, 17:24
Zitat von: svenska
Und das ist so nicht richtig: Nicht jede Hardware kann DMA und nicht jede Hardware kann die gerade per DMA gelesenen Daten auch wieder zurückschieben.
Es bleibt ja allgemein erstmal gültig, das es im speziellen dann Geräte gibt die etwas nicht können, änder ja nichts an der Tatsache das es Treiber gibt die es können.
Die Geschwindigkeit spielt dann meine Meinung nach keine Rolle mehr, es muss ja nicht der gesamte Speicher ausgelesen werden, es reicht ja auch der nötige ;)

Zitat von: svenska
Dennoch sollte ein Treiber nicht auf den gesamten Speicher zugreifen können; versucht er es dennoch, gibt es halt einen GPF.
Was unter einem Mikrokernel klar sein sollte, aber in nem monolithen kannst du das nicht hinbekommen (nicht auf jeder Architektur und nicht ohne sehr sehr viel Aufwand).

Zitat von: svenska
Das bezog sich darauf, dass man, wenn man mit einer Hardware den Speicher ohne IOMMU auslesen möchte, die Daten halt zweimal mit DMA (oder DMA+PIO) durch langsame Subsysteme transportieren muss.
Nicht unbedingt, wenn du den ausgelesenen Speicher einfach per Netzwerk rausschickst.

@taljeth

Du hast recht, man braucht dafür nicht unbedingt Segmente, aber dann ein freies Register, wo man nen Thread spezifischen Wert speichern kann. Was aber unter x86 (auch nicht im 64bit Modus) ratsam ist, da zu wenige Register bzw. auf bestimmte Register nicht aus dem UserMode zugegriffen werden kann (z.B. Debugging-Register die man ja für sowas missbrauchen könnte).
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: kevin am 31. May 2011, 19:58
Zitat von: taljeth
Dafür braucht man aber keine Segmente.
Und was ist deiner Meinung nach das fs Register ;)
Eine Segmentruine. ;)

Letztendlich ist es auf x86_64 nicht wesentlich mehr als ein Register mit einem Pointer, den man für manche Adressierungsarten draufaddieren kann. Das ist eine relative bequeme Methode, aber dafür kann man genausogut andere Mechanismen hernehmen, z.B. ein Allzweckregister reservieren oder was Nicht-x86-Architekturen eben sonst machen, um TLS zu implementieren. Du meinst doch nicht, dass es TLS nur auf x86 gibt, oder?
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: kevin am 31. May 2011, 20:01
Das bezog sich darauf, dass man, wenn man mit einer Hardware den Speicher ohne IOMMU auslesen möchte, die Daten halt zweimal mit DMA (oder DMA+PIO) durch langsame Subsysteme transportieren muss. Das ist nicht besonders performant.
Ich habe es nicht konkret ausprobiert, aber der Datentransfer, den ich brauche, um Ring 0 zu kriegen, dürfte sich sehr in Grenzen halten. Und alles weitere kann ich dann ja wieder direkt im RAM machen.
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: FlashBurn am 31. May 2011, 20:18
Zitat von: taljeth
Letztendlich ist es auf x86_64 nicht wesentlich mehr als ein Register mit einem Pointer, den man für manche Adressierungsarten draufaddieren kann.
Auf der einen Seite ist es eigentlich egal, aber es werden dort keine Limit-Checks mehr durchgeführt?

Zitat von: taljeth
Du meinst doch nicht, dass es TLS nur auf x86 gibt, oder?
Die nehmen ein Allgemeinregister, aber das ist unter x86 nicht zu empfehlen. Gibt es eigentlich noch eine Architektur (die man Leistungsmäßig zumindestens mit nem ARM Cortex A8 vergleichen kann) die auch nur so wenig Register hat und keine Segment Register?
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: erik.vikinger am 31. May 2011, 21:36
Hallo,


Dafür braucht man aber keine Segmente. Ein einziger Pointer als TLS reicht, um alles machen zu können, wenn man nicht die Threads voneinander abschotten will. Letztendlich ist ja in der Regel %fs auf x86_64 genau dieser eine Pointer und nicht mehr. Und in der Struktur, auf die er zeigt, kann man dann eine Freispeicherliste für das threadlokale malloc aufhängen, wenn man mag.
Ja, es geht auch ohne Segmente, aber die volle Flexibilität und Performance die man mit Segmenten ohne irgendwelche Zusatzticks bieten kann wird man mit Flat-Memory trotzdem nicht hinbekommen (ob man diese Flexibilität auch tatsächlich benötigt ist jetzt mal unerheblich). Gerade dieser Mechanismus mit den Slots (den FlashBurn beschrieben hat) dürfte in irgendeiner Form zur Compilezeit begrenzt sein ansonsten wird das Modifizieren der Strukturen nur noch wesentlich komplizierter.


Genau für das Prüfen ob genügend Platz ist. Dafür wird bei VLAs eine Funktion aufgerufen
Naja, kann man so machen, aber ob das die effizienteste Lösung ist möchte ich dennoch bezweifeln.

und da kann ich dann auch gleich malloc aufrufen (muss dann ntürlich am Ende der Funktion auch noch free aufrufen). Der Unterschied sollte, je nach Größe mal auf dem Stack und mal auf dem Heap schneller sein.
Also ich behaupte das Speicher allozieren auf dem Stack immer schneller ist, egal ob es sich um 4 Bytes oder um 1GByte handelt, es bleibt ne simple Addition/Subtraktion. Ich sehe auch nicht wie das überhaupt von der Größe beeinflusst werden könnte.

Deswegen sollte sowas auch der Programmierer entscheiden, der weiß am besten wie groß die Arrays am meisten sind.
Gerade der Programmierer weiß oft am wenigsten wie groß der Workload später tatsächlich wird. Der kann höchstens ein paar Abschätzungen und Worst-Case-Betrachtungen durchführen oder eine optimale Workload-Größe für den Anwender empfehlen.

(insbesondere da er nicht dachte das jemand versucht ein solches VLA auf dem Stack anzulegen, aber Studenten haben noch jede Dummheit mitgenommen ;) )
Wieso nur betrachtest Du das allozieren von Speicher auf dem Stack als Dummheit? Ich vermisse da immer noch ein handfestes Argument.

das ab einer gewissen Arraygröße auf dem Stack das Programm beendet wird (zwecks nicht genug Stack)
Achso, es geht darum ob es überhaupt läuft. Du hattest heute Mittag von "da zeitiger flöten geht" geschrieben und da hatte ich vermutet das Du irgendein Laufzeitproblem o.ä. meinst.

Zitat von: erik
Ja leider, und das trotz dessen das in einem heutigen PCs locker mal ein paar GB Speicher stecken. Ich empfinde das als beschämend.
Nicht wirklich .....
Doch, das ist beschämend. Völlig egal wie viel RAM wirklich im Rechner steckt, das es auf einer >=32Bit-Plattform nicht möglich ist einfach mal 16 MByte oder auch 256 MByte auf dem Stack abzulegen ist einfach nur beschämend. Ich verstehe natürlich die technischen Zwänge hinter Flat-Memory die sowas eben unmöglich machen aber von außen betrachtet, ohne sich um die tatsächliche Realisierung der Speicherverwaltung zu kümmern, ist es einfach unverständlich warum ich als Programmierer den vorhandenen Speicher nicht so benutzen kann wie ich das gerne möchte.

Im Endeffekt ist es allgemein (weil es ja Platformübergreifend sein soll) so, das man ne Funktion aufruft (sowas wie tls_get_data(size_t mid, size_t offset))
Ich denke man wird eher ein Register opfern. Wenn 16 oder mehr Register vorhanden sind dürfte das eher verschmerzbar sein als ein teurer Funktionsaufruf (vor allem kann man dieses Register ja auch mal auf dem Stack sichern wenn im entsprechenden Code-Abschnitt kein TLS benutzt wird und gerade dieses eine Register fehlt). Das x86 dafür Segment-Register hat ist da eher ein nettes Zusatzfeature so das man wenigstens keines der normalen Register opfern muss.


Das bezog sich darauf, dass man, wenn man mit einer Hardware den Speicher ohne IOMMU auslesen möchte, die Daten halt zweimal mit DMA (oder DMA+PIO) durch langsame Subsysteme transportieren muss. Das ist nicht besonders performant.
Wenn man den kompletten RAM dumpen will wird das so oder so nicht besonders performant. Wohin möchtest Du denn den vorhandenen Speicher kopieren? Etwa in den vorhandenen Speicher? Nein, man wird eh den Speicherinhalt komplett irgendeiner Hardware übergeben müssen, und ob das nun der HDD-Controller oder der Ethernet-Controller ist spielt da IMHO keine so große Rolle mehr. Wenn es aber darum geht eigenen Code in den Kernel zu injizieren bzw. auf anderem Weg Ring-0-Rechte zu erlangen dann dürfte die erforderliche Datenmenge ziemlich klein sein, wenn man die Adressen genau kennt dürfte das mit weniger als ein paar KByte auskommen und das geht dann wirklich schnell genug.


Grüße
Erik
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: Jidder am 31. May 2011, 21:38
Völlig egal wie viel RAM wirklich im Rechner steckt, das es auf einer >=32Bit-Plattform nicht möglich ist einfach mal 16 MByte oder auch 256 MByte auf dem Stack abzulegen ist einfach nur beschämend. Ich verstehe natürlich die technischen Zwänge hinter Flat-Memory die sowas eben unmöglich machen aber von außen betrachtet, ohne sich um die tatsächliche Realisierung der Speicherverwaltung zu kümmern, ist es einfach unverständlich warum ich als Programmierer den vorhandenen Speicher nicht so benutzen kann wie ich das gerne möchte.
Man kann doch den Stack-Pointer verändern?!?
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: erik.vikinger am 31. May 2011, 21:55
Man kann doch den Stack-Pointer verändern?!?
ist anzunehmen, ja. Und was willst Du damit sagen?!?
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: FlashBurn am 31. May 2011, 21:55
Zitat von: erik
Naja, kann man so machen, aber ob das die effizienteste Lösung ist möchte ich dennoch bezweifeln.
So wie ich das verstanden hatte, ist das keine Sache von kann man machen, sondern muss man machen, es muss jede Page angefasst und zwar in der richtigen Reihenfolge, damit die Guardpage eine Page weiter gesetzt wird.
Das Problem ist hier die Sicherheit, das man bestimmte Sachen verhindern möchte. Dazu kommt halt noch ALR, wo es dann sein kann das du zwar viel freien RAM hättest der Stack aber an einer Stelle ist wo er einfach nicht größer werden kann. Vorallem was willst du machen wenn der Speicher voll ist, dann bekommst du das da auch nicht drauf.
Dann kommt noch hinzu wie der VMM aufgebaut ist, bei mir ist es z.B. nicht einfach mal möglich sich neuen Speicher zu holen in dem man einfach willkürlich auf eine Page zugreift und die dann gemappt wird, sondern der Speicher muss vom OS angefordert werden.

Zitat von: erik
Wieso nur betrachtest Du das allozieren von Speicher auf dem Stack als Dummheit? Ich vermisse da immer noch ein handfestes Argument.
Also erstmal sollte man wissen das der Stack begrenzt ist und wo diese Grenze ungefähr liegt und da sollte es klar sein, das ab einer Gewissen Größe kein Platz mehr auf dem Stack ist.
Dazu kommt, das der Stack für mich für kleine überschaubare Sachen zuständig ist, aber ab einer gewissen Größe ist es nicht mehr nur kurzzeitig sondern länger und da fällt es dann auch nicht mehr ins Gewicht ob man malloc oder den Stack benutzt.

Zitat von: erik
Achso, es geht darum ob es überhaupt läuft. Du hattest heute Mittag von "da zeitiger flöten geht" geschrieben und da hatte ich vermutet das Du irgendein Laufzeitproblem o.ä. meinst.
Ich weiß die Aufgabe nicht mehr genau, aber einer Funktion wurde die Größe übergeben und daraufhin hat man nen neues Array von Int Werten angelegt, was man dann damit gemacht hat, keine Ahnung mehr. Und wenn du das auf dem Stack machst, geht es relativ zeitig flöten, da du halt versuchst auf Speicher zuzugreifen, auf den du keine Rechte hast und machst du das über/malloc geht das wesentlich länger (größer).

Zitat von: erik
Doch, das ist beschämend. Völlig egal wie viel RAM wirklich im Rechner steckt, das es auf einer >=32Bit-Plattform nicht möglich ist einfach mal 16 MByte oder auch 256 MByte auf dem Stack abzulegen ist einfach nur beschämend.
Wie gesagt, was machst du wenn du soviel Platz auf dem Stack nicht findest, aber sich woanders im Prozess eine Lücke findet die groß genug ist? Was machst du bei mehreren Threads die alle nen Stack brauchen und da willst du dann jedes Mal 256MB für den Stack (eigentlich ja sogar mehr) reservieren? Und wo packst du Libraries und den Heap hin?

Zitat von: erik
Ich denke man wird eher ein Register opfern.
Ist ja richtig, aber auf x86 wird zum Bsp gs und auf x86-64 fs genommen, weil halt kein Register über ist und da man den Standard Platformunabhängig machen wollte hat man sich für die Funktionen entschieden. Das jede Platform diese Funktionen anders implementiert und diese dann vom Compiler geinlinet werden, das ist klar und dann läuft es genau auf solch ein Register hinaus.

Zitat von: PorkChicken
Man kann doch den Stack-Pointer verändern?!?
Das werde ich z.B. unter meinem OS nicht zulassen. Ich überprüfe jedes Mal wenn ein Syscall gemacht wird, ob der Stackpointer noch innerhalb des Stackbereichs liegt und wenn nicht dann gibts entweder nen Fehlercode oder der Prozess wird beendet.
Das der Programmierer sich selbst um den Stack gekümmert hat, die Zeiten sind vorbei, vorallem umgeht er damit ja alle Sicherheits Maßnahmen vom OS (und darauf legt ihr ja immer wert ;) ).
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: Jidder am 31. May 2011, 21:59
@Erik: Dass es sich nicht lohnt soviele Worte darüber zu verlieren, dass man angeblich nicht den vorhanden Speicher so nutzen kann wie man möchte.
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: kevin am 31. May 2011, 22:33
Das werde ich z.B. unter meinem OS nicht zulassen. Ich überprüfe jedes Mal wenn ein Syscall gemacht wird, ob der Stackpointer noch innerhalb des Stackbereichs liegt und wenn nicht dann gibts entweder nen Fehlercode oder der Prozess wird beendet.
Das der Programmierer sich selbst um den Stack gekümmert hat, die Zeiten sind vorbei, vorallem umgeht er damit ja alle Sicherheits Maßnahmen vom OS (und darauf legt ihr ja immer wert ;) ).
Welche Sicherheitsmaßnahmen umgeht man denn mit einem Stackwechsel? Und wenn das geht, heißt das nicht, dass diese Sicherheitsmaßnahmen schlicht und einfach nichts taugen?
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: erik.vikinger am 01. June 2011, 10:04
Hallo,


es muss jede Page angefasst und zwar in der richtigen Reihenfolge
Warum muss jede Page vom Stack in der richtigen Reihenfolge angefasst werden?
Die Guard-Page ist IMHO immer die letzte Page (bei x86 die an der niedrigsten Adresse) vom maximal möglichen Stack und die wird prinzipiell nie gemappt und ein Zugriff führt immer zum Stack-Overflow-Kill.

Vorallem was willst du machen wenn der Speicher voll ist, dann bekommst du das da auch nicht drauf.
Wenn der Speicher voll ist ist eh zu spät aber wenn mein Programm in seinem virtuellen Adressraum noch knapp 2 GBytes frei hat dann sollte es eigentlich auch möglich sein mal 16 MBytes auf den Stack zu legen.

Dann kommt noch hinzu wie der VMM aufgebaut ist
Der C-Standard interessiert sich nicht für den VMM, dort wird mir gesagt das ich alles mögliche als lokale Variable auf den Stack legen kann und fertig. Wie das dann konkret umgesetzt wird ist ein Implementierungsdetail. Meiner persönlichen Meinung nach ist es Aufgabe der Implementierung (was Compiler, libc, OS usw. mit einschließt) die Dinge die der C-Standard zusichert auch zur Verfügung zu stellen und gerade an der Stelle hat Flat-Memory eben eine Schwäche mit dem Stack. Mir ist klar warum diese Schwäche existiert und ich muss diese Schwäche auch in meinen Programmen berücksichtigen aber ich empfinde das eben als unpraktisch und nicht nachvollziehbar.

und wo diese Grenze ungefähr liegt
Warum sollte ich das als reiner C-Programmierer wissen? Mich interessieren doch nicht die spezifischen Eigenheiten der drunter liegenden Plattform, deswegen gibt es doch den Compiler (und die restliche Kette bis hin zum OS) damit diese Dinge vor mir verborgen werden und ich nur den C-Standard kennen muss.

Dazu kommt, das der Stack für mich für kleine überschaubare Sachen zuständig ist
Definiere "kleine". Wenn Du da eine Grenze ziehst dann musst Du die auch sauber begründen können. Der C-Standard zieht dort keine Grenze. Natürlich ist dem Programmierer bewusst das Speicher nicht unbegrenzt zur Verfügung steht aber warum soll der Stack eine "kleine" Grenze haben und der Heap nicht?

Wie gesagt, was machst du wenn du soviel Platz auf dem Stack nicht findest, aber sich woanders im Prozess eine Lücke findet die groß genug ist? Was machst du bei mehreren Threads die alle nen Stack brauchen und da willst du dann jedes Mal 256MB für den Stack (eigentlich ja sogar mehr) reservieren? Und wo packst du Libraries und den Heap hin?
Diese Dinge fallen allesamt in den Verantwortungsbereich der Implementierung und nicht des C-Programmierers.


Dass es sich nicht lohnt soviele Worte darüber zu verlieren, dass man angeblich nicht den vorhanden Speicher so nutzen kann wie man möchte.
Wenn Du das mit dem "angeblich" ernst meinst dann beweise mir das man mit reinen ANSI-C-Mitteln 256 MBytes auf den Stack legen und benutzen kann! Auf Windows und Linux (und noch mindestens einer nicht-x86-32Bit-Plattform mit normalem/unmodifiziertem General-Purpose-OS), ohne zusätzliche (OS-spezifische) Librarys und ohne Compiler/Assembler/Linker/....-spezifische Tricks.


Grüße
Erik
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: FlashBurn am 01. June 2011, 10:30
Zitat von: taljeth
Welche Sicherheitsmaßnahmen umgeht man denn mit einem Stackwechsel? Und wenn das geht, heißt das nicht, dass diese Sicherheitsmaßnahmen schlicht und einfach nichts taugen?
Wenn man sich selbst nen Stack einrichtet, dann gibt es keine Guardpage mehr und ich als OS sage dann, das ich keinen Syscall von einem nicht "registrierten" Stack zulasse.

Zitat von: erik
Warum muss jede Page vom Stack in der richtigen Reihenfolge angefasst werden?
So wie ich das mal verstanden hatte, wird die Guardpage immer nur eine Page weitergesetzt und deswegen muss das passieren. Ich habe gerade mal nachgeguckt und scheint nicht mehr so zu sein, aber irgendwo gab es halt Probleme, wenn du ein sehr großes Array anlegst und dort auf den Index 0 zugreifst und zw. der Page wo du da zugreifst und der letzten Page (die gemappt ist) vom Stack eine zu große Lücker (oder überhaupt eine Lücke ist) gibt es einen Fehler, weil der Stack ja wachsen soll und nicht das da irgendwelche Lücken entstehen sollen.

Zitat von: erik
Wenn der Speicher voll ist ist eh zu spät aber wenn mein Programm in seinem virtuellen Adressraum noch knapp 2 GBytes frei hat dann sollte es eigentlich auch möglich sein mal 16 MBytes auf den Stack zu legen.
Ignorierst du eigentlich ALR ;) Guck dir die Verteilung der Libraries und der Stacks in einem aktuellen Windows mal an, da kann noch so viel Speicher frei sein, du wirst halt durch die Lücken begrenzt.

Genauso kann man sagen, ich habe 4GB RAM in meinem PC und die will ich auch komplett nutzen und zwar auch in einem Programm! Geht halt nicht, ist Architektur bedingt und gut ist.

Zitat von: erik
Warum sollte ich das als reiner C-Programmierer wissen? Mich interessieren doch nicht die spezifischen Eigenheiten der drunter liegenden Plattform, deswegen gibt es doch den Compiler (und die restliche Kette bis hin zum OS) damit diese Dinge vor mir verborgen werden und ich nur den C-Standard kennen muss.
Wenn du willst das dein Programm läuft und vorallem wenn du es verkaufen willst, dann solltest du das schon wissen. Ich meine deine Kunden haben bestimmt kein Verständnis dafür wenn du ihnen sagst, aber der C-Standard sichert mir das zu, was kann ich dafür wenn das OS das nicht umsetzen kann ;)

Zitat von: erik
Natürlich ist dem Programmierer bewusst das Speicher nicht unbegrenzt zur Verfügung steht aber warum soll der Stack eine "kleine" Grenze haben und der Heap nicht?
Weil es halt so ist. Windows hat z.B. einen Standardstack von 1MB (stand auf der MSDN Seite wo ich wegen der Guardpage geguckt hatte) und das empfinde ich auch erstmal als ausreichend, sicher wenn man bestimmte Programme (was wahrscheinlich vorallem wissenschaftliche sein werden, die eine sehr tiefe Rekursion nutzen) schreibt, dann muss man das ändern, aber wie gesagt, das weiß man dann auch.

Zitat von: erik
beweise mir das man mit reinen ANSI-C-Mitteln 256 MBytes auf den Stack legen und benutzen kann! Auf Windows und Linux (und noch mindestens einer nicht-x86-32Bit-Plattform mit normalem/unmodifiziertem General-Purpose-OS), ohne zusätzliche (OS-spezifische) Librarys und ohne Compiler/Assembler/Linker/....-spezifische Tricks.
Du hast eine Sache vergessen, zusätzliche Programme ;) Denn unter Windows steht das ja im EXE-Header und entweder du änderst das per Hand oder du nutzt entsprechende Tools dafür.

Ansonsten kann man sagen das es auf keinem (mir bekannten) OS ohne irgendwelchen Tricks funktioniert. Jetzt aber die Gegenfrage, was willst du mit diesen 256MB machen. Denn wiegesagt, wenn du auf soviel Speicher arbeitest fällt der Aufruf von malloc/free auch nicht mehr ins Gewicht und wenn du solch große Stacks ohne weiteres zulassen würdest (was ja wohl früher auch theoretisch möglich gewesen sein müsste, da kein Multithreading), dürften die Nachteile die (noch nicht von dir genannten) Vorteile aufwiegen.

Noch eine Sache, wenn du solche großen Stacks zulässt musst du ja auch immer diesen Bereich reservieren und das willst du in jedem Programm machen, obwohl die meisten sehr gut mit wesentlich weniger auskommen? Denn wenn du diesen Bereich nicht reservierst, wie bekommst du dann raus, ob das jetzt ein Zugriff durch einen Fehlerhaften Pointer war oder ein gewollter Zugrifft durch den Stack?
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: kevin am 01. June 2011, 10:34
Zitat von: taljeth
Welche Sicherheitsmaßnahmen umgeht man denn mit einem Stackwechsel? Und wenn das geht, heißt das nicht, dass diese Sicherheitsmaßnahmen schlicht und einfach nichts taugen?
Wenn man sich selbst nen Stack einrichtet, dann gibt es keine Guardpage mehr und ich als OS sage dann, das ich keinen Syscall von einem nicht "registrierten" Stack zulasse.
Als rein willkürlche Erziehungsmaßnahme für den Programmierer?

Oder ist es für den Kernel gefährlich, einen Syscall auszuführen, wenn der Userspace den Stack gewechselt hat und möglicherweise (!) keine Guard Page mehr hat?
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: FlashBurn am 01. June 2011, 10:45
Zitat von: taljeth
Oder ist es für den Kernel gefährlich, einen Syscall auszuführen, wenn der Userspace den Stack gewechselt hat und möglicherweise (!) keine Guard Page mehr hat?
Jap! Das Problem ist einfach, das ich Exceptions gerne aus dem Kernel raushalten möchte und es ist halt blöd wenn ich vor jedem Stackzugriff (und damit meine ich wirklich jeden) erstmal gucken müssten ob der Speicher auch wirklich gemappt ist usw.
Wenn ich aber einfach nur teste ob der Stack innerhalb des Stacks vom Thread liegt, ist das eine einzige Überprüfung und ich brauche mir dann, was das betrifft keine Sorgen mehr machen.
Allerdings muss ich dann wenn ich Daten aus dem UserSpace in den KernelSpace kopieren will wieder bei jedem Zugriff kontrollieren ob der auch in Ordnung geht.

Wie meinst du das eigentlich mit dem möglicherweise? Das impliziert ja das es eine geben könnte, das ist aber deswegen nicht der Fall, weil der User eine solche Page gar nicht erstellen kann (bei mir).
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: kevin am 01. June 2011, 13:13
Dann hast du halt eine mangelhafte API, wenn man das damit nicht machen kann. ;)

Bevor der Kernel Pointer vom Userspace benutzt, muss er sowieso immer prüfen. Machst du die Parameterübergabe für Syscalls über den Stack oder wo würde der Kernel sonst explizit auf den Stack des Userspace zugreifen?
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: erik.vikinger am 01. June 2011, 13:18
Hallo,


Wenn man sich selbst nen Stack einrichtet, dann gibt es keine Guardpage mehr und ich als OS sage dann, das ich keinen Syscall von einem nicht "registrierten" Stack zulasse.
Das Problem kommt IMHO daher das Du den Stack als etwas besonderes betrachtest und speziell behandelst. Ich würde Stack eher als normalen Speicher mit MAP_LAZY betrachten und die Guard-Page ist einfach eine "freie" Page im virtuellen Adressraum am Ende vom Stack bei deren Zugriff eben der Prozess gekillt wird (so wie bei jedem anderen Pagefault auf andere nicht gemappte Pages auch). Das einzigste was man bei der Guardpage beachten muss ist das diese nicht anderweitig alloziert werden darf. Mit dieser Vorgehensweise kann man auf dem Stack auch große Arrays anlegen und die beim Index 0 beginnend befüllen. Wenn Du aber den Stack als komplexes dynamisches System betrachtest dann werden einige Dinge eben komplizierter als nötig.

Zitat von: erik
Wenn der Speicher voll ist ist eh zu spät aber wenn mein Programm in seinem virtuellen Adressraum noch knapp 2 GBytes frei hat dann sollte es eigentlich auch möglich sein mal 16 MBytes auf den Stack zu legen.
Ignorierst du eigentlich ALR ;) ....
Nein, ich ignoriere ASLR nicht! Wenn Du bei einem Programm das von seinen 2 GByte virtuellen Adressraum gerade mal 10 MByte benutzt jedes kleine Datenhäppchen komplett zufällig verstreust so das es keine Lücke mit mehr als 16 MByte mehr gibt dann bist Du selber schuld, denn kann man die 16 MByte gar nicht mehr allozieren (weder per Stack noch per Heap). Schau Dir das ASLR mal bei Windows, Linux und Mac OS genauer an, ganz so chaotisch wie Du es Dir scheinbar vorstellst gehen diese OSe da nicht ran sonst würden ja ziemlich viele Programme nicht mehr funktionieren können.

Genauso kann man sagen, ich habe 4GB RAM in meinem PC und die will ich auch komplett nutzen und zwar auch in einem Programm! Geht halt nicht, ist Architektur bedingt und gut ist.
Wenn Du nur ein 32Bit-System hast dann kann man mit einem Programm eben keine 4 GBytes nutzen, bei meiner 32Bit-Architektur könntest Du das nicht mal mit mehreren Programmen. Auf einem 64Bit-System geht das problemlos, egal ob per Flat-Memory oder per Segmentierung. Es gibt eben immer Grenzen, das ist richtig.

Zitat von: erik
Natürlich ist dem Programmierer bewusst das Speicher nicht unbegrenzt zur Verfügung steht aber warum soll der Stack eine "kleine" Grenze haben und der Heap nicht?
Weil es halt so ist.
Ungenügend! Sorry, aber das ist keine Begründung.

Du hast eine Sache vergessen, zusätzliche Programme ;)
Das war mit den "...." bei "Compiler/Assembler/Linker/....-spezifische Tricks" gemeint. ;) Es gibt gewiss immer irgendwo ein paar Tricks aber die sind eben nicht Teil des üblichen Weges.

Ansonsten kann man sagen das es auf keinem (mir bekannten) OS ohne irgendwelchen Tricks funktioniert.
Genau darauf wollte ich hinaus. Ohne irgendwelche Spezial-Tricks geht das auf den normalen General-Purpose-OSen nicht.

Jetzt aber die Gegenfrage, was willst du mit diesen 256MB machen.
Das ist doch gar nicht der relevante Punkt. Es könnte ja sein das der Programmierer eines Programms immer nur kleine Workloads gesehen hat und für ein bestimmtes Problem eben auf VLAs zurückgreift aber der Endanwender deutlich größere Workloads benutzt und natürlich keine Ahnung von den Grenzen des System hat. Bei Flat-Memory muss eben der Programmierer immer aufpassen was er macht wenn er den Stack benutzen möchte wogegen er das bei Segmentierung nicht tun muss. Klar werde auch ich die maximale Größe (bis zu der mein OS Stack-Segmente selbstständig vergrößert) vorgeben, ich denke mal 256 MByte sollten für die 32Bit-Variante angemessen sein und für die 64Bit-Variante wohl 4 GByte oder auch 1 TByte (wenn es zum Swapping kommt ist das ein Problem des Anwenders und vor allem unabhängig davon ob dieser Speicherbedarf nun per Heap oder per Stack generiert wurde). Was mich an Flat-Memory stört ist das diese Grenze für den Stack so unverhältnismäßig klein ist in Relation zu den anderen Grenzen, für jemand der von Speicherlayouts keine Ahnung hat ist das einfach nicht nachvollziehbar.

dürften die Nachteile die (noch nicht von dir genannten) Vorteile aufwiegen.
Der Vorteil flexibler Stacks ist einfach die Flexibilität die den Programmierer entlastet und auch etwas Performance bringt. Welche grundsätzlichen Nachteile siehst Du denn in großen Stacks (mal von den internen Problemen der von Dir benutzten Speicherverwaltung abgesehen)?

Noch eine Sache, wenn du solche großen Stacks zulässt musst du ja auch immer diesen Bereich reservieren
Oder ich entscheide mich für ein Speicher-Model das damit grundsätzlich keine Probleme hat.


Als rein willkürlche Erziehungsmaßnahme für den Programmierer?
Manchmal sind aber ein paar Erziehungsmaßnamen einfach erforderlich damit die Programmierer nicht auf zu blöde Gedanken kommen. Denn wenn man ihnen den kleinen Finger reicht wollen die als nächstes den ganzen Arm und wenn man den Arm nicht so gut verteidigen kann ist es manchmal besser schon beim kleinen Finger eine künstliche Grenze zu ziehen (auch wenn der kleine Finger noch kein Problem darstellt) damit man insgesamt weniger Aufwand hat. ;)


Das Problem ist einfach, das ich Exceptions gerne aus dem Kernel raushalten möchte und es ist halt blöd wenn ich vor jedem Stackzugriff (und damit meine ich wirklich jeden) erstmal gucken müssten ob der Speicher auch wirklich gemappt ist usw.
Wofür hast Du denn dann für jeden einzenen Thread in Deinem System noch einen zusätzlichen Kernel-Mode-Stack? Auf diesen müsste doch beim Ring-Wechsel automatisch umgeschalten werden, oder etwa nicht?

Wenn ich aber einfach nur teste ob der Stack innerhalb des Stacks vom Thread liegt, ist das eine einzige Überprüfung und ich brauche mir dann, was das betrifft keine Sorgen mehr machen.
Das könnte eventuell etwas zu naiv sein, wenn ESP 4 Bytes vor der Guard-Page steht dann wirst Du spätestens beim zweiten PUSH auch so ein Problem haben.

Allerdings muss ich dann wenn ich Daten aus dem UserSpace in den KernelSpace kopieren will wieder bei jedem Zugriff kontrollieren ob der auch in Ordnung geht.
Aber nur solche Zugriffe sind doch überhaupt gefährdet und die sollten doch bei einem Micro-Kernel wirklich extrem selten sein (also mir fallen da nur ganz wenige Syscalls ein wo das überhaupt erforderlich ist).


Grüße
Erik
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: Svenska am 01. June 2011, 13:34
Jetzt aber die Gegenfrage, was willst du mit diesen 256MB machen.
Beispielsweise einen rekursiven FloodFill in der Bildverarbeitung zur Objektranderkennung benutzen. Je nach Bildinhalt ist die Rekursionstiefe enorm.
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: FlashBurn am 01. June 2011, 13:46
Zitat von: erik
Das Problem kommt IMHO daher das Du den Stack als etwas besonderes betrachtest und speziell behandelst.
Aus VMM Sicht nicht, der kennt sowas wie nen Stack gar nicht.

Zitat von: erik
Ich würde Stack eher als normalen Speicher mit MAP_LAZY betrachten und die Guard-Page ist einfach eine "freie" Page im virtuellen Adressraum am Ende vom Stack bei deren Zugriff eben der Prozess gekillt wird (so wie bei jedem anderen Pagefault auf andere nicht gemappte Pages auch).
Mehr oder weniger so mache ich es auch, aber bei dem Stackbereich der vom OS erstellt wurde, kann ich 100% davon ausgehen das es MAP_LAZY ist, bei dem Stack der vom User kommt, kann ich da nicht mehr von ausgehen, sondern muss davon ausgehen, dass das nicht der Fall ist und genau das möchte ich nicht.
Zumal ich die Guardpage schon als etwas besonderes betrachtet, weil ich so sagen kann das ein Stack-Overflow stattfunden hat und nicht irgendein Zugriff auf eine Page wo das Programm nichts zu suchen hatte.

Zitat von: erik
Wenn Du bei einem Programm das von seinen 2 GByte virtuellen Adressraum gerade mal 10 MByte benutzt jedes kleine Datenhäppchen komplett zufällig verstreust so das es keine Lücke mit mehr als 16 MByte mehr gibt dann bist Du selber schuld, denn kann man die 16 MByte gar nicht mehr allozieren (weder per Stack noch per Heap).
Wir sind doch aber inzwischen bei 256MB auf dem Stack und da wird das mit den Lücken schon problematisch. Dann kommt es noch drauf an, wie viele Libraries du nutzt und viele Threads du nutzt usw usf.

Zitat von: erik
Es könnte ja sein das der Programmierer eines Programms immer nur kleine Workloads gesehen hat und für ein bestimmtes Problem eben auf VLAs zurückgreift aber der Endanwender deutlich größere Workloads benutzt und natürlich keine Ahnung von den Grenzen des System hat.
Das ist dann ganz eindeutig ein Programmierfehler! Ich kann ja auch nicht sagen, normalerweise werden da Zahlen eingegeben und ich rechne mit nichts anderem. Das sind Fehler und die müssen abgefangen werden.

Du bist doch sogar jemand gewesen, der meinte man muss auch nen Überlauf von nem 64bit Timer (der erst in mehreren hundert Jahren passieren wird) abfangen. Jetzt sagst du mit einmal muss man ja doch nicht, weil es halt selten bis gar nicht auftritt?!

Zitat von: erik
Der Vorteil flexibler Stacks ist einfach die Flexibilität die den Programmierer entlastet und auch etwas Performance bringt. Welche grundsätzlichen Nachteile siehst Du denn in großen Stacks (mal von den internen Problemen der von Dir benutzten Speicherverwaltung abgesehen)?
Du solltest ab einer gewissen Größe einfach den Speicher auch ausrichten und das hieße ja, dass du jedes Mal nachprüfen musst, ob diese Größe vorhanden ist oder nicht und dann gegebenenfalls ausrichten muss. Da kann ich dann auch malloc/free aufrufen.

Vorallem wenn ich mir sowas wie nen 256MB Array vorstelle, würde ich sagen ist es schneller wenn man es sofort mappen lassen würde und auch gleich durch 4MB Pages. Da kann dann der Stack wieder von der Performance her nicht mithalten, da dieser immer erstmal nen Pagefault wirft und jedes Mal eine 4KB Page mappt. Dann kommt noch hinzu das ja 4MB Pages nen extra TLB haben. Außerdem, wenn du auf solch einem Array arbeitest, sollte die Zeit der Erstellung keine Rolle spielen (wie ich schon sagte).

Unter 64bit sollte das alles kein Problem sein, da man dort genügend virtuellen Speicher zur Verfügung hat, aber unter 32bit muss man halt Kompromisse eingehen. Obwohl ich auch unter 64bit (oder gerade da) lieber große Pages den 4KB Pages vorziehen würde (der Performance wegen).

Zitat von: erik
Oder ich entscheide mich für ein Speicher-Model das damit grundsätzlich keine Probleme hat.
Meinst du damit jetzt zw. Flat-Paged-Memory und Segmented-Memory? Weil, da habe ich nicht wirklich eine Wahl!

Zitat von: erik
Wofür hast Du denn dann für jeden einzenen Thread in Deinem System noch einen zusätzlichen Kernel-Mode-Stack? Auf diesen müsste doch beim Ring-Wechsel automatisch umgeschalten werden, oder etwa nicht?
Jap, aber die Parameter für den Syscall liegen auf dem UserMode Stack.

Zitat von: svenska
Beispielsweise einen rekursiven FloodFill in der Bildverarbeitung zur Objektranderkennung benutzen. Je nach Bildinhalt ist die Rekursionstiefe enorm.
Keine Ahnung was das ist, aber da weißt du ja, dass das Eintreten kann und musst also entsprechende Vorkehrungen treffen und wie steht das im Verhältnis zur Bildgröße? Läuft das auch per Multithreading (wo es dann echt Probleme geben wird)?
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: erik.vikinger am 01. June 2011, 15:16
Hallo,


Zumal ich die Guardpage schon als etwas besonderes betrachtet, weil ich so sagen kann das ein Stack-Overflow stattfunden hat und nicht irgendein Zugriff auf eine Page wo das Programm nichts zu suchen hatte.
Da nützt Dir auch die Guard-Page nichts, auf die könnte auch zufällig ein uninitialisierter Pointer zeigen. Einigermaßen (aber nicht zu 100%) sicher kannst Du das ermitteln indem Du den verursachenden Befehle analysierst ob das z.B. PUSH war oder sonstwie per ESP oder EBP zugegriffen wurde (EBP ist zwar ein gutes Indiz aber keine Garantie für einen Stack-Zugriff).

Wir sind doch aber inzwischen bei 256MB auf dem Stack
Nein, hierbei waren wir noch bei 16 MBytes. Aber das ist auch völlig egal, wenn Du für eine bestimmte Speicheranforderung keine passende Lücke mehr hast dann geht die eh nicht. Egal ob per Stack oder per Heap! Was mich am Flat-Memory-Model stört ist das dort der Stack eine zusätzliche/künstliche und unverhältnismäßig kleine Grenze bekommt. Auch auf einem 64Bit-System ist diese Grenze für den Stack deutlich kleiner als für den Heap (wenn auch insgesamt auf höherem Niveau) und das ist einfach ein konzeptioneller Bug.

Das sind Fehler und die müssen abgefangen werden.
Die Größe des Workloads ist doch kein Fehler. Das Problem, welches ich hier anprangere, ist das Flat-Memory den Programmierer dazu zwingt anhand der Workload-Größe eine Fallunterscheidung (kleines kommt auf den Stack und großes auf den Heap) zu machen oder man wählt grundsätzlich den sichereren Weg und opfert dafür immer Performance.

Wenn für den Stack die selben Limits gelten würden wie für den Heap dann wäre ein Stack-Overflow immer das selbe wie ein Out-of-Memory, bei new gibt es doch eine SW-Exception wenn kein Speicher mehr vorhanden ist und bei einem Funktionsaufruf gibt es dann eben auch eine SW-Exception wenn nicht mehr genug Stack verfügbar ist. Wenn die Grenzen jeweils identisch sind kann ich mich als Programmierer je nach Aufgabenstellung für die elegantere Lösung entschieden und muss da keine Fallunterscheidung bauen, nebst dessen das so eine Fallunterscheidung oft gar nicht vorher machbar ist (weil man, so wie in Svenskas Beispiel, den Aufwand nicht vorher abschätzen kann). Es geht jedenfalls nicht darum irgendwelche Fehler-Erkennungsmaßnahmen einzusparen sondern um unnütze Komplexität die bei einem flexibleren Speicher-Model nicht erforderlich wäre.

Den Speicher auf dem Stack auszurichten kostet genau 2 zusätzliche Assemblerbefehle (beim Aufräumen macht das gar keinen Zusatzaufwand), an den hohen Preis eines malloc kommt das noch lange nicht ran.

Das einzigste was bleibt ist die Größe der Pages, aber auch hier könnte das OS ja von sich aus größere Pages benutzen wenn es genügend zusammenhängenden virtuellen Speicher im Prozess gibt. Und spätestens bei Segmentierung ist auch das wieder hinfällig weil man dort ja das teure Paging ganz abschalten kann.

Meinst du damit jetzt zw. Flat-Paged-Memory und Segmented-Memory? Weil, da habe ich nicht wirklich eine Wahl!
Das Du keine Wahl hast liegt daran das Du nicht wählen willst. Wer zwingt Dich denn Dich mit Flat-Memory zufrieden zu geben?

Die Welt in der wir leben gestalten wir selber! Wer auch sonst?


Grüße
Erik
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: FlashBurn am 01. June 2011, 16:14
Zitat von: erik
Da nützt Dir auch die Guard-Page nichts, auf die könnte auch zufällig ein uninitialisierter Pointer zeigen. Einigermaßen (aber nicht zu 100%) sicher kannst Du das ermitteln indem Du den verursachenden Befehle analysierst ob das z.B. PUSH war oder sonstwie per ESP oder EBP zugegriffen wurde (EBP ist zwar ein gutes Indiz aber keine Garantie für einen Stack-Zugriff).
Das ist ein interessanter Ansatz, schonmal unter akutellen OS ausprobiert, was passiert wenn man auf die Guardpage zugreift?

Ich würde mich immer auf ESP konzentrieren, weil das eigentlich immer den Momenten "Stackverbrauch" anzeigen sollte.

Zitat von: erik
Auch auf einem 64Bit-System ist diese Grenze für den Stack deutlich kleiner als für den Heap (wenn auch insgesamt auf höherem Niveau) und das ist einfach ein konzeptioneller Bug.
Ich denke eher, dass das Problem ist, das jedes Anwendung den Speicher anders nutzt und du irgendeine Möglichkeit bieten müsstest den Stack entsprechend zu konfigurieren und das könnte an der Portabilität scheitern.

Ich meine wann braucht man nen großen Stack, wenn man viele lokale Sachen hat, aber globale Sachen wirst du ja wohl nicht auf den Stack packen oder? Ich meine damit besonderns, wenn es ums Multithreading geht und mehrere Threads sollen auf einem Buffer oder einer Datenstruktur arbeiten. Sicher könnte man das auch irgendwie mit nem Stack lösen, aber wäre das nicht wieder umständlicher und aufwändiger (vorallem unter 32bit)?

Zitat von: erik
Die Größe des Workloads ist doch kein Fehler. Das Problem, welches ich hier anprangere, ist das Flat-Memory den Programmierer dazu zwingt anhand der Workload-Größe eine Fallunterscheidung (kleines kommt auf den Stack und großes auf den Heap) zu machen oder man wählt grundsätzlich den sichereren Weg und opfert dafür immer Performance.
Das meinte ich auch gar nicht, sondern das es ein Fehler ist ein bekanntes Problem nicht abzufangen. Was bringt es dir, wenn du trotzig sagst, aber der Stack müsste das halt schaffen und dein Programm funktioniert dann halt nicht?

Zitat von: erik
Wenn für den Stack die selben Limits gelten würden wie für den Heap dann wäre ein Stack-Overflow immer das selbe wie ein Out-of-Memory, bei new gibt es doch eine SW-Exception wenn kein Speicher mehr vorhanden ist und bei einem Funktionsaufruf gibt es dann eben auch eine SW-Exception wenn nicht mehr genug Stack verfügbar ist.
Und wo kommt dann die Exception hin (vom Speicher her)? Ich meine wenn der Stack voll ist kannst du die Exception ja nicht mehr werfen und abfangen lassen, weil nix mehr auf den Stack geht.

Zitat von: erik
Den Speicher auf dem Stack auszurichten kostet genau 2 zusätzliche Assemblerbefehle (beim Aufräumen macht das gar keinen Zusatzaufwand), an den hohen Preis eines malloc kommt das noch lange nicht ran.
Wie willst du das machen? Und auf welchen Wert willst du ausrichten? Ich meine wenn ich nen 16byte Objekt habe, muss das nicht an 4k ausgerichtet werden, aber bei ein paar MB wäre das sicher nicht verkehrt und wenn wir dann zu den großen Pages kommen und du nen großes Objekt hast, willst bzw. musst du es halt an z.B. 4MB ausrichten und du kannst den Speicher dazwischen nicht nutzen, was bei malloc kein Problem wäre.

Zitat von: erik
Und spätestens bei Segmentierung ist auch das wieder hinfällig weil man dort ja das teure Paging ganz abschalten kann.
Reden wir jetzt von der Theorie oder der Praxis? Weil seien wir ehrlich, in der Praxis gibt es keine Segmentierung mehr.

Zitat von: erik
Das Du keine Wahl hast liegt daran das Du nicht wählen willst. Wer zwingt Dich denn Dich mit Flat-Memory zufrieden zu geben?
Meine Zeit, mein Geld, meine Intelligenz (weil ich einfach nicht in der Lage wäre sowas selber zu designen) und es gibt bestimmt noch mehr Sachen.

Solange ich vorhandene Möglichkeiten (und aktuelle und portable) nutzen möchte, gibt es halt nur Flat-Memory.
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: erik.vikinger am 01. June 2011, 16:58
Hallo,


Ich denke eher, dass das Problem ist, das jedes Anwendung den Speicher anders nutzt
Richtig!

und du irgendeine Möglichkeit bieten müsstest den Stack entsprechend zu konfigurieren und das könnte an der Portabilität scheitern.
Nein, ich erwarte das sich das System den aktuellen Bedürfnissen (die jedes mal anders sein können) meines Programms selber anpasst. Natürlich ist mir klar dass das mit Flat-Memory nur sehr begrenzt funktioniert, als Programmierer muss ich mich oft mit den daraus resultierenden Restriktionen auseinander setzen (beruflich und privat). Ich weiß das ich nicht einfach so programmieren kann wie ich es gerne würde, ich weiß aber auch das es besser geht und genau das ist es was mich ärgert (und um zu beweisen das es wirklich besser geht hab ich mich dazu entschlossen ein passendes System zu entwickeln).

Ich meine wann braucht man nen großen Stack
Rekursion und VLAs sind Beispiele die für kleine Workloads oft die optimale Performance bringen aber eben bei größeren Workloads auf die Nase fallen. Als Programmierer muss ich mich nun entscheiden ob ich eine Art Fall-Back-Lösung implementiere (also für mein eines Problem zwei verschiedene Lösungen entwickle) und eine passende Fallunterscheidung dazu packe oder ob ich einfach immer den sichereren Weg gehe (um Code und Arbeit zu sparen, außerdem gibt es ja auch Probleme wo so eine Fallunterscheidung gar nicht einfach möglich ist) und dafür eben bei kleinen Workloads auf Performance verzichte, ich persönlich empfinde solche Entscheidungen als eklig. Viel lieber würde ich bei der Wahl der richtigen Lösung eher auf Eleganz, Einfachheit und Performance achten als auf die Zwänge des verwendeten Systems.

Und ich bin nicht trotzig! ;) Ich passe mich den Zwängen von Flat-Memory immer wieder erfolgreich an, was u.a. daran liegt das ich diese genau kenne und verstehe.

Und wo kommt dann die Exception hin (vom Speicher her)?
Dieses Problem hat man doch bei jeder Art von Out-of-Memory-Exception also wird es dafür auch passende Lösungen geben, nebst dessen das man beim Stack ja nicht erst dann abbrechen muss wenn wirklich gar nichts mehr geht (ein paar 100 Bytes Notreserve würden bei einem Stack der etliche MB groß werden kann nichts mehr ausmachen).

Wie willst du das machen?
Also wenn Du nicht weißt wie man einen Integer auf das nächst kleinere Vielfache einer bestimmten Zweierpotenz aufrundet dann werd ich das wohl auch nicht erklären können. Wenn die Zweierpotenz zur Compilezeit fest steht dann sind das eben 2 Assemblerbefehle, ansonsten ein paar mehr aber immer noch deutlich weniger als malloc.

Und auf welchen Wert willst du ausrichten?
Das ist Sache des Compilers, aber eventuell kann ich diesem ja per pragma o.ä. einen Hinweis geben.

Warum ich auf 4 kB oder gar 4 MB ausrichten sollte verstehe ich aber nicht, mehr als auf die Größe einer Cache-Line lohnt sich einfach nicht.

Weil seien wir ehrlich, in der Praxis gibt es keine Segmentierung mehr.
Wenn der PC an dem Du gerade sitzt einen (oder mehrere) x86-Prozessor hat dann steht vor Dir der Beweis das es Segmentierung real gibt (auch wenn Personen wie ich der Meinung sind das die Segmentierung des 386-PM noch längst nicht das Optimum darstellt so ist diese immerhin eine recht brauchbare Grundlage). Alles was Dir fehlt ist ein passendes OS und das kostet Dich als praktizierender OS-Dever zumindest kein Geld.


Grüße
Erik
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: FlashBurn am 01. June 2011, 17:24
Zitat von: erik
Dieses Problem hat man doch bei jeder Art von Out-of-Memory-Exception also wird es dafür auch passende Lösungen geben, nebst dessen das man beim Stack ja nicht erst dann abbrechen muss wenn wirklich gar nichts mehr geht (ein paar 100 Bytes Notreserve würden bei einem Stack der etliche MB groß werden kann nichts mehr ausmachen).
Ich habe hier ein Problem damit, dass ich nicht wüsste wie ich feststellen kann ob das Ende das Stacks schon erreicht ist oder nicht (vorallem wenn es dynamisch ist).

Zitat von: erik
Also wenn Du nicht weißt wie man einen Integer auf das nächst kleinere Vielfache einer bestimmten Zweierpotenz aufrundet dann werd ich das wohl auch nicht erklären können. Wenn die Zweierpotenz zur Compilezeit fest steht dann sind das eben 2 Assemblerbefehle, ansonsten ein paar mehr aber immer noch deutlich weniger als malloc.
Spontan weiß ich es wirklich nicht, aber könnte es bestimmt brauchen (ich weiß wie es mit ein paar mehr Befehlen geht). Also versuch es mal.

Ansonsten sprachen wir von VLAs und sowas, also dynamische Sachen die nicht zur Compilezeit bekannt sind und ja das eigentliche Problem darstellen.

Zitat von: erik
Warum ich auf 4 kB oder gar 4 MB ausrichten sollte verstehe ich aber nicht, mehr als auf die Größe einer Cache-Line lohnt sich einfach nicht.
Naja, es gibt da erstens mal Sachen die wohlen an einer bestimmten 2er Potenz ausgerichtet werden (ist z.B. beim FPU Kontext so und ich glaube auch bei einiges SSE Sachen), das könnte man natürlich lösen in dem man immer ne größere Menge vom Stack holt und die Adresse dann ausrichtet.
Aber um auf z.B. die 4MB zurück zu kommen. Wenn ich nen 256MB Array allozieren möchte und richtig Performance brauche, dann will ich 4MB große Pages nutzen und dafür muss die Adresse auch virtuell an 4MB ausgerichtet sein.

Zitat von: erik
Wenn der PC an dem Du gerade sitzt einen (oder mehrere) x86-Prozessor hat dann steht vor Dir der Beweis das es Segmentierung real gibt (auch wenn Personen wie ich der Meinung sind das die Segmentierung des 386-PM noch längst nicht das Optimum darstellt so ist diese immerhin eine recht brauchbare Grundlage).
Also erstens gibt es nicht nur PCs mit x86 CPUs und zweitens, wollten wir doch aktuell bleiben und da zählt dann 64bit und da gibt es das nicht mehr. Dann kommt noch hinzu das ich mir meinen eigenen Compiler schreiben müsste bzw. einen vorhandenen modifizieren müsste und das übersteigt dann wirklich meine momentanen Fähigkeiten (obwohl ich so nen Compiler auch sehr interessant finde ;) ).
Portabel wäre das ganze dann aber immernoch nicht.

Zumal das Problem, das sich nicht grundsätzlich (oder besser sogar meistens) das bessere durchsätzt, bestehen bleibt. Du stehst dann also mit deiner Architektur alleine da. Aus Hobbysicht ist das in Ordnung und sogar zu begrüßen (weil du was wirklich eigenes und so noch nicht vorhandenes geschaffen hast und auf dich stolz sein kannst), aber aus wirtschaftlicher Sicht ist das eben scheiße.

Aus genau dem Grund denke ich auch das sich ARM (so wie die Systeme momentan funktionieren/aufgebaut sind) nicht so richtig im allgemeinen PC Markt ein richtiger Gegner für Intel wird. Bei Servern vllt, aber nicht für Ottonormalverbraucher der auch Spielen will.
Denn aus OS Dever Sicht sind die ARM Systeme eine wahre Quahl :( Es gibt sicher Möglichkeiten da was zu machen (ich habe da auch schon so meine Ideen), aber viele Sachen sind einfach zu unterschiedlich trotz eventuell halbwegs gleicher CPU.
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: erik.vikinger am 02. June 2011, 11:24
Hallo,


Ich habe hier ein Problem damit, dass ich nicht wüsste wie ich feststellen kann ob das Ende das Stacks schon erreicht ist oder nicht (vorallem wenn es dynamisch ist).
Hm, stimmt, dafür bieten typische Flat-Memory-Systeme gar keinen Mechanismus an. Aber große/dynamische Stacks scheitern bei Flat-Memory schon an ganz anderen Dingen. Eigentlich war das mit der SW-Exception beim Stack-Ende ja auch auf mein System bezogen und ich hab geeignete HW-Mechanismen (eben die Segmentierung) um das sauber zu managen.

Spontan weiß ich es wirklich nicht, aber könnte es bestimmt brauchen (ich weiß wie es mit ein paar mehr Befehlen geht). Also versuch es mal.
Okay, nehmen wir an Du möchtest auf 2^8 Ausrichten (also die 8 ist gegeben) dann nehmen wir folgende Formel:align = 8;
ptr_align = ( ptr + ((1 << align)-1) ) & (~((1 << align)-1));
Das "((1 << align)-1)" wird zu 0x000000FF und das "(~((1 << align)-1))" wird zu 0xFFFFFF00. Diese zwei Parameter kann der Compiler zur Compilezeit ermitteln, falls die 8 fest vorgegeben ist, so das nur eine Addition und eine Und-Operation bleiben um von einem beliebigen ptr auf einen ausgerichteten ptr_align aufzurunden. Falls die 8 nicht fest sondern dynamisch ist kommen noch ein Shift-Links, eine Subtraktion und eine NOT-Operation hinzu. Das ganze in valide Assemblerbefehle zu überführen überlasse ich jetzt trotzdem mal Dir, aber ich denke Du weißt jetzt wie das geht.

Ansonsten sprachen wir von VLAs und sowas, also dynamische Sachen die nicht zur Compilezeit bekannt sind und ja das eigentliche Problem darstellen.
Naja, die Ausrichtung ansich (also die zugrunde liegende Zweierpotenz) sollte eigentlich schon zur Compilezeit bekannt sein.

Aber um auf z.B. die 4MB zurück zu kommen. Wenn ich nen 256MB Array allozieren möchte und richtig Performance brauche, dann will ich 4MB große Pages nutzen und dafür muss die Adresse auch virtuell an 4MB ausgerichtet sein.
Selbst auf einem Paging-basierten Flat-Memory-System ist es nicht unbedingt erforderlich einen 256 MB-Puffer auf 4 MB auszurichten, es muss doch nur möglich sein das der gesamte Puffer mit möglichst großen Pages gemappt wird und wenn vor und hinter den Puffer auch Daten liegen (so das auch bei einem unausgerichteten Puffer die erste und letzte Page voll genutzt wird) dann sollte das auch funktionieren. Für den CPU-Cache ist nur eine Ausrichtung auf die Cache-Line-Größe relevant. Gröbere Alignmets können eventuell sogar störend wirken wie wir damals beim Hyper-Threading des Pentium 4 gesehen haben.

Also erstens gibt es nicht nur PCs mit x86 CPUs und zweitens, wollten wir doch aktuell bleiben und da zählt dann 64bit und da gibt es das nicht mehr.
Das ist natürlich beides richtig, trotzdem würden die CPU-Hersteller das anders machen wenn denn eine echte Nachfrage bestünde.

Mit dem "Wer zwingt Dich denn Dich mit Flat-Memory zufrieden zu geben?" war auch gemeint "Wer zwingt Dich denn die Flat-Memory-CPUs zu kaufen? Als mündiger Verbraucher kannst Du Dich doch auch dazu entschließen die nicht zu kaufen.". Ich weiß dass das ein doofer Spruch ist, einfach weil wenn Du der einzigste bist der nein sagt dann interessiert das die CPU-Herstellen ziemlich genau gar nicht.
Falls ich mit meinem System erfolgreich bin und zeigen kann das es auch besser geht entsteht da vielleicht doch auch etwas mehr Nachfrage nach Alternativen. ;) Jaja, in meinem Alter hat man noch träume.

Dann kommt noch hinzu das ich mir meinen eigenen Compiler schreiben müsste bzw. einen vorhandenen modifizieren müsste und das übersteigt dann wirklich meine momentanen Fähigkeiten
Ich hab das auch noch nie gemacht und trotzdem denke ich mir "man wächst auch an seinen Aufgaben".

Portabel wäre das ganze dann aber immernoch nicht.
Was IMHO noch nicht mal ein echtes Problem wäre. Wenn Du mit funktionierender Segmentierung zeigen kannst das Du alle Flat-Memory-Programme ausführen kannst aber die Flat-Memory-Systeme Deine Programme nicht ausführen können hast Du doch klar Deine Überlegenheit demonstriert, vor allem wenn Deine Programme auch noch deutlich einfacher/eleganter/... sind.

Zumal das Problem, das sich nicht grundsätzlich (oder besser sogar meistens) das bessere durchsätzt, bestehen bleibt.
Das ist zwar richtig, aber wenn sich das Schlechtere durchgesetzt hat hatte das meistens bestimmte Gründe die sich aus dem Umfeld ergeben haben, an denen kann man ja arbeiten.

(weil du was wirklich eigenes und so noch nicht vorhandenes geschaffen hast und auf dich stolz sein kannst)
Oh ja, wenn ich das wirklich hinkriege werde ich sicher vor lauter Stolz fast platzen. ;)

Denn aus OS Dever Sicht sind die ARM Systeme eine wahre Quahl
Also da übertreibst Du schon ein wenig. ARM bemüht sich doch nun schon seit ein paar Jahren viele der Infrastruktur-Details (wie IRQ-Controller usw.) zu vereinheitlichen. Aber wenn selbst Microsoft zumindest ein paar ARM-Systeme mit seinem nächsten Windows unterstützen möchte dann werden die HW-Hersteller auch den entsprechenden Druck spüren und sich bemühen die Systeme ähnlich einheitlich zu gestalten wie die PC-Plattform.


Grüße
Erik


PS.: ob rizor eigentlich böse auf uns zwei ist weil wir seinen Thread so arg haben abdriften lassen?
Auch sonst sollten wir vielleicht ein wenig vorsichtiger sein, immerhin sind bereits 4 der "Top 10 Themen" im wesentlichen durch unsere laaaaangen Dialoge entstanden. Nicht das man uns hier nach raus wirft wegen Überlastung der Forumsdatenbank. :roll:
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: FlashBurn am 02. June 2011, 12:09
Das mit dem alignen kenne ich doch schon ;) Irgendwie war im in dem Moment nicht bewusst das es genau das ist.

Zitat von: erik
Naja, die Ausrichtung ansich (also die zugrunde liegende Zweierpotenz) sollte eigentlich schon zur Compilezeit bekannt sein.
Wie kommst du darauf? Ich meine man nutzt ja VLAs weil es halt nicht zur Compilezeit bekannt ist und wenn in 99% der Fälle immer Sachen <1024 auftreten, aber halt in einem Prozent der Fälle dann alles andere kommen kann, kannst du die zweier Potenz halt nicht wissen.

Zitat von: erik
Selbst auf einem Paging-basierten Flat-Memory-System ist es nicht unbedingt erforderlich einen 256 MB-Puffer auf 4 MB auszurichten, es muss doch nur möglich sein das der gesamte Puffer mit möglichst großen Pages gemappt wird und wenn vor und hinter den Puffer auch Daten liegen (so das auch bei einem unausgerichteten Puffer die erste und letzte Page voll genutzt wird) dann sollte das auch funktionieren.
Ich dachte da jetzt auch an die TLBs, die ja doch ganz schön voll sein werden (gibt es dazu eigentlich mal Benchmarks oder Abhandlungen ab welcher Größe ein TLB nicht mehr wesentlich mehr Performance bringt?) und da könnte es schon was bringen wenn nicht erst im RAM nachgeguckt werden muss. Zumal kommt dann noch hinzu das man im RAM dann 1024 mal für eine 4MB Page nachgucken müsste. Meinst du nicht dass das Auswirkungen hat?

Zitat von: erik
Als mündiger Verbraucher kannst Du Dich doch auch dazu entschließen die nicht zu kaufen.
Dieser Aussage konnte ich schon in dem Fach Wirtschaftsethik nicht zustimmen. Was machst du wenn du halt keine Wahl, also keine Alternative, hast? Ich will was bestimmtes machen, aber habe nur eine einzige Möglichkeit das zu machen. Da muss ich mich dann entscheiden zw machen oder nicht machen und das ist für mich keine wirkliche Wahl.

Zitat von: erik
Das ist zwar richtig, aber wenn sich das Schlechtere durchgesetzt hat hatte das meistens bestimmte Gründe die sich aus dem Umfeld ergeben haben, an denen kann man ja arbeiten.
Ich behaupte mal das es oft einfach am fehlendem Kapital lag. Der mit der dickeren Breiftasche gewinnt nun mal meistens (auch leider im Rechtssystem).

Zitat von: erik
Also da übertreibst Du schon ein wenig. ARM bemüht sich doch nun schon seit ein paar Jahren viele der Infrastruktur-Details (wie IRQ-Controller usw.) zu vereinheitlichen.
Naja, ich sage mal sowas wie den IRQ-Controller kann ich bei meinem Kernel-Design noch verstecken, aber wenn ich dann an nen monolithen denke, da gibt es dann Probleme, die die meisten nicht als Probleme sehen, ich aber schon.

Konkret betrifft es dass du den Kernel für jedes Board neu kompilieren musst, obwohl die selbe Hardware vorhanden ist. Es geht dabei um das Problem, das es nicht sowas wie ACPI oder richtig standardisierte Adressen gibt. Ein und das selbe Gerät kann auf 2 unterschiedlichen Boards (obwohl die selbe Hardware) an unterschiedlichen Adressen sein. Sprich nen monolithen wirst du dann jedes mal mit ner anderen Konfiguration kompilieren um die entsprechenden Adressen zu setzen.
Ein Mikrokernel hat es da schon ein wenig einfacher (obwohl man das was mir vorschwebt auch ganz einfach für nen monolithen umsetzen kann), ich möchte dann einfach die Adressen in eine Konfigurationsdatei speichern (und die gesamte Hardware die auf so einem Board vorhanden ist -> auch ein Problem, wie stellt man fest was vorhanden ist?) und mein Device-Server lädt dann die entsprechenden Treiber und mappt ihnen den Speicher der Geräte.

Zitat von: erik
Auch sonst sollten wir vielleicht ein wenig vorsichtiger sein, immerhin sind bereits 4 der "Top 10 Themen" im wesentlichen durch unsere laaaaangen Dialoge entstanden. Nicht das man uns hier nach raus wirft wegen Überlastung der Forumsdatenbank.
Denke (oder besser hoffe) ich eigentlich nicht, aber vllt sollte man dann irgendwann mal das Ergebnis (sofern es eins gab) zusammenfassen. Damit es andere dann leichter haben.
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: erik.vikinger am 02. June 2011, 16:00
Hallo,


Das mit dem alignen kenne ich doch schon
Hätte mich auch sehr gewundert wenn es anders wäre, das gehört IMHO schon zu den absoluten Basics die jeder anständige Programmierer kennen sollte.

Ich meine man nutzt ja VLAs weil es halt nicht zur Compilezeit bekannt ist ....
Die Größe des VLA ist natürlich erst zur Laufzeit bekannt aber das Alignment (welches in meinem Beispiel durch die 8 dargestellt wurde) kannst Du schon zur Compilezeit vorgeben. Wenn Du z.B. immer auf 256 Bytes ausrichtest um vom CPU-Cache her die volle Performance zu bekommen dann verschwendest Du zwar ein paar Bytes was aber nur bei kleinen Größen nennenswert ist und da Du ja einen flexiblen Stack hast ist das auch nur halb so schlimm (auf dem Heap hat man bei kleinen Objekten prozentual auch den größeren Verschnitt).

Ich dachte da jetzt auch an die TLBs
Schon klar, aber um 4 MB-Pages nutzen zu können muss der 256 MB-Puffer nicht zwangsläufig an 4 MB ausgerichtet sein. Wenn vor und hinter dem Puffer auch benutzter/gemappter Speicher ist kann man oft trotzdem 4 MB-Pages nutzen. Das heißt man kann auch mit unausgerichteten Daten den TLB schonen.

(gibt es dazu eigentlich mal Benchmarks oder Abhandlungen ab welcher Größe ein TLB nicht mehr wesentlich mehr Performance bringt?)
So viel TLB konnte noch kein CPU-Hersteller implementieren damit man sagen könnten "noch mehr TLB bringt nicht mehr was" und ich bezweifle auch dass das jemals gelingen wird, selbst wenn die CPU-Hersteller noch nen fetten L3-TLB hinten dran hängen wird dessen Latenz dann wieder sehr hoch so das der erzielbare Performancegewinn gegenüber dem Page-Table-LookUp aus dem normalen CPU-Cache (>= L2) heraus wieder vernachlässigbar ist. Vor allem der L1-TLB (den es für Code und Daten in heutigen CPUs getrennt gibt) ist eine extrem Transistor-intensive Angelegenheit und das obwohl der meist nur 8 oder 16 Einträge hat. So ähnlich will ich das auch machen: 2 kleine L1-TLBs mit je 8 Einträgen die immer eine Latenz von nur 1 Takt haben und dahinter einen gemeinsamen L2-TLB mit vielleicht 64 oder 128 Einträgen der dann aber schon zwischen 2 und 10 Takte Latenz haben wird (abhängig von der Page-Größe die ich ja erst weiß wenn ich einen zur aktuellen linearen Adresse passenden Eintrag gefunden hab). Die Grundkosten die Paging verursacht werden mit zunehmender Speichermenge die damit verwaltet wird auch steigen (sicher nicht linear aber doch erheblich, selbst bei enormen Siliziumeinsatz) was einer der Gründe ist warum ich dem mit Segmentierung entgehen will.

Zitat von: erik
Als mündiger Verbraucher kannst Du Dich doch auch dazu entschließen die nicht zu kaufen.
Dieser Aussage konnte ich schon in dem Fach Wirtschaftsethik nicht zustimmen.
Ja, das ist in der Tat eine schwere Entscheidung. Ist eben alles ein Frage der Prioritäten. Wenn Dir das "ob" wichtiger ist als das "wie" dann ist natürlich klar das Du Dich auch mit einem weniger passenden Produkt zufrieden gibst.

Da muss ich mich dann entscheiden zw machen oder nicht machen und das ist für mich keine wirkliche Wahl.
Doch, auch das ist eine Wahl die Du treffen könntest wenn Du den wolltest.

Ich behaupte mal das es oft einfach am fehlendem Kapital lag.
Meistens ja, aber es gab sicher auch schon Fälle wo sich das Bessere durchgesetzt hat wenn den dessen Vorsprung wirklich erheblich ist. Das ist bei der Segmentierung ja mein großer Vorteil, mein Vorsprung wird um so größer je mehr Speicher in einem typischen PC steckt, die Zeit arbeitet also für mich.

Deine ARM-Probleme sind für mich aber nicht wirklich nachvollziehbar, wenn man die Adresse der Geräte wirklich fest einkompiliert hat man es auch nicht besser verdient. Wenn man aus ARM wirklich einen vollwertigen PC machen würde dann liefe das auch auf Bussysteme wie PCI-Express hinaus und damit gibt es dann einen leistungsfähigen P&P-Mechanismus und Dein Problem ist gelöst. Auch in aktuellen PC-Chipsätzen sind die meisten integrierten Geräte PCI-Devices, es gibt in heutigen PCs nur noch wenige Dinge die an festen Adressen hängen. Auch deswegen möchte ich komplett auf PCI setzen, bei mir wird sogar die CPU ein PCI-Device so das ich den da dran befindlichen RAM im OS-Loader so konfigurieren kann wie das OS es gerne hätte ohne mich um HW-spezifische Dinge kümmern zu müssen.

Denke (oder besser hoffe) ich eigentlich nicht, aber vllt sollte man dann irgendwann mal das Ergebnis (sofern es eins gab) zusammenfassen. Damit es andere dann leichter haben.
Ich weiß nicht so recht, wenn wir für die Zusammenfassung noch mal 2 Seiten benötigen wird das schlussendlich auch nicht wirklich übersichtlicher. Vielleicht sollten wir da eine extra Liste mit den "FlashBurn vs. Erik" Themen (mit Link) und dem jeweiligen Ausgang in knapper Kurzform aufmachen in der wir aber nicht diskutieren. ;)


Grüße
Erik
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: FlashBurn am 02. June 2011, 16:09
Zitat von: erik
Doch, auch das ist eine Wahl die Du treffen könntest wenn Du den wolltest.
Spätestens (und das ist jetzt wirklich ne extrem Situation) wenn es um dein eigenes Leben oder um das Lebem dir wichtiger Menschen geht, hast du diese Wahl halt nicht mehr oder meinst du das eine Wahl zw Leben und Tod eine Wahl ist?

Zitat von: erik
Deine ARM-Probleme sind für mich aber nicht wirklich nachvollziehbar, wenn man die Adresse der Geräte wirklich fest einkompiliert hat man es auch nicht besser verdient.
Nicht das die Adressen fest im Kernel einprogrammiert sind, sondern das es keine Möglichkeit gibt (außer man weiß es bzw. man muss es wissen) an die Infos ranzukommen, da es halt sowas wie ACPI nicht gibt. Das meiste wird immer im Bootloader fest einprogrammiert bzw. halt im Linux-Kernel per Konfigurationsskript geregelt.

Es müsste sich halt endlich mal nen Standard festgelegt werden, wie man die Geräte auf der ARM Architektur zur Laufzeit enumerieren kann.
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: erik.vikinger am 02. June 2011, 16:33
Hallo,


oder meinst du das eine Wahl zw Leben und Tod eine Wahl ist?
Rein vom philosophischen Standpunkt aus betrachtet ist auch das eine Wahl, man muss nur den Mut haben sich dieser Wahl auch zu stellen. Je nach Situation wird es sicherlich auch für beide Optionen Argumente geben. Mein eigenes Leben möchte ich jedenfalls nicht um jeden Preis, bei meinem Sohn wären aber wieder meine Gefühle im Spiel die mir eine rationale Entscheidung dann wohl doch nahezu unmöglich machen.

Es müsste sich halt endlich mal nen Standard festgelegt werden, wie man die Geräte auf der ARM Architektur zur Laufzeit enumerieren kann.
Genau das würde PCI ja bringen. Es gibt ja ein paar größere ARM-Controller die bereits voll auf PCI(-Express) setzen. Die Probleme die Du beschreibst kommen ja eher von den (mittleren) Mikrocontrollern.


Was mir noch einfällt: das Meiste worüber wir zwei diskutiert und gestritten haben war ja Speicherverwaltung und SLAB-Allocatoren, vielleicht sollte man mal eine Art Zusammenfassung in der Form
    "Die Ansichten des FlashBurn und des Erik über Speichermanagement im allgemeinen und SLAB-Allocatoren im speziellen"
anfertigen. ;)


Grüße
Erik
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: FlashBurn am 02. June 2011, 17:07
Zitat von: erik
Genau das würde PCI ja bringen.
Ich weiß von meinem AC100 (Tegra2), das er wohl kein PCI Bus hat. Zumal dann immernoch das Problem wäre, wie greifst du auf den PCI Bus zu, wenn du nicht weißt an welche Adresse die Register gemappt wurden?
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: Svenska am 02. June 2011, 19:24
Denn aus OS Dever Sicht sind die ARM Systeme eine wahre Quahl :( Es gibt sicher Möglichkeiten da was zu machen (ich habe da auch schon so meine Ideen), aber viele Sachen sind einfach zu unterschiedlich trotz eventuell halbwegs gleicher CPU.
Du verwechselst die CPU-Architektur mit der Plattform. Die CPU-Architektur ist eben keine Qual (sondern sogar ziemlich effizient und einfach zu programmieren, im Gegensatz zu x86), aber es gibt keine standardisierte Plattform.

Bei x86 haben sich nur zwei Plattformen durchgesetzt: IBM-PC und Apple Mac. Es gab früher mehr Plattformen, auf denen auch DOS lief, denn DOS ist plattformunabhängig trotz Assembler: In einem Betriebssystemdesign musst du nur den HAL (DOS: IO.SYS) entsprechend auslegen. Je nach CPU hast du eine gewisse Menge an OnChip-Hardware, da zählt auch der PCI-Controller dazu und wenn die große Masse der Geräte PCI-Geräte sind, dann ist der Rest egal.

Die neuen ARM Cortexe sind auf dem richtigen Weg (z.B. standardisierter IRQ-Controller NVIC). Wobei ich persönlich bezweifle, dass sich in der nächsten Zeit eine Plattform etabliert - das ist nicht im Interesse der entwickelnden Firmen und dem Endkunden ist es egal, da reichen die Betriebssystemtreiber für das mitgelieferte Betriebssystem (WinCE, Linux) aus.

Schade finde ich, dass z.B. vom OpenTom-Projekt nichts mehr passiert ist. Aber das ist jetzt endgültig OffTopic.

Gruß,
Sebastian
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: FlashBurn am 02. June 2011, 20:41
Zitat von: svenska
Du verwechselst die CPU-Architektur mit der Plattform.
Ah, wieder was gelernt ;) Ich meine natürlich die Plattform.
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: FlashBurn am 04. June 2011, 16:07
Auch wenn es nicht hierhin gehört (wollte aber keinen eigenen Thread aufmachen, da nur nen Hinweis) dank vorallem MS (so wie es scheint; Windows 8) scheint UEFI die Firmware für ARM SoCs zu werden. Damit wäre doch eine große Hürde genommen (ob man UEFI nun mag oder nicht).
Titel: Re:SLAB-Allocator als Basis fuer kmalloc?
Beitrag von: erik.vikinger am 06. June 2011, 21:07
Hallo,


Ich weiß von meinem AC100 (Tegra2), das er wohl kein PCI Bus hat.
Der Tegra2 hat auf jeden Fall einen PCI-Express-Root drin (leider nur einen Port mit nur einer Lane und nur 2,5GBit/s). Wie viele der internen Devices noch als PCI-Device verwaltet werden weiß ich aber auch nicht. Von einigen Marvell-ARM-SoCs weiß ich das die ebenfalls PCI-Express-Roots drin haben (sogar mehrere Ports und auch jeweils mit mehreren Lanes) und auch einige der internen Devices (u.a. SATA-Host-Controller oder Ethernet-NICs) als PCI-Devices verwaltet werden.

Zumal dann immernoch das Problem wäre, wie greifst du auf den PCI Bus zu, wenn du nicht weißt an welche Adresse die Register gemappt wurden?
Da würde sich bei ARM ja gerade dieses Coprozessor-Interface anbieten, auf diese Weise würden keine besonderen Speicheradressen von Nöten sein.


Das auf ARM jetzt auch UEFI einziehen soll kommt natürlich einer Katastrophe gleich, wenn Intel schon mal eine SW-Spezifikation mit ausarbeitet dann kommt da fast immer ein unbeherrschbar riesiger Ballon bei raus. Zumindest für mich persönlich hat das aber vielleicht einen Vorteil, dann kommen eventuell mal Graphikkarten raus die ein UEFI-BIOS drauf haben und das könnte ich sogar auf meiner Plattform laufen lassen (falls ich den den unmenschlich großen Aufwand einer eigenen UEFI-VM auf mich nehme) und käme damit in den Genus zumindest einer primitiven Text-Konsole (obwohl ich denke das es einfacher wäre das selber in einem FPGA zu realisieren als eine UEFI-Umgebung zu schaffen). Zumindest die Hersteller von Flash-Chips werden sich freuen wenn dann auch auf ARM eine simple Firmware (die nicht viel mehr leisten muss außer einen Linux-Kernel oder einen Windows-Kernel zu booten) etliche MB benötigt.


Grüße
Erik