秒以上の精度を簡単に取得できるようにする工夫2008年12月16日 02時55分57秒

プログラムでは時折、一部の処理に異常な時間が掛かるようになることもある。そのような場合、デバッガを使うとプログラムの実行速度が遅くなるので、問題が見えなくなる場合もある。

ただ単に全体的な遅さを処理するのであれば、解析プログラムなども使えるのだが、特定の部分だけを探す時は、一筋縄ではいかない事もある。また、解析プログラムを設定する手間も、掛かる事もある。

そうなると、デバッグ用の出力が比較的手軽になってくる。しかし、ミリ秒単位、またはそれ以上の精度の時間を取得するには、複数の呼び出しが必要で、面倒になることが多々あった。

そこで、とった方法がこれ。デバッグを始めるときに以下のコードを一番良く使われるヘッダーファイルに入れてしまう。今回のはミリ秒での時間を取得。


#ifndef UYOTA
#define UYOTA
extern "C" {
#include <sys/time.h>
static long uyota()
{
   struct timeval timeval; struct tm tm;
   gettimeofday(&timeval,NULL);
   localtime_r(&timeval.tv_sec, &tm);
   return long (tm.tm_sec*1000 + timeval.tv_usec/1000);
}
}

#endif

C++ だったらそのまま、C だったら extern を取り除く。関数が static に宣言されるので、読み込まれるファイル毎にこの関数が存在する事になるが、どうせ一時的なもの。これで、他の正しい流儀の関数のような手間も掛からず簡単に使えるようになる。

また、一時的にのみ入れるデバッグ関数やテスト用のプログラムに特別な裏口を作る場合などには、いつも自分の名前を組み込む様にしている。一時的なデバッグ関数入り場合はファイルごと消してしまう場合も多いが、ファイルを比較したりする場合に、目立つので作業がやりやすい。また、誰かが裏口を調べたい時には、自分の名前を探すように言えるので、簡単に見付けてくれる。

型のバイト数を調べる2008年11月26日 02時15分13秒

C や C++ 言語では、int を始めとする整数型の大きさが定義されているわけではない。環境依存で、各最適な大きさを確保出来るように、ある程度の柔軟性が認められている。

異なったアーキテクチャやエンディアンを持つシステム間で、直接バイナリを交換するのには、全ての構造体の要素の大きさを完全に一致させる必要がある。

逆に言えば、エンディアン間の違いはバイトを入れ換えるしか無いが、OS やアーキテクチャなどを跨いで、構造体の内部構造を一致させることも可能だ。なるべく避けたい事態だが、時と場合によっては、必要になる。いちいち文字列に変換をしていたら、パフォーマンスが大幅に落ちるためだ。

以下のプログラムで、各型の大きさが調べられる。


#include <stdio.h>

int main(void)
{
       printf("type\t\tbyte\n");
       printf("void\t\t%zd\n", sizeof(void*));
       printf("char\t\t%zd\n", sizeof(char));
       printf("short\t\t%zd\n", sizeof(short));
       printf("int\t\t%zd\n", sizeof(int));
       printf("long\t\t%zd\n", sizeof(long));
       printf("long long\t%zd\n", sizeof(long long));
       printf("float\t\t%zd\n", sizeof(float));
       printf("double\t\t%zd\n", sizeof(double));
       printf("long double\t%zd\n", sizeof(long double));
       return 0;
}

何の変哲も無いコードだが、一回づつ必要になる度に書くのも面倒だ。

awk 演習: ファイルを分割する2008年11月18日 06時11分53秒

ファイルを複数に分割する必要がでてきた。普通に行毎、バイト毎の塊にファイルを分割をするのであれば、split がある。しかし、今回やりたいのは、行毎にラウンドロビンで複数のファイルに分けたいのだ。

例えば、二つのファイルに分けるとしよう。奇数行をファイルに、偶数行を二つ目のファイル分ける。パフォーマンスの計測や負荷テストなどで、入力ファイルを複数に分割するときなどに、このような分割を行うことがある。一つのプロセスでは賄い切れないので、複数からデータを供給するのだが、データの順番などを出来るだけ保つようにする為だ。


awk '{print > ++i ".txt"; if(i > 1)i = 0}'

これに入力ファイル渡すと、1.txt と 2.txt に交互に書き出される。もし、三分割をしたいのなら 1 を 3 に、七分割をしたいのなら 7 に置き換える。i ".txt" が文字列の連結として扱われて、1.txt などのファイル名に変わる。

一部の awk の実装だと、このように print 先に評価文があると警告をだすものもある。


awk '{print > sprintf("%d.txt". ++i); if(i > 1)i = 0}'

sprintf で回避出来ることもある。もしこれで警告が出るのであれば、ファイル名を一時変数に入れて、print > file のすれば、ファイルのリダイレクトを実装している awk なら、どれでも動く。

実行例だ。


% nawk '{print >  sprintf("%d.txt", ++i); if(i > 1)i = 0}'
1
2
3
4
5
6
% head *
==> 1.txt <==
1
3
5

==> 2.txt <==
2
4
6

awk 演習: 80 文字毎に改行2008年11月15日 03時34分55秒

lp でプリントする時に、一行が 80 文字以上あると、一列に入り切らない。そこで、80 文字毎に改行をする。enscript などが入っていないので、awk が頼りだった。

80 文字毎に文字を簡単に挿入できるプログラムは知らないので、簡単に仕立てあげた。


{ line = $0
  while(length(line) > 80)
  {
    print substr(line, 1, 80)
    line = substr(line, 81)
  }
  print line
}

一列が 80 文字よりある間は、80 文字出力してから 81 文字目からを新しい一行として処理を続ける。

awk は文字を単語毎に扱うのは得意だが、C 言語のように文字単位で扱うのはあまり得意ではない。そのような時は、substr と index 関数が主だった手段になる。