Que fait la fonction Sys_PageIn () dans Quake?

8

J'ai remarqué que dans le processus d'initialisation du Quake d'origine, la fonction suivante est appelée.

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];
        }
    }
}

Je pense que je ne suis tout simplement pas assez familier avec la pagination pour comprendre cette fonction. le void * ptr passé à la fonction est un morceau de mémoire récemment malloc () de taille octets. Il s'agit de la fonction entière - j est une variable non référencée. Ma meilleure supposition est que le volatile int sys_checksum force le système à lire physiquement tout l'espace qui était juste malloc () 'd, peut-être pour s'assurer que ces espaces existent dans la mémoire virtuelle? Est-ce correct? Et pourquoi quelqu'un ferait ça? Est-ce pour une raison archaïque de Win95?

Philippe
la source

Réponses:

6

Votre supposition est fondamentalement correcte, et cela se fait comme une optimisation (très probablement; je ne peux que spéculer bien sûr car je n'ai pas écrit le code).

Bien qu'une application dans Windows semble avoir un accès complet à toute la plage de RAM de la machine (ou au moins la plage qui lui est signalée par le système d'exploitation), en pratique, le système d'exploitation virtualise l'accès d'une application à la mémoire physique réelle et stockera régions (pages) de mémoire virtuelle sur le disque lorsque cela est nécessaire. Le processus de transfert de ces régions du disque vers la RAM physique est souvent appelé «paging in» (lors du passage du disque à la RAM) ou «paging out» (lors du passage de la RAM au disque).

Le disque IO est lent, comparé à la RAM, et donc éviter la pagination est idéal pour atteindre des performances maximales. L'intention de cette fonction semble être de tenter de minimiser la pagination pendant la durée de vie du programme en forçant le système d'exploitation à paginer toute la mémoire au début du programme - le forçage est accompli en essayant de lire à partir de toute la mémoire.

Vraisemblablement, Windows 95 avait une sorte de code pour détecter et arrêter ce comportement, qui, selon le commentaire, est contourné en lisant la mémoire selon un modèle particulier. Il est logique que le système d' exploitation ferait cela, parce que forcer une page en complète comme cela forcera d' autres processus mémoire à paginée sur le disque, ce qui ralentit probablement les bas.

On peut faire valoir qu'il s'agit d'un comportement acceptable pour un jeu, car un utilisateur n'exécutera généralement le jeu et n'essaiera pas de faire beaucoup de multitâche pendant que le jeu est en cours, donc sacrifier les performances d'autres processus qui peuvent être en cours d'exécution n'est pas ce mal.

Quelques autres notes:

  • Ce genre de chose ne fonctionnera probablement pas aussi bien aujourd'hui que dans Windows 95. La nature des programmateurs de système d'exploitation a beaucoup changé depuis lors, donc ce n'est pas nécessairement une technique que je vous suggérerais d'adopter à moins que vous ne soyez convaincant des données et des mesures de profileur pour soutenir le fait que votre tentative est un avantage.

  • volatileest un indice de l'implémentation pour éviter une optimisation agressive d'un objet ainsi déclaré car cet objet pourrait changer via signifie que l'implémentation ne peut pas être prévue. En d'autres termes, c'est comme un drapeau "ne m'optimisez pas". De cette façon, le compilateur, même s'il se rend compte que la variable essentiellement inutilisée de façon significative, n'optimisera pas les lectures de la mémoire dans cette variable dans le cadre de sa passe d'optimisation.

  • j être inutilisé n'est probablement qu'un oubli.


la source
1

