我从未做过剖析。昨天我编写了一个ProfilingTimer类,其中包含一个静态时间表(一个map< std :: string,long long>)用于时间存储。
构造函数存储起始刻度,析构函数计算经过的时间并将其添加到地图中:
ProfilingTimer::ProfilingTimer(std::string name)
: mLocalNameLength(name.length())
{
sNestedName += name;
sNestedName += " > ";
mStartTick = Platform::GetTimerTicks();
}
ProfilingTimer::~ProfilingTimer()
{
long long totalTicks = Platform::GetTimerTicks() - mStartTick;
sTimetable[sNestedName] += totalTicks;
sNestedName.erase(sNestedName.length() - mLocalNameLength - 3);
}
在我要配置的每个功能(或{block})中,我需要添加:
ProfilingTimer _ProfilingTimer("identifier");
当我从Visual C ++ 2010 Professional构建发行版时,此分析工作正常。但是当我构建为Debug时,我得到了一个巨大的fps下降(从63下降到~20)。
这些是我打印时间表(Debug build)时得到的数字:
Update() > Tower::Update > : 2551 ms (84100m%)
Update() > Tower::Update > Tower::Update1 > : 1313 ms (43284m%)
Update() > Tower::Update > Tower::Update1 > Tower::FindNewTarget > : 6 ms (204m%)
Update() > Tower::Update > Tower::Update1 > Tower::HasTargetInRange > : 5 ms (184m%)
Update() > Tower::Update > Tower::Update2 > : 659 ms (21756m%)
Update() > Tower::Update > Tower::Update2 > Tower::HasTargetInRange > : 5 ms (187m%)
Update1和Update2分别是Update的前半部分和后半部分。为什么他们加起来不是84.1%?
仍然这84%是一个巨大的数字 - 在发布版本中我得到了这个输出:
Update() > : 770 ms (1549m%)
Update() > Tower::Update > : 722 ms (1452m%)
Update() > Tower::Update > Tower::FindNewTarget > : 44 ms (89m%)
Update() > Tower::Update > Tower::HasTargetInRange > : 92 ms (187m%)
1,4%而非84,1%。这是一个巨大的差异!
任何人都知道为什么?
编辑:我认为发布比Debug快得多,但为什么这个分析如此耗时? std :: map the time hogger还是我做错了什么?编辑:更新了代码。不需要启动,现在存储mLocalName的长度而不是实际的字符串。
答案 0 :(得分:2)
Microsoft在调试模式下为其容器库添加了大量安全检查。这是有益的。你宁愿在诸如vector::operator[]
之类的函数中捕获越界异常等,而不是破译内存损坏(仍然会建议调用vector::at
。)但是,还有很多其他的事情要进入插入影响代码及其性能的调试器挂钩。
答案 1 :(得分:2)
使用长字符串作为std::map
的索引可能不是执行此操作的最快方法。具有共同开头的长字符串意味着每次比较其中两个字符串时,必须查看许多字符以查看字符串是否相等。 std::map
基本上是一个二叉树,并在每个查找/插入上进行O(log(n))比较。使用较短或数字键可以加快所有地图操作。
此外,使用std::unordered_map
可能(或可能不会)提高速度,具体取决于地图包含的元素数量以及使用的密钥类型。
在分析类中,构造函数应该将名称作为引用,以避免创建该字符串的不必要副本:
ProfilingTimer::ProfilingTimer(const std::string &name)
通常避免不必要的副本是个好主意。例如,您可能并不真正需要mLocalName
成员,而只是存储字符串长度就足够了。
可能经常调用分析函数,因此在程序运行时会出现小的延迟。
答案 2 :(得分:2)
您的代码存在一些性能问题。
mLocalName
甚至存在?请直接参考name
。unordered_map
供您使用。不使用sTimetable[sNestedName] = 0;
,而是使用已检索的迭代器。
Timetable::iterator loc = sTimetable.find(sNestedName);
if(loc == sTimetable.end())
sTimetable[sNestedName] = 0;
附录:Visual Studio最后检查了一个分析器。为什么不用它?