Autor Thema: IPC Methoden  (Gelesen 12919 mal)

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #20 am: 01. September 2010, 18:55 »
Hallo,


Wie kommst du darauf das mein System X-fach langsamer sei? Ich meine wir gehen einfach mal davon aus, dass alle Daten in die Pipe passen ohne das der Writer warten muss, das die Daten wieder daraus gelesen werden.
Das Problem ist IMHO das die Daten dafür schon 2 mal kopiert werden müssen (einmal rein in die Pipe und einmal raus).

Im normal Fall läuft es doch so ab, du allokierst einen Speicherbereich für deinen Buffer für eine Nachricht, kopierst die erforderlichen Sachen in den Buffer rein und machst einen Syscall das du eine Nachricht versenden willst. Die Nachricht wird dann in einen Buffer im Kernel kopiert (dieser muss auch vorher allokiert werden, was bei dynamic-size Msgs unter Umständen ne "Weile" dauern kann).
Wenn der Empfänger dann die Nachricht abholt gibt es 2 Möglichkeiten, entweder sein Empfangsbuffer ist für die Nachricht groß genug oder er muss erstmal einen Syscall machen um zu wissen wie groß die Nachricht ist. Dann allokiert er einen Buffer und ruft nen Syscall auf, das er die Nachricht haben will. Die Nachricht wird dann aus dem Kernelbuffer in den Buffer des Clienten kopiert.
So läuft es nur ab wenn der Empfänger die Nachrichten selber aktiv abholen muss (Du also selber zur Post hinlaufen musst), wenn die Nachrichten aber zugestellt werden (also der Postbote zu Dir kommt und auch automagisch das exakt passende Transportbehältnis hat) dann gibt es dieses Problem nicht.

So ungefähr sollte das auf allen Systemen aussehen die asynchrones IPC zur Verfügung stellen.
Das wäre sehr schade, obwohl dann hätte ich es deutlich leichter ein OS zu bauen das signifikant schneller ist als die anderen. ;)

den Speicher, wo der Buffer drin liegt, kannst du dem Sender auch nicht einfach wegnehmen.
Wer hat was von wegnehmen gesagt? Der Client verliert seinen Speicher nicht, schließlich soll ja die für ihn bestimmte Antwort dort rein.

Ich weiß das man beim synchronen IPC versucht das Kopieren zu vermeiden, aber wie will man das mit sehr großen Nachrichten anstellen?
Mapping!

Weil die Nachricht müsste ja in den Kernelstack des Senders passen, damit du ihn einfach vom Kernelstack in den Userstack des Empfängers kopieren kannst.
Was haben die Messages der User-Mode-Applikationen auf dem Stack vom Kernel zu suchen? Oder überhaupt auf irgendeinem Stack? Okay, tyndur legt die Messages auch auf den User-Mode-Stack und hat daher vermutlich gewisse Größenbeschränkungen, aber das tyndur-Konzept ist für synchrones IPC sicher nicht der Idealfall.

Zitat von: erik
Aha, deswegen ein Haufen extra Syscalls für das Memory-Sharing usw?
Ich verstehe nicht was du mit den extra Syscalls meinst.
Naja, z.B. im fread müssten nicht nur Syscalls für das IPC stecken sondern auch welche für das Memory-Mapping. Ich meine das pro Vorgang mehrere (verschiedene) Syscall nötig sind, ich würde versuchen das auf so wenige wie möglich zu beschränken.

Aus meiner Sicht ist das schneller/besser als wenn ich sage, das er die Daten per Msg verschickt.
Das ich da anderer Meinung bin dürfte wohl mittlerweile außer Frage stehen. Kopieren ist IMHO ein unnützer Vorgang für synchrones IPC.

Wieso? kommt dem Zero-copy ziemlich nahe, bzw. ist es sogar. Das dürfte so ähnlich wie dein Konzept aussehen.
Also 2 mal kopieren ist IMHO was anderes als 0 mal kopieren. Insofern kann ich auch keine Ähnlichkeit zu meinem Konzept erkennen.

ich will nicht ohne das es der Prozess weiß, in den Pagingtabellen rumfummeln.
Warum nicht? In meinem Konzept wird doch auch in der LDT der Prozesse rumgefummelt wenn es dem Kernel in den Kram passt. Ich kann da kein Problem sehen.

Denn fread sagt das du den Buffer übergibst wo die Daten rein sollen und nicht das du nen Buffer zurück bekommst wo die Daten drin sind.
Ganz genau! Der Client (in diesem Fall der aufrufende Code) gibt seinem Buffer dem Service (also fread) damit der Service dort was rein legt. Genau das will ich auf IPC-Ebene nachbauen. Ich würde es mir extrem unhandlich vorstellen wenn fread mir nen Pointer auf die gelesenen Daten zurück geben würde, so müsste ich immer erst noch kopieren wenn ich mehrere Häppchen einer Datei in einem zusammenhängenden Array haben will.

