2012-02-12
■[ハードウェア] Seasonic 660W 80PLUS GOLD SS-660KM

先日、メインマシンの電源が入らなくなり、いろいろと調べたところ、電源が逝かれてしまったことが判明したので、急遽、新しい電源ユニットを購入することになりました。友人曰く、冬は電源が死にやすいらしい。というか、基本、常時稼働のマシンだったので、ほとんど電源を落とすことがなかったのですが、たまたま、電源を落としてしまったところ、二度と電源が入らなくなってしまうという・・・。
で、購入したのが、Seasonic 660W 80PLUS GOLD SS-660KM。
オウルテック シーソニック電源 660W 80PLUS GOLD SS-660KM
- 出版社/メーカー: オウルテック
- 発売日: 2010/10/26
- メディア: Personal Computers
- クリック: 6回
- この商品を含むブログ (2件) を見る
以前の電源ユニットは、SilverStone SST-ST45NF 400Wという、ファンレス電源だったのですが、ファンレスだったが故に弱ってたという仮説も成り立つので、今回は、あえてファン付きにしました。80PLUS GOLDなので、効率は良いはずで無駄な発熱がなさそうなこと、さらに、ネットでの評判では、かなり静かということでこいつにしました。
評判通り、音はかなり静か。深夜の家で耳を澄ましても何も聞こえない・・・というより、ファン、回ってないんじゃ?っていう話です。
2012-02-01
■ 効率的なメモリブロックサイズ

