最近、コードを書くとき、keyword 引数を使うようになってきたんだけど、
def foo(a: true) do_something if a end foo(a: false)
のつもりで、
def foo(a = true) do_something if a end
と書いてしまって、foo(a: false) とやっても a は Hash object {a: false} になってしまい、偽にならなくて困ったという話。なんとなく動いちゃってるから、よくわからなかったという。
オプショナル引数禁止、とかできるといいのかもしれないな。
仮想マシン上で TSC (time stamp counter) がどうなるか、という話。
てっきり、CPU の物理 TSC が返るのかと思ったら、ちゃんと VT-x では trap するようになっているようで。
#if defined(__GNUC__) && defined(__i386__)
typedef unsigned long long tick_t;
static inline tick_t
tick(void)
{
unsigned long long int x;
__asm__ __volatile__ ("rdtsc" : "=A" (x));
return x;
}
#elif defined(__GNUC__) && defined(__x86_64__)
typedef unsigned long long tick_t;
static __inline__ tick_t
tick(void)
{
unsigned long hi, lo;
__asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
return ((unsigned long long)lo)|( ((unsigned long long)hi)<<32);
}
#elif defined(_WIN32) && defined(_MSC_VER)
#include <intrin.h>
typedef unsigned __int64 tick_t;
static tick_t
tick(void)
{
return __rdtsc();
}
#else /* use clock */
typedef clock_t tick_t;
static inline tick_t
tick(void)
{
return clock();
}
#endif
int main()
{
volatile int n = 0x100000;
int i;
for (i=0; i<n; i++) {
tick();
}
}
#if 0
$ gcc -O0 rdtsc.c && time ./a.out
仮想マシン(VirtualBox on Windows):
real 0m1.744s
user 0m1.740s
sys 0m0.000s
同じマシンでのVC:
real 0m0.049s
user 0m0.000s
sys 0m0.015s
別の実機(Debian/Squeeze):
real 0m0.039s
user 0m0.040s
sys 0m0.000s
#endif
明らかに結果が違う。
Stack overflow で、Why is RDTSC a virtualized instruction on modern processors? では、同じような質問をされているんだけど、accuracy が重要なんだよ、とか、そういう話。
side-channel attack というか、VM 上で動いているかどうかの判定に使われないようにする、っていうのも、結局 rdtsc が 30 倍程度遅くなることがわかってしまうので、無理なんじゃないかなぁ。
offsetting を VM-exitting ごとに適切に再設定すれば、RDTSC 命令自体は、CPU 1 命令で済むのかと思ったけど、offsetting の仕様を適切に理解できていない気もする。
元々、clock_gettime() がえらい遅い、ということで調べ始めたのだけど。VM 上の時間取得は大変(鬼門)だなぁ。準仮想化のターゲットにしないのかしら(ホスト側の設定値がそのまま見える、的な)。