2014年9月5日金曜日

The Silver Searcher (ag)を使う

agをインストールして、vimからも使えるようにします。

使用した環境

Xubuntu 14.04

agとは

超高速grepです。
こちらで、概要を知れました。
http://gihyo.jp/admin/serial/01/ubuntu-recipe/0287

私はよく次のようなgrepを実行するのですが、
$ grep -irn pattern .
それがagだと次のように代わります。
$ ag -i pattern
また、agは、.(ドット)から始まるファイルをデフォルトで検索対象から除外するので、.svnとか.gitとかが配下にあるディレクトリだとgrepよりもさらに便利です。

インストール

$ sudo apt-get install silversearcher-ag

vimからも使えるようにする

こちらを参照しました。
http://blog.glidenote.com/blog/2013/02/28/the-silver-searcher-better-than-ack/

Vundle.vimを使っているので、.vimrcに次を追加しました。
Bundle 'rking/ag.vim'

vimのコマンドラインから次のように使えます。
:Ag -i pattern

参考

ag本家はここみたいです。
https://github.com/ggreer/the_silver_searcher

2014年8月23日土曜日

golang: time.Tick() の精度

time.Tick()がどの程度の精度を持っているか気になったので実行結果を見てみました。
実行環境に依ると思いますが、今回の結果としては、1ms間隔のTickを要求して、平均1023us、標準偏差232usでした。思った以上に精度が悪かったです。
この結果が、golangのタイマーの実装に依るものなのか、OSのタイマーの精度に依るものなのか、までは調べていません。実行環境がLinuxだったので、後者の影響が大きいと思います。

使用した環境

Xubuntu 12.04
go1.3

テストコード

以下のコードtime_precision.goは、1ms間隔のTickを1000回取得して、その平均値を計算しています。
package main

import (
        "fmt"
        "sync"
        "time"
)

const numof_sample = 1000
const interval_millisec = 1

func main() {
        times := make([]time.Time, numof_sample)
        tick := time.Tick(interval_millisec * time.Millisecond)
        var wg sync.WaitGroup

        wg.Add(1)
        go func() {
                for i := 0; i < len(times); i++ {
                        times[i] = <-tick
                }
                wg.Done()
        }()
        wg.Wait()

        ave := int64(0)
        for i := 1; i < len(times); i++ {
                diff := times[i].UnixNano() - times[i-1].UnixNano()
                ave += diff
                fmt.Printf("tick interval: %6d [us]\n", diff/1000)
        }
        ave /= int64(len(times) - 1)
        fmt.Printf("ave: %6d [us]\n", ave/1000)
}

実行結果

$ go run time_precision.go
tick interval:    964 [us]
tick interval:   1002 [us]
tick interval:   1004 [us]
tick interval:    974 [us]
tick interval:    971 [us]
tick interval:   1023 [us]
tick interval:   1024 [us]
tick interval:   1025 [us]
(中略)
tick interval:   1374 [us]
tick interval:    509 [us]
tick interval:   1480 [us]
tick interval:    540 [us]
tick interval:   1684 [us]
tick interval:    337 [us]
tick interval:    929 [us]
ave:   1023 [us]

平均は、1023usでした。
別途標準偏差を計算すると、標準偏差は232usでした。
msオーダではtime.Tick()の精度はあまり期待できないようです。

参考

http://stackoverflow.com/questions/14610459/how-precise-is-gos-time-really
http://d.hatena.ne.jp/naoya/20080122/1200960926

2014年8月1日金曜日

GoでHelloWorld

使用した環境

Xubuntu 12.04
go1.3

インストール

次のURLから自分の環境に合ったバイナリをダウンロードする。
http://golang.org/dl/

解凍
tar xzf go1.3.linux-386.tar.gz

解凍してできたディレクトリgoは、/usr/local/以下に置くか、自分の好きな場所に置くか、どちらかを選ぶ。
/usr/local/以下に置く場合は、$/HOME/.profileでPATHに加えるだけ。
export PATH=$PATH:/usr/local/go/bin

自分の好きな場所に置く場合は、$/HOME/.profileで環境変数GOROOTをexportして、PATHに加える。
export GOROOT=$HOME/go
export PATH=$PATH:$GOROOT/bin

HelloWorld

以下の内容を、hello.goに保存する。
package main

