- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
我需要在 Windows 上对一些实时代码进行性能分析。
我不能使用任何常规分析器(Vtune、Codeanalyst),因为我不能减慢可执行文件的速度。所以我使用的是我自己的基于 QueryPerformanceCounter() 的计时类。
那么是否有任何现有的(免费)C++ 库来记录结果 - 但我需要将它们缓冲到运行结束,我没有时间在我的时候写入文件或事件日志收集数据。
我自己很容易滚动,但是如果有办法将 log4cplus/qDebug 或类似的日志记录到缓冲区并稍后转储,它将节省一些精力。
最佳答案
我也写了一个类来做这件事,因为我找不到任何东西可以做我想要的,但仍然很容易通过复制粘贴编码技术合并到现有代码中。
(编辑)请注意,正如评论中提到的,计时行为本身会改变您计时的性质。但是,我相信您对此非常了解。这个类对我发现热点和瓶颈仍然非常有用,除了给我至少一个粗略的高边估计某些代码需要多长时间运行。我在此处展示的代码从未 旨在具有生产值(value)。就这样使用它。
这是我类(class)的示例输出:
Timer Precision = 385 ns
=== Item Trials Ttl Time Avg Time Mean Time StdDev ===
DB Connect 1 0.11 s 0.11 s 0.11 s 0.0000 ps
Entry Parse 3813 0.33 s 86 us 82 us 18 us
File Load 1 50 ms 50 ms 50 ms 0.0000 ps
Option Parse 1 5 ms 5 ms 5 ms 0.0000 ps
Record Update 3812 0.53 s 140 us 127 us 49 us
============================================================================
每个“项目”都是我想要计时的一段代码。 Timer
对象使用 RAII(通过 auto_ptr
)来允许自动启动和停止。下面是一些示例客户端代码,演示了如何使用它:
int main(int ac, char* av[])
{
std::auto_ptr<dbg::Timer> section_timer(new dbg::Timer("Option Parse"));
// MAGIC: Parse the command line...
section_timer = auto_ptr<dbg::Timer>(new dbg::Timer("File Load"));
// MAGIC: Load a big file...
section_timer = auto_ptr<dbg::Timer>(new dbg::Timer("DB Connect"));
// MAGIC: Establish a DB connection...
for( /* for each item in the file*/ )
{
section_timer = auto_ptr<dbg::Timer>(new dbg::Timer("Entry Parse"));
// MAGIC: Parse the incoming item
section_timer = auto_ptr<dbg::Timer>(new dbg::Timer("Record Update"));
// MAGIC: Update the database
}
// Dump the output shown above
cout << dbg::Timer::DumpTrials() << endl;
}
这个类的实现在一个包含库中。你不需要编译任何东西。我使用 Boost.Format 进行字符串格式化,但这可以简单地替换。
这是实现(我的实际实现将它分成两个文件,core.h
和 core_dbg.hpp
;后者是 #include
直接从前者编辑)。
namespace dbg
{
class Timer
{
public:
inline Timer(const std::string & name);
inline Timer(const Timer& rhs);
inline virtual ~Timer();
inline std::string format_now() const;
double current_elapsed() const;
Timer& operator=(const std::string& name);
static std::string DumpTrials(bool ClipboardAlso=false);
static void Reset();
static std::string format_elapsed(double d) ;
private:
typedef std::string key_type;
typedef double time_type;
typedef std::multimap<key_type, time_type> times;
static __int64 TimerFreq();
LARGE_INTEGER startTime_, stopTime_;
mutable LARGE_INTEGER intermediateTime_;
std::string label_;
static times& TimeMap();
struct extract_key : public std::unary_function<times::value_type, key_type>
{
std::string operator()(times::value_type const & r) const
{
return r.first;
}
};
struct extract_val : public std::unary_function<times::value_type, time_type>
{
time_type operator()(times::value_type const & r) const
{
return r.second;
}
};
struct match_key : public std::unary_function<times::value_type, bool>
{
match_key(key_type const & key_) : key(key_) {};
bool operator()(times::value_type const & rhs) const
{
return key == rhs.first;
}
match_key& operator=(const match_key& rhs)
{
key = rhs.key;
return * this;
}
protected:
key_type key;
};
struct accum_key : public std::binary_function<time_type, times::value_type, time_type>
{
accum_key(key_type const & key_) : key(key_), n(0) {};
time_type operator()(time_type const & v, times::value_type const & rhs) const
{
if( key == rhs.first )
{
++n;
return rhs.second + v;
}
return v;
}
private:
times::key_type key;
mutable size_t n;
};
};
inline Timer::Timer(const std::string & name)
{
label_ = name;
QueryPerformanceCounter(&startTime_);
}
inline double Timer::current_elapsed() const
{
QueryPerformanceCounter(&intermediateTime_);
__int64 clocks = intermediateTime_.QuadPart-startTime_.QuadPart;
double elapsed = (double)clocks/(double)TimerFreq();
return elapsed;
}
inline Timer::~Timer()
{
double elapsed = current_elapsed();
stopTime_.QuadPart = intermediateTime_.QuadPart;
TimeMap().insert(std::make_pair(label_,elapsed));
};
inline Timer& Timer::operator=(const std::string& name)
{
double elapsed = current_elapsed();
stopTime_.QuadPart = intermediateTime_.QuadPart;
TimeMap().insert(std::make_pair(label_,elapsed));
label_ = name;
QueryPerformanceCounter(&startTime_);
return * this;
}
inline Timer::Timer(const Timer& rhs)
{
double elapsed = current_elapsed();
stopTime_.QuadPart = intermediateTime_.QuadPart;
TimeMap().insert(std::make_pair(label_,elapsed));
label_ = rhs.label_;
QueryPerformanceCounter(&startTime_);
}
inline std::string Timer::format_now() const
{
return format_elapsed(current_elapsed());
}
inline std::string Timer::DumpTrials(bool ClipboardAlso)
{
using boost::io::group;
if( TimeMap().empty() )
{
return "No trials\r\n";
}
std::string ret = (boost::format("\r\n\r\nTimer Precision = %s\r\n\r\n")
% format_elapsed(1.0/(double)TimerFreq())).str();
// get a list of keys
typedef std::set<std::string> keyset;
keyset keys;
std::transform(TimeMap().begin(), TimeMap().end(), std::inserter(keys, keys.begin()), extract_key());
size_t maxrows = 0;
typedef std::vector<std::string> strings;
strings lines;
static const size_t t = 9;
std::string head =
(boost::format("=== %-s %-s %-s %-s %-s %-s ===")
//% (t*2)
//% (t*2)
% group(std::setw(t*2), std::setprecision(t*2), "Item" )
//% t
//% t
% group(std::setw(t), std::setprecision(t), "Trials")
//% t
//% t
% group(std::setw(t), std::setprecision(t), "Ttl Time" )
//% t
//% t
% group(std::setw(t), std::setprecision(t), "Avg Time" )
//% t
//% t
% group(std::setw(t), std::setprecision(t), "Mean Time" )
//% t
//% t
% group(std::setw(t), std::setprecision(t), "StdDev")
).str();
ret += (boost::format("\r\n%s\r\n") % head).str();
if( ClipboardAlso )
lines.push_back("Item\tTrials\tTtl Time\tAvg Time\tMean Time\tStdDev\r\n");
// dump the values for each key
for( keyset::iterator key = keys.begin(); keys.end() != key; ++key )
{
time_type ttl = 0;
ttl = std::accumulate(TimeMap().begin(), TimeMap().end(), ttl, accum_key(*key));
size_t num = std::count_if( TimeMap().begin(), TimeMap().end(), match_key(*key));
if( num > maxrows )
maxrows = num;
time_type avg = ttl / num;
// compute mean
std::vector<time_type> sortedTimes;
dibcore::stl::transform_if(TimeMap().begin(), TimeMap().end(), std::inserter(sortedTimes, sortedTimes.begin()), extract_val(), match_key(*key));
std::sort(sortedTimes.begin(), sortedTimes.end());
size_t mid = (size_t)floor((double)num/2.0);
double mean = ( num > 1 && (num % 2) != 0 ) ? (sortedTimes[mid]+sortedTimes[mid+1])/2.0 : sortedTimes[mid];
// compute variance
double sum = 0.0;
if( num > 1 )
{
for( std::vector<time_type>::iterator cur = sortedTimes.begin(); sortedTimes.end() != cur; ++cur )
sum += pow(*cur-mean,2.0);
}
// compute std dev
double stddev = num > 1 ? sqrt(sum/((double)num-1.0)) : 0.0;
ret += (boost::format(" %-s %-s %-s %-s %-s %-s\r\n")
% group(std::setw(t*2), std::setprecision(t*2) , (*key))
% group(std::setw(t), std::setprecision(t) , (boost::format("%d") %num).str() )
% group(std::setw(t), std::setprecision(t) , format_elapsed(ttl).c_str() )
% group(std::setw(t), std::setprecision(t) , format_elapsed(avg) )
% group(std::setw(t), std::setprecision(t) , format_elapsed(mean) )
% group(std::setw(t), std::setprecision(t) , format_elapsed(stddev)) ).str();
if( ClipboardAlso )
lines.push_back((
boost::format("%s\t%s\t%s\t%s\t%s\t%s\r\n")
% (*key )
% (boost::format("%d") %num)
% format_elapsed(ttl)
% format_elapsed(avg)
% format_elapsed(mean)
% format_elapsed(stddev)
).str());
}
ret += (boost::format("%s\r\n")
% std::string(head.length(),'=') ).str();
if( ClipboardAlso )
{
// dump header row of data block
lines.push_back("");
{
std::string s;
for( keyset::iterator key = keys.begin(); key != keys.end(); ++key )
{
if( key != keys.begin() )
s.append("\t");
s.append(*key);
}
s.append("\r\n");
lines.push_back(s);
}
// blow out the flat map of time values to a seperate vector of times for each key
typedef std::map<std::string, std::vector<time_type> > nodematrix;
nodematrix nodes;
for( times::iterator time = TimeMap().begin(); time != TimeMap().end(); ++time )
nodes[time->first].push_back(time->second);
// dump each data point
for( size_t row = 0; row < maxrows; ++row )
{
std::string rowDump;
for( keyset::iterator key = keys.begin(); key != keys.end(); ++key )
{
if( key != keys.begin() )
rowDump.append("\t");
if( nodes[*key].size() > row )
rowDump.append((
boost::format("%f")
% nodes[*key][row]
).str());
}
rowDump.append("\r\n");
lines.push_back(rowDump);
}
// dump to the clipboard
std::string dump;
for( strings::iterator s = lines.begin(); s != lines.end(); ++s )
{
dump.append(*s);
}
OpenClipboard(0);
EmptyClipboard();
HGLOBAL hg = GlobalAlloc(GMEM_MOVEABLE, dump.length()+1);
if( hg )
{
char* buf = (char*)GlobalLock(hg);
if( buf )
{
std::copy(dump.begin(), dump.end(), buf);
buf[dump.length()] = 0;
}
GlobalUnlock(hg);
SetClipboardData(CF_TEXT, hg);
}
CloseClipboard();
}
return ret;
}
inline std::string Timer::format_elapsed(double d)
{
if( d < 0.00000001 )
{
// show in ps with 4 digits
return (boost::format("%0.4f ps") % (d * 1000000000000.0)).str();
}
if( d < 0.00001 )
{
// show in ns
return (boost::format("%0.0f ns")% (d * 1000000000.0)).str();
}
if( d < 0.001 )
{
// show in us
return (boost::format("%0.0f us") % (d * 1000000.0)).str();
}
if( d < 0.1 )
{
// show in ms
return (boost::format("%0.0f ms") % (d * 1000.0)).str();
}
if( d <= 60.0 )
{
// show in seconds
return (boost::format("%0.2f s") % d).str();
}
if( d < 3600.0 )
{
// show in min:sec
return (boost::format("%01.0f:%02.2f") % floor(d/60.0) % fmod(d,60.0)).str();
}
// show in h:min:sec
return (boost::format("%01.0f:%02.0f:%02.2f") % floor(d/3600.0) % floor(fmod(d,3600.0)/60.0) % fmod(d,60.0)).str();
}
inline void Timer::Reset()
{
TimeMap().clear();
}
inline __int64 Timer::TimerFreq()
{
static __int64 freq = 0;
static bool init = false;
if( !init )
{
LARGE_INTEGER li;
QueryPerformanceFrequency(&li);
freq = li.QuadPart;
init = true;
}
return freq;
}
inline Timer::times& Timer::TimeMap()
{
static times times_;
return times_;
}
}; // namespace dbg
关于C++ 日志记录和性能调整库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4727006/
#include using namespace std; class C{ private: int value; public: C(){ value = 0;
这个问题已经有答案了: What is the difference between char a[] = ?string?; and char *p = ?string?;? (8 个回答) 已关闭
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 7 年前。 此帖子已于 8 个月
除了调试之外,是否有任何针对 c、c++ 或 c# 的测试工具,其工作原理类似于将独立函数复制粘贴到某个文本框,然后在其他文本框中输入参数? 最佳答案 也许您会考虑单元测试。我推荐你谷歌测试和谷歌模拟
我想在第二台显示器中移动一个窗口 (HWND)。问题是我尝试了很多方法,例如将分辨率加倍或输入负值,但它永远无法将窗口放在我的第二台显示器上。 关于如何在 C/C++/c# 中执行此操作的任何线索 最
我正在寻找 C/C++/C## 中不同类型 DES 的现有实现。我的运行平台是Windows XP/Vista/7。 我正在尝试编写一个 C# 程序,它将使用 DES 算法进行加密和解密。我需要一些实
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
有没有办法强制将另一个 窗口置于顶部? 不是应用程序的窗口,而是另一个已经在系统上运行的窗口。 (Windows, C/C++/C#) 最佳答案 SetWindowPos(that_window_ha
假设您可以在 C/C++ 或 Csharp 之间做出选择,并且您打算在 Windows 和 Linux 服务器上运行同一服务器的多个实例,那么构建套接字服务器应用程序的最明智选择是什么? 最佳答案 如
你们能告诉我它们之间的区别吗? 顺便问一下,有什么叫C++库或C库的吗? 最佳答案 C++ 标准库 和 C 标准库 是 C++ 和 C 标准定义的库,提供给 C++ 和 C 程序使用。那是那些词的共同
下面的测试代码,我将输出信息放在注释中。我使用的是 gcc 4.8.5 和 Centos 7.2。 #include #include class C { public:
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
我的客户将使用名为 annoucement 的结构/类与客户通信。我想我会用 C++ 编写服务器。会有很多不同的类继承annoucement。我的问题是通过网络将这些类发送给客户端 我想也许我应该使用
我在 C# 中有以下函数: public Matrix ConcatDescriptors(IList> descriptors) { int cols = descriptors[0].Co
我有一个项目要编写一个函数来对某些数据执行某些操作。我可以用 C/C++ 编写代码,但我不想与雇主共享该函数的代码。相反,我只想让他有权在他自己的代码中调用该函数。是否可以?我想到了这两种方法 - 在
我使用的是编写糟糕的第 3 方 (C/C++) Api。我从托管代码(C++/CLI)中使用它。有时会出现“访问冲突错误”。这使整个应用程序崩溃。我知道我无法处理这些错误[如果指针访问非法内存位置等,
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。 关闭 7 年前。
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于 Stack Overflow 来说是偏离主题的,因为
我有一些 C 代码,将使用 P/Invoke 从 C# 调用。我正在尝试为这个 C 函数定义一个 C# 等效项。 SomeData* DoSomething(); struct SomeData {
这个问题已经有答案了: Why are these constructs using pre and post-increment undefined behavior? (14 个回答) 已关闭 6
我是一名优秀的程序员,十分优秀!