とっても環境依存で実装依存な事なんですが、一方で、メモリ効率っていうのは非常に大事なファクターです。
特に小さな構造体をメモリにたくさん配置するような場合、メモリのアラインメント(データをCPUが効率的にアクセスできるきりの良いアドレスに配置すること、16バイトとか、32バイトといった単位になることが多い)のため、メモリが無駄になることが多いです。
例えば、現状のIntel x86系で32-bit OSだと、6バイトのメモリを確保するなんてことをすると、アラインメント単位がおそらく、16バイトなので、10バイト分が利用されることなく無駄な領域として残されることになります。ただし、一般的に、mallocやnewで確保されるメモリブロックには管理領域という領域が確保されるので、
char* p = new char[10];
っていう処理が果たして何バイトの領域を必要として、結果、どれだけの領域を確保するのかは実際に試してみないといけません(コードを読んでも良いんですが、それだと環境毎にソースを読まないといけないので、簡単なコードを実行する方が楽です)。
ということで、実験コード。テスト用コードなのでメモリを解放していません。
// memalign.cpp #include <stdio.h> #include <stdlib.h> int main(int argc, char* argv[]) { if(argc < 3) { printf("%s BLOCK_SIZE COUNT\n", argv[0]); return -1; } size_t blockSize = atoi(argv[1]); size_t count = atoi(argv[2]); for(size_t i = 0; i < count; i++) { unsigned char *p = new unsigned char[blockSize]; printf("%u\t%p\n", i, p); } }
32ビット環境でのテスト
これを、Visual Studio 2010 SP1の32ビット版コンパイラ:
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86
でビルドしてテストしてみます。最初に、10バイトのブロックを10個確保してみます。
C:\work>memalign 10 20 0 00793C08 1 00791A00 2 00791A18 3 00791A30 4 00791A48 5 00791A60 6 00791A78 7 00791A90 8 00791AA8 9 00791AC0
そうすると、最初の奴は無視するとして、メモリブロックの間隔が、0x18(24)バイト単位で推移していることになります。つまり、10バイト確保すると、実際には、24バイトが消費されているわけです!
次は、8バイトを確保する実験。
C:\work>memalign 8 10 0 00963C08 1 00961A00 2 00961A10 3 00961A20 4 00961A30 5 00961A40 6 00961A50 7 00961A60 8 00961A70 9 00961A80
綺麗に16バイトずつ確保されているのが分かります。結論から言うと、この環境においては、管理ブロックが8バイトで、さらに、メモリブロックの先頭が8バイトに揃うようにメモリが確保されているわけです。つまり、1〜8バイトのメモリ確保は、結果的には、16バイトのメモリを消費するということです。16バイトのメモリ確保は、32バイトのメモリ消費です。メモリがもったいないと思って、メモリ確保のサイズをケチるときにはこの事実をキッチリと頭に入れておく必要があります。実装依存ですけど。
1バイトを確保してみると、
C:\work>memalign 1 10 0 00513C10 1 00511A00 2 00511A10 3 00511A20 4 00511A30 5 00511A40 6 00511A50 7 00511A60 8 00511A70 9 00511A80
やっぱり16バイト持って行かれます。無駄すぎる。
64ビット環境でのテスト
次に、Visual Studio 2010 SP1の64ビット版コンパイラ:
Microsoft (R) C/C++ Optimizing Compiler Version 16.00.40219.01 for x64
で試します。最初は、さっきと同じで、10バイトのブロックを10個確保してみます。
C:\work>memalign 10 10 0 00000000004A8520 1 00000000004A8540 2 00000000004A8560 3 00000000004A8580 4 00000000004A85A0 5 00000000004A85C0 6 00000000004A85E0 7 00000000004A8600 8 00000000004A8620 9 00000000004A8640
64ビットなのでアドレス表記が16桁になっています。今回はアドレスの間隔が32バイト。
つまり、10バイト確保する毎に、32バイトを消費しています。
試しに1バイト確保してみると、
C:\work>memalign 1 10 0 0000000000538E30 1 0000000000538E50 2 0000000000538E70 3 0000000000538E90 4 0000000000538EB0 5 0000000000538ED0 6 0000000000538EF0 7 0000000000538F10 8 0000000000538F30 9 0000000000538F50
やっぱりというかなんというか、32バイト確保しています!32ビット版に輪を掛けてもったいなさ過ぎ!
32バイトというのは64ビット環境での最小ブロック単位なわけです。
テストすれば分かりますが、こっちは、24バイト確保すると32バイト消費し、25バイト確保すると、48バイト消費します。
つまり、管理領域は、8バイト。32ビット版と管理領域のサイズが同じなので、よく考えるとお得かも知れません。
Mac OS X 10.7 + g++ 4.2.1
OS X 10.7での結果。
$ ./memalign 16 10 0 0x10df00a00 1 0x10df00a10 2 0x10df00a20 3 0x10df00a30 4 0x10df00a40 5 0x10df00a50 6 0x10df00a60 7 0x10df00a70 8 0x10df00a80 9 0x10df00a90
素敵なことに、メモリのブロックには管理ブロックは付きません。綺麗に、16バイト単位で並んでいます。
Ubuntu 11.10 (GNU/Linux 3.0.0-13-server x86_64) + g++ 4.6.1
$ ./memalign 1 10 0 0x1186010 1 0x1186030 2 0x1186050 3 0x1186070 4 0x1186090 5 0x11860b0 6 0x11860d0 7 0x11860f0 8 0x1186110 9 0x1186130 $ ./memalign 24 10 0 0x1045010 1 0x1045030 2 0x1045050 3 0x1045070 4 0x1045090 5 0x10450b0 6 0x10450d0 7 0x10450f0 8 0x1045110 9 0x1045130 $ ./memalign 28 10 0 0x1a5d010 1 0x1a5d040 2 0x1a5d070 3 0x1a5d0a0 4 0x1a5d0d0 5 0x1a5d100 6 0x1a5d130 7 0x1a5d160 8 0x1a5d190 9 0x1a5d1c0
1バイトでも32バイトを消費してくれます。24バイト確保と28バイト確保の結果から、管理領域は、8バイト。Windows 64ビット版と大きくは変わらないようですね。
参考文献
x64 Software Conventionsについてっぽいので、32ビットについては微妙だけど、mallocは16バイトアラインメントと書いてある。
malloc Alignment - Visual Studio .2010
glibcのアラインメントは、8の倍数(64ビットなら、16の倍数)
3.2.2.7 Allocating Aligned Memory Blocks - The GNU C Library
Mac OS Xのアラインメント(というかメモリ粒度)は16バイト。
Tips for Allocating Memory - Mac OS X Developer Library
追記
誤解を招くといけないので、追記しておきますが、
int *p = new int[10];
が10*16バイト消費したりするわけではありません。この場合、ブロックの先頭は16バイト単位にアラインメントされますが、32ビットのintの値は継ぎ目なく確保されるので、この場合は、おそらく、4*10+8=48バイトしか消費しません。
あくまでも、malloc/newした時のメモリ確保の最小単位が16バイトで、管理ブロックのサイズが8バイトだということです。
2011-12-29
■[Android][Java] MapView用のAPI Keyを署名から自動判別したい