import "fmt"

func main() {
    fmt.Printf("hello, world\n")
}

実行する。
$ go run hello.go
hello, world

参考
http://golang.jp/install
http://golang.org/doc/install

2014年7月31日木曜日

C/C++のdo-whileでcontinueしたときの振る舞い

自分が思ってたのと違った振る舞いだったので、記載しておく。

do-while continue

#include <stdio.h>
#define TRUE    1
#define FALSE   0

typedef unsigned char BOOL;

int main(void)
{

        BOOL inLoop = TRUE;

        printf("--- loop begin ---\n");
        do
        {
                if(inLoop)
                {
                        printf("--- in loop ---\n");
                        continue;
                }
        }
        while(FALSE);
        printf("--- loop end ---\n");

        return 0;
}

振る舞い

--- loop begin ---
--- in loop ---
--- loop end ---
inLoopな限り、無限ループさせようとしたものの、そうはならなかった。

2014年7月29日火曜日

Google code prettifyをBloggerに設定する

自分用メモ。

設定

BloggerのHTML編集から、<head></head>タグ内に次の内容を追加する。

<script src="https://google-code-prettify.googlecode.com/svn/loader/run_prettify.js?autoload=true&amp;skin=sunburst&amp;lang=css" defer="defer"></script>

続いて<body>タグに次の内容を追加する。(これはなくても動く模様)
<body onload="prettyPrint()">

Hello world

次のようにHTML編集する。
<pre class="prettyprint">#include &lt;stdio.h&gt;

int main(void)
{
    printf("Hello world\n");

    return 0;
}
</pre>
その結果、以下のように表示される。
#include <stdio.h>

int main(void)
{
    printf("Hello world\n");

    return 0;
}

参考にしたページ
http://blog.pamelafox.org/2010/08/how-to-pretty-print-code-snippets-in.html
https://code.google.com/p/google-code-prettify/wiki/GettingStarted

2014年7月18日金曜日

シグナルハンドラを実行するスレッドとスタック

気になったので、実際にコードを動かして振る舞いを見てみました。
結論としては、今回使用した環境では、シグナルを受け取ったスレッドが、そのスレッドのスタック上でシグナルハンドラを実行するようです。この振る舞いがPOSIX標準などで決まっているのかどうかは私にはわかりませんでした。
調べる前は、シグナルハンドラ用のスタックが別にあるのだろうか、などと想像していました。処理系によるんでしょうか(?)。

使用した環境

Xubuntu 12.04
gcc 4.6.3

使用したコード

#include <stdio.h>
#include <signal.h>
#include <sys/resource.h>
#include <pthread.h>

static void signalHandler_(
        int signum,
        siginfo_t* info,
        void* ucontext
        )
{
        printf("--- signal handler ---\n");
        printf("thread id:          [0x%08x]\n", (unsigned int)pthread_self());
        printf("signum:             [%d]\n", signum);
        printf("siginfo_t.si_signo: [%d]\n", info->si_signo);
        printf("siginfo_t.si_errno: [%d]\n", info->si_errno);
        printf("siginfo_t.si_code:  [%d]\n", info->si_code);
        printf("&signum:            [%p]\n", &signum);
        printf("&info:              [%p]\n", &info);
        printf("&ucontext:          [%p]\n", &ucontext);
        printf("\n");
}
static void* run_(
        void* arg
        )
{
        pthread_mutex_t* mutex = (pthread_mutex_t*)arg;
        pthread_attr_t attr;
        void* stack_addr;
        size_t stack_size;

        pthread_getattr_np(pthread_self(), &attr);
        pthread_attr_getstack(&attr, &stack_addr, &stack_size);

        pthread_mutex_lock(mutex);

        printf("--- pthread ---\n");
        printf("thread id:          [0x%08x]\n", (unsigned int)pthread_self());
        printf("stack addr:         [%p]\n", stack_addr);
        printf("stack size:         [0x%08x]\n", stack_size);
        printf("&arg:               [%p]\n", &arg);
        printf("\n");
        raise(SIGINT);
        raise(SIGINT);

        pthread_mutex_unlock(mutex);

        return NULL;
}

