Loading [MathJax]/jax/output/HTML-CSS/config.js

2012年12月16日日曜日

Mac で glGetString(GL_EXTENSIONS)

Mac の OpenGL 3.2 で glGetString(GL_EXTENSIONS) がなぜか NULL を返すと思ったら、今は glGetIntergerv(GL_NUM_EXTENSIONS, &i) と glGetStringi(GL_EXTENSSIONS, i) を使うことになっていた。

#include <OpenGL/OpenGL.h>
#include <OpenGL/gl3.h>
#include <iostream>

int main()
{
 CGLPixelFormatAttribute attribs[] = {
  kCGLPFAOpenGLProfile, (CGLPixelFormatAttribute)kCGLOGLPVersion_3_2_Core,
  (CGLPixelFormatAttribute)0
 };
 CGLPixelFormatObj pix;
 GLint npix;
 CGLChoosePixelFormat(attribs, &pix, &npix);

 CGLContextObj ctx;
 CGLCreateContext(pix, 0, &ctx);
 CGLSetCurrentContext(ctx);

 std::cout << "vendor : " << glGetString(GL_VENDOR) << std::endl;
 std::cout << "renderer : " << glGetString(GL_RENDERER) << std::endl;
 std::cout << "version : " << glGetString(GL_VERSION) << std::endl;
 std::cout << "shader : " << glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl;

 std::cout << "extensions : " << std::endl;
 GLint count;
 glGetIntegerv(GL_NUM_EXTENSIONS, &count);
 for (GLint i = 0; i < count; i++)
 {
  std::cout << "\t" << glGetStringi(GL_EXTENSIONS, i) << std::endl;
 }

 CGLReleaseContext(ctx);
 CGLReleasePixelFormat(pix);
 return 0;
}
コンパイル方法:
$ clang++ -Wall -framework OpenGL -framework Foundation -o gl gl.cpp
実行結果:
vendor : NVIDIA Corporation
renderer : NVIDIA GeForce GT 650M OpenGL Engine
version : 3.2 NVIDIA-8.6.22
shader : 1.50
extensions : 
 GL_ARB_instanced_arrays
 GL_ARB_occlusion_query2
 GL_ARB_shader_bit_encoding
 GL_ARB_timer_query
 GL_EXT_depth_bounds_test
 GL_EXT_framebuffer_multisample_blit_scaled
 GL_EXT_texture_compression_s3tc
 GL_EXT_texture_filter_anisotropic
 GL_EXT_texture_mirror_clamp
 GL_EXT_texture_sRGB_decode
 GL_APPLE_client_storage
 GL_APPLE_container_object_shareable
 GL_APPLE_object_purgeable
 GL_APPLE_rgb_422
 GL_APPLE_row_bytes
 GL_APPLE_texture_range

2012年6月17日日曜日

PrallelsでLinuxが動かない

ParallelsでLinuxを動かそうと思ったらカーネルに制御が移った直後にハングして動かなかった。いろいろ試してみるとカーネルが2.6.39ならOKで3.0だとNG。 覚悟を決めてgit-bisectしていくとIvy Bridgeで導入された仮想環境でのセキュリティ絡みの機能を有効にするパッチが入ってから起動しなくなっていた。
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=commit;h=de5397ad5b9a

Parallelsの問題っぽいのでParallelsフォーラムに書き込んで対応を待つことにした。

今回初めてgit-bisecを使ってみたけど、結構便利だね。この手の二分探索を手作業でやるのは面倒だし。

追記 (7/16) :
Build7.0.15104 (Revision 778994; Tue, 10 Jul 2012) で修正された様子。
http://kb.parallels.com/en/113626

2012年6月13日水曜日

再インストール

MacをUNIX的に使おうとするとファイルシステムがCase Sensitiveじゃないと何かとトラブルの元。なのでSSDをCase Sensitiveにフォーマットしなおして再インストール始めたら残り10時間とかのたまっている。どうもOSイメージを全てダウンロードしているっぽい。リカバリパーティション消してないのに...

2012年6月12日火曜日

Retina Display MacBook Pro 開封