Raymond Chen y répond directement dans un post ultérieur sur son blog The Old New Thing (Maximus Minimius avait la bonne source, il s'avère que 3 ans trop tôt pour une explication directe): https://blogs.msdn.microsoft.com/oldnewthing / 20151111-00 /? P = 91972

Ce que ce code fait, c'est accéder au bloc de mémoire spécifié par les paramètres ptr et size dans un modèle inhabituel: il lit l'octet zéro, puis l'octet avec un décalage de 16 pages, puis l'octet un, puis un octet avec un décalage de 16 pages plus un, et ainsi de suite, alternant entre un octet et son homologue 16 pages à venir.

Ce modèle d'accès spécifique dans Windows 95 a vaincu l'algorithme de détection «analyse séquentielle de la mémoire».

Rappelons que les ordinateurs de l'ère Windows 95 avaient 4 Mo de RAM. Supposons que vous travailliez depuis longtemps sur un document. Enfin, vous avez terminé et vous fermez la fenêtre ou la minimisez. Boom, maintenant votre bureau est visible et le bitmap du fond d'écran doit être paginé. Si votre écran est de 1024 × 768 à 16 bits par pixel, cela donne 1,5 Mo de mémoire. La pagination dans 1,5 Mo de mémoire signifie que le bitmap signifie le retrait de 1,5 Mo de mémoire utilisé pour d'autres choses, et cela représente beaucoup de mémoire pour une machine qui n'a que 4 Mo pour travailler (d'autant plus qu'une grande partie de ces 4 Mo appartient à des choses qui ne peut pas être paginé). Le phénomène que nous avons vu était que repeindre votre bureau viderait la majeure partie de votre mémoire.

Et puis la prochaine chose que vous faites est probablement de lancer une nouvelle application, qui couvrira le fond d'écran, de sorte que la mémoire du fond d'écran ne sera plus nécessaire. Nous avons donc essentiellement purgé toute la mémoire de votre système afin de gérer un énorme bloc de mémoire accessible une seule fois.

L'astuce utilisée par Windows 95 était de surveiller votre modèle de défauts de page, et s'il voyait que vous faisiez un accès séquentiel à la mémoire, il commençait à marquer la mémoire 16 pages derrière l'accès actuel comme non récemment consultée . Dans le cas d'un balayage séquentiel direct, cela signifie que le tampon entier parcourt une fenêtre de mémoire de 64 Ko, quelle que soit la taille du tampon. Avec cette astuce, un tampon de 4 Mo finit par ne consommer que 64 Ko de mémoire, au lieu d'utiliser toute la mémoire de votre système.

La Sys_Page­Infonction détruit spécifiquement le détecteur à balayage séquentiel en remontant intentionnellement 16 pages et en accédant à nouveau à la page. Cela le marque comme récemment utilisé , contrebalançant le fait que le détecteur à balayage séquentiel n'avait pas été utilisé récemment . Résultat: les pages mémoire sont toutes marquées comme récemment utilisées et ne sont plus des candidats privilégiés pour être paginées.

Tyler Szabo
la source
0

Ressuscitant cela, j'ai remarqué récemment cette entrée sur le site de Raymond Chen: http://blogs.msdn.com/b/oldnewthing/archive/2012/08/13/10334566.aspx

Pourquoi suis-je dans les crédits Quake? Je ne me souviens pas de ce que j'ai fait spécifiquement ... les conseils que j'ai donnés étaient presque certainement liés à la gestion de la mémoire et à l'échange.

Cela indique qu'il existe au moins une possibilité décente que cette fonction soit le résultat des conseils de Raymond (et lorsque Raymond Chen dit "vous devez le faire", il y a au moins une possibilité décente qu'il a raison).

Il est facile d'oublier de nos jours, mais en 1996 le PC gamer moyen aurait eu peut - être 16 Mo de RAM, max et Quake était un absolu monstre d'un programme. À cette époque, les disques durs utilisés pour broyer sans relâche en raison de la pagination, et extraire toute la mémoire allouée de cette manière auraient (au moins) aidé à éviter que le fichier d'échange ne soit touché au moment de l'exécution, ce qui aurait pu entraîner un blocage de quoi que ce soit jusqu'à une seconde ou plus.

Maximus Minimus
la source