int main(void)
{
        struct sigaction action;
        pthread_t thread1;
        pthread_t thread2;
        pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

        action.sa_sigaction = signalHandler_;
        sigfillset(&(action.sa_mask));
        action.sa_flags = SA_SIGINFO;
        sigaction(SIGINT, &action, NULL);

        printf("--- main ---\n");
        printf("thread id:          [0x%08x]\n", (unsigned int)pthread_self());
        printf("&action:            [%p]\n", &action);
        printf("&thread1:           [%p]\n", &thread1);
        printf("&thread2:           [%p]\n", &thread2);
        printf("\n");

        raise(SIGINT);
        raise(SIGINT);

        pthread_mutex_lock(&mutex);
        pthread_create(&thread1, NULL, run_, &mutex);
        pthread_create(&thread2, NULL, run_, &mutex);
        pthread_mutex_unlock(&mutex);
        pthread_join(thread1, NULL);
        pthread_join(thread2, NULL);

        return 0;
}

コードの実行結果

--- main ---
thread id:          [0x401f9d00]
&action:            [0xbfb5be00]
&thread1:           [0xbfb5be8c]
&thread2:           [0xbfb5be90]

--- signal handler ---
thread id:          [0x401f9d00]
signum:             [2]
siginfo_t.si_signo: [2]
siginfo_t.si_errno: [0]
siginfo_t.si_code:  [-6]
&signum:            [0xbfb5bcd0]
&info:              [0xbfb5bcd4]
&ucontext:          [0xbfb5bcd8] ← &thread2のアドレス 0xbfb5be90よりも小さいアドレス。

--- signal handler ---
thread id:          [0x401f9d00]
signum:             [2]
siginfo_t.si_signo: [2]
siginfo_t.si_errno: [0]
siginfo_t.si_code:  [-6]
&signum:            [0xbfb5bcd0]
&info:              [0xbfb5bcd4]
&ucontext:          [0xbfb5bcd8]

--- pthread ---
thread id:          [0x403fbb40]
stack addr:         [0x401fb000]
stack size:         [0x00201000]
&arg:               [0x403fb31c]

--- signal handler ---
thread id:          [0x403fbb40]
signum:             [2]
siginfo_t.si_signo: [2]
siginfo_t.si_errno: [0]
siginfo_t.si_code:  [-6]
&signum:            [0x403fb1e0]
&info:              [0x403fb1e4]
&ucontext:          [0x403fb1e8] ← &argのアドレス 0x403fb31cよりも小さいアドレス

--- signal handler ---
thread id:          [0x403fbb40]
signum:             [2]
siginfo_t.si_signo: [2]
siginfo_t.si_errno: [0]
siginfo_t.si_code:  [-6]
&signum:            [0x403fb1e0]
&info:              [0x403fb1e4]
&ucontext:          [0x403fb1e8]

--- pthread ---
thread id:          [0x405fcb40]
stack addr:         [0x403fc000]
stack size:         [0x00201000]
&arg:               [0x405fc31c]

--- signal handler ---
thread id:          [0x405fcb40]
signum:             [2]
siginfo_t.si_signo: [2]
siginfo_t.si_errno: [0]
siginfo_t.si_code:  [-6]
&signum:            [0x405fc1e0]
&info:              [0x405fc1e4]
&ucontext:          [0x405fc1e8] ← &argのアドレス 0x405fb31cよりも小さいアドレス

--- signal handler ---
thread id:          [0x405fcb40]
signum:             [2]
siginfo_t.si_signo: [2]
siginfo_t.si_errno: [0]
siginfo_t.si_code:  [-6]
&signum:            [0x405fc1e0]
&info:              [0x405fc1e4]
&ucontext:          [0x405fc1e8]

printfで表示させたスレッドIDとスタックのアドレスから判断するに、シグナルを受け取ったスレッドが、そのスレッドのスタック上でシグナルハンドラを実行していることがわかります。


最後に、上記とは直接関係ないですが、シグナルに関して参考にしたページ。
http://www.nminoru.jp/~nminoru/programming/stackoverflow_handling.html
http://codezine.jp/article/detail/4700
http://www.jpcert.or.jp/sc-rules/c-sig30-c.html

2014年7月16日水曜日

SpinでHelloWorld

モデル検査ツールの1つとして知られているSpinでHelloWorldします。

使用した環境

Xubuntu 12.04
Spin Version 6.3.2

Spinのインストール