Android上で、MapViewを使おうとすると、API Keyをlayout.xmlに書き込まないといけない。
さらに、このAPI Keyはアプリの署名から生成されるので、デバッグ用の署名(debug.keystore)とリリース用の署名で別々のモノを使わないといけない。
そうすると、リリース時にAPI Keyを入れ替えるだけのためにコードを修正しないといけなくなるわけで、スゲーめんどくさいし、間違えて、リリース用のAPI Keyをリポジトリにcommitしちゃったりして周りに迷惑を掛けたりして・・・みたいな事になる。
これに関して、
Android ApiキーをRelease版とDebug版で切り替える方法
の様なことをやっている方もいるのだけども、正直、android:debuggableを見るのも微妙な気がする。というか、android:debuggable使ってない・・・。
ので、apkの署名で使うAPI Keyを切り替えようと考えました。
要は、アプリ上で、
MapView mapView = new MapView(this, getMapApiKey());
のような感じで署名に対応したAPI Keyを自動的に返してくれるといいなぁと。
元ネタは、たまたま、この記事を見つけたから。
今回は、apkの署名がデバッグ用とリリース用で違うから問題なわけで、それを検出して、対応するAPI Keyを貰えれば良い。で、Google様から貰えるAPI Keyは、署名に対応しているので、署名を文字列化したものを直接コードに挿入したいところなんだけど、署名をそのまま書き込むのは気が引けるのと、そもそも、文字列としては極めてでかいことなど、どうなんだろうという感じなので、
Sign Up for the Android Maps API
ということで、ほぼ丸ままコピペ出来るコード。例外処理はいい加減ですが。コード中の、XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XXの部分は、Google様からAPI Keyを貰うときに渡したフィンガープリントの文字列をそのまま書いて貰って、その下のAPI Keyの部分は対応するキーに。複数のプロジェクトで共有しているモジュールの場合は、全部のプロジェクト用の対応をここに追加してもいいかもしれない。
// パッケージ署名に対応するAPI Keyを返す String getMapApiKey() { PackageManager pm = getPackageManager(); try { PackageInfo pi = pm.getPackageInfo(getPackageName(), PackageManager.GET_SIGNATURES); for (Signature sig : pi.signatures) { String key = getMapApiKey(sig); if (key != null) return key; } } catch (NameNotFoundException e) { e.printStackTrace(); } return null; } // 与えられた署名に対応するAPI Keyを返す static String getMapApiKey(Signature sig) { String sigStr = getSignatureFingerPrint(sig); // デバッグ用署名(debug.keystore)に対応するAPI Key if (sigStr.equals("XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX")) return "<<デバッグ用署名用のAPI Keyをここに挿入>>"; // リリース用署名に対応するAPI Key if (sigStr.equals("XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX")) return "<<リリース用署名用のAPI Keyをここに挿入>>"; // その他の署名とAPI Keyの対応など // ... return null; } // 署名のMD5を文字列形式で返す static String getSignatureFingerPrint(Signature sig) { try { MessageDigest md = MessageDigest.getInstance("MD5"); md.update(sig.toByteArray()); return hex(md.digest()); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); return null; } } // バイト列の16進文字列化 static String hex(byte[] bin) { StringBuilder sb = new StringBuilder(bin.length * 3 - 1); for (int i = 0; i < bin.length; i++) { sb.append(String.format("%02X", bin[i])); if (i + 1 < bin.length) sb.append(':'); } return sb.toString(); }
2011-12-08
■[Android][C++] ndk-buildを使わないでプログラムをビルドする