Du hast mich erst überzeugt das mein Konzept richtiger Mist ist, wenn ich ein besser (eventuell mit deiner Hilft ;) ) habe. Aber es sollte auch vernünftig für Paging umzusetzen sein.
Ich möchte Dir eigentlich nichts vorgeben, nur wenn das Konzept in Deinem Kopf gereift ist kannst Du es auch ordentlich umsetzen. Mit dem Paging kann man wunderbar Speicher von überallher nach überallhin mappen (krass, jetzt mache ich schon Werbung für Flat-Memory).


Grüße
Erik
Reality is that which, when you stop believing in it, doesn't go away.

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #21 am: 01. September 2010, 20:07 »
Zitat von: erik
So läuft es nur ab wenn der Empfänger die Nachrichten selber aktiv abholen muss (Du also selber zur Post hinlaufen musst), wenn die Nachrichten aber zugestellt werden (also der Postbote zu Dir kommt und auch automagisch das exakt passende Transportbehältnis hat) dann gibt es dieses Problem nicht.
Gut ich will mein IPC darauf aufbauen, das man selber entscheidet wann man eine Nachricht bekommen möchte, sprich das man diese selbst abholt (das ist für mich auch das ganze Konzept des recv Syscall´s).

Ich bin mir eigentlich auch sicher (du kannst mich gerne vom Gegenteil überzeugen) das z.B. Linux auch "nur" die Daten aus seinem VFS/Cache in den Client-Buffer kopiert.

Zitat von: erik
So läuft es nur ab wenn der Empfänger die Nachrichten selber aktiv abholen muss (Du also selber zur Post hinlaufen musst), wenn die Nachrichten aber zugestellt werden (also der Postbote zu Dir kommt und auch automagisch das exakt passende Transportbehältnis hat) dann gibt es dieses Problem nicht.
Ich kann nur Vermutungen anstellen, aber ich denke mal, dass du das IPC an sich überbewertest. Im Fall von z.B. Haiku liegt das komplette VFS-System im Kernel, die werden also auch nur 1x Kopieren oder den Speicher reinmappen.

Man kann natürlich sein IPC System so aufbauen das man praktisch alle Probleme damit lösen kann (wie du es machst). Da muss man dann aber abwägen was leichter ist und für wen es leichter ist. Ich würde mir nämlich nicht noch zusätzliche Komplexität in den Kernel holen wollen (á la ich mappe das dann in den Client-Buffer). Ziel eines Mikrokernels ist es doch so viel wie möglich an Aufgaben (und auch Komplexität) aus dem Kernel zu holen und in den UserSpace zu packen.

Zitat von: erik
Was haben die Messages der User-Mode-Applikationen auf dem Stack vom Kernel zu suchen? Oder überhaupt auf irgendeinem Stack? Okay, tyndur legt die Messages auch auf den User-Mode-Stack und hat daher vermutlich gewisse Größenbeschränkungen, aber das tyndur-Konzept ist für synchrones IPC sicher nicht der Idealfall.
Ich orientiere mich bei schnellem IPC immer am L4-Kernel. Ich habe gerade mal so ein Paper über dessen IPC System überflogen und die haben synchrones IPC mit dynamic-size Msgs. Es wird versucht so viel wie möglich einer Nachricht in den Registern zu "kopieren" (was meiner Meinung nach auf x86 nicht wirklich viel bringt, zwecks verdammt weniger Register), wirds doch mehr wird es in einen Buffer kopiert (im Kernel) und wird es wirklich viel, werden Pages in gemappt.
Soweit ich das verstanden habe, weiß der Sender aber im Prinzip wie die Nachricht versendet wird, da für längere Msgs ein wenig mehr Aufwand auf Seite des Senders betrieben werden muss, aber auch auf Seite des Empfängers.
Auch gibt es da genau das Problem, das die Nachricht nur empfangen werden kann, wenn du damit rechnest bzw. weißt wie groß die Nachricht ist, die du bekommst.
Wie das dann genau mit dem Page mapping funktionier weiß ich nicht, nur das man da eine Nachricht so senden kann, das einem der Speicher praktisch weggenommen wird (wie als wenn man ne SharedMem Region erstellt und diese dann im eigenen Prozess unmappt und an einen anderen weiterschickt).
So einen Syscall könnte ich natürlich auch machen, damit würde ich mir ein paar Kernelaufrufe ersparen, aber mal sehen.

Zitat von: erik
Das ich da anderer Meinung bin dürfte wohl mittlerweile außer Frage stehen. Kopieren ist IMHO ein unnützer Vorgang für synchrones IPC.
Da bin ich wieder anderer Meinung. Gut passt die Nachricht in die Register muss nicht kopiert werden, ist die Nachricht verdammt groß mappst du einfach, aber was ist mit dem was dazwischen liegt, da wo du trotz mapping kopieren musst und was für die Register zu groß ist?
Ich behaupte mal das der Großteil der versendeten Nachricht da reinfällt.

