By Shirou [F.a.w] WAKAYAMA
Pentium Counter thanks for ngt and tsuboi.
pentium counter は,RDTSC (Real Time-Stamp Counter)命令によって読むこ
とができる 64 ビットのタイムスタンプのことです.このカウンタは CPU が
リセットされてから何ステップ経過したかを cycle 単位で数えています.

さて,その pentium counter ですが,FreeBSD では

% sysctl machdep.tsc_freq

で値がかえってくれば,そのマシンでは pentium カウンタがとれます.かえっ
てくる値は CPU クロックの値です.
# ちなみに athlon ではかえってこない.

で,プログラム的にどー取るかというと,

#define readTSC(x) __asm __volatile(".byte 0x0f, 0x31" : "=A" (x))

とか宣言しておいて,x に 64 bit な変数(たとえば int64_t)をつっこんでや
ると取れると思います.
## ちなみに athlon だと machdep.tsc_freq は取れないので,CPU のクロッ
## クは自分で調べないと駄目.
### CPUの実クロック数の調べ方としては、boot -vで起動することで、
### boot message(dmesg中にも)に TSC clockと、値が表示されるようになります。
### FreeBSD-4.7Sで確認。 thanks > nobuo
#### でも、これだと、いちいち再起動しなきゃいけないので、他の方法があれ
#### ばいいなぁ。

これで得られるのは cycle 数なので,時間をはかる始点と終点の cycle 数を
引いて,CPU クロック(Hz)でわらなければならない.

これで出てくる値が実際に始点から終点までにかかった時間(ナノ秒)となる.

測定をする時,gettimeofday はやめましょう :-)

以下にプログラム例を書きます。

#define CPUHZ 600025023  ←sysctl machdep.tsc_freqの値
#define PENCNT_TO_NSEC(count, clock) (((count)*1000*1000*1000)/(clock))
#define PENCNT_TO_USEC(count, clock) (((count)*1000*1000)/(clock))
#define PENCNT_TO_MSEC(count, clock) (((count)*1000)/(clock))
#define PENCNT_TO_SEC(count, clock) ((count)/(clock))

#define readTSC(x) __asm __volatile(".byte 0x0f, 0x31" : "=A" (x))

以上をヘッダファイルに記述します。

  unsigned long long start_count, cur_count,count;

  readTSC(start_count);

/*
ここに処理を記述。
*/

  readTSC(cur_count);

  count = cur_count - start_count;

  fprintf (stderr,
	     "start %d  end %d\n"
	     ,(int)start_count,(int)cur_count);

  fprintf (stderr, "PENCNT %d nsec(%d/%d)\n",
	(int)PENCNT_TO_NSEC(count, CPUHZ),(int)count, (int)CPUHZ);
  fprintf (stderr, "PENCNT %d usec(%d/%d)\n",
	(int)PENCNT_TO_USEC(count, CPUHZ),(int)count, (int)CPUHZ);
  fprintf (stderr, "PENCNT %d msec(%d/%d)\n",
	(int)PENCNT_TO_MSEC(count, CPUHZ),(int)count, (int)CPUHZ);
  fprintf (stderr, "PENCNT %d sec(%d/%d)\n",
	(int)PENCNT_TO_SEC(count, CPUHZ),(int)count, (int)CPUHZ);

などとします。

Address already in use thanks for gon.
Address already in use ... とかなって「休憩だ!」とならないためには...
set setsockopt SO_REUSEADDR !!

FD      INIT_FD;
int     one = 1;

/* Create Socket */
if ( (INIT_FD = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == ERR ) {
        perror("[init_socket()] socket");
        return (ERR);
}

setsockopt(INIT_FD, SOL_SOCKET,SO_REUSEADDR,(char *) &one,sizeof(int));
setsockopt(INIT_FD, SOL_SOCKET,SO_USELOOPBACK,(char *) &one,sizeof(int))

デバグメッセージ thanks for gon.
/* Debug Level */
#define DEBUGLEVEL	4
void dbprintf		__P((short, char *, ...));

/*---------------------------------------------------------------------*
 * debug printf
 *---------------------------------------------------------------------*/
#include <stdio.h>
#include <stdarg.h>

void
dbprintf(short dblev, char *fmt, ...)
{
	if ( dblev <= DEBUGLEVEL ) {
		va_list argp;
		fprintf(stderr, "##DEBUG L=%hd## ", dblev);
		va_start(argp, fmt);
		vfprintf(stderr, fmt, argp);
		va_end(argp);
		fprintf(stderr, "\n");
		fflush(stderr);
	}
	return;
}

で,

#define DBG_INFO	1
...

とやっておいて

dbprintf(DBG_INFO,"print = %d",i);
とかすればいいわけですよね.

レベル段階表示より,個別にデバッグ表示させたいときには
char で bitmask かけた方がいいですね.

あとは,上の中で if() でフィルタかけているところを
マクロでかけられたらかっこいい.

だれかやってみない?
可変長マクロ thanks for furu.
GNU Cにおけるマクロは,関数とほぼ同様に,可変個数の引数を受け取ること
ができます.マクロの定義構文は関数の定義に使われる。

#define eprintf(format, args...) fprintf(stderr, format, ##args)

詳しくは,

http://www.asahi-net.or.jp/~wg5k-ickw/html/online/gcc-2.95.1/gcc_3.html#SEC32
 
です.
getopt
引数解析にはgetoptを。

int getopt(int argc, char * const *argv, const char *optstring);

optstringには、解析したい引数を全部書きます。"h:"のように、:をつけると、
その引数に対する引数をとることができます。また、"ab:"とすれば、-aと、-b
と-bのargを取り出してくれます。

なお、getoptは --helpなどのような複数文字の引数は扱えません。

#include <stdio.h>
#include <unistd.h> // for getopt

int
main(int argc, char **argv){
  int c;

  while((c = getopt(argc, argv, "h:m:p:")) != EOF){
    switch(c){
    case 'h':
      printf("%c:%s\n",optopt,optarg);
      break;
    case 'm':
      printf("%c:%s\n",optopt,optarg);
      break;
    case 'p':
      printf("%c:%s\n",optopt,optarg);
      break;
    case '?':
      printf("%s: illegal option -- %c\n",argv[0],optopt);
      usage();
      break;
    }
  }
  return 0;
}