TimeSlice的测量方法

在操作系统相关方面会涉及到时间片这部分的认识和测量 在网上似乎没有找到相关的文章 所以这里写下一份供大家参考
如有误 望指正

code

这里的两个函数返回都是***纳秒级(ns)***的时间

#ifndef __TIME_SLICE_
#define __TIME_SLICE_ 1
#include<iostream>
#include<chrono>
#include<thread>
#include<atomic>

size_t singleThreadSliceMeasure(size_t times);
#ifdef _WIN32
    #include<windows.h>
#endif

class semaphore{
        // bool hold;
        std::atomic_bool hold;
        semaphore():semaphore(true){}
        semaphore(bool have):hold(have){}
    public:
        static semaphore& object(){
            static semaphore signal;
            return signal;
        }
        // busy wait
        static void get(){
            bool temp=false;
            while(!object().hold.exchange(temp));
        }
        static void release(){
            object().hold=true;
        }
};



/**
 * @brief return the measured OS time slice
 * @return the average time of the time slice in nanosecs
 * @warning only support Windows and Linux/Unix 
 * maybe?
*/
size_t TimeSliceMeasure(size_t times=64,bool sout=false){
    const unsigned int threads=std::thread::hardware_concurrency()+1;
    size_t sum=0,time=0;
    #ifdef _WIN32
        /**
         * @brief return the measured windows time slice
         * @return the average time of the time slice in nanosecs
        */
        std::chrono::_V2::system_clock::time_point beg,end;
        while(times--){
            beg=std::chrono::system_clock::now();
            // `Sleep` only guarantees that the thread will sleep for at least that length of time.
            Sleep(1);
            end=std::chrono::system_clock::now();
            sum+=(end-beg).count();
        }
        time=sum/times;
    // #elif __linux__
    #else
        // race condition maybe
        using milli=std::chrono::duration<long double, std::milli>;
        int actual=0;
        const auto &&second=std::chrono::duration<long double>{1};
        const auto &&milsec=std::chrono::duration<long double, std::milli>{1};
        auto fn=[&](){
            std::chrono::_V2::system_clock::time_point stl=std::chrono::system_clock::now();
            std::chrono::_V2::system_clock::time_point beg=std::chrono::system_clock::now();
            std::chrono::_V2::system_clock::time_point end=std::chrono::system_clock::now();
            while((end-stl)<second){
                end=std::chrono::system_clock::now();
                if((end-beg)>milsec){
                    semaphore::get();
                    sum+=(end-beg).count();
                    ++actual;
                    semaphore::release();
                    beg=std::chrono::system_clock::now();
                }else{
                    beg=end;
                }
            }
        };
        for(int i=0;i<threads;++i){
            std::thread tr(fn);
            tr.detach();
        }
        std::this_thread::sleep_for(std::chrono::duration<long double>{2});
        time=sum/actual;
    #endif
    if(sout){
        std::cout<<"Time Slice:"<<time/1000000<<"ms"<<std::endl;
    }
    return time;
}

size_t singleThreadSliceMeasure(size_t times){
    const auto &&milsec=std::chrono::duration<long double, std::milli>{1};
    size_t temp=times,sum=0;
    std::chrono::_V2::system_clock::time_point beg=std::chrono::system_clock::now();
    std::chrono::_V2::system_clock::time_point end=std::chrono::system_clock::now();
    while(temp){
        end=std::chrono::system_clock::now();
        if((end-beg)>milsec){
            semaphore::get();
            sum+=(end-beg).count();
            --temp;
            semaphore::release();
            // puts("Yep");
            beg=std::chrono::system_clock::now();
        }else{
            beg=end;
        }
    }
    return sum/times;
}
#endif//__TIME_SLICE_

解析

semaphore

class semaphore{
        // bool hold;
        std::atomic_bool hold;
        semaphore():semaphore(true){}
        semaphore(bool have):hold(have){}
    public:
        static semaphore& object(){
            static semaphore signal;
            return signal;
        }
        // busy wait
        static void get(){
            bool temp=false;
            while(!object().hold.exchange(temp));
        }
        static void release(){
            object().hold=true;
        }
};

信号量用的单例模式 因为代码中为多次及时取一个平均 为了预防 race condition 保证原子性 所以使用了一个atomic_bool 来表示

当然乱调用release函数会有问题 这只是个自用的一个小代码 为了简单 直接使用的 busy wait 方式来等待
因为开的线程并不多
同时会访问资源的线程也可以认为只有一个 所以可以忽略这个微秒级或者更低的时间消耗

core

整个算法的核心部分

  • 利用<chrono>库的纳秒级时钟来计时
  • 时间迭代
  • 记录当前线程被挂起后再次运行所间隔的长时间段

问题也有 在于该线程被挂起的时间不确定 会有一些数据过大
目前的解决办法是增加线程的存活时长 多获得数据来减小这个误差

std::chrono::_V2::system_clock::time_point stl=std::chrono::system_clock::now();
std::chrono::_V2::system_clock::time_point beg=std::chrono::system_clock::now();
std::chrono::_V2::system_clock::time_point end=std::chrono::system_clock::now();
while((end-stl)<second){
    end=std::chrono::system_clock::now();
    if((end-beg)>milsec){
        semaphore::get();
        sum+=(end-beg).count();
        ++actual;
        semaphore::release();
        beg=std::chrono::system_clock::now();
    }else{
        beg=end;
    }
}

about Windows

大家会发现 Windows 这块的代码比较简单
这里的简单是因为利用了Windows调度的特性 也就是利用了Sleep函数

Java似乎也有类似的特性

具体的原因我没有过多的研究 可以参考下方链接

std::chrono::_V2::system_clock::time_point beg,end;
while(times--){
    beg=std::chrono::system_clock::now();
    Sleep(1);
    end=std::chrono::system_clock::now();
    sum+=(end-beg).count();
}

Sleep reference

the other function

size_t singleThreadSliceMeasure(size_t times){
    const auto &&milsec=std::chrono::duration<long double, std::milli>{1};
    size_t temp=times,sum=0;
    std::chrono::_V2::system_clock::time_point beg=std::chrono::system_clock::now();
    std::chrono::_V2::system_clock::time_point end=std::chrono::system_clock::now();
    while(temp){
        end=std::chrono::system_clock::now();
        if((end-beg)>milsec){
            sum+=(end-beg).count();
            --temp;
            beg=std::chrono::system_clock::now();
        }else{
            beg=end;
        }
    }
    return sum/times;
}

也可以使用单线程的测量方式
不过就是在低负载的情况下比较慢 得到一次结果的时间比较长 需要耐心等待

about sleep_for
std::this_thread::sleep_for(std::chrono::duration<long double>{2});

这是标准库的函数 字面值常量是在C++14标准之后才有的 这里没用所以C++11的标准就能编译了

sleep_for 是会阻塞当前线程 让当前线程进入waiting状态的 所以在开始线程需要多开一个

其他的一些可参考资料

  1. 时间片测量-SO
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值