我与编程领域的几个人进行了友好的竞争,最近我们对编写高效代码非常感兴趣。我们的挑战是尝试不惜任何代价(可读性,可重用性等)优化代码(在cpu时间和复杂性方面)。
问题是,现在我们需要比较我们的代码,看看哪种方法与其他方法相比更好,但我们不知道任何工具用于此目的。
我的问题是,是否有一些(任何!)工具需要一段代码 作为输入并计算触发器或cpu指令的数量 运行它需要什么?有没有任何工具可以衡量最佳性 代码?
P.S。目标语言是c ++,但很高兴知道这些工具是否也适用于java。
答案 0 :(得分:11)
这是一个小C ++ 11秒表我喜欢在需要时间时推出:
#include <chrono>
#include <ctime>
template <typename T> class basic_stopwatch
{
typedef T clock;
typename clock::time_point p;
typename clock::duration d;
public:
void tick() { p = clock::now(); }
void tock() { d += clock::now() - p; }
void reset() { d = clock::duration::zero(); }
template <typename S> unsigned long long int report() const
{
return std::chrono::duration_cast<S>(d).count();
}
unsigned long long int report_ms() const
{
return report<std::chrono::milliseconds>();
}
basic_stopwatch() : p(), d() { }
};
struct c_clock
{
typedef std::clock_t time_point;
typedef std::clock_t duration;
static time_point now() { return std::clock(); }
};
template <> unsigned long long int basic_stopwatch<c_clock>::report_ms() const
{
return 1000. * double(d) / double(CLOCKS_PER_SEC);
}
typedef basic_stopwatch<std::chrono::high_resolution_clock> stopwatch;
typedef basic_stopwatch<c_clock> cstopwatch;
用法:
stopwatch sw;
sw.tick();
run_long_code();
sw.tock();
std::cout << "This took " << sw.report_ms() << "ms.\n";
在任何体面的实现中,默认的high_resolution_clock
应该提供非常准确的时序信息。
答案 1 :(得分:3)
来自std::clock()
的{{1}}函数返回当前进程花费了多少CPU时间(这意味着它不计算程序空闲的时间,因为CPU正在执行其他任务)。此功能可用于准确测量算法的执行时间。使用常量<ctime>
(也来自std::CLOCKS_PER_SEC
)将返回值转换为秒。
答案 2 :(得分:1)
从内联汇编中,您可以使用rdtsc指令将32位(最低有效部分)计数器转换为eax,将32位(最高有效部分)转换为edx。如果您的代码太小,您可以使用eax寄存器检查总认可的cpu-cycles。如果计数超过最大值。 32位值,每个最大32位值周期edx递增。
int cpu_clk1a=0;
int cpu_clk1b=0;
int cpu_clk2a=0;
int cpu_clk2b=0;
int max=0;
std::cin>>max; //loop limit
__asm
{
push eax
push edx
rdtsc //gets current cpu-clock-counter into eax&edx
mov [cpu_clk1a],eax
mov [cpu_clk1b],edx
pop edx
pop eax
}
long temp=0;
for(int i=0;i<max;i++)
{
temp+=clock();//needed to defy optimization to actually measure something
//even the smartest compiler cannot know what
//the clock would be
}
__asm
{
push eax
push edx
rdtsc //gets current cpu-clock-counter into aex&edx
mov [cpu_clk2a],eax
mov [cpu_clk2b],edx
pop edx
pop eax
}
std::cout<<(cpu_clk2a-cpu_clk1a)<<std::endl;
//if your loop takes more than ~2billions of cpu-clocks, use cpu_clk1b and 2b
getchar();
getchar();
输出:在我的机器上进行10000次迭代的1000次迭代和800000次CPU循环的74000次CPU循环。因为clock()非常耗时。
我机器上的CPU周期分辨率:~1000个周期。是的,您需要超过数千个加法/减法(快速指令)才能相对正确地测量它。
假设cpu工作频率恒定,对于1GHz cpu,1000 cpu-cycle几乎等于1微秒。在这之前你应该先加热你的cpu。
答案 3 :(得分:0)
从一段代码中计算cpu时间的详细数量非常困难。 执行此操作的常规方法是将较差/平均/最佳输入数据设计为测试用例。并根据您的实际代码对这些测试用例进行时序分析。没有详细的输入测试数据和条件时,没有任何工具可以告诉你翻牌。
答案 4 :(得分:0)
有一些名为profilers的软件正是您想要的。
Windows的一个示例是AMD code analyser和gprof用于POSIX。
答案 5 :(得分:0)
最适合您的目的是valgrind/callgrind
答案 6 :(得分:0)
测量CPU指令的数量是没用的。
性能与瓶颈有关,取决于手头的问题,瓶颈可能是网络,磁盘IO,内存或CPU。
对于一场友谊比赛,我建议时机。这当然意味着提供足够大的测试用例来进行有意义的测量。
在Unix上,您可以使用gettimeofday
进行相对精确的测量。