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();