22

のマニュアルページの文言に混乱していますarch_prctl(2)。具体的には、次のように述べています。

64 ビット セグメント ベースのコンテキスト スイッチはかなり高価です。 カーネル 2.5 以降では、modify_ldt(2) で LDT を設定するか、set_thread_area(2) システム コールを使用して、セグメント セレクターを使用して 32 ビット ベースを設定する方が高速な代替手段になる場合があります。arch_prctl() は、4GB を超えるベースを設定する場合にのみ必要です。アドレス空間の最初の 2GB のメモリは、MAP_32BIT フラグを指定して mmap(2) を使用することで割り当てることができます。

これは、このシステム コールを使用するプロセスのコンテキスト スイッチがパフォーマンス ペナルティを受けることを意味するのでしょうか、それとも正確な意味は何ですか?

Linux カーネルのソースを調べたところ、4 GiB 未満のアドレスには LDT が使用され、4 GiB を超えるアドレスにはモデル固有のレジスタが使用されているようです。

からdo_arch_prctl:

case ARCH_SET_FS:
        /* handle small bases via the GDT because that's faster to
           switch. */
        if (addr <= 0xffffffff) {
                set_32bit_tls(task, FS_TLS, addr);
                if (doit) {
                        load_TLS(&task->thread, cpu);
                        loadsegment(fs, FS_TLS_SEL);
                }
                task->thread.fsindex = FS_TLS_SEL;
                task->thread.fs = 0;
        } else {
                task->thread.fsindex = 0;
                task->thread.fs = addr;
                if (doit) {
                        /* set the selector to 0 to not confuse
                           __switch_to */
                        loadsegment(fs, 0);
                        ret = wrmsrl_safe(MSR_FS_BASE, addr);
                }
        }
        put_cpu();
        break;

GDT を使用すると、レジスタに書き込むよりも高速になるのはなぜですか? また、FS と GS を更新する費用は、プロセスを切り替えるときにのみ支払われると思います。つまり、実行するプロセスがスケジュールされていないときに、システム コールを介してカーネルに入る追加費用はありませんか?

4

1 に答える 1

3

うわー、これは12月に質問されたのに誰も答えなかったの?ご存知の方もいらっしゃるかもしれませんが、もしそうなら申し訳ありません。

これは、wrmsr を実行する手順が遅いためです。タスク切り替え時にセグメントレジスタをロードする方が簡単で高速です。

最新の Intel プロセッサでは、「rdfsbase」、「wrfsbase」、「rdgsbase」、および「wrgsbase」命令を追加することで、FS および GS のベース レジスタに直接アクセスできるようになり、以前よりもはるかに困難になりません。実際、カーネルは、必要に応じてユーザー モードからの使用を許可できます。最新の Linux カーネルが wrfsbase を利用して、4 GB 未満の TLS 領域の割り当てを不要にするかどうかを確認することをお勧めします。

Linux での状況はわかりませんが、Windows 7 以降の Windows NT には、アプリケーション開発者向けのオプション機能として、ユーザー モードのスレッド スケジューリングがあります。Linux や Mac OS X と同様に、Windows は、セグメント レジスタのベース アドレス (x86-64 Windows では GS) を使用して x86 にスレッド ローカル ストレージを実装します。この機能はファイバーに似ていますが、カーネルによって認識される方法で、プログラムが独自のスレッド コンテキストを別のスレッド コンテキストに切り替えることができる点が異なります。

Windows でのユーザー モード スケジューリングは、スケジュール可能なスレッドごとに TLS ブロック (Windows では "スレッド環境ブロック" または TEB と呼ばれます) を指すセグメントを含む LDT を作成することによって実装されます。ユーザーモードは、コンテキストスイッチに加えて GS ベースをリロードすることで、スレッドを切り替えることができます。これには、Linux の arch_prctl のパフォーマンス ノートにあるように、TEB を 2^32 未満にする必要があります。そうしないと、ユーザー モード スケジューリングで、wrmsr を実行するために別のスレッドに切り替えるたびに NT カーネルを呼び出す必要があり、ポイント全体が無効になります。ユーザー モード スケジューリングの。

Windows 8.1 では、wrgsbase のサポートが追加され、ユーザー モードでも有効になりました。8.1 のユーザー モード スケジューリングでは、GS セグメントのリロードの代わりに wrgsbase が使用され、CPU に LDT がある場合は LDT が使用されます。

于 2014-06-14T18:57:54.337 に答える