espresso3389の日記 このページをアンテナに追加 RSSフィード

日記の検索

2012-02-12

[] Seasonic 660W 80PLUS GOLD SS-660KM 03:45  Seasonic 660W 80PLUS GOLD SS-660KMを含むブックマーク  Seasonic 660W 80PLUS GOLD SS-660KMのブックマークコメント

先日、メインマシンの電源が入らなくなり、いろいろと調べたところ、電源が逝かれてしまったことが判明したので、急遽、新しい電源ユニットを購入することになりました。友人曰く、冬は電源が死にやすいらしい。というか、基本、常時稼働のマシンだったので、ほとんど電源を落とすことがなかったのですが、たまたま、電源を落としてしまったところ、二度と電源が入らなくなってしまうという・・・。

で、購入したのが、Seasonic 660W 80PLUS GOLD SS-660KM。

オウルテック シーソニック電源 660W 80PLUS GOLD SS-660KM

オウルテック シーソニック電源 660W 80PLUS GOLD SS-660KM

以前の電源ユニットは、SilverStone SST-ST45NF 400Wという、ファンレス電源だったのですが、ファンレスだったが故に弱ってたという仮説も成り立つので、今回は、あえてファン付きにしました。80PLUS GOLDなので、効率は良いはずで無駄な発熱がなさそうなこと、さらに、ネットでの評判では、かなり静かということでこいつにしました。

f:id:espresso3389:20120211184821j:image

f:id:espresso3389:20120211181725j:image

評判通り、音はかなり静か。深夜の家で耳を澄ましても何も聞こえない・・・というより、ファン、回ってないんじゃ?っていう話です。

トラックバック - http://d.hatena.ne.jp/espresso3389/20120212

2012-02-01

効率的なメモリブロックサイズ 14:52  効率的なメモリブロックサイズを含むブックマーク  効率的なメモリブロックサイズのブックマークコメント

とっても環境依存で実装依存な事なんですが、一方で、メモリ効率っていうのは非常に大事なファクターです。

特に小さな構造体をメモリにたくさん配置するような場合、メモリのアラインメント(データを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バイトだということです。

トラックバック - http://d.hatena.ne.jp/espresso3389/20120201

2011-12-29

[][] MapView用のAPI Key署名から自動判別したい 03:25  MapView用のAPI Keyを署名から自動判別したいを含むブックマーク  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)の自己署名を検証する」

今回は、apkの署名デバッグ用とリリース用で違うから問題なわけで、それを検出して、対応するAPI Keyを貰えれば良い。で、Google様から貰えるAPI Keyは、署名に対応しているので、署名文字列化したものを直接コードに挿入したいところなんだけど、署名をそのまま書き込むのは気が引けるのと、そもそも、文字列としては極めてでかいことなど、どうなんだろうという感じなので、

Sign Up for the Android Maps API

にあるように署名MD5で比較するようにする。

ということで、ほぼ丸ままコピペ出来るコード。例外処理はいい加減ですが。コード中の、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();
}
トラックバック - http://d.hatena.ne.jp/espresso3389/20111229

2011-12-08

[][] ndk-buildを使わないでプログラムビルドする 03:10  ndk-buildを使わないでプログラムをビルドするを含むブックマーク  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などを設定してあげれば良い感じみたいだ。

トラックバック - http://d.hatena.ne.jp/espresso3389/20111208

2011-11-08

[][] 16GB(8GBx2) on ThinkPad T420s 出直し 11:00  16GB(8GBx2) on ThinkPad T420s 出直しを含むブックマーク  16GB(8GBx2) on ThinkPad T420s 出直しのブックマークコメント

初期不良にぶつかってしまって、12GBという中途半端な状況になっていましたが、パソコンショップアークに連絡後、着払いで不良品を返して、今日、本日、交換の品が届きました!仕事が早い。

f:id:espresso3389:20111108104030j:image

ということで、気を取り直して、エクスペリエンスインデックスを取り直し。

f:id:espresso3389:20111108105647p:image

f:id:espresso3389:20111108105648p:image

やっぱり、同じモジュールを二枚にすれば、パフォーマンスはちゃんと出ています。4GBx2の時とパフォーマンスは変わってないどころか、グラフィックスの数字が上がっています。そんなところに影響があるのかぁという感じです。

これで、VMwareVMを動かしまくっても全く問題のない環境が出来ました!

トラックバック - http://d.hatena.ne.jp/espresso3389/20111108