Was macht die Funktion Sys_PageIn () in Quake?

8

Ich habe beim Initialisierungsprozess des ursprünglichen Quake festgestellt, dass die folgende Funktion aufgerufen wird.

volatile int sys_checksum;

//  **lots of code**

void Sys_PageIn(void *ptr, int size)
{
    byte *x;
    int j,m,n;
//touch all memory to make sure its there.  The 16-page skip is to
//keep Win 95 from thinking we're trying to page ourselves in (we are
//doing that, of course, but there's no reason we shouldn't)
    x = (byte *)ptr;

    for (n=0 ; n<4 ; n++)
    {
        for (m=0; m<(size - 16 * 0x1000) ; m += 4)
        {
            sys_checksum += *(int *)&x[m];
            sys_checksum += *(int *)&x[m + 16 * 0x10000];
        }
    }
}

Ich glaube, ich bin mit Paging einfach nicht vertraut genug, um diese Funktion zu verstehen. Das an die Funktion übergebene void * ptr ist ein kürzlich von malloc () erstelltes Speicherelement mit einer Größe von Bytes. Dies ist die gesamte Funktion - j ist eine nicht referenzierte Variable. Ich vermute, dass die flüchtige int sys_checksum das System dazu zwingt, den gesamten Speicherplatz, der nur malloc () 'd war, physisch zu lesen, um möglicherweise sicherzustellen, dass diese Speicherplätze im virtuellen Speicher vorhanden sind. Ist das richtig? Und warum sollte jemand das tun? Ist es aus einem veralteten Win95-Grund?

Philip
quelle

Antworten:

6

Ihre Vermutung ist im Grunde genommen richtig und wird als Optimierung durchgeführt (höchstwahrscheinlich kann ich natürlich nur spekulieren, da ich den Code nicht geschrieben habe).

Während eine Anwendung in Windows anscheinend vollen Zugriff auf den gesamten RAM-Bereich des Computers hat (oder zumindest auf den vom Betriebssystem gemeldeten Bereich), virtualisiert das Betriebssystem in der Praxis den Zugriff einer Anwendung auf den tatsächlichen physischen Speicher und speichert ihn Regionen (Seiten) des virtuellen Speichers auf die Festplatte, wenn dies erforderlich ist. Das Übertragen dieser Bereiche von der Festplatte auf den physischen RAM wird häufig als "Paging in" (beim Übergang von der Festplatte zum RAM) oder "Paging out" (beim Übergang von der RAM zur Festplatte) bezeichnet.

Die Festplatten-E / A ist im Vergleich zum RAM langsam. Daher ist das Vermeiden von Paging ideal, um maximale Leistung zu erzielen. Die Absicht dieser Funktion scheint darin zu bestehen, das Paging während der Lebensdauer des Programms zu minimieren, indem das Betriebssystem gezwungen wird, den gesamten Speicher zu Beginn des Programms einzublenden. Das Forcen wird durch den Versuch erreicht, aus dem gesamten Speicher zu lesen.

Vermutlich hatte Windows 95 eine Art Code, um dieses Verhalten zu erkennen und zu stoppen. Der Kommentar deutet darauf hin, dass es durch Lesen des Speichers in einem bestimmten Muster umgangen wird. Es macht Sinn , dass das OS dies tun würde, weil eine komplette Seite in Zwingen wie dies andere Prozesse Speicher zwingen wird , auf die Festplatte ausgelagert werden soll, wahrscheinlich verlangsamen sie nach unten.

Es kann argumentiert werden, dass dies ein akzeptables Verhalten für ein Spiel ist, da ein Benutzer das Spiel im Allgemeinen nur ausführt und nicht versucht, viel Multitasking auszuführen, während das Spiel läuft, sodass die Leistung anderer Prozesse, die möglicherweise ausgeführt werden, nicht beeinträchtigt wird das Böse.

Einige andere Hinweise:

  • Diese Art von Dingen wird heute wahrscheinlich nicht annähernd so gut funktionieren wie in Windows 95. Die Art der OS-Scheduler hat sich seitdem stark verändert, daher ist es nicht unbedingt eine Technik, die ich Ihnen empfehlen würde, es sei denn, Sie haben überzeugend Profilerdaten und Metriken, um die Tatsache zu unterstützen, dass Ihr Versuch von Vorteil ist.

  • volatileist ein Hinweis auf die Implementierung, um eine aggressive Optimierung eines so deklarierten Objekts zu vermeiden, da sich dieses Objekt möglicherweise über Mittel ändert, die von der Implementierung nicht vorhergesagt werden können. Mit anderen Worten, es ist wie eine Flagge "Optimiere mich nicht". Auf diese Weise optimiert der Compiler die Lesevorgänge aus dem Speicher in diese Variable im Rahmen seines Optimierungsdurchlaufs nicht, selbst wenn er feststellt, dass die Variable im Wesentlichen in keiner signifikanten Weise verwendet wird.

  • j unbenutzt zu sein ist wahrscheinlich nur ein Versehen.


