如何在c ++中计算冒泡排序、插入排序和选择排序函数的时间(以毫秒为单位)
Posted
技术标签:
【中文标题】如何在c ++中计算冒泡排序、插入排序和选择排序函数的时间(以毫秒为单位)【英文标题】:How to calculate time in milliseconds of functions of bubble sort, insertion sort and selection sort in c++ 【发布时间】:2022-01-11 04:35:45 【问题描述】:应该使用哪些函数来计算函数的时间 有没有为此目的的内置函数。
【问题讨论】:
可能重复***.com/questions/44433440/… 【参考方案1】:您可以使用此代码:
auto a = chrono::steady_clock::now();
//write your code here
auto b = chrono::steady_clock::now();
double time = chrono::duration <double, milli> (b - a).count();
cout << endl << "Time ---> " << time;
【讨论】:
【参考方案2】:没有专门用于计算函数所用时间的内置内容。
有内置函数可以检索当前时间。有关详细信息,请参阅std::chrono::high_resolution_clock::now()
。
要对函数计时,您应该(至少通常)在进入函数之后检索当前时间,并在退出之前再次检索。
然后,您可以将两者相减,并使用std::duration_cast
将其转换为方便的持续时间(毫秒、微秒或纳秒,视情况而定)。
把它们放在一起,你可以(例如)得到这样的东西:
template <class T, class U, template<class, class> class F, typename ...Args>
auto timer(F<T,U> f, std::string const &label, Args && ...args)
using namespace std::chrono;
auto start = high_resolution_clock::now();
auto holder = f(std::forward<Args>(args)...);
auto stop = high_resolution_clock::now();
std::cout << label << " time: " << duration_cast<microseconds>(stop - start).count() << "\n";
return holder;
这使您可以传递一些任意函数(以及要传递给该函数的参数)并打印出函数执行所用的时间。目前它正在执行微秒,但将其更改为毫秒应该是微不足道的。
最后,这会返回被调用函数产生的任何值,所以如果你有类似的东西:
x = f(a, b, c);
您可以将其替换为:
x = timer(f, a, b, c);
...打印出f
消耗的时间。
【讨论】:
std::steady_clock
通常不推荐用于计时吗? std::high_resolution_clock
允许与 std::system_clock
相同,这会受到进程外部时间更改的影响。
time.h 库中的任何函数可以用于此目的吗?
std::high_resolution_clock 在 Linux 上只是一个内核调用 clock_gettime() 的包装器,尽管它通常是一个 VDSO 并在用户空间中解析。尽管如此,如果 NTP/PTP 偏移量太大,时钟可能会及时回退。 stable_clock 保证不会及时跳跃或扭曲。
@Galik:我不确定“通常推荐”,但对我来说这听起来像是一个糟糕的权衡。对于计时功能,您的首要任务是分辨率。是的,在大多数地方,您的函数每年可能会记录两次大约 1 小时或 -1 小时的时间,但如果您关心毫秒,那么一个小时是如此巨大的异常值,以至于将其过滤掉是微不足道的。
@AsadullahShaukat:不可靠,不。 clock()
可能是最接近的。它应该给 CPU 时间,但一些实现却给了 wall time,而且分辨率通常很粗糙(通常在几十到几百毫秒的数量级)。 time()
应该是给wall time的,一般分辨率是1秒。【参考方案3】:
我通常不以秒为单位计算时间,因为它在具有不同 CPU 频率的机器上会有所不同。我通常使用 CPU 周期,这样如果您在笔记本电脑或超频的高端服务器上运行,它将大致相同。周期还可以更好地反映和关联其他机器特性,如 CPU 缓存延迟。这是Linux内核内部使用的
# cat /sys/devices/system/clocksource/clocksource0/current_clocksource
tsc
每个 CPU 架构都有某种内部时间戳计数器。在 x86_64 上,它是 TSC(时间戳计数器),可以使用 Intel 内在 '__builtin_ia32_rdtsc()' 读取,如
#include <cstdint>
static inline std::uint64_t now()
return __builtin_ia32_rdtsc();
然后在您的代码上,您可以执行以下操作:
std::uint64_t t0 = now();
call_my_algo();
uint64_t t1 = now();
uint64_t ticks = t1>=t0 ? t1-t0 : (std::numeric_limits<uint64_t>::max() - t0)+t1;
最后一行是处理翻转,但这应该在 177 年中只发生一次,所以不是真正的问题。您只需 t1-t0
即可逃脱惩罚。
rdtsc 调用对 std::chrono 的优势在于您没有调用 glibc 和内核,而这正是 chrono 最终所做的。开销很小,因此这种方法非常适合微基准测试。
有几点需要注意。每个核心都包含自己的时间戳计数器,因此如果它们不同步,那么如果进程从一个核心移动到另一个核心,或者新的时间戳可能低于 start 从而差异变为负数,那么您可能会读取错误 - 因此滴答声将下溢.但这些现在很少见,在旧机器中更常见。
您可以检查您机器上的 TSC 是否值得信任
cat /proc/cpuinfo | grep tsc | tr ' ' '\n' | grep tsc | sort | uniq
constant_tsc
nonstop_tsc
rdtscp
tsc
tsc_scale
constant_tsc - 时间戳计数器频率恒定
nonstop_tsc - 计数器不会在 C 状态下停止
rdtscp - cpu 有 rdtscp 指令(返回时间戳和核心)
tsc - cpu 有时间戳计数器
tsc_scale - amd tsc 缩放支持
你应该小心,无论你使用 std::chrono,它最终会在 Linux 上调用 clock_gettime(),或者如果你使用 TSC,编译器可能会颠倒你的语句顺序,这样上面的代码就可以成为
std::uint64_t t0 = now();
uint64_t t1 = now();
uint64_t ticks = t1>=t0?t1-t0 : (std::numeric_limits<uint64_t>::max() - t0)+t1;
call_my_algo();
因此,您将不会测量任何东西。避免这种情况的一种方法是设置优化障碍,例如
#include <cstdint>
static inline std::uint64_t now()
asm volatile ( "" ::: "memory" );
return __builtin_ia32_rdtsc();
还有记忆障碍的问题,可能非常复杂。
【讨论】:
你的“开始”实际上是你的“t0”吗? 是的!那是一个错字,我现在改正它。以上是关于如何在c ++中计算冒泡排序、插入排序和选择排序函数的时间(以毫秒为单位)的主要内容,如果未能解决你的问题,请参考以下文章