公式サイトからSpinのソースファイル*.tar.gzをダウンロードする。
*.tar.gzを解凍して、makeする。
tar xzf spin632.tar.gz
cd Spin/Src6.3.2
make
これで、実行できるバイナリファイルspinが作成される。
あとは、このバイナリファイルにPATHを通せば完了。

※Windowsの場合は、公式サイトでWindows用の実行バイナリが配布されているので、それをダウンロードすればよし。

HelloWorld

次の内容を、helloworld.promとして新規保存する。
active proctype helloworld()
{
        printf("hello world\n");
}
次のコマンドを実行すると、HelloWorld。
$ spin helloworld.prom
      hello world
1 process created


2014年7月15日火曜日

Vimのcolorscheme

ググるといろいろ出てくるが、結局、次のサイトでランダム表示させて出てきたno_quarterというcolorschemeにした。
http://bytefluent.com/vivify/

gvimだけじゃなく、コンソール上でvimを使う機会がある人は、ctermfgやctermbgに注意するとよい。colorschemeによってはguifgやguibgしか定義していないために、コンソール上で立ち上げると色が適切に変わらなかったりする。
あと、コンソールの種類や設定によって使える色の数が変わる。8色とか、256色とか。set t_Co=256 でググれ。

いい感じのcolorschemeをまとめてくれているサイト

http://takuyan.hatenablog.com/entry/20110425/1303746056
http://cocopon.me/blog/?p=841

colorschemeを改造、自作するときに参考になるサイト

http://d.hatena.ne.jp/thinca/20130410/1365530054

2014年7月2日水曜日

Vagrant 素振り

Vagrantを初めてさわってみた記録です。
印象は、Vagrant( ・∀・)イイ!! でした。

Vagrantとは何か。

ググりました。
主に以下のページを参照しました。
「Vagrant」って何ぞ?(・o・)
仮想環境構築ツール「Vagrant」で開発環境を仮想マシン上に自動作成する
Vagrant で作ったり壊したりできる Windows 環境を手に入れるまでの手順

使用した環境

Windows 7 Professional SP1 64bit(ホストPC)
VirtualBox 4.3.12
Vagrant 1.6.3
Git 1.9.4

やったこと

Vagrantをインストールする

Vagrantの公式サイトからWindows用のインストーラをダウンロードして、インストールした。
インストーラによるインストールが終わったあと、Windowsのパスに「C:\HashiCorp\Vagrant\bin」を追加した。このパスを通しておかないと、あとでGit Bashのターミナルからたどれない(はず)。

VirtualBoxをインストールする

VirtualBoxの公式サイトからWindows用のインストーラをダウンロードして、インストールした。

Gitをインストールする

Gitの公式サイトからWindows用のインストーラをダウンロードして、インストールした。
実際、gitバイナリは今必要ではなく、必要なのはsshバイナリ。GitのWindowsインストーラはMinGWの(おそらく主要な)コマンド一式をインストールしてくれて、そこにsshも入っているため今回インストールしている。
cygwinがすでにインストールされているなどしてsshが使えるなら、GitのWindowsインストーラによるインストールは不要。

Vagrantにさわる

Varant公式のGetting Startedを見ながら、コマンドを実行していきました。

まず、先にインストールしたGit Bashを起動して、そのターミナルから次のコマンドを実行する。vagrant up すると、インターネットから仮想マシンをダウンロードするので、それなりに時間かかります。
$ mkdir temp
$ cd temp
$ vagrant init hashicorp/precise32
$ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Importing base box 'hashicorp/precise32'...
==> default: Matching MAC address for NAT networking...
==> default: Checking if box 'hashicorp/precise32' is up to date...
==> default: Setting the name of the VM: temp_default_1404227001641_88575
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
    default: Adapter 1: nat
==> default: Forwarding ports...
    default: 22 => 2222 (adapter 1)
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
    default: SSH address: 127.0.0.1:2222
    default: SSH username: vagrant
    default: SSH auth method: private key
==> default: Machine booted and ready!
==> default: Checking for guest additions in VM...
    default: The guest additions on this VM do not match the installed version of
    default: VirtualBox! In most cases this is fine, but in rare cases it can
    default: prevent things such as shared folders from working properly. If you see
    default: shared folder errors, please make sure the guest additions within the
    default: virtual machine match the version of VirtualBox you have installed on
    default: your host and reload your VM.
    default:
    default: Guest Additions Version: 4.2.0
    default: VirtualBox Version: 4.3