朝一で銀座のApple Storeに行ってRetina Display MacBook Proを買ってきました。店の前に着いたのは開店二時間前の午前八時。 先客は8人でしたが開店するころには60人ぐらいの列になっていました。「ちょっと張り切って早く来すぎたかな?」とも思ったけど、「僕の分もあるかな?」とやきもきせずに済んだのでヨシとしよう。

開店10分ぐらい前になって隣に並んでいた人に「メモリって増設できるのかな?」と言われて「そういえば、薄くなってるし、MacBook Airの例もあるし、もしかしたら増設できないのかも...」と思ったけど、時すでに遅し。すでに買う気満々だったしお店の人は「カスタマイズはUSキーボードを選ぶことしかできません。」というので迷わずカスタマイズなしのメモリ8GBで買ってきました。

会社についてネットをみると「Retina Display MacBook Proはメモリを増設できないらしい。」という情報があったものの、「らしい。」ばっかではっきりした情報がなかったので自分で確認してみることにしました。

ネジは五芒星型のの特殊ネジ。会社帰りに秋葉原の秋葉館によってMacBook Air用のドライバーを買ってきました。もちろん今日発売なのでRetina Display MacBook Pro対応等とは書いてありませんが普通に使えます。

ネジは10個。ネジさえ取れば裏蓋は簡単に外れました。

シンメトリーでいつも以上に美しい中身。

そして肝心のメモリ

うん。マザボにばっちり直付け!

ハイ。メモリ増設の余地はまったくありませんでした。ちなみにチップはハイニックスのH5TC2G83CFRとい256M×8bitのチップが見える限りでは16個。16個じゃ4Gbyteなので裏にもう16個ついてんのかね。姉妹品(?)で容量が倍のチップもあるみたいなので16GBモデルではそっちが載ってるんでしょうね。
ちなみにハイニックスはVerilogのシミュレーションモデルを提供してました。謎のノイズが乗ってちゃんと動かなかったけど大学のときにFPGAでSDRAMコントローラを作ろうとしたことがありました。そのときは確かマイクロンのシミュレーションモデルのお世話になりました。僕の中ではシミュレーションモデルを提供してくれるメーカーは印象UPです。(だから何だろね。)

せっかく(ドライバー買ってまで)開けたんで他の部品も見てみましょう。

まず、SSD。

チップは全てサムスンのS4LJ204X01-Y040, K9UHGY8U7A-HCK0, K4T2G314QF-MCF7。この組み合わせは単体のSSD(830シリーズ)としても売っていて高速なものらしい。スバラシイ。SSDは別基盤になっていて対応品さえ発売されれば交換できそう。

無線LANモジュール。

詳細は知らん。ぐぐってすらいない。

バッテリー。8460mAh。工学ドライブ跡地は全てバッテリーが使ってるんじゃないかというほどデカイ。Designed by Apple in California Assembled in China, Apple Japanと書いてある。電池自体は日本製?

CPU。詳しくはヒートパイプの下。

(おそらく)ノースブリッジ。詳細はヒートパイプの下で。

謎チップ1, 型番E208B361。ぐぐっても出てこない。

謎チップ2, 型番DSL3510L。ThunderBoltコントローラらしいが詳細不明。

というわけでメモリの増設はできませんでした。実際のところ8GBでも困らないんだけど、会社で使ってるMacBookがメモリ16GBなので気になるんですよ。メモリ16GBがいい人はおとなしくWebで注文するのが吉です。

2012年5月27日日曜日

GRUBに選んだカーネルを覚えておかせる

Ubuntu(実際に使っているのはLinux Mintだけど)をデスクトップ用途で使うにはCONFIG_PREEMPTの有効になったlowlatencyカーネルを使いたいところ。

でもlowlatencyカーネルをインストールしてもGRUBはデフォルトでは一番上にリストされる(lowlatencyとは限らない)カーネルを起動するために、毎度手動でlowlatencyカーネルを選ばなくちゃいけない。

/etc/grub/defaultのGRUB_DEFAULTでlowlatencyカーネルを指定するにしても番号で指定してしまっては新しいカーネルがインストールするたびに番号が変わってしまうかもしれないし、名前で指定しても新しいlowlatencyカーネルをインストールする度に手動で変更しないといけない。

