NAKAMURA Minoru の日記 (2010年4月)

先月の日記(2010年03月) 今月の日記(2010年04月)
2002 | 10 | 11 | 12
2003 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2004 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2005 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2006 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2007 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2008 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2009 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2010 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2011 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2012 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2013 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2014 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2015 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2016 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2017 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2018 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2019 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2020 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2021 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2022 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2023 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2024 | 1 | 2 | 3
ホームページ | 最新のコメント50
インデックス: 食べ歩き | Java | プログラム | UNIX | 画像
最新の日記へのリンク | この日記ページをはてなアンテナに追加 この日記ページをはてなブックマークに追加
はてな ダイアリー アンテナ ブックマーク ブログ
Twitter | mixi | Facebook | slideshare | github | Qiita



4/31 (木)

2台目のデジカメは Canon の IXY 10S

生まれて最初に買ったデジカメ MINOLTA DiMAGE Xi (2003年1月12日の日記) は、バッテリーの不調のために実用上使用不能になっていた(2010年1月12日の日記)。 しばらくデジカメなしの日々を送っていたがいろいろ不便なので、意を決して新横浜のヨドバシカメラで Canon のIXY 10S を購入。

Canon の PowerShot やリコーの CX シリーズのようなのにも惹かれたが、これまで自分の写真の撮り方を考えると、ほとんどオートに任せっぱなしだということに気づく。 ならボタンの多いコンパクトデジカメを買っても使いこなせないと思い直して、接写が綺麗に撮れる機種として IXY 10S を選んだ。

ヨドバシで色々なデジカメを物色した後に、DiMAGE Xi を手で持つと重さが全然違うことに気づく。 DiMAGE Xi はスカスカなのに、今時のデジカメは中身がずっしりと搭載されているのね。 自分がウォッチしない間に随分デジカメも進化していたようだ。


4/22 (木)

[Prog] mmap と truncate の競合

mmap でファイルをメモリマップする使われ方は多い。 メモリへの書き込み内容は msync を使うとファイルに書き戻され、逆にファイルに行なわれた変更もメモリに再反映される。

ただマップ中のファイルを truncate で縮小した場合、mmap した領域がなくなってしまう場合がある。 この時、メモリ領域と truncate の削除された部分の関係をどうするのかは、POSIX では決まっておらず OS/システム依存のようだ。

If the size of the mapped file changes after the call to mmap(), the effects of references to portions of the mapped region that correspond to added or removed portions of the file may vary among systems that conform to the Single UNIX Specification.

Linux の場合、man の記述では動作は unspecified になっている。

(RHEL4 Update3 の man mmap)
If the size of the mapped file changes after the call to mmap() as a result of some other operation on the mapped file, the effect of references to portions of the mapped region that correspond to added or removed portions of the file is unspecified.
(RHEL5.5 の man mmap)
A file is mapped in multiples of the page size. For a file that is not a multiple of the page size, the remaining memory is zeroed when mapped, and writes to that region are not written out to the file. The effect of changing the size of the underlying file of a mapping on the pages that correspond to added or removed regions of the file is unspecified.

実際に実行してみると truncate で解放した部分は、過去にアクセスできた領域もアクセスできなくなり SIGSEGV が発生するようになるようだ。

truncate で縮小したファイルをさらに write で元に戻すとどうなるのだろうか? 何事もなく新しい拡張部分にアクセスできるのだろうか?


4/16 (金)

GbE のスイッチングハブが壊れた

自宅の I/O DATA の GbE スイッチングハブ ETG-SH8 が、深夜になんともいえない異音を発生させるようになった。 ファンの部分が音を出しているようだ。

一度分解して掃除してみたが、異音がでるのは直らない。 騒音を出し続けるわけにもいかないので廃棄するか…


4/14 (水)

[Prog] C 言語のヌルポインタ(NULL pointer) の意味について

Slashdot(3.)に Ksplice blog の記事(1., 2.) が紹介されている。

  1. Ksplice blog | Much ado about NULL: An introduction to virtual memory
  2. Ksplice blog | Much ado about NULL: Exploiting a kernel NULL dereference
  3. Slashdot | How To Explit NULL Pointers

