测试cache在cpu之间移动耗时,及其他原子操作

cpu E3 1230v2 8核 3.3GHz
分线程取得cache,判断并写入正数,等待其变为负数后进行下一次写入
总线程抢得cache,对正数取反,每当取反一次,计数+1

分线程数量为1时,输出约为1400万/s
这说明cache反复在cpu之间“移动”的频率达到1400万每秒

参考数据:
本机单线程     对相同变量 原子操作 +=1 约为1.533亿次每秒
本机2线程      对相同变量 原子操作 +=1 约为6952万次每秒 每个线程
本机2线程对相同cache的不同变量 原子操作 +=1 约为3670万次每秒 每个线程 ←第一次注意到
本机2线程对不同cache的  变量 原子操作 +=1 约为1.4亿次每秒 每个线程
本机2线程对不同cache的  变量 原子操作 +=1 约为1.4亿次每秒 每个线程
本机3线程对不同cache的  变量 原子操作 +=1 约为1.2亿次每秒 每个线程

本机1线程原子操作(加锁) if (cas(v, 0→1)) set 0 else try_again 约为1.19亿次每秒 1线程。
本机1线程原子操作(加锁) if (v= =0 && cas(v, 0→1)) set 0 else try_again 约为1.19亿次每秒 1线程
本机2线程原子操作(加锁) if (cas(v, 0→1)) set 0 else try_again 约为1400万次每秒 每个线程;总和2800万/s。
本机2线程原子操作(加锁) if (v= =0 && cas(v, 0→1)) set 0 else try_again 约为1700万次每秒 每线程;总和3400万/s。

单线程 EnterCiriticalSection和Leave 约5000万+/s
双线程 EnterCiriticalSection和Leave 各1100万/s

spdlog中使用的mpmc队列,单线程人队约为6000万次每秒(它尽量地在每个数据的内存上使用了原子操作,避免了集中在队列元数据也就是指针变量上进行原子操作)然而此mpmc队列在双线程入队时性能下降到总和入队2000万/s。spdlog这种技巧是无法对一个原子变量做累加的(也就是无法用于循环不定长流指针的累加)

从下面代码测试的1400万每秒,到原子操作6952万每秒,似乎可以判定原子操作有特别的优化(快速发现内存的变化)

以上数据综合推测一个不定长元素的字节流,入队性能不会超过3400万/s。本人实现的已达3000万次/s看来已经没有提升空间了。

    struct Item
    {
        int32_t value = 0;
      //  uint64_t _[(64 - sizeof(uint32_t)) / sizeof(uint64_t)];
    };
    //static_assert(sizeof(Item) == 64);
    enum { THREADCOUNT =  1};
    Item datas[THREADCOUNT] = {};
	//分线程,每个线程将其关联的值从0改为1,并等待直到主线程将1改为负数
    for (int tid = 0; tid < THREADCOUNT; ++tid)
    {
        std::thread([tid, &datas] 
        {
            int count = 0;
            DWORD t = timeGetTime();
            while (true)
            {
                (volatile int32_t&)datas[tid].value = 1;
                while ((volatile int32_t&)datas[tid].value > 0)
                    //asm_pause()
                    ;

                ++count;
                if ((count & 0xFFFFF) == 0)
                {
                    //printf("%d %d\n", tid, count / (timeGetTime() - t));
                }
            }
        }).detach();
    }
	//主线程,扫描所有关联值,对每个正数取反,每当取反一次正数就计数+1,偶尔输出改变次数/历史总时间
    std::thread([&datas]
    {
        int count = 0;
        DWORD t = timeGetTime();

        while(true)
        {
            for (int tid = 0; tid < THREADCOUNT; ++tid)
            {
                int32_t v = (volatile int32_t&)datas[tid].value;
                if (v > 0)
                {
                    (volatile int32_t&)datas[tid].value = -v;

                    ++count;
                    if ((count & 0xFFFFF) == 0)
                    {
                        printf("%d %I64d\n", tid, count * 1000LL / (timeGetTime() - t));
                    }
                }
            }
            //asm_pause();
        }
    }).join();

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 11
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值