どちらもいまいちだなと思ってgrubのinfoマニュアルを見るとGRUB_SAVEDEFAULTという設定があった。

`GRUB_SAVEDEFAULT'
     If this option is set to `true', then, when an entry is selected,
     save it as a new default entry for use by future runs of GRUB.
     This is only useful if `GRUB_DEFAULT=saved'; it is a separate
     option because `GRUB_DEFAULT=saved' is useful without this option,
     in conjunction with `grub-set-default' or `grub-reboot'.  Unset by
     default.  This option relies on the environment block, which may
     not be available in all situations (*note Environment block::).

要するに/etc/default/grubに

GRUB_DEFAULT=saved
GRUB_SAVEDEFAULT=true
と書いておけば前回起動したの同じカーネルで起動してくれるようになる。
(update-grubするのを忘れずに!)

これで新しいカーネルをインストールする度に/etc/default/grubをいじる必要がなくなって少しだけ幸せ。

2012年5月25日金曜日

Linuxでwprintfを使う

Linux で wchar_t と wprintf を使ってどうやって日本語を出すのかわからなかったのでメモ。
#include <stdio.h>
#include <wchar.h>
#include <locale.h>

int main(int argc, char *argv[])
{
 wchar_t *str = L"( ´∀`)";
 setlocale(LC_ALL, "");
 fwide(stdout,1);
 wprintf(L"%ls\n",str);
 return 0;
}

Javaのソースコード&実行環境の文字コード指定

日本語表示しようとしたら ? と表示された場合の対応。
環境は OSX 10.7, Java 1.6.0_31。
javac -encoding UTF-8 Foo.java
java -Dfile.encoding=UTF-8 Foo

2012年5月18日金曜日

vimでinfoドキュメント

Linuxで食わず嫌いしているコマンドにinfoがある。
有用な情報が載ってるんだろうなとは思いつつも Emacs な操作体系で vim 派としては避けてしまう。
で、探してみたらありました。vim で info ドキュメントをみる方法。
詳しくは info.vim : vimエディタでinfoドキュメントを参照 をご覧下さい(笑)

なんですが、ちょっと補足。
このスクリプトは h キーをヘルプ表示に割り当てていて左にカーソル移動できなくなってしまっているので、
--- info.vim.orig 2012-05-18 02:10:24.000000000 +0900
+++ info.vim 2012-05-18 03:04:13.000000000 +0900
@@ -151,7 +151,7 @@
     endif
 
     " FIXME: <h> is move cursor left
-    noremap <buffer> h  :call <SID>Help()<cr>
+    noremap <buffer> H  :call <SID>Help()<cr>
     noremap <buffer> <CR> :call <SID>FollowLink()<cr>
     noremap <buffer> <C-]> :call <SID>FollowLink()<cr>
     " FIXME: <l> is move cursor right
等としておきます。

info ドキュメント参照用の起動スクリプトは次のようにしました。
#!/bin/sh
view -c :set\ nonumber -c :set\ tabstop=8 -c :set\ filetype=info -c :Info\ $*
info ドキュメントは8タブで書いてあるので tabstop=8 に、うっかり :w と叩くと表示している内容をカレントディレクトリに保存できてしまうので、view を起動するようにして防ぎます。
上のファイルを ${HOME}/local/bin/info として使おうとしたら info という名前が何かと衝突しているようでうまく動かなかったので viminfo という名前で保存して .bashrc に alias info=viminfo と書くようにしました。


追記 :
Ctrl-T での戻る動作がおかしいのに気付いたんですが、patch for info.vim のパッチを適用したら解決しました。
ついでに view で起動する必要もなくなりました。

2012年5月14日月曜日

CONFIG_HZ

詳細Linuxカーネルがタイマー周りのところまで読み進んだ。
そう言えば以前、CONFIG_HZの値が変更になったもめてたなと思って今はどうなってるんだろうと思ってちょっと調べてみた。 v2.6.13になる時に1000Hz->250Hzになったあと、x86は2.6.27で1000Hzに戻りPPC64(ppc64_defconfig)は2.6.33で100Hzになってた。 x86に関しては250Hzになる時は話題になってたけど、1000Hzに戻った理由は見つけられなかった。
なんでもどったんだろ?

