【问题标题】:How to calculate time in milliseconds of functions of bubble sort, insertion sort and selection sort in c++如何在c ++中计算冒泡排序、插入排序和选择排序函数的时间(以毫秒为单位)
【发布时间】:2022-01-11 04:35:45
【问题描述】:

应该使用哪些函数来计算函数的时间 有没有为此目的的内置函数。

【问题讨论】:

标签: c++ sorting


【解决方案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”吗?
    • 是的!那是一个错字,我现在改正它。
    猜你喜欢
    • 2015-04-25
    • 2016-11-01
    • 2015-02-14
    • 2013-06-20
    • 2012-10-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多