|
|
nono 0.1.5
//
// nono
// Copyright (C) 2020 nono project
// Licensed under nono-license.txt
//
#include "config-nono.h"
#include <atomic>
#include <cstdio>
#include <inttypes.h>
#include <pthread.h>
#include <sys/time.h>
#if defined(__NetBSD__)
#include <atomic.h>
#endif
volatile uint64_t shared;
volatile uint32_t terminate;
uint64_t result;
const uint64_t loopcnt = 10000000;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
std::atomic<uint64_t> shared5(0);
std::atomic<uint32_t> terminate5(0);
// test1: なにもしない
void
test1_init()
{
}
void *
test1_prod(void *arg)
{
for (uint64_t i = 0; i < loopcnt; i++) {
shared++;
}
terminate = 1;
return NULL;
}
void *
test1_cons(void *arg)
{
do {
result += shared;
shared = 0;
} while (terminate == 0);
return NULL;
}
// test2: pthread_mutex
void
test2_init()
{
}
void *
test2_prod(void *arg)
{
for (uint64_t i = 0; i < loopcnt; i++) {
pthread_mutex_lock(&mutex);
shared++;
pthread_mutex_unlock(&mutex);
}
terminate = 1;
return NULL;
}
void *
test2_cons(void *arg)
{
uint32_t t;
do {
pthread_mutex_lock(&mutex);
result += shared;
shared = 0;
t = terminate;
pthread_mutex_unlock(&mutex);
} while (t == 0);
result += shared;
return NULL;
}
#if defined(__NetBSD__)
// test3: atomic.h
void
test3_init()
{
}
void *
test3_prod(void *arg)
{
for (uint64_t i = 0; i < loopcnt; i++) {
atomic_add_64(&shared, 1);
}
terminate = 1;
return NULL;
}
void *
test3_cons(void *arg)
{
do {
result += atomic_swap_64(&shared, 0);
} while (terminate == 0);
// 見落とした分
result += atomic_swap_64(&shared, 0);
return NULL;
}
#endif
#if defined(__clang_version__)
// test4: clang's builtin
#else
// test4: GCC's builtin atomic
void
test4_init()
{
}
#define ATOMIC_TYPE __ATOMIC_SEQ_CST
void *
test4_prod(void *arg)
{
for (uint64_t i = 0; i < loopcnt; i++) {
__atomic_add_fetch(&shared, 1, ATOMIC_TYPE);
}
terminate = 1;
return NULL;
}
void *
test4_cons(void *arg)
{
do {
result += __atomic_exchange_8(&shared, 0, ATOMIC_TYPE);
} while (terminate == 0);
//
result += __atomic_exchange_8(&shared, 0, ATOMIC_TYPE);
return NULL;
}
#endif // __GNUC__
// test5: std::atomic
void
test5_init()
{
}
void *
test5_prod(void *arg)
{
for (uint64_t i = 0; i < loopcnt; i++) {
shared5.fetch_add(1);
}
terminate = 1;
return NULL;
}
void *
test5_cons(void *arg)
{
do {
result += shared5.exchange(0);
} while (terminate == 0);
//
result += shared5.exchange(0);
return NULL;
}
// メインルーチン
int
test(const char *name,
void (*init)(), void *(*prod)(void *), void *(*cons)(void *))
{
pthread_t t1;
pthread_t t2;
struct timeval start, end, tv;
printf("%-20s: ", name); fflush(stdout);
result = 0;
shared = 0;
terminate = false;
init();
gettimeofday(&start, NULL);
pthread_create(&t1, NULL, prod, NULL);
pthread_create(&t2, NULL, cons, NULL);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
gettimeofday(&end, NULL);
timersub(&end, &start, &tv);
printf("time=%d.%06d, ", (int)tv.tv_sec, (int)tv.tv_usec);
printf("result=%" PRIu64 "\n", result);
return 0;
}
int
main(int ac, char *av[])
{
printf("compiled by ");
#if defined(__clang_version__)
printf("clang %s", __clang_version__);
#elif defined(__GNUC__) && defined(__VERSION__)
printf("gcc %s", __VERSION__);
#else
printf("unknown compiler");
#endif
printf("\n");
test("test1(no atomics)", test1_init, test1_prod, test1_cons);
#if defined(__NetBSD__)
test("test3(atomic.h)", test3_init, test3_prod, test3_cons);
#endif
#if defined(__clang_version__)
#else
test("test4(gcc builtin)", test4_init, test4_prod, test4_cons);
#endif
test("test5(std::atomic)", test5_init, test5_prod, test5_cons);
test("test2(pthread_mutex)",test2_init, test2_prod, test2_cons);
return 0;
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.