c++ builder XE4, 10.2 Tokyo > 関数の処理時間チェック > C実装のソースを計測する > v0.1, v0.3 > _LARGE_INTEGER / QueryPerformanceFrequency() / 複数の結果

```txt:動作環境
C++ Builder XE4

RAD Studio 10.2 Tokyo Update 2 (追記: 2017/12/28)
   - v0.3を動作確認
```

- C実装の計算用ソースとヘッダがある
- マイコンとWinで使う共通実装
- ファイルスコープstatic サブ関数での計算処理時間を計測したい
- XE4のソフトをWin7で実行すると1msec以下となる
- ソースに余分なコードを極力追加したくない

案

- 外部ソースに実装した関数を用意する
- 計測対象ソースには外部関数のコール文を追加する
  - triggerStart()
  - triggerStop()
  - オシロスコープでトリガ機能を使うイメージ
  - TStringList()でその時点の時刻(usec含む)を保持
  - 対象ソースにはCUDA用のCHECKマクロと同等機能を使ってtriggerStart()とtriggerStop()の処理をはさむ > [関連](http://qiita.com/7of9/items/bd7752e4779c088c67e0)
     - 対象関数の取替えが楽になる
  - 計測結果をRでグラフ化
     - 必要であれば
  - start, stopの対応をハッシュで探す?
- 該当の関数を多重回実行する仕組みを検討
  - usec時刻を保持できない場合の代案
  - どのサブ関数が重いか探すために使う

などなど

関連 http://qiita.com/7of9/items/1dd75f14c507e80c7a89
関連 http://stackoverflow.com/questions/6030586/calculating-the-speed-of-routines
関連 [Sine function using Taylor expansion (C Programming)](http://stackoverflow.com/questions/8647126/sine-function-using-taylor-expansion-c-programming)
関連 http://qiita.com/7of9/items/a59f79b3c38ef3e178ed


### code v0.1

5分で作った適当コード

関連 [Sine function using Taylor expansion (C Programming)](http://stackoverflow.com/questions/8647126/sine-function-using-taylor-expansion-c-programming)
のTaylor展開のsine()計算を1000回まわして計測してみた。

```Unit1.h
//---------------------------------------------------------------------------

#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:	// IDE で管理されるコンポーネント
	TButton *Button1;
	void __fastcall Button1Click(TObject *Sender);
private:	// ユーザー宣言
public:		// ユーザー宣言
	void __fastcall OffTrigger(String funcname);
	void __fastcall OnTrigger(String funcname);

	__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
```
 
```Unit1.cpp
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include <math.h>
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
	: TForm(Owner)
{
}
//---------------------------------------------------------------------------

long int factorial(int m)
{
	if (m==0 || m==1) return (1);
	else      return (m*factorial(m-1));
}
double power(double x,int n)
{
	double val=1;
	int i;
	for (i=1;i<=n;i++)
	{
		val*=x;
	}
	return val;
}

double sine(double x)
{
	int n;
	double val=0;
	for (n=0;n<8;n++)
	{
		double p = power(-1,n);
		double px = power(x,2*n+1);
		long fac = factorial(2*n+1);
		val += p * px / fac;
	}
	return val;
}

//---------------------------------------------------------------------------

#define CHECK(call,name)                              \
{                                                     \
	OnTrigger(name);                                  \
	call                                              \
	OffTrigger(name);                                 \
}

//---------------------------------------------------------------------------

void __fastcall TForm1::OffTrigger(String funcname)
{
	// check start time
	String msg = L"Stop[" + funcname + L"()]:" + Now().FormatString(L"hh:nn:ss.mm:ss.zzz");
	OutputDebugString(msg.c_str());
}

void __fastcall TForm1::OnTrigger(String funcname)
{
	// check end time
	String msg = L"Start[" + funcname + L"()]:" + Now().FormatString(L"hh:nn:ss.mm:ss.zzz");
	OutputDebugString(msg.c_str());
}

void __fastcall TForm1::Button1Click(TObject *Sender)
{
	double x;
	double deg2pi = acos(-1.0) / 180.0;


	CHECK(
	for(int loop = 0; loop < 1000; loop++) {
		x = sine(loop * deg2pi);
		int nop=1;
	}
	, L"sine"
	)

	//
}
//---------------------------------------------------------------------------
```

```txt:実行結果
デバッグ出力: Start[sine()]:16:41:02.10:02.126 プロセス Project1.exe (3708)
デバッグ出力: Stop[sine()]:16:41:02.10:02.127 プロセス Project1.exe (3708)
```

1000回のsine()に1msec弱かかる (分解しきれてない)。

~~TODO: usecまでの表示~~
Now()からusecを計算する処理を入れたら、それ自体で2msec程度増えた。これはやめた方がよさそう。

OnTrigger(), OffTrigger()の処理は単純に値を渡すだけ、などの軽い処理にする必要がある。

TODO: 外部関数化。今後10年くらい使いたい。

## v0.2 > QueryPerformanceCounter()使用版

計測部分だけ以下のようにした。

```Unit1.cpp
static _LARGE_INTEGER Freq;
static _LARGE_INTEGER StartCount;
static _LARGE_INTEGER StopCount;
double timing_sec;

void __fastcall TForm1::OffTrigger(String funcname)
{
	QueryPerformanceCounter(&StopCount);

	timing_sec = (double)(StopCount.QuadPart - StartCount.QuadPart) / Freq.QuadPart;
	double timing_msec = timing_sec * 1000;
	int nop=1;

	String msg = L"[" + funcname + String().sprintf(L"] takes %.3f msec", timing_msec);
    OutputDebugString(msg.c_str());
}

void __fastcall TForm1::OnTrigger(String funcname)
{
	QueryPerformanceFrequency(&Freq);
	QueryPerformanceCounter(&StartCount);
}
```

```txt:結果例
デバッグ出力: [sine] takes 1.779 msec プロセス Project1.exe (5976)
デバッグ出力: [sine] takes 1.915 msec プロセス Project1.exe (5976)
デバッグ出力: [sine] takes 1.749 msec プロセス Project1.exe (5976)
デバッグ出力: [sine] takes 1.560 msec プロセス Project1.exe (5976)
```

ループ回数を10倍にした時にも線形的に10倍の時間になるので、あっているような気がする。

_LARGE_INTEGER関連 http://birdhouse.hateblo.jp/entry/2016/02/23/171734
 
QueryPerformanceFrequency関連
http://stackoverflow.com/questions/6030586/calculating-the-speed-of-routines


### code v0.3 > 複数の結果を格納

複数の結果を`proc_msec[]`に格納するようにしてみた。

ただし、以下のような構造の場合、funcAとfuncBを同時には測定できない (測定するとオーバヘッドによる誤差がfuncAに生じる)。

funcB, funcC, funcDの処理速度比較には使えそう。

```
void funcA() {
   funcB();
   funcC();
   funcD();
}
```

```Utni1.h
//---------------------------------------------------------------------------

#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:	// IDE で管理されるコンポーネント
	TButton *Button1;
	void __fastcall Button1Click(TObject *Sender);
private:	// ユーザー宣言
public:		// ユーザー宣言
//	void __fastcall OffTrigger(String funcname);
//	void __fastcall OnTrigger(String funcname);

	__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
```

```Unit1.cpp
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include <math.h>
#include <stdint.h>
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
	: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall OnTrigger(String funcname);
void __fastcall OffTrigger(String funcname);

#define CHECK(call,name)                              \
{                                                     \
	OnTrigger(name);                                  \
	call                                              \
	OffTrigger(name);                                 \
}
//---------------------------------------------------------------------------

long int factorial(int m)
{
	if (m==0 || m==1) return (1);
	else      return (m*factorial(m-1));
}
double power(double x,int n)
{
	double val=1;
	int i;
	for (i=1;i<=n;i++)
	{
		val*=x;
	}
	return val;
}

double sine(double x)
{
	int n;
	double val=0;
	for (n=0;n<8;n++)
	{
CHECK(
		double p = power(-1,n);
		double px = power(x,2*n+1);
		long fac = factorial(2*n+1);
		val += p * px / fac;
, L"power"
)
	}
	return val;
}

//---------------------------------------------------------------------------

static _LARGE_INTEGER Freq;
static _LARGE_INTEGER StartCount;
static _LARGE_INTEGER StopCount;
static int pos = -1;
#define MAX_NUM (10)
static double proc_msec[MAX_NUM] = {0.0};
static String funcnames[MAX_NUM];

void __fastcall OnTrigger(String funcname)
{
	QueryPerformanceFrequency(&Freq);
	QueryPerformanceCounter(&StartCount);
}

void __fastcall OffTrigger(String funcname)
{
	QueryPerformanceCounter(&StopCount);

	double timing_sec = (double)(StopCount.QuadPart - StartCount.QuadPart) / Freq.QuadPart;
	double timing_msec = timing_sec * 1000;
	pos++;
	if (pos >= MAX_NUM) {
		return; // overflow
	}
	proc_msec[pos] = timing_msec;
	funcnames[pos] = funcname;
}

//---------------------------------------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)
{
	double x;
	double deg2pi = acos(-1.0) / 180.0;


//CHECK(
	for(int loop = 0; loop < 3000; loop++) {
		x = sine(loop * deg2pi);
		int nop=1;
	}
//, L"sine"
//)

	int nop = 1;

	//
}
//---------------------------------------------------------------------------
```

![qiita.png](https://qiita-image-store.s3.amazonaws.com/0/32870/3555222a-4c8a-c757-abd0-ea204cb6a6c3.png)

![qiita.png](https://qiita-image-store.s3.amazonaws.com/0/32870/b9134d38-fba7-5e48-a5d9-cdd944e2ce21.png)

上記はmsecの値だが、多少ばらつきがあるのは否めない。