Zitat von: erik
Ganz genau! Der Client (in diesem Fall der aufrufende Code) gibt seinem Buffer dem Service (also fread) damit der Service dort was rein legt. Genau das will ich auf IPC-Ebene nachbauen. Ich würde es mir extrem unhandlich vorstellen wenn fread mir nen Pointer auf die gelesenen Daten zurück geben würde, so müsste ich immer erst noch kopieren wenn ich mehrere Häppchen einer Datei in einem zusammenhängenden Array haben will.
Da komme ich jetzt nicht mit, wenn du mehrere Häppchen einer Datei in einem zusammenhängenden Array haben willst, dann muss doch irgendwo kopiert werden. Ob das nun fread macht oder ob du das erst nach dem fread machst ist dann schon fast egal, es muss gemacht werden.

Ich wage sogar zu behaupten das es bei bestimmten Sachen mehr Sinn macht, eine Datei vollständig in den Prozess einzulesen und aus diesem Buffer dann deine Häppchen rauszuholen, als sehr viele fread Aufrufe zu tätigen und deine Häppchen so zu holen!

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #22 am: 01. September 2010, 20:28 »
Was mir noch eingefallen ist, wenn du mal vom aktiven Abholen (so wie du es nennst, sprich wo du sagst in welchen Buffer die Nachricht soll) ausgehst, dann fällt auch Mapping flach. Denn damit Mapping funktioniert, müssen der Buffer wo die Nachricht drin ist und der Buffer wo die Nachricht rein soll das selbe Pageoffset haben, ansonsten klappt das nicht.

Wenn ich jetzt mal mit dem Gedanken spiele, das ich meinen recv-Syscall so umbaue, dass dieser mir den Buffer zurück gibt (mit der Nachricht drin), dann habe ich nur noch das Problem, was mache ich mit kleinen Nachrichten? Denn ich müsste jedes Mal mind. 1 Page allokieren um die kleine Nachricht da rein zu kopieren und eine extra Page für sagen wir 32bytes finde ich dann doch ganz schön übertrieben. Auch müsste ich mir dann was einfallen lassen wie der Empfänger (wo die Nachricht reinkopiert/rein gemappt wurde) den Speicher wieder freigeben kann. Denn ein "free(bufferOfMsg)" geht nicht, da ja der Speicher von dem UserAllocator gar nicht erfasst ist und das auch nicht möglich ist, da ich (als Kernel) nicht wissen kann, was für einen Allocator der Prozess benutzt und wo dessen Datenstrukturen sind und wie diese aufgebaut sind.

Edit::

Was mir gerade noch so durch den Kopf gegangen ist, mit synchronen IPC machst du dir auch das Leben schwer wenn es um Multithreading geht.
Wenn ich mal dein Bsp mit dem "ls" über 10000 Dateien nehme, dann könnte ich mehrere Anfragen (wenn das möglich ist, das weiß ich jetzt nicht so genau) mit einmal in meine Pipe schreiben und würde beim Versuch eine Antwort aus der anderen Pipe zu lesen blockieren. Der VFS-Service bearbeitet die erste Anfrage, packt die Antwort in die Pipe und weckt mich auf. Wenn man jetzt auf einem SMP-System ist, dann können jetzt der Client und der Service gleichzeitig auf verschiedenen CPUs laufen. Da noch Anfragen in der Pipe sind, kann der Service eine weitere bearbeiten. Gleichzeitig hat der Client die Antwort gelesen und verarbeitet und könnte jetzt eine weitere Anfrage in die Pipe schicken und wird dann nach der nächsten Antwort gucken, da ja der VFS-Service gleichzeitig lief, ist es gar nicht so unwahrscheinlich das er bereits eine neue Antwort in die Pipe geschrieben hat und der Client somit weiter arbeiten kann.
Im optimalen Fall kann das so für die ganzen 10000 Dateien laufen. Das Nachrichten senden und empfangen würde also komplett ohne Syscalls auskommen und es könnte alles Paralell geschehen. Sowas war auch ein Grund wieso ich unbedingt eine solche Pipe im UserSpace für viele Sachen nehmen will.

Was mich auch noch beschäftigt hat ist die Geschichte mit dem Datei laden. Bei einer 300MB Datei wird es unwahrscheinlich das diese von noch einem Prozess geladen wird, aber wenn wir irgendwelche kleinen Dateien nehmen dann wird es schon wahrscheinlicher.
Was ich eigentlich will, du musst die Daten der Dateien kopieren, weil du (auf jeden Fall beim Paging) ja nicht davon ausgehen kannst, dass jeder Buffer wo die Dateien so rein sollen immer das gleiche Pageoffset haben!
Wie machst du es überhaupt wenn eine Datei mehrmals geöffnet/gelesen wird? Lädst du die dann jedes Mal neu oder kopierst du in dem Fall auch?
« Letzte Änderung: 02. September 2010, 10:39 von FlashBurn »

 

Einloggen