Untitled-2

Untitled-1 の画像はクリックすると表示される仕掛けだったのですが、気付かなかった人が多かったかも。
要するに boot.ini の /INTAFFINITY の代替物です。P1 では全く割り込み処理がなされていない。

ソースコード置いておきますね。自己責任でどうぞ

Untitled-1

また、よくわからないものを作ってしまった。
Interrupt Affinity Policy Tool が何でもかんでも認識してしまうので、ついかっとなって作った。今は後悔している

interrupt_affinity

------------Overall Summary:--------------

P0     K 0:00:43.571 (25.1%)  U 0:00:25.802 (14.9%)  I 0:01:44.255 (60.0%)  DPC 0:00:01.981 ( 1.1%)  Interrupt 0:00:01.825 ( 1.1%)
       Interrupts= 232946, Interrupt Rate= 1342/sec.

P1     K 0:00:00.811 ( 0.5%)  U 0:00:00.062 ( 0.0%)  I 0:02:52.755 (99.5%)  DPC 0:00:00.015 ( 0.0%)  Interrupt 0:00:00.000 ( 0.0%)
       Interrupts= 118817, Interrupt Rate= 684/sec.

TOTAL  K 0:00:44.382 (12.8%)  U 0:00:25.864 ( 7.4%)  I 0:04:37.010 (79.8%)  DPC 0:00:01.996 ( 0.6%)  Interrupt 0:00:01.825 ( 0.5%)
       Total Interrupts= 351763, Total Interrupt Rate= 2026/sec.

Core Parking Internals - 解答編 & Interrupt Affinity Policy Tool の簡単な説明

Core Parking は万能ではないで出題した、Parked (保留) 状態のコアが CPU を利用している状態の解答編です。

実は Core Parking は負荷に応じて直接 CPU を Throttling State (省電力状態) に落とすわけではありません。
いくつかの段階を経て CPU を省電力状態へ落とすのです。過程は以下のようになります。

  1. システムの負荷に応じて最適な CPU数を選択する
  2. 余分な Core を Parked (保留) 扱いへ変更
  3. Unparked Core (通常状態の Core) を中心にスケジューリングを行う
  4. 結果的に Parked 状態の Core が Idle状態になる
  5. Idle状態が続いている Core を Throttling状態 (省電力状態) へ移行

さて、Windows 7 で Core Parking を利用する方法で紹介したように Windows 7 でも Core Parking は有効にできるのですが、
Multi-core だが Non-NUMA (複数のソケットを利用していない場合) にどのような問題があるでしょうか。

答えは Affinity Mask にあります。

SetProcessAffinityMask(), SetThreadAffinityMask() 関数により、明示的に特定の論理プロセッサに Thread を紐付けることができますが、
“Affinity” (親和性) という名前に似つかわしくなく強制的に特定の論理プロセッサへの紐付けとなります。

結果、Core Parking で用いられている 3. の動作は Affinity Mask を持つスレッドには適用されず
Core Parking は万能ではないの図の例で Affinity Mask は CPU0 のみになっているスレッドは
Parked (保留状態) の論理プロセッサで実行されます。このため両方の Core が使用率 100% となっていたのです。

 

以前は L3 Cache を CPU パッケージの外側に置くことが多かったのですが、Memory Access の Latency が
性能に対し支配的になった現在は CPU の Cache は CPU の Core から非常に近い場所に置かれるようになりました。

そのため、現代の(小規模な) NUMA Architecture は以下の図のように構成されています。

image

Cache Coherent とは、Processor 0, 1 内の各キャッシュの内容が同時に変更されても”一貫性”を保てることを意味しています。
(ただし、Atomic 命令を用いない場合には同一の対象への読み書きが一貫性を喪失する可能性があります。)
Processor 1 が Processor 0 に接続された Memory を参照する際にはこの Cache Coherent Interconnect を利用することになります。
その動作は Processor 1 に直接接続された Memory を参照するよりも低速なものとなります。
そのため、このような構成を NUMA (Non-Uniform Memory Access; 非均一メモリアクセス) と呼びます。

※Cache Coherent に関しては 【コラム】コンピュータアーキテクチャの話 (13) キャッシュの構造や働き(上級編) - キャッシュコヒーレンシ (外部) が詳しいです。

Windows Server 2003 以前でも Interrupt Affinity Tool を用いて各NIC (Ethernet Controller) の割り込み処理を行う
論理プロセッサを明示的に指定することがあったと思いますが、Windows Server 2008, Windows 7 からは新しい Interrupt Affinity Policy ツールが提供されています。
新しい Interrupt Affinity Policy Tool では、論理プロセッサへの指定ではなく、デバイスとの距離を考慮した設定が可能になっています。

