Leistungsunterschied zwischen Systemaufruf und Funktionsaufruf

8

Ich höre oft Treiber-Entwicklern zu, dass es gut sei, Kernel-Modus-Switches so weit wie möglich zu vermeiden. Ich konnte den genauen Grund nicht verstehen. Um mit meinem Verständnis zu beginnen, ist -

  1. Systemaufrufe sind Software-Interrupts. Auf x86 werden sie durch den Befehl sysenter ausgelöst. Das sieht tatsächlich wie eine Verzweigungsinstruktion aus, die das Ziel von einem maschinenspezifischen Register übernimmt.
  2. Systemaufrufe müssen den Adressraum oder den Prozesskontext nicht wirklich ändern.
  3. Sie speichern jedoch Register im Prozessstapel und ändern den Stapelzeiger zum Kernel-Stack.

Unter diesen Operationen funktioniert syscall so ziemlich wie ein normaler Funktionsaufruf. Obwohl der Sender sich wie ein falsch vorhergesagter Zweig verhalten könnte, der zu ROB-Flush in der Prozessor-Pipeline führen könnte. Selbst das ist nicht wirklich schlecht, es ist wie jeder andere falsch vorhergesagte Zweig.

Ich habe ein paar Leute gehört, die auf Stack Overflow antworteten:

  1. Sie wissen nie, wie lange syscall braucht - [me] yeah, aber das ist bei jeder Funktion der Fall. Die benötigte Zeit hängt von der Funktion
  2. ab
  3. Es ist oft Zeitplanung. - Der Prozess [me] kann verschoben werden, auch wenn er ständig im Benutzermodus ausgeführt wird. ex, while(1); garantiert keinen Kontextwechsel.

Woher kommen die tatsächlichen syscall-Kosten?

    
APKar 23.06.2012, 13:17
quelle

2 Antworten

3

Sie geben nicht an, für welches Betriebssystem Sie sich interessieren. Lass mich trotzdem eine Antwort versuchen.

Die CPU-Anweisungen syscall und sysenter sollten nicht mit dem Konzept eines Systemaufrufs und dessen Funktion verwechselt werden Darstellung in den jeweiligen Betriebssystemen.

Die beste Erklärung für den Unterschied in dem Overhead, der durch die jeweilige Anweisung entsteht, finden Sie in den Abschnitten Operation des Intel® 64 und IA-32 Architectures Developer's Manual Band 2A (für int , siehe Seite 3-392) und Volume 2B (für sysenter siehe Seite 4-463). Vergessen Sie auch nicht, währenddessen auf iretd und sysexit zu schauen.

Ein zufälliges Zählen des Pseudocodes für die Operationen ergibt:

  • 408 Zeilen für int
  • 55 Zeilen für sysenter

Hinweis: Obwohl die vorhandene Antwort insofern richtig ist, als sysenter und syscall keine Interrupts oder in irgendeiner Weise Interrupts sind, ältere Kernel in der Linux- und Windows-Welt verwendete Interrupts, um ihren Systemaufrufmechanismus zu implementieren . Unter Linux war dies int 0x80 und Windows int 0x2E . Und folglich musste das IDT auf diesen Kernel-Versionen vorbereitet werden, um einen Interrupt-Handler für den jeweiligen Interrupt bereitzustellen. Bei neueren Systemen haben die Anweisungen sysenter und syscall die alten Möglichkeiten vollständig ersetzt. Mit sysenter wird das MSR (maschinenspezifische Register) 0x176 mit der Adresse des Handlers für sysenter initialisiert (siehe das unten verlinkte Lesematerial).

Unter Windows ...

Ein Systemaufruf unter Windows führt genau wie unter Linux zum Wechsel in den Kernel-Modus. Der Scheduler von NT gibt keine Garantien über die Zeit, die ein Thread gewährt wird. Außerdem entfernt es Zeit von Threads und kann sogar verhungernde Threads enden. Im Allgemeinen kann man sagen, dass der Benutzermoduscode durch den Kernelmoduscode vorweggenommen werden kann (mit sehr wenigen sehr spezifischen Ausnahmen, die Sie sicherlich in der "erweiterten Treiberschreibklasse" erhalten werden). Das macht Sinn, wenn wir nur ein Beispiel betrachten. Benutzermoduscode kann ausgelagert werden - oder die Daten, auf die er zuzugreifen versucht. Nun hat die CPU nicht die geringste Ahnung, wie sie auf die Seiten in der Swap- / Paging-Datei zugreifen kann. Daher ist ein Zwischenschritt erforderlich. Und das ist auch der Grund, warum der Kernelmodus-Code dem Benutzermoduscode zuvorkommen muss. Es ist auch der Grund für einen der produktivsten Bug-Check-Codes in Windows und meist durch Treiber von Drittanbietern verursacht: IRQL_NOT_LESS_OR_EQUAL . Es bedeutet, dass ein Treiber auf ausgelagerten Speicher zugegriffen hat, wenn es nicht möglich war, den Code, der diesen Speicher berührt, vorher zu löschen.

Weiter lesen

  1. SYSENTER und SYSEXIT in Windows von Geoff Chappell (immer eine Lektüre meiner Erfahrung wert!)
  2. SySenter-basierter System-Aufrufmechanismus in Linux 2.6
  3. Windows NT-Plattform-spezifische Diskussion: Wie funktionieren Windows NT Systemaufrufe WIRKLICH?
  4. Windows NT-Plattform-spezifische Diskussion: Optimierung des Systemaufrufs mit der SYSTENTER-Anweisung
  5. Windows Internals, 5. Aufl., von Russinovich et. al. - Seiten 125 bis 132.
  6. ReactOS-Implementierung von KiFastSystemCall
0xC0000022L 05.03.2013 01:14
quelle
2

SYSENTER / SYSCALL ist nicht ein Software-Interrupt; Der ganze Punkt dieser Anweisungen ist, einen Overhead zu vermeiden, der durch das Ausgeben von IRQ und das Aufrufen des Interrupt-Handlers verursacht wird.

Das Speichern von Registern auf der Stack-Kosten-Zeit ist ein Ort, von dem die Kosten des Systemprotokolls kommen.

Ein anderer Ort kommt von dem Kernel-Modus-Schalter selbst. Es müssen die Segmentregister geändert werden - CS, DS, ES, FS, GS, alle müssen geändert werden (es ist weniger kostenaufwendig auf x86-64, da die Segmentierung meist ungenutzt ist, aber man muss immer noch weit zum Kernel-Code springen) und ändert auch CPU-Ring der Ausführung.

Zum Schluss: Funktionsaufruf ist (auf modernen Systemen, wo die Segmentierung nicht verwendet wird) in der Nähe des Anrufs, während der Syscall Fernruf und Ringwechsel beinhaltet.

    
Griwes 23.06.2012 13:30
quelle