2012年5月5日土曜日

初期ページテーブル

x86_64 Linux 起動時のページテーブルをみてみる。
ページグローバルディレクトリ等の用語はx86_64ではなくLinuxのものに従います。
以下のソースコードは linux-3.4-rc5/arch/x86/kernel/head_64.S です。

ページグローバルディレクトリ

まずページグローバルディレクトリ。
 /*
  * This default setting generates an ident mapping at address 0x100000
  * and a mapping for the kernel that precisely maps virtual address
  * 0xffffffff80000000 to physical address 0x000000. (always using
  * 2Mbyte large pages provided by PAE mode)
  */
NEXT_PAGE(init_level4_pgt)
 .quad level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE
 .org init_level4_pgt + L4_PAGE_OFFSET*8, 0
 .quad level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE
 .org init_level4_pgt + L4_START_KERNEL*8, 0
 /* (2^48-(2*1024*1024*1024))/(2^39) = 511 */
 .quad level3_kernel_pgt - __START_KERNEL_map + _PAGE_TABLE
コメント中にでてくるident mappingというのはリニアアドレスと物理アドレスが等しくなるマッピングのことのよう。 ここでは3つのエントリを定義している。
entry index address
          0 0x0000000000000000-0x0000007fffffffff
        272 0xffff880000000000-0xffff887fffffffff
        511 0xffffff8000000000-0xffffffffffffffff
エントリは512個ありますが、表にないものは無効なエントリです。
x86_64においてはアドレスの63-48ビットは47ビットの符号拡張になるのでエントリ番号272と511の上位2バイトが0xffffになっていることに注意。

ページアッパーディレクトリ

二つのページアッパーディレクトリが定義されている。
NEXT_PAGE(level3_ident_pgt)
 .quad level2_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE
 .fill 511,8,0

NEXT_PAGE(level3_kernel_pgt)
 .fill L3_START_KERNEL,8,0
 /* (2^48-(2*1024*1024*1024)-((2^39)*511))/(2^30) = 510 */
 .quad level2_kernel_pgt - __START_KERNEL_map + _KERNPG_TABLE
 .quad level2_fixmap_pgt - __START_KERNEL_map + _PAGE_TABLE
一つ目のlevel3_ident_pgtには先頭の1GBをマップするもの。
entry index address
          0 0x0000000000000000-0x000000003fffffff
二つ目のlevel3_kernel_pgtはカーネル用にお尻の2Gをマップするためのもの。
entry index address
        510 0x0000007f80000000-0x0000007fbfffffff
        511 0x0000007fc0000000-0x0000007fffffffff

ページミドルディレクトリ

これは四つ定義されている。まずそのうちの二つについて。
NEXT_PAGE(level2_ident_pgt)
 /* Since I easily can, map the first 1G.
  * Don't set NX because code runs from these pages.
  */
 PMDS(0, __PAGE_KERNEL_IDENT_LARGE_EXEC, PTRS_PER_PMD)

NEXT_PAGE(level2_kernel_pgt)
 /*
  * 512 MB kernel mapping. We spend a full page on this pagetable
  * anyway.
  *
  * The kernel code+data+bss must not be bigger than that.
  *
  * (NOTE: at +512MB starts the module area, see MODULES_VADDR.
  *  If you want to increase this then increase MODULES_VADDR
  *  too.)
  */
 PMDS(0, __PAGE_KERNEL_LARGE_EXEC,
  KERNEL_IMAGE_SIZE/PMD_SIZE)
一つ目のlevel2_ident_pgtはマクロでテーブルの全エントリをラージページ属性の有効なエントリとして定義さている。ラージページなので対応するページテーブルは必要ない。
次のlevel2_kernel_pgtはKERNEL_IMAGESIZE(512MBとdefineされている)分だけ有効なエントリを定義する。これもらラージページ属性付きなので対応するペーテーブルはない。
三つめはラージページ属性なしでページテーブルを使用するエントリとして定義する。
NEXT_PAGE(level2_fixmap_pgt)
 .fill 506,8,0
 .quad level1_fixmap_pgt - __START_KERNEL_map + _PAGE_TABLE
 /* 8MB reserved for vsyscalls + a 2MB hole = 4 + 1 entries */
 .fill 5,8,0