このように、NUMA を意識したプログラミングでは Affinity Mask を論理プロセッサに対して明示的に設定するのではなく、
その論理プロセッサがどのような配置をなされているかを意識する必要があります。

Core Parking を有効に利用するためには、SetProcessAffinityMaskUpdateMode() の利用を、
I/O 処理が中心で、特定のプロセッサにスケジュールさせたい場合には GetNumaNumberFromHandle() から I/O の対象に近いノードを取得し
SetThreadIdealProcessorEx() を利用する、といった工夫が必要になります。

もちろん何も指定しなくとも OS側でスケジューリングの調整は行われますが、I/O 処理に性能が強く影響される場合などはこういった API を活用していく必要があるでしょう。

Core Parking は万能ではない

(解答編はこちら)

先日、Windows 7 で Core Parking を利用する方法 を紹介しましたが、Core Parking と実際の CPU 電力状態は必ずしも一致しません。

そこでクイズです。

image

CPU 0 は保留状態 (Parked) になっていますが、CPU 使用率は 100% となっています。なぜでしょうか?

JumpList はどこに保存されているのか

10行で理解する JumpList (VS2010 beta 2 編) で JumpList の使用方法を解説しましたが、アプリケーションを終了しても JumpList は保持されています。この情報はどこに保存されているのでしょうか?

答えは %AppData%\Microsoft\Windows\Recent\CustomDestinations です。

10行で理解する JumpList (VS2010 beta 2 編) で作成したアプリケーションを実行すると、このようにファイルが追加されます。

image

image

ここで、このファイルを削除してみましょう。

image

削除すると、JumpList もクリアされます。

image

このファイルはバイナリ形式ですが、内容をメモ帳で開くと

image

追加したタスクが登録されているのが確認できます。

その他、一意性を保つためにマシン名やパスが含まれていることがわかります。これらを直接インストーラなどで配布しないように気をつけてください。

Visual Studio 2010 Professional beta 2 はこちらから入手することが可能です。

Visual Studio 2010 Ultimate Beta 2 ISO (英語)
http://www.microsoft.com/downloads/details.aspx?FamilyID=dc333ac8-596d-41e3-ba6c-84264e761b81&displaylang=en

10行で理解する JumpList (VS2010 beta 2 編)

(保存先はJumpList はどこに保存されているのか で取り上げています)

.NET Framework 4.0 beta 2 より、新たに System.Windows.Shell 名前空間 (PresentationFramework 4.0) が追加されました。

JumpList は Windows 7 より新たに導入されたタスクバーの機能です。

image

図 Pin された Live Messenger のアイコンを右クリックした際に表示される JumpList

JumpList をカスタマイズすることによって、このようにアプリケーション固有のよく使われる Task を追加することが可能です。
では、JumpList を利用するために必要なコードを書いてみましょう。

Visual Studio 2010 beta 2 で新しいプロジェクト (Windows Forms Application) を作成し、以下のコードを追加します。

using System;
using System.ComponentModel;
using System.Windows.Forms;

using System.Windows.Shell;

namespace JumpListTest
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            JumpList jumpList = new JumpList(
                new JumpItem[] { new JumpTask() { Arguments = "/Task1", Title = "CustomTask1" } }, true, true);

            jumpList.Apply();
        }
    }
}

jumpList のアイテムを編集した場合には Apply() を呼び出すことを忘れないでください。

このプログラムを実行すると以下のように JumpList が作成されます。

image

アプリケーションをタスクバーに Pin し、終了させると図のように JumpList が保持されていることを確認できます。

image

ここで追加した CustomTask1 には引数として “/Task1” が割り当てられています。次にProgram.cs を開き、以下の太字になっている行を追加します。

using System;
using System.Linq;
using System.Windows.Forms;

namespace JumpListTest
{
    static class Program
    {
        [STAThread]
        static void Main()
        {
            if (Environment.GetCommandLineArgs().Contains("/Task1"))
            {

                // ここに処理を追加する
                MessageBox.Show("CustomTask1 が呼び出された");
                return;
            }

            Application.Run(new Form1());
        }
    }
}

ここでタスクバーから CustomTask1 を選択すると

image

と表示されます。このように .NET Framework 4.0 では数行追加するだけでアプリケーションで Windows 7 の新機能を利用することができます。

ソースコードを添付しましたので実際に試してみてください。

Windows 7 & Internet Explorer 8 Developer Day 補足説明 - (予定)

掲載予定のコード

