Sys_PageIn()関数はQuakeで何をしますか?


8

オリジナルのQuakeの初期化プロセスで、次の関数が呼び出されることに気付きました。

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

私はこの機能を理解するのに十分なページングに慣れていないと思います。関数に渡されるvoid * ptrは、サイズがバイトである、最近malloc()されたメモリです。これは関数全体です-jは参照されない変数です。私の推測では、揮発性のint sys_checksumが、システムにmalloc()されたすべてのスペースを物理的に読み取らせ、おそらくこれらのスペースが仮想メモリに存在することを確認していると思いますか?これは正しいですか?そして、なぜ誰かがこれを行うのですか?それはいくつかの時代遅れのWin95の理由のためですか?

回答:


6

あなたの推測は基本的に正しいです、そしてそれは最適化として行われています(おそらく、私はコードを記述しなかったので、もちろん推測することしかできません)。

Windowsのアプリケーションは、マシンのRAMの全範囲(または少なくともOSから報告された範囲)に完全にアクセスできるように見えますが、実際には、OSは実際の物理メモリへのアプリケーションのアクセスを仮想化しており、必要に応じて、仮想メモリのディスクへの領域(ページ)。これらの領域をディスクから物理RAMに転送するプロセスは、「ページングイン」(ディスクからRAMに移動する場合)または「ページングアウト」(RAMからディスクに移動する場合)と呼ばれます。

RAMに比べてディスクIOは遅いため、ページングを回避することは、最大のパフォーマンスを達成するために理想的です。この関数の目的は、プログラムの開始時にOSにすべてのメモリをページングさせることにより、プログラムの存続期間中のページングを最小限に抑えることです-強制は、すべてのメモリからの読み取りを試行することによって行われます。

Windows 95には、この動作を検出して停止するための何らかのコードがあったと考えられます。コメントは、メモリを特定のパターンで読み取ることによって回避されていることを示しています。このような完全なページインを強制すると、他のプロセスのメモリがディスクにページアウトされ、おそらくそれらの速度低下するため、OSがこれを行うことは理にかなっています。

ユーザーは通常ゲームを実行するだけであり、ゲームが起動している間は多くのマルチタスクを実行しようとしないため、実行可能な他のプロセスのパフォーマンスを犠牲にすることはないため、これはゲームにとって許容できる動作であると主張できます。その悪。

その他の注意事項:

  • この種のことは、おそらくWindows 95に戻ったときほどうまく機能しない可能性があります。それ以降、OSスケジューラーの性質はかなり大きく変化しているため、説得力のない限り、必ずしも採用することをお勧めする手法ではありません。プロファイラーのデータとメトリックは、あなたの試みが利益であることをサポートします。

  • volatileそのオブジェクトが変更される可能性があるため、実装の予測が期待できないため、宣言されたオブジェクトの積極的な最適化を回避するための実装へのヒントです。つまり、「最適化しないでください」というフラグのようなものです。このように、コンパイラーは、変数が実質的に未使用であることを認識したとしても、最適化パスの一部としてメモリーからその変数への読み取りを最適化しません。

  • j 未使用であることはおそらく見落としです。


1

Raymond Chenは、彼のブログ「The Old New Thing(Maximus Minimiusが適切な情報源を持っていたため、3年前に直接説明すると早すぎる)で、これについて直接回答しています。https://blogs.msdn.microsoft.com/oldnewthing / 20151111-00 /?p = 91972

このコードは、ptrパラメータとsizeパラメータで指定されたメモリブロックに異常なパターンでアクセスします。バイト0、次に16ページのオフセットのバイト、次にバイト1、次に16ページのオフセットのバイトを読み取ります。 1つ、というように、バイトと16ページ先の対応するバイトを交互に切り替えます。

Windows 95のこの特定のアクセスパターンは、「シーケンシャルメモリスキャン」検出アルゴリズムを無効にしました。

Windows 95時代のコンピュータには4MBのRAMがあったことを思い出してください。長い間ドキュメントで作業していたとしましょう。最後に、完了です。ウィンドウを閉じるか、最小化します。ブーム、デスクトップが表示され、壁紙のビットマップをページインする必要があります。画面が1024×768、16ビット/ピクセルの場合、1.5 MBのメモリになります。1.5MBのメモリをページングすると、ビットマップが1.5MBのメモリを他のメモリに使用することになります。これは、4MBしか動作しないマシンでは大量のメモリです(特に、4MBの多くはメモリに属しているため)ページアウトの対象にはなりません)。私たちが目にした現象は、デスクトップを再描画するとメモリの大部分がフラッシュされることでした。

次に、壁紙をカバーする新しいアプリケーションを起動して、壁紙のメモリが不要になるようにします。したがって、1回だけアクセスされたメモリの巨大なブロックを処理するために、基本的にはシステム内のすべてのメモリをパージしました。

Windows 95が使用したトリックは、ページフォールトのパターンを監視することでした。シーケンシャルメモリアクセスを実行していることがわかった場合は、現在のアクセスの16ページ後ろのメモリを最近アクセスされていないものとしてマークし始めました。ストレートシーケンシャルスキャンの場合、これは、バッファサイズに関係なく、バッファ全体が64KBのメモリウィンドウを循環することを意味します。このトリックでは、システム内のすべてのメモリを使用するのとは対照的に、4MBのバッファは64KBのメモリしか消費しません。

このSys_Page­In関数は、意図的に16ページ前に戻ってページに再度アクセスすることにより、特に順次スキャン検出器を無効にします。これにより、最近使用されたというマークが付けられ、シーケンシャルスキャン検出器が行った最近使用されいないものに対抗します。結果:メモリページはすべて最近使用されたものとしてマークされ、ページアウトされるための主要な候補ではなくなります。


0

これを復活させて、最近、Raymond Chenのサイトのこのエントリに気づきました:http : //blogs.msdn.com/b/oldnewthing/archive/2012/08/13/10334566.aspx

なぜ私は地震クレジットにいるのですか?私が具体的に何をしたのか覚えていません...私が行ったアドバイスは、ほぼ間違いなくメモリ管理とスワッピングに関連していたものです。

これは、この関数がレイモンドのアドバイスの結果である可能性が少なくともある程度あることを示しています(レイモンドチェンが「これを行う必要がある」と言った場合、少なくとも彼が正しい可能性はある程度あります)。

今日は忘れがちですが、1996年には、平均的なゲーマーPCのRAMは最大で16MB でしたが、Quakeはプログラムの絶対的な怪物でした。当時は、ページングが原因で容赦なく削り取られていたハードディスクと、この方法で割り当てられたすべてのメモリをプルすることで、実行時にページファイルにアクセスする必要がなくなり、ストールが発生した可能性があります。 1秒以上の何か。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.