entry index address
        506 0x000000003f400000-0x000000003f5fffff

ページテーブル

最後のページテーブルは場所だけ確保されていて内容は定義されていない。
NEXT_PAGE(level1_fixmap_pgt)
 .fill 512,8,0

まとめ

以上を合わせると起動時には次のアドレスを変換するためのページテーブルが用意されていることになる。
0x0000000000000000-0x000000003fffffff
0xffff880000000000-0xffffff803fffffff
0xffffffff80000000-0xffffffff9fffffff
0xffffffffff400000-0xffffffffff5fffff

x86_64 Linuxのメモリマップ

まず、
linux-3.4-rc5/Documentation/x86/x86_64/mm.txt
<previous description obsolete, deleted>

Virtual memory map with 4 level page tables:

0000000000000000 - 00007fffffffffff (=47 bits) user space, different per mm
hole caused by [48:63] sign extension
ffff800000000000 - ffff80ffffffffff (=40 bits) guard hole
ffff880000000000 - ffffc7ffffffffff (=64 TB) direct mapping of all phys. memory
ffffc80000000000 - ffffc8ffffffffff (=40 bits) hole
ffffc90000000000 - ffffe8ffffffffff (=45 bits) vmalloc/ioremap space
ffffe90000000000 - ffffe9ffffffffff (=40 bits) hole
ffffea0000000000 - ffffeaffffffffff (=40 bits) virtual memory map (1TB)
... unused hole ... 
ffffffff80000000 - ffffffffa0000000 (=512 MB)  kernel text mapping, from phys 0
ffffffffa0000000 - fffffffffff00000 (=1536 MB) module mapping space

The direct mapping covers all memory in the system up to the highest
memory address (this means in some cases it can also include PCI memory
holes).

vmalloc space is lazily synchronized into the different PML4 pages of
the processes using the page fault handler, with init_level4_pgt as
reference.

Current X86-64 implementations only support 40 bits of address space,
but we support up to 46 bits. This expands into MBZ space in the page tables.

-Andi Kleen, Jul 2004
とあり、前から128TBがユーザー空間でお尻の2Gがカーネル空間になっている。
その間に97TBカーネル用にヒープやIO用の空間がある。
x86_64の現在の実装は48ビットのアドレス空間(256T)を持ち、上位16ビットは実質的には意味を持たない。ではアドレスを指定するときにその16ビットはどのような値にしておけばよいかという疑問がでる。インテルのマニュアルではそれに関する記述を見つけられなかったが、AMDのマニュアルには
Bits 63:48 are a sign extension of bit 47, as required for canonical-address forms.
とあり、上のドキュメントの中の
hole caused by [48:63] sign extension
も理解できる。
以上大雑把に理解すると、x86_64のLinuxにおいては64ビットのアドレス空間の先頭の128Tがユーザー空間、お尻の128Tがカーネル空間、その間の領域は無効なアドレスということになる。


Bloggerは基本タグ打ちな世界なんだな。
わかってきたよママン

x86_64のページテーブル

φ(..)メモメモ
ページグローバル
ディレクトリ
ページアッパー
ディレクトリ
ページミドル
ディレクトリ
ページ
テーブル
ページ内
オフセット
ビット幅999912
1エントリあたりの管理サイズ512GB1GB2MB4KB-


っとここまで古の"てがきえいちてぃーえむえる"という技で表書いたけど、それがBloggerの流儀なん!?
めんどくせー!

ぶろぐ

長続きしたためしが無いけどまたブログ初めてみます。
はてぶろにしようかと思ったけどアフィリエイトぉぉとささやく小人さんの気配がしたのでGoogle先生が用意してくれたBloggerにしました。 まずははてぶろにポストしたばかりのプログラムネタをこっちに引っ越すところから始めます。