読者です 読者をやめる 読者になる 読者になる

ゲームデバックとかで使えそうな実行時間と回数を計測するクラスを作った

C++

プログラミングあるある
プログラムが遅いけど思い当たる節が多過ぎてどこがネックかわからない

なのでこんな感じにに動くクラスを作ってみた

template<class T>
using debug_timer = typename DebugTimer::Timer<T>;
int main()
{
	std::vector<int> v = Make10000();//10000の要素を持つ配列

	for (int i = 0; i < 100; ++i)
	{
		std::random_shuffle(v.begin(), v.end());
		{
			class Stable_sort{};		//識別用クラス
			debug_timer<Stable_sort> c;	//生存時間と生成回数を測る
			std::stable_sort(v.begin(), v.end());
		}
		std::random_shuffle(v.begin(), v.end());
		{
			class Sort{};
			debug_timer<Sort> c;
			std::sort(v.begin(), v.end());
		}
	}
	OutPut();//結果を出力する
	}
}

結果

?AVStable_sort@?4?main@ 100     3563
?AVSort@?5?main@        100     3246

どうやらstable_sortのほうが時間がかかっているらしい
左側の意味不明で文字化けしてるような識別子はtypeid.nameから拾得している
例えば

?AVStable_sort@?4?main@ == typeid(Stable_sort).name()

である(少なくともこの環境では)
実装依存バリバリだがどのコンパイラでも少なくとも解読しようと思えば何とか解読できるレベルの文字列を返してくれるので性質上ユーザーに見せる者でもないしこれでいいだろう
コンパイラが吐く意味不明なエラーを考えればこんなもの楽々である(ハズ)

こちら肝心のソース

#pragma once
#include<chrono>
#include<string>
#include<list>
class DebugTimer
{
	struct Data
	{
		Data(const std::string&id)
			:id(id)
		{
			Get_List().push_back(this);
		}
		std::chrono::system_clock::duration time;
		int count = 0;
		std::string id;
	};
public:
	template<class ID_class>
	class Timer
	{
	public:
		Timer()
			:begin(std::chrono::system_clock::now())
		{}
		~Timer()
		{
			get().time += std::chrono::system_clock::now() - begin;
			++get().count;
		}
	private:
		const std::chrono::system_clock::time_point begin;
		inline static Data &get(){ static Data c(typeid(ID_class).name()); return c; }
	};

	//何もしないタイマー。release時にでも
	template<class>
	class No_Debug_Timer{};
	inline static std::list<Data*> &Get_List(){ static std::list<Data*> list; return list; }
};

get_listでリストを受け取る。それだけ



余談だがVSだと

class Sort{};
debug_timer<Sort> c;

debug_timer<class Sort> c;

にしても動いた。規格はともかくとしてこういったものは二行より一行のほうが良い
マクロを使えば済む話でもあるが