これは Linux 上のユーザプログラムやカーネルドライバーなどを書くときに、NULL pointer のデリファレンスをしてもエラーやカーネルパニックが発生しないようにしようというネタだ。

記事の本意と外れるし、Ksplice blog の筆者は Linux に限定した話をしているし、そもそもあまり気にすることもないとは思うのだが、C 言語の仕様上 NULL pointer はアドレス0 を意味しない ということは知っておいても損はない。 得にもならないが。

C のソースコードの (void*)0 は数値表現の 0 になるとは限らない。 また (void*)0 をデリファレンスした時に生じるメモリアクセスはアドレス 0 以外で発生するかもしれない。 これは C FAQ (5章) に詳しい。

typedef union {
    void      *ptr;
    uintptr_t value;
} ptr_val_u;


ptr_val_u  u;

u.ptr = 0;             // この 0 はヌルポインタ
assert(u.value == 0);  // 常に成立するとは限らない。

大多数の UNIX 系 OS は、まさに NULL pointer をデリファレンスしたことをエラーとして捕捉できるように、ユーザプロセスの 0 ページ目をアクセス禁止にしている。 ただ古いアーキテクチャや古い OS では、0 ページに何か重要なデータが配置されていたりする。 この場合、NULL pointer の内部表現が 0 以外だったりする。

AIX on POWER の NULL pointer の扱い

ところで元のスラッシュドットの記事の、コメント欄に AIX の話をしている人がいたのだが、このネタは知らなかった。 すごいおもしろい。