1. Explorer Browser Control を用いた Shell API の利用 (Code Pack for .NET, VS2008, C#)

2. Shell Library を用いたライブラリーの利用 (Code Pack for .NET, VS2008, C#)

3. Taskbar JumpList (Code Pack for .NET, VS2008, C#), (VS2010, .NET 4.0 beta 2, C#)

4. Sensor API (照度計) (Code Pack for .NET, VS2008, C#)

その他、扱ってほしい内容ありましたらコメントまたは twitter @mskwt までお願いします。

Windows 7 & Internet Explorer 8 Developer Day 補足説明

週末~来週末にかけてこちらで補足説明を行う予定です。よろしくお願いします

「Windows 7 & Internet Explorer 8 Developer Day」開催

blog で告知するのをすっかり忘れていましたが、Windows 7 発売開始前日の10/21 にセミナーを開催します。

本セミナーでは Windows 7 の新機能のご紹介、またそれらを活用したアプリケーション開発手法、Internet Explorer 8 の新機能活用をデモを交えてわかりやすく解説する予定です。
デモではマルチタッチ対応ノートパソコンも使用します。まだ触れたことがないという方にもお勧めです。

Windows Code Pack for .NET を用いてのマネージド開発もきちんと取り上げますので興味のある方はぜひご参加ください。

登録はこちらから

Tech Fielders セミナー 東京 [Windows 7 & Internet Explorer 8 Developer Day]

http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032427921&Culture=ja-JP

Windows 7 で Core Parking を利用する方法

日経ソフトウエアで連載中の「どこが変わるの!? Windows 7 プログラミング」最終回でも Windows 7, Windows Server 2008 R2 で強化された省電力機能について取り上げましたが、それに関連して Windows 7 で Core Parking (コア保留)を有効にする方法を取り上げたいと思います。

Core Parking とは、負荷がそれほど高くない場合に全ての CPUコアを利用せず、不必要なコアを”保留状態”にして使用しているコアを減らし、電力を削減する機能です。
Windows 7 はクライアントOS であるため、負荷の上昇に対してなるべく早く高性能状態へ移行する目的で Core Parkingに関する設定は既定ではオフになっています。

しかし、私もそうなのですが PCをつけっぱなしで運用しているけれど外出時にはより省電力状態で運用したい、そんな方もおられると思います。
そこで今回は Windows 7 で Core Parking を利用する裏技について紹介します。

CPU を含め、Windows 7 における電力設定は全て HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Power\PowerSettings\ 以下に記述があるのですが、電源のオプションで表示されない設定が数多くあることはあまり知られていません。

power_settings

CPU の電力制御に関係する HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Power\PowerSettings\54533251-82be-4824-96c1-47b60b740d00 以下を覗いてみると、

hidden_settings

上の図のように、Attributes (REG_DWORD) が 0x00000001 に設定され、表示されていないものが数多く存在することがわかります。

それでは、Core Parking を有効にするため、いくつかの設定を変更してみましょう。

HKLM\SYSTEM\CurrentControlSet\Control\Power\PowerSettings\54533251-82be-4824-96c1-47b60b740d00\ 以下

0cc5b647-c1df-4637-891a-dec35c318583
3b04d4fd-1cc7-4f23-ab1c-d1337819c4bb
447235c7-6a8d-4cc0-8e24-9eaf70b96e2b
5d76a2ca-e8c0-402f-a133-2158492d58ad
a55612aa-f624-42c6-a443-7397d064c04f
ea062031-0e34-4ff1-9b6d-eb1059334028

内の、”Attributes” を “_Attributes” と名前を変更すると、

power_options

と、設定が増えます。(英語版ですみません…)

ここで、Processor performance core parking min cores を 1/(コアの個数) …Dual Core なら 50%, Quad Core なら 25% に、
Allow Throttle States を On に、Processor idle disable を Enable idle に、Processor performance core parking core override を Disabled に、
Processor performance core parking max cores を 1 - 1/(コアの個数) …Dual Core なら 50%, Quad Core なら 75% に設定します。

(後で Language pack を入れて日本語に書き直すかもしれません)

その設定を適用すると、

resource_monitor

このように、Core Parking によって CPU が片方 (当方 Dual Core環境なため)保留状態になります。
Quad Core環境だが、外出時に使用コア数を減らしたいといった方にお勧めです。

あ、お決まりのセリフですが、

警告 : レジストリ エディタまたは別の方法を使用してレジストリを誤って変更すると、深刻な問題が発生することがあります。最悪の場合、オペレーティング システムの再インストールが必要になることがあります。マイクロソフトは、レジストリの変更により発生した問題に関しては、一切責任を負わないものとします。レジストリの変更は、自己の責任において行ってください。

ということで、自己責任で行ってくださいね。

追記: 近いうちにこの辺をいじるツールをこっそり公開する予定です。

MSDN Flash 2009/8/11 No.330 の答え - (2)

もう先月の話になるのですね…2つ目のコードの問題について解説したいと思います。
掲載したコードは以下の通り

char s[10];
memset(s, 0, 10);
double *val = (double*) (&s[2]);
printf("%lf\n", *val);

期待される実行結果は x86, x64環境では 0.000000 と表示、Itanium環境では整列違反例外によるプログラムの異常終了です。

これを一度に Itaniumでのアセンブリに展開すると話がややこしくなるので、

char s[10];
double *val;
double val2;
memset(s, 0, 10);
val = (double*) (&s[2]);
val2 = *val; // 問題の部分
printf("%lf\n", val2);

と書き直すことにします。

このコードをコンパイルすると

{   .mib  //R-Addr: 0X01e0
    adds    r29=val$, sp                    //6     cc:0
    adds    r27=val2$, sp                    //6     cc:0
    nop.b     0;;
}
{   .mmi  //R-Addr: 0X01f0
    ld8    r28=[r29];;                    //6     cc:1
    ldfd    f6=[r28]                    //6     cc:3
    nop.i     0;;
}
{   .mmi  //R-Addr: 0X0200
    stfd    [r27]=f6;;                    //6     cc:9
    adds    r26=val2$, sp                    //7     cc:0
    addl    r25=@gprel(__imp_printf#),gp            //7     cc:0
}

となります。

val2 = *val; が

ld8 r28=[r29];;
ldfd f6=[r28]

と展開されていることがわかります。しかし、この r29 は 16-bytes aligned を仮定された char s[10] の 2-bytes目を指しているので miss-alignedとなります。
Itaniumでは参照されるアドレスは自然長に整列されていなければなりません。この場合、8-bytes alignmentでなければならないため整列違反例外となるわけです。

このように、渡された型が自然長に整列されているかどうかわからない場合は __unaligned キーワードをつけることで問題を回避することができます。2行目を

__unaligned double *val;

と書き換えると、コンパイルの結果は

{   .mmi  //R-Addr: 0X01e0
    adds    r29=val$, sp;;                    //6     cc:0
    ld8    r28=[r29]                    //6     cc:1
    adds    r29=val2$, sp;;                    //6     cc:1
}
{   .mib  //R-Addr: 0X01f0
    mov    r27=r28                        //6     cc:2
    adds    r26=1, r28                    //6     cc:2
    nop.b     0;;
}
{   .mmb  //R-Addr: 0X0200
    ld1    r25=[r27], 2                    //6     cc:3
    ld1    r22=[r26], 2                    //6     cc:3
    nop.b     0;;
}
{   .mmi  //R-Addr: 0X0210
    ld1    r20=[r27], 2                    //6     cc:4
    ld1    r18=[r26], 2                    //6     cc:4
    dep    r21=r22, r25, 8, 8;;                //10     cc:4
}
{   .mmi  //R-Addr: 0X0220
    ld1    r16=[r27], 2                    //6     cc:5
    ld1    r11=[r26], 2                    //6     cc:5
    dep    r19=r20, r21, 16, 8;;                //6     cc:5
}
{   .mmi  //R-Addr: 0X0230
    ld1    r9=[r27]                    //6     cc:6
    ld1    r31=[r26]                    //6     cc:6
    dep    r17=r18, r19, 24, 8;;                //6     cc:6
}
{   .mii  //R-Addr: 0X0240
    nop.m     0
    dep    r15=r16, r17, 32, 8;;                //6     cc:7
    dep    r10=r11, r15, 40, 8;;                //6     cc:8, 00000028H
}

{   .mii  //R-Addr: 0X0250
    nop.m     0
    dep    r8=r9, r10, 48, 8;;                //6     cc:9, 00000030H
    dep    r30=r31, r8, 56, 8;;                //6     cc:10, 00000038H
}
{   .mmi  //R-Addr: 0X0260
    setf.d    f6=r30;;                    //6     cc:11
    stfd    [r29]=f6                    //6     cc:17
    nop.i     0;;
}

となり、このコードは問題なく動作するようになります。(しかし、長くて読む気にならないのは気のせいでしょうか…)

違いは ld8 が 8個の ld1 に置き換えられているところです。つまり、double val; を構成する全ての領域を 1-byteずつ読み込んでいることになります。

問題なく動作するようになったとしても、3-cyclesで完了する処理に 9-cyclesもかけることになるわけですから処理は遅くなります。

 

x86/x64 においても、自然長への整列がなされていない場合はキャッシュヒットに対するペナルティが課せられるため動作が低下します。

このように、自然長に配置されていないスタックや構造体を用いる場合には十分に注意しましょう。

T2-311 「64 ビット アプリケーション開発のポイント」のデモで使用したスライド

ドライバの開発における落とし穴と称しながら、32bit Native <-> 64bit NativeやManagedにおける構造体の取り扱いの話に繋がる内容となってしまいましたが、参考までに置いておきますね。

MSDN Flash 2009/8/11 No.330 の答え - (2) も書かなくては…。

Windows 7 / Server 2008 R2 - 英語版におけるキーボード問題

RTM配布開始に伴い英語版をインストールした際、キーボード配列の問題に悩まされることがあると思います。

PS/2 Keyboard を使用している場合には OS にその責任があります…と言っても英語版をインストールした場合に英語キーボードとして認識されるのは当然なのですが…

問題は USB Keyboard が正しく日本語キーボードとして認識されない場合です。

コンピュータに USB キーボードを接続したときに Windows Vista で正しいキーボード レイアウトが使用されないことがある
http://support.microsoft.com/kb/927824/ja

で指摘されている通り、本来は USB HID (Human Input Device) が適切な対応言語を申告するべきなのですが、私の環境でも正しいキーボードレイアウトが申告されず、正しく認識されないことがあります。

詳細は上記の URL に書かれていますが、Vista, Windows7 では
HKLM\SYSTEM\CurrentControlSet\Services\i8042prt\Parameters 以下の

LayerDriver JPN を “kbd106.dll” に、OverrideKeyboardIdentifier を “PCAT_106KEY” にすることで解決できます。

LayerDriver JPN の変更は英語版の Windows 2000/XP/Server 2003 にも有効です。私は試したことがないのですが、”kbd106n.dll”を指定することによって NEC 106 配列を利用することも可能かもしれません

Posted 17 August 09 08:27 by masaki | 0 Comments   
Filed under
twitter はじめました

@mskwt です。なにをつぶやこう?

Posted 13 August 09 09:25 by masaki | 0 Comments   
Filed under
Windows 7 の新機能 - ユーザーモードスケジューラー (UMS; User Mode Scheduler)

Windows 7, Windows Server 2008 R2 の新機能を紹介していこうと思います。UI変更は取り上げられる機会が多いのですが Kernelの変更についてはあまり情報が出ていませんよね。そんなわけで今回は User Mode Scheduler について取り上げたいと思います。

従来の Threading の実装では、I/O操作や同期処理などで生じるカーネルモード処理の待機のために多くのコンテキストスイッチが必要とされていました。 OS の動作に詳しい方はよくご存知だと思いますが、それぞれの Thread には実行状態を保存するコンテキストが割り当てられています。

image
コンテキストスイッチはそれ自体がオーバーヘッドを伴う処理であり、またスケジューリングが OS に委ねられているため、例えば数値計算のように切り替えを自分で制御したい場合にも常に汎用的な排他処理を利用しなければなりませんでした。

Windows NT では Threading が抱えるこれらの課題に対し、Fiber (軽量スレッド)が実装されました。しかし個々の Fiber は対応するカーネルモードスレッドを持たないため、システムコールの呼び出しには注意を要することになりました。

新たに導入された UMS では Fiber の軽量さと通常の Threading が持つ柔軟性を同時に実現することができます。 UMSは Windows Server 2008 R2, Windows 7 (x64) で利用可能です。
UMS ではユーザーモードのスレッドの切り替えにカーネルモードのスレッドを切り替える必要がありません。よってコンテキストスイッチを軽減することが可能となります。

image

また UMS内のスレッドでシステムコールが行われた場合、対応するカーネルスレッドへの切り替えが行われシステムコールは対応するカーネルモードスレッドで行われます。これにより安全にシステムコールを行うことが可能となります。

image

また、カーネルモードスレッドによって処理がブロックされた場合、UMS ではカーネルモードスレッドはそのままに、待機状態のユーザーモードスレッドを実行することで CPU の性能を無駄なく発揮できます。

これらの特徴により、数値計算や、処理時間が I/O 処理に対して相対的に長い Thread Pool では大きな恩恵を受けることができます。
次期開発環境である Visual Studio 2010 では標準 C++ TR1 拡張に加えて並列プログラミングをサポートするための機能が追加されます。その基盤として Concurrency Runtime (ConcRT) が提供されますが、Concurrency Runtime では UMS を内部で使用する予定です。

実際に UMSを利用したプログラムの例はまたの機会に取り上げたいと思います。

More Posts Next page »

Search

This Blog

Syndication

Page view tracker