quelle
1

Raymond Chen antwortet direkt in einem späteren Beitrag auf seinem Blog The Old New Thing (Maximus Minimius hatte die richtige Quelle, es stellt sich heraus, dass es nur 3 Jahre zu früh für eine direkte Erklärung ist): https://blogs.msdn.microsoft.com/oldnewthing / 20151111-00 /? P = 91972

Dieser Code greift in einem ungewöhnlichen Muster auf den durch die Parameter ptr und size angegebenen Speicherblock zu: Er liest Byte Null, dann das Byte mit einem Versatz von 16 Seiten, dann das Byte Eins und dann ein Byte mit einem Versatz von 16 Seiten plus eins und so weiter, abwechselnd zwischen einem Byte und seinem Gegenstück 16 Seiten voraus.

Dieses spezielle Zugriffsmuster in Windows 95 besiegte den Erkennungsalgorithmus "Sequential Memory Scan".

Denken Sie daran, dass Computer in der Windows 95-Ära 4 MB RAM hatten. Angenommen, Sie haben lange in einem Dokument gearbeitet. Schließlich sind Sie fertig und schließen das Fenster oder minimieren es. Boom, jetzt ist Ihr Desktop sichtbar und die Hintergrund-Bitmap muss eingelagert werden. Wenn Ihr Bildschirm 1024 × 768 mit 16 Bit pro Pixel ist, entspricht dies 1,5 MB Speicher. Das Blättern in 1,5 MB Speicher bedeutet, dass für die Bitmap 1,5 MB Speicher ausgegeben werden, der für andere Dinge verwendet wird, und das ist viel Speicher für einen Computer, auf dem nur 4 MB zu arbeiten sind (zumal ein Großteil dieser 4 MB zu Sachen gehört) das kann nicht ausgelagert werden). Das Phänomen, das wir gesehen haben, war, dass das Neulackieren Ihres Desktops den größten Teil Ihres Speichers leeren würde.

Und als nächstes starten Sie wahrscheinlich eine neue Anwendung, die das Hintergrundbild abdeckt, sodass der Hintergrundbildspeicher nicht mehr benötigt wird. Wir haben also im Grunde den gesamten Speicher in Ihrem System gelöscht, um einen riesigen Speicherblock zu verarbeiten, auf den nur einmal zugegriffen wurde.

Der Trick, den Windows 95 verwendete, bestand darin, Ihr Muster von Seitenfehlern zu beobachten. Wenn festgestellt wurde, dass Sie einen sequentiellen Speicherzugriff ausführen, wurde der Speicher 16 Seiten hinter dem aktuellen Zugriff als nicht kürzlich aufgerufen markiert . Bei einem geraden sequentiellen Scan bedeutet dies, dass der gesamte Puffer unabhängig von der Puffergröße ein 64-KB-Speicherfenster durchläuft. Mit diesem Trick verbraucht ein 4-MB-Puffer nur 64 KB Speicher, anstatt den gesamten Speicher in Ihrem System zu verwenden.

Die Sys_Page­InFunktion besiegt speziell den Sequential-Scan-Detektor, indem sie absichtlich 16 Seiten zurückblättert und erneut auf die Seite zugreift. Dies führt dazu, dass es als kürzlich verwendet markiert wird , was dem nicht kürzlich verwendeten Markieren entgegenwirkt , das der Sequential-Scan-Detektor durchgeführt hat. Ergebnis: Die Speicherseiten sind alle als kürzlich verwendet markiert und sind keine Hauptkandidaten mehr für das Auslagern.

Tyler Szabo
quelle
0

Als ich dies wiederbelebte, bemerkte ich kürzlich diesen Eintrag auf der Website von Raymond Chen: http://blogs.msdn.com/b/oldnewthing/archive/2012/08/13/10334566.aspx

Warum bin ich im Quake-Abspann? Ich erinnere mich nicht, was ich speziell getan habe ... Der Rat, den ich gab, bezog sich mit ziemlicher Sicherheit auf die Speicherverwaltung und den Austausch.

Dies weist darauf hin, dass es zumindest eine vernünftige Möglichkeit gibt, dass diese Funktion das Ergebnis von Raymonds Rat ist (und wenn Raymond Chen sagt, dass Sie dies tun müssen, besteht zumindest eine vernünftige Möglichkeit, dass er Recht hat).

Heutzutage ist es leicht zu vergessen, aber 1996 hatte der durchschnittliche Gamer-PC vielleicht 16 MB RAM, max , und Quake war ein absolutes Monster eines Programms. In jenen Tagen haben Festplatten, die aufgrund von Paging unerbittlich weggeschliffen wurden, und das Abrufen des gesamten zugewiesenen Speichers auf diese Weise (zumindest) dazu beigetragen, zu verhindern, dass die Auslagerungsdatei zur Laufzeit berührt werden musste, was zu einem Stillstand von hätte führen können alles bis zu einer Sekunde oder länger.

Maximus Minimus
quelle