普段は、ndk-buildでビルドをしているのが楽だし、便利なんですが、時に、外部のライブラリがconfigureとか使ってて、自前でAndroid.mkとかを作るのが面倒なことがあります。というか、試しに自前で作ってみようとしたけど、新旧の情報が錯綜しており、また、C++を使った場合のリンク方法がさっぱりとか、とりあえず、root化した端末でコマンドラインベースのコードを動かしてみたいけど・・・な場合にどうやれば良いのか全く分かりませんでした。
結局、当たり前ながら、じゃぁ、ndk-buildは何をやってるんでございましょうということになるんですが、これを見てみるために凄く簡単なサンプルを作ってみます。
sample/
jni/
Application.mk
Android.mk
sample.cpp
というディレクトリ構造で、
# Application.mk APP_ABI := armeabi-v7a # RTTI、例外を使うためにstatic GNU STLを利用する APP_STL := gnustl_static
# Android.mk LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := sample LOCAL_CFLAGS := LOCAL_SRC_FILES += sample.cpp LOCAL_STATIC_LIBRARIES += gnustl_static include $(BUILD_EXECUTABLE)
// sample.cpp #include <iostream> #include <vector> int main(int argc, char* argv[]) { // 単にSTLが使えているかどうかをチェックしたい std::vector<int> v(256); std::cout << "Hello, world." << v.size() << std::endl; }
っていうのを作って、jni/ディレクトリで
ndk-build -n
とやると(ちなみに、/opt/android-ndk-r7にAndroid NDK r7をインストールしている)、
rm -f /somewhere/sample/libs/armeabi/lib*.so /somewhere/sample/libs/armeabi-v7a/lib*.so /somewhere/sample/libs/x86/lib*.so rm -f /somewhere/sample/libs/armeabi/gdbserver /somewhere/sample/libs/armeabi-v7a/gdbserver /somewhere/sample/libs/x86/gdbserver rm -f /somewhere/sample/libs/armeabi/gdb.setup /somewhere/sample/libs/armeabi-v7a/gdb.setup /somewhere/sample/libs/x86/gdb.setup mkdir -p /somewhere/sample/obj/local/armeabi-v7a/objs/helloworld/ echo """Compile++ thumb"" : helloworld <= sample.cpp" ccache /opt/android-ndk-r7/toolchains/arm-linux-androideabi-4.4.3/prebuilt/darwin-x86/bin/arm-linux-androideabi-g++ -MMD -MP -MF /somewhere/sample/obj/local/armeabi-v7a/objs/helloworld/sample.o.d -fpic -ffunction-sections -funwind-tables -fstack-protector -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ -Wno-psabi -march=armv7-a -mfloat-abi=softfp -mfpu=vfp -fno-exceptions -fno-rtti -mthumb -Os -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64 -I/opt/android-ndk-r7/sources/cxx-stl/gnu-libstdc++/include -I/opt/android-ndk-r7/sources/cxx-stl/gnu-libstdc++/libs/armeabi-v7a/include -I/opt/android-ndk-r7/sources/cxx-stl/gnu-libstdc++/include -I/opt/android-ndk-r7/sources/cxx-stl/gnu-libstdc++/libs/armeabi-v7a/include -I/somewhere/sample/jni -DANDROID -Wa,--noexecstack -fexceptions -frtti -fexceptions -frtti -O2 -DNDEBUG -g -fexceptions -frtti -I/opt/android-ndk-r7/platforms/android-3/arch-arm/usr/include -c /somewhere/sample/jni/sample.cpp -o /somewhere/sample/obj/local/armeabi-v7a/objs/helloworld/sample.o mkdir -p /somewhere/sample/obj/local/armeabi-v7a/ echo "Prebuilt : libgnustl_static.a <= <NDK>/sources/cxx-stl/gnu-libstdc++/libs/armeabi-v7a/" cp -f /opt/android-ndk-r7/sources/cxx-stl/gnu-libstdc++/libs/armeabi-v7a/libgnustl_static.a /somewhere/sample/obj/local/armeabi-v7a/libgnustl_static.a mkdir -p /somewhere/sample/obj/local/armeabi-v7a/ echo "Executable : helloworld" /opt/android-ndk-r7/toolchains/arm-linux-androideabi-4.4.3/prebuilt/darwin-x86/bin/arm-linux-androideabi-g++ -Wl,--gc-sections -Wl,-z,nocopyreloc --sysroot=/opt/android-ndk-r7/platforms/android-3/arch-arm /somewhere/sample/obj/local/armeabi-v7a/objs/helloworld/sample.o /somewhere/sample/obj/local/armeabi-v7a/libgnustl_static.a /somewhere/sample/obj/local/armeabi-v7a/libgnustl_static.a /opt/android-ndk-r7/toolchains/arm-linux-androideabi-4.4.3/prebuilt/darwin-x86/bin/../lib/gcc/arm-linux-androideabi/4.4.3/libgcc.a -Wl,--fix-cortex-a8 -Wl,--no-undefined -Wl,-z,noexecstack -lc -lm -o /somewhere/sample/obj/local/armeabi-v7a/helloworld echo "Install : helloworld => libs/armeabi-v7a/helloworld" mkdir -p /somewhere/sample/libs/armeabi-v7a install -p /somewhere/sample/obj/local/armeabi-v7a/helloworld /somewhere/sample/libs/armeabi-v7a/helloworld /opt/android-ndk-r7/toolchains/arm-linux-androideabi-4.4.3/prebuilt/darwin-x86/bin/arm-linux-androideabi-strip --strip-unneeded /somewhere/sample/libs/armeabi-v7a/helloworld
という感じのことをやっている事が分かる。
つまり、まとめると、コンパイル、リンク、リンク後処理として、
# コンパイル /opt/android-ndk-r7/toolchains/arm-linux-androideabi-4.4.3/prebuilt/darwin-x86/bin/arm-linux-androideabi-g++ \ -MMD -MP -MF \ /somewhere/sample/obj/local/armeabi-v7a/objs/helloworld/sample.o.d \ -fpic \ -ffunction-sections -funwind-tables -fstack-protector \ -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ \ -Wno-psabi \ -march=armv7-a -mfloat-abi=softfp -mfpu=vfp \ -fno-exceptions -fno-rtti \ -mthumb \ -Os \ -fomit-frame-pointer \ -fno-strict-aliasing \ -finline-limit=64 \ -I/opt/android-ndk-r7/sources/cxx-stl/gnu-libstdc++/include \ -I/opt/android-ndk-r7/sources/cxx-stl/gnu-libstdc++/libs/armeabi-v7a/include \ -I/somewhere/sample/jni \ -DANDROID \ -Wa,--noexecstack \ -O2 -DNDEBUG -g \ -I/opt/android-ndk-r7/platforms/android-3/arch-arm/usr/include \ -c /somewhere/sample/jni/sample.cpp \ -o /somewhere/sample/obj/local/armeabi-v7a/objs/helloworld/sample.o
# リンク /opt/android-ndk-r7/toolchains/arm-linux-androideabi-4.4.3/prebuilt/darwin-x86/bin/arm-linux-androideabi-g++ \ -Wl,--gc-sections \ -Wl,-z,nocopyreloc \ --sysroot=/opt/android-ndk-r7/platforms/android-3/arch-arm \ /somewhere/sample/obj/local/armeabi-v7a/objs/helloworld/sample.o \ /somewhere/sample/obj/local/armeabi-v7a/libgnustl_static.a \ /opt/android-ndk-r7/toolchains/arm-linux-androideabi-4.4.3/prebuilt/darwin-x86/lib/gcc/arm-linux-androideabi/4.4.3/libgcc.a \ -Wl,--fix-cortex-a8 \ -Wl,--no-undefined \ -Wl,-z,noexecstack \ -lc -lm \ -o /somewhere/sample/obj/local/armeabi-v7a/helloworld
# デバッグ情報の除去 /opt/android-ndk-r7/toolchains/arm-linux-androideabi-4.4.3/prebuilt/darwin-x86/bin/arm-linux-androideabi-strip \ --strip-unneeded \ /somewhere/sample/libs/armeabi-v7a/helloworld
ということが分かる(一部、重複など簡略化済み)。
あとは、この辺を配慮した上でconfigure様に、CC/CXX/LD/CFLAGS/LDFLAGSなどを設定してあげれば良い感じみたいだ。