OS dependent by mdf356 (774923) writes: <mdf356 AT gmail DOT com> on Tuesday April 13, @05:14PM (#31839076)
This is very OS dependent.

For example, on AIX on POWER, page 0 in both real and virtual addressing modes is readable by all and writable by none. So a read from a NULL pointer produces junk data (actually interrupt machine code) and a write is fatal.
Re:OS dependent by russotto (537200) writes: on Tuesday April 13, @08:32PM (#31840674)
| So a read from a NULL pointer produces junk data (actually interrupt machine code) and a write is fatal.

IIRC, the first two words of the AIX page 0 are 0xdeadbeef 0xbadfca11. Because of the way the AIX function pointers work, calling page 0 results in the PC being set to 0xdeadbeef and R2 to 0xbadfca11, and the register dump (for the misaligned PC) immediately tells you what you did wrong. (The reason AIX page 0 is readable is for a specific compiler optimization -- the case "if (foo && *foo)" and its cousins. If page 0 is guaranteed readable, the short circuit can be ignored and a branch avoided)

As for " how to turn any NULL pointer into a root exploit"... not. First you have to be able to map page zero, and then the NULL pointer read must be a function pointer. The author says "it's quite common that a NULL pointer dereference is, or can be easily turned into, a NULL function pointer dereference", but that seems a bit handwavy to me.

AIX on POWER は、0 ページ目がライトができないが、リードができるらしい。 だから NULL pointer をデリファレンスするとジャンクデータが読めるとのこと。

これは関数ポインタを使った関数呼び出しで、NULL 関数ポインタを確実に失敗させるための保護処理のようだ。 コメントから判断するに AIX の関数ポインタは飛び先アドレスそのものを格納するのではなく、(IA-64 ABI のように)飛び先アドレスの入ったメモリ位置を間接的に格納するようだ。 そして AIX の 0 ページの最初の2ワードは固定的に 0xdeadbeef 0xbadfca11 が設定されており、NULL 関数ポインタを使った呼び出しをすると PC は 0xdeadbeef に、R2 レジスタが 0xbadfca11 に設定される。 飛び先となるアドレスは不正境界なのでここでエラーが発生し、エラーを検出できる。

なぜ AIX で 0 ページ目が読める必要があるかというと、if (foo && *foo) のようなパターンのコンパイラ最適化のためらしい。 *foo のロード命令と foo != 0 の判定の制御依存が切れる。 そのため分岐が一つ減らせるし、ロード命令を先行させることが可能になるからだ。 Out-of-order 以前の CPU では、OS まで巻き込んだ涙ぐましい努力が積み重ねられたようだ。

[時事] 中国で M7.1 の地震

中国の青海省で現地時間午前7時49分(日本時間8時49分)に M7.1 の地震が発生。

コメントを書き込む
[1] [AH] 2010-05-24 20:04:30
C++のメンバ変数へのポインタのnullについては
非零の内部表現を持つコンパイラ実装が多いです

4/9 (木)

[CPU] Intel の x86 系 CPU の分岐予測

Intel の x86 系 CPU の分岐予測方法を調べていた(2009年4月27日の日記)のだが、Pentium Pro (NetBurst) の分岐予測アルゴリズムが判明。 使われているアルゴリズムは、Yeh & Patt の Two-level branch prediction が元になっている。 以下に参考文献。

NetBurst や Core 系は Two-level branch prediction が使われている。 少なくとも PentiumPro の場合は以下のハードを持つらしい。

  • 4-way set assosicative の 4096 個のエントリを持つ Branch History Table(BHT)。
  • BHT の 1 つのエントリは 4-bit の分岐履歴を保存。
  • セット毎に独立した Pattern Table。

上記より、

  • 少数の分岐命令が 4 回以下の繰り返しパターンで動いている場合には完全な予測が可能。
  • 5回以上の繰り返しの場合、Pattern Table (PAT) の動作によって分岐予測の成功か失敗が決まる。 PAT は 2 ビット飽和カウンターだが、Taken または Not-taken を Strong に確信しているのか、Weak で予測しているのかで次の予測が変わってくる。 また同じセットに属する BHT は PAT を共有するので、調査中の条件分岐命令以外の条件分岐命令の動作の影響を受けるようだ。

Core i7 に関してはもう一度実験してみよう。


4/2 (金)

[CPU] Core i7 の Turbo Boost 機能

試験マシンの Core i7 は Turbo Boost 機能が有効になっていたようで、周波数が小刻みに変化していることに気づく。 /proc/cpuinfo の CPU 周波数がコロコロ変わっている。 それで Time-Stamp Counter(TSC) がどのように変化しているのかが気になる。

Intel のサイトにある Intel64 and IA-32 Architectures Software Developer's Manuals が今年の3月に更新されており、手元のバージョンと比べて Core i7 以降の話が大幅に追加されていた。 それによると TSC は従来の Constant TSC と比べて、Invariant TSC という振る舞いが導入されているようだ。 Turbo Boost の動作に関わらず TSC は一定で動いていると考えて良いようだ。

  1. Constant TSCはプロセッサのコアが周波数を変えても一定の時刻で TSC を刻む。Pentium4 以降に導入される。
  2. Invariant TSCは Constant TSC の一定性に加え、各種節電モードに対しても一定の時刻で TSC を刻む。 そのため実時間タイマーとして使用することも可能。 主に Core i7 以降に導入。

ただ問題は TSC の周波数をどうやって取得すればいいのかと、取得した値は実機の TSC 周波数と一致するのかという点だ。 実機 Xeon X5570 (2.93GHz) の /sys/devices/system/cpu/cpuN/cpufreq/ を除くと Turbo Boost の下限は 1596000、上限は 2927000 とでる。 一方、数秒間に渡って実測した TSC の周波数は 2,933,400,207 になる。

TSC 周波数は Turbo Boost の上限に近いようだが、実際にはかなり(292700 と 2933400)のブレがある。 実際はどうなんだろう?

Linux での Turbo Boost 機能の確認の仕方

Turbo Boost 機能の有効下の状況では、各 CPU の周波数は /proc/cpuinfo ではなく、/sys/devices/system/cpu/cpuN/cpufreq/ 以下の状況を参照する必要がある。 /proc/cpuinfo は正しい値を返さないようだ。

追記: 4/12

Xeon X5570 の Max Turbo Frequency は 3.33GHz。 この環境は Turbo Boost 機能が有効になっていないと判明。

追記: 4/22

Turbo Boost の有効化に成功した。

まず /sys/devices/system/cpu/cpuN/cpufreq/ にある周波数は、Turbo Boost の周波数を直接していないようだ。 scaling_available_frequencies は以下の1行を持っているが、

2927000 2926000 2793000 2660000 2527000 2394000 2261000 2128000 1995000 1862000 1729000 1596000 

2926000 は基本となる周波数だが、その横の 2927000 は Turbo Boost 選択時の象徴的な周波数らしい。 Turbo Boost が無効な場合には 2927000 が表示されない。

実際に CPU コアを Turbo Boost 状態にするには、cpuspeed デーモンを起動する必要があった。 cpuspeed デーモンが何をやっているのかはよく分かっていないが、これを起動しないと

Turbo Boost 機能の確認は Linux ACPI で配られている Power management tools の中の turbostat を使えばよい。 一部のコアに負荷をかけると周波数が 2.93GHz を越えて行くのが確認できる。

# ./turbostat -v
CPUID GenuineIntel 11 levels family:model:stepping 6:26:5
Nehalem multiplier 22, TSC frequency 2933 MHz
Nehalem 4 cores active: 24 mult, max turbo frequency = 3200 MHz
Nehalem 3 cores active: 24 mult, max turbo frequency = 3200 MHz
Nehalem 2 cores active: 25 mult, max turbo frequency = 3333 MHz
Nehalem 1 core active: 25 mult, max turbo frequency = 3333 MHz

 CPU   GHz    TSC    %c0    %c1    %c3    %c6   %pc3   %pc6   %pc7 
 avg   3.2*   2.93  14.78   5.64  22.06  57.51   0.00   0.00   0.00
   0   3.2*   2.93   9.96   4.56  54.38  31.10   0.00   0.00   0.00
   1   ****   2.93  99.32   0.68   0.00   0.00   0.00   0.00   0.00
   2   3.2*   2.93   1.30   3.17  61.69  33.85   0.00   0.00   0.00
   3   2.4*   2.93   1.43   4.31  60.45  33.81   0.00   0.00   0.00
   4   1.6*   2.93   1.48   7.44   0.00  91.08   0.00   0.00   0.00
   5   1.6*   2.93   1.54   7.79   0.00  90.68   0.00   0.00   0.00
   6   1.6*   2.93   1.59   8.52   0.00  89.89   0.00   0.00   0.00
   7   1.6*   2.93   1.63   8.68   0.00  89.68   0.00   0.00   0.00

追記: 4/28

Linux カーネルは CPU Frequency scaling 機能により、CPU の周波数調整の方法を規定しているようだ。 /sys/devices/system/cpu/cpuN/cpufreq/scaling_governor という仮想ファイルがそれで、これに "performance"、"ondemand"、"userspace"、"powersave"、"conservative" の 5 つのパラメータを設定できる。

RHEL5 のカーネルではデフォルトが "userpsace" になっており、これは周波数制御を外部のプログラム、つまり cpuspeed デーモン、に調整を委ねるということ。

設定を scaling_governor を "ondemand" にすると、cpuspeed デーモンを走行させなくても Turbo Boost がきく。


先月の日記(2010年03月) 今月の日記(2010年04月)
2002 | 10 | 11 | 12
2003 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2004 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2005 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2006 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2007 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2008 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2009 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2010 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2011 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2012 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2013 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2014 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2015 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2016 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2017 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2018 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2019 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2020 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2021 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2022 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2023 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2024 | 1 | 2 | 3
ホームページ | 最新のコメント50
インデックス: 食べ歩き | Java | プログラム | UNIX | 画像
最新の日記へのリンク | この日記ページをはてなアンテナに追加 この日記ページをはてなブックマークに追加
はてな ダイアリー アンテナ ブックマーク ブログ
Twitter | mixi | Facebook | slideshare | github | Qiita


Written by NAKAMURA Minoru, Email: nminoru atmark nminoru dot jp, Twitter:@nminoru_jp