==> default: Mounting shared folders...
    default: /vagrant => C:/Users/yasu_kei/temp 
vagrant upの実行が完了して、以上のようにエラーが出ていないようであれば、仮想マシンはすでに起動しています。vagrant ssh を実行すると、仮想マシンにsshでログインできます。
$ vagrant ssh
Welcome to Ubuntu 12.04 LTS (GNU/Linux 3.2.0-23-generic-pae i686)
 * Documentation:  https://help.ubuntu.com/
Welcome to your Vagrant-built virtual machine.
Last login: Fri Sep 14 06:22:31 2012 from 10.0.2.2
vagrant@precise32:~$
これで仮想マシンにログインできているので、あとはやりたい放題できます。
現状で、Vagrantがデフォルトで設定してくれる設定があります。
その設定は、NATの設定、ポートフォワーディングの設定、共有フォルダの設定、です。

NATの設定

すでに仮想マシンからインターネットにアクセスできます。wgetやpingなど通ります。
vagrant@precise32:~$ wget http://www.google.co.jp
--2014-07-01 15:17:07--  http://www.google.co.jp/
Resolving www.google.co.jp (www.google.co.jp)... 173.194.117.223, 173.194.117.216, 173.194.117.207, ...
Connecting to www.google.co.jp (www.google.co.jp)|173.194.117.223|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [text/html]
Saving to: `index.html'
    [ <=>                                   ] 11,272      --.-K/s   in 0s
2014-07-01 15:17:08 (47.7 MB/s) - `index.html' saved [11272]
vagrant@precise32:~$

ポートフォワーディングの設定

先にvagrant up したときのログに出ていますが、ホストマシンの2222ポートが仮想マシンの22ポートにポートフォワーディングされています。なので、ホストマシンからsshクライアントで仮想マシンにログインできます。ログインアカウントは、「vagrant」、パスワードも、「vagrant」です。
$ ssh vagrant@localhost -p 2222
vagrant@localhost's password:
Welcome to Ubuntu 12.04 LTS (GNU/Linux 3.2.0-23-generic-pae i686)
 * Documentation:  https://help.ubuntu.com/
Welcome to your Vagrant-built virtual machine.
Last login: Tue Jul  1 15:23:29 2014 from 10.0.2.2
vagrant@precise32:~$

共有フォルダの設定

仮想マシンの/vagrant ディレクトリがホストマシンとの共有フォルダとして設定されています。
vagrant@precise32:~$ cd /vagrant/
vagrant@precise32:/vagrant$ ls
Vagrantfile
vagrant@precise32:/vagrant$ touch aaa
vagrant@precise32:/vagrant$ ls
aaa  Vagrantfile
vagrant@precise32:/vagrant$

ホストマシンのvagrant up を実行したフォルダに、「aaa」ファイルが作成されているはずです。

以上デフォルトの仮想マシンの設定ですが、ここから自身で変更していくには、Vagrantfileファイルを編集します。Vagrantfileファイルは、Vagrant up を実行するフォルダに配置されています。Vagrantfileファイルの書式については、Vagrant公式サイトやインターネット上の情報を参照してください。

仮想マシンの止め方

止め方が3つあります。
vagrant suspend
 Windowsでいうスリープです。次回、vagrant up すると、suspend状態から仮想マシンが復帰します。
vagrant halt
 Windowsでいうシャットダウンです。次回、vagrant up すると、仮想マシンを起動します。
vagrant destroy
 haltしたあと、仮想マシンそのものを削除します。次回、vagrant up すると、仮想マシンを一から作成し直して、仮想マシンを起動します。(ただしインターネットからのダウンロードはし直しません)

vagrant up を実行したフォルダで、同じくコマンドを実行します。
$ vagrant halt
==> default: Attempting graceful shutdown of VM...

以上で、仮想マシンをVagrantで簡単に起動、停止できるようになりました。

次の話題

続く話題は、仮想マシンのプロビジョニング(初期設定)です。
ググったところによると、プロビジョニングには、Puppet、Chef、Ansible、Saltといったプロビジョニングに特化したツールがあるようで、それらツールをVagrantとともに用いるのが一般的なようです。