- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我需要在现有的 C++ 代码中实现遥测功能,以分析哪些方法执行时间过长。可以在文本文件中记录时间戳。这是正确的方法还是有任何其他方法可以在 c++ 中进行。由于我是 vc++ 的新手,请提供您的建议。
最佳答案
我开发了最简单的C++代码自剖析代码。它以调用树的形式收集和显示统计信息。您可以根据需要修改它。使用,只需要添加TRACE
分析 block 中的宏。
#pragma once
#include <vector>
#include <string>
#include <windows.h>
typedef double Time;
typedef unsigned int uint;
#ifndef FLATTEN_RECURSION
#define FLATTEN_RECURSION 1
#endif
class Profiler
{
static Time getCurrentTime()
{
LARGE_INTEGER time;
LARGE_INTEGER freq;
QueryPerformanceCounter(&time);
QueryPerformanceFrequency(&freq);
return 1.0 * time.QuadPart / freq.QuadPart;
}
struct Entry
{
Time fullTime_ = Time(0);
const char* name_;
uint started_ = 0;
Time startTime_ = Time(0);
Entry(const char* name) { name_ = name; }
void start()
{
if (!started_) startTime_ = getCurrentTime();
started_++;
}
void stop()
{
started_--;
if (!started_)
fullTime_ += getCurrentTime() - startTime_;
}
};
struct CallTreeNode
{
const Entry& entry_;
std::vector<CallTreeNode> childs_;
CallTreeNode(const Entry& entry) : entry_(entry)
{}
CallTreeNode& addCall(const Entry& entry)
{
for (auto& itr : childs_)
if (&itr.entry_ == &entry)
return itr;
childs_.push_back(CallTreeNode(entry));
return childs_.back();
}
};
std::vector<CallTreeNode*> callStack_;
Entry rootEntry = Entry("root");
CallTreeNode root = CallTreeNode(rootEntry);
Time duration_;
Profiler()
{
rootEntry.start();
callStack_.push_back(&root);
}
void printTreeImpl(
CallTreeNode& node,
std::string& out,
bool last = true,
const std::string& prefix = "")
{
out += prefix + (last ? '\xC0' : '\xC3') + std::string("\xC4\xC4")
+ node.entry_.name_ + " rate: "
+ std::to_string(node.entry_.fullTime_ / duration_ * 100)
+ "% full time: " + std::to_string(node.entry_.fullTime_) + '\n';
const int childsNum = (int)node.childs_.size();
for (int i = 0; i < childsNum; i++)
printTreeImpl(node.childs_[i], out, i == (childsNum - 1), prefix + (last ? ' ' : '\xB3') + " ");
}
void forward(const Entry& entry)
{
callStack_.push_back(&callStack_.back()->addCall(entry));
}
void backward(const Entry& entry)
{
callStack_.pop_back();
}
public:
Profiler(Profiler const&) = delete;
void operator=(Profiler const&) = delete;
static Profiler& getInstance()
{
static Profiler instance;
return instance;
}
static Entry newEntry(const char* name)
{
return Entry(name);
}
std::string printCallTree()
{
auto& inst = getInstance();
inst.duration_ = inst.getCurrentTime() - inst.rootEntry.startTime_;
inst.rootEntry.fullTime_ += duration_;
std::string out;
inst.printTreeImpl(root, out);
return out;
}
class ProfilerAutoStopper
{
Entry& entry_;
public:
ProfilerAutoStopper(Entry& entry) : entry_(entry)
{
if (!entry_.started_ || !FLATTEN_RECURSION)
getInstance().forward(entry_);
entry_.start();
}
~ProfilerAutoStopper()
{
entry_.stop();
if (!entry_.started_ || !FLATTEN_RECURSION)
getInstance().backward(entry_);
}
};
};
#define TRACE \
static auto pflrEntry = Profiler::newEntry(__FUNCTION__); \
Profiler::ProfilerAutoStopper autoStopper(pflrEntry);
使用的关键思想:
ProfilerAutoStopper
用于在进入和退出 block 时自动启动和停止计时器。这消除了多个启动/停止错误并正确处理异常。std::vector<CallTreeNode*> callStack_
堆栈和CallTreeNode
树结构用于构建调用树。void foo()
{
TRACE;
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
void recursive(int level)
{
TRACE;
if (--level) recursive(level);
std::this_thread::sleep_for(std::chrono::milliseconds(5));
}
void bar()
{
TRACE;
foo();
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
int main()
{
{
TRACE;
for (int i = 0; i < 10; i++)
foo();
recursive(10);
bar();
}
std::cout << Profiler::getInstance().printCallTree() << std::endl;
return 0;
}
└──root rate: 100.000000% full time: 0.191205
└──main rate: 99.971599% full time: 0.191150
├──foo rate: 62.788339% full time: 0.120054
├──recursive rate: 31.276141% full time: 0.059801
│ └──recursive rate: 31.276141% full time: 0.059801
│ └──recursive rate: 31.276141% full time: 0.059801
│ └──recursive rate: 31.276141% full time: 0.059801
│ └──recursive rate: 31.276141% full time: 0.059801
│ └──recursive rate: 31.276141% full time: 0.059801
│ └──recursive rate: 31.276141% full time: 0.059801
│ └──recursive rate: 31.276141% full time: 0.059801
│ └──recursive rate: 31.276141% full time: 0.059801
│ └──recursive rate: 31.276141% full time: 0.059801
└──bar rate: 11.446139% full time: 0.021886
└──foo rate: 62.788339% full time: 0.120054
使用 FLATTEN_RECURSION 1
└──root rate: 100.000000% full time: 0.190720
└──main rate: 99.944164% full time: 0.190614
├──foo rate: 62.658680% full time: 0.119503
├──recursive rate: 31.347459% full time: 0.059786
└──bar rate: 11.477065% full time: 0.021889
└──foo rate: 62.658680% full time: 0.119503
关于c++ - 如何在现有 C++ 代码中功能性地实现遥测,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55331277/
用普通 Cordova 启动了一个项目。此消息不断出现: You have been opted out of telemetry. To change this, run: cordova tele
背景: 我正在处理一个非常古老的应用程序,它很少且间歇性地生成异常。 当前的做法: 通常我们程序员使用全局异常处理程序来处理罕见的未知数,像这样连接: [STAThread] [SecurityPer
我使用此代码通过 TelemetryClient 记录异常: var appInsightsRoleName = "tracking"; var telemetry = new ExceptionTe
Android 版本。 > 4.3标准安卓信标库估计信标。Eddystone-UID包遥测包。 我正在尝试从 Eddystone-UID 包传输的遥测包中读取温度传感器传输。根据 Android Be
我按照此 Microsoft article 设置了使用 Azure 的 Application Insights 在 IIS 上运行的本地 .NET 应用程序 。而且效果一直很好。 据我了解,这是一
我刚刚 fork 了新的 mapbox 库并试图将它作为一个模块添加到我的项目中。主要问题是 gradle 在同步时出错,因为我无法访问遥测 2.0.0-SNAPSHOT Error:Could no
我想在 Application Insights 的请求事件中包含 header ,并找到了以下帖子,其中包含针对具有 HttpContext 的应用程序的解决方案。我正在使用 Nancy 应用程序,
我需要使用遥测向 QnA 用户发送有关我的 Azure 机器人见解的问题和答案。已经尝试过本教程: https://docs.microsoft.com/en-us/azure/bot-service
我是 Azure Application Insights 的长期用户,并且经常使用 TelemetryClient 的 TrackTrace() 和 TrackException()我编写的每个企业
我们在 AKS 中托管了一个小型 API,它是使用 .Net core 2.2 编写的。它一直运行良好,我们已经在 Azure 门户中看到了我们所有的 App Insights 遥测数据,如预期的那样
我是一名优秀的程序员,十分优秀!