1510 lines
36 KiB
C++
1510 lines
36 KiB
C++
/*
|
|
* dsltest.actor.cpp
|
|
*
|
|
* This source file is part of the FoundationDB open source project
|
|
*
|
|
* Copyright 2013-2022 Apple Inc. and the FoundationDB project authors
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include <iostream>
|
|
#include <algorithm>
|
|
#include "flow/FastRef.h"
|
|
#undef ERROR
|
|
#include "fdbrpc/simulator.h"
|
|
#include "fdbrpc/ActorFuzz.h"
|
|
#include "flow/DeterministicRandom.h"
|
|
#include "flow/ThreadHelper.actor.h"
|
|
#include "flow/actorcompiler.h" // This must be the last #include.
|
|
|
|
void* allocateLargePages(int total);
|
|
|
|
bool testFuzzActor(Future<int> (*actor)(FutureStream<int> const&, PromiseStream<int> const&, Future<Void> const&),
|
|
const char* desc,
|
|
std::vector<int> const& expectedOutput) {
|
|
// Run the test 5 times with different "timing"
|
|
int i, outCount;
|
|
bool ok = true;
|
|
for (int trial = 0; trial < 5; trial++) {
|
|
PromiseStream<int> in, out;
|
|
Promise<Void> err;
|
|
int before = deterministicRandom()->randomInt(0, 4);
|
|
int errorBefore = before + deterministicRandom()->randomInt(0, 4);
|
|
// printf("\t\tTrial #%d: %d, %d\n", trial, before, errorBefore);
|
|
if (errorBefore <= before)
|
|
err.sendError(operation_failed());
|
|
for (i = 0; i < before; i++) {
|
|
in.send((i + 1) * 1000);
|
|
}
|
|
Future<int> ret = (*actor)(in.getFuture(), out, err.getFuture());
|
|
while (i < 1000000 && !ret.isReady()) {
|
|
i++;
|
|
if (errorBefore == i)
|
|
err.sendError(operation_failed());
|
|
in.send(i * 1000);
|
|
}
|
|
if (ret.isReady()) {
|
|
if (ret.isError())
|
|
out.send(ret.getError().code());
|
|
else
|
|
out.send(ret.get());
|
|
} else {
|
|
printf("\tERROR: %s did not return after consuming %d input values\n", desc, i);
|
|
if (trial)
|
|
printf("\t\tResult was inconsistent between runs! (Trial %d)\n", trial);
|
|
ok = false;
|
|
// return false;
|
|
}
|
|
|
|
outCount = -1;
|
|
while (out.getFuture().isReady()) {
|
|
int o = out.getFuture().pop();
|
|
outCount++;
|
|
if (outCount < expectedOutput.size() && expectedOutput[outCount] != o) {
|
|
printf("\tERROR: %s output #%d incorrect: %d != expected %d\n",
|
|
desc,
|
|
outCount,
|
|
o,
|
|
expectedOutput[outCount]);
|
|
if (trial)
|
|
printf("\t\tResult was inconsistent between runs!\n");
|
|
ok = false;
|
|
// return false;
|
|
}
|
|
}
|
|
if (outCount + 1 != expectedOutput.size()) {
|
|
printf(
|
|
"\tERROR: %s output length incorrect: %d != expected %zu\n", desc, outCount + 1, expectedOutput.size());
|
|
if (trial)
|
|
printf("\t\tResult was inconsistent between runs!\n");
|
|
ok = false;
|
|
// return false;
|
|
}
|
|
|
|
// We might have put in values that weren't actually consumed...
|
|
while (in.getFuture().isReady()) {
|
|
in.getFuture().pop();
|
|
i--;
|
|
}
|
|
}
|
|
// printf("\t%s: OK, %d input values -> %d output values\n", desc, i, outCount);
|
|
return ok;
|
|
}
|
|
|
|
#if 0
|
|
void memoryTest2() {
|
|
const int Size = 2000 << 20;
|
|
const int Reads = 4 << 20;
|
|
const int MaxThreads = 4;
|
|
|
|
char* block = new char[Size];
|
|
memset(block, 0, Size);
|
|
|
|
char** random = new char*[ Reads * MaxThreads ];
|
|
random[0] = block;
|
|
for(int i=1; i<Reads*MaxThreads; ) {
|
|
char *s = &block[ deterministicRandom()->randomInt(0, Size) ];
|
|
random[i++] = s;
|
|
/*for(int j=0; j<10 && i<Reads*MaxThreads; j++,i++) {
|
|
random[i] = s + deterministicRandom()->randomInt(0, 4096);
|
|
if (random[i] >= block+Size) random[i] -= Size;
|
|
}*/
|
|
}
|
|
|
|
for(int threads=1; threads<=MaxThreads; threads++) {
|
|
double tstart = timer();
|
|
|
|
std::vector<ThreadFuture<Void>> done;
|
|
for(int t=0; t<threads; t++) {
|
|
char** r = random + Reads*t;
|
|
done.push_back(
|
|
inThread<Void>( [r,Reads] () -> Void {
|
|
for(int i=0; i<Reads; i++)
|
|
if ( *r[i] )
|
|
std::cout << "Does not happen" << std::endl;
|
|
return Void();
|
|
}));
|
|
}
|
|
waitForAll(done).getBlocking();
|
|
double duration = timer() - tstart;
|
|
|
|
std::cout << format("%d threads: %f sec, %0.2fM/sec", threads, duration, Reads*threads/1e6/duration) << std::endl;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
enum { MaxTraversalsPerThread = 64 };
|
|
|
|
void showNumaStatus();
|
|
void* numaAllocate(size_t size);
|
|
|
|
#if 0
|
|
void memoryTest() {
|
|
//memoryTest2();
|
|
//return;
|
|
|
|
showNumaStatus();
|
|
|
|
const int N = 128<<20; // 128 = 1GB
|
|
const int N2 = 8<<20;
|
|
std::cout << "Preparing memory test with " << N / 1e6 * sizeof(void*) << " MB" << std::endl;
|
|
void **x;
|
|
if (0) {
|
|
std::cout << " NUMA large pages" << std::endl;
|
|
x = (void**)numaAllocate(size_t(N)*sizeof(void*));
|
|
} else if (1) {
|
|
std::cout << " Normal pages" << std::endl;
|
|
x = new void*[ N ];
|
|
printf(" at %p\n", x);
|
|
} else {
|
|
std::cout << " Large pages" << std::endl;
|
|
x = (void**)allocate(N*sizeof(void*), true);
|
|
}
|
|
memset(x, 0, ((int64_t)N) * sizeof(void*));
|
|
|
|
showNumaStatus();
|
|
|
|
if (1) {
|
|
std::cout <<" Random permutation" << std::endl;
|
|
// Random cyclic permutation
|
|
for(int i=0; i<N; i++)
|
|
x[i] = &x[i];
|
|
// Sattolo's algorithm
|
|
for(int n = N-1; n >= 1; n--) {
|
|
int k = deterministicRandom()->randomInt(0, n); //random.IRandomX(0, n-1);
|
|
std::swap( x[k], x[n] );
|
|
}
|
|
} else {
|
|
std::cout <<" Sequential permutation" << std::endl;
|
|
// Sequential
|
|
for(int i=0; i<N-1; i++)
|
|
x[i] = &x[i+1];
|
|
x[N-1] = &x[0];
|
|
}
|
|
void **p = x;
|
|
for(int i=0; i<N; i++) {
|
|
p = (void**)*p;
|
|
if (p == x) {
|
|
std::cout << "Cycle " << i << std::endl;
|
|
if (i != N-1) terminate();
|
|
}
|
|
}
|
|
|
|
const int MT = 16;
|
|
for(int TraversalsPerThread = 1; TraversalsPerThread <= MaxTraversalsPerThread; TraversalsPerThread *= 2)
|
|
{
|
|
const int PseudoThreads = MT * TraversalsPerThread;
|
|
void **starts[MT*MaxTraversalsPerThread];
|
|
for(int t=0; t<PseudoThreads; t++) {
|
|
starts[t] = &x[ N/PseudoThreads * t ];
|
|
//starts[t] = &x[ deterministicRandom()->randomInt(0,N) ];
|
|
}
|
|
for(int T=1; T<=MT; T+=T) {
|
|
double start = timer();
|
|
std::vector< Future<double> > done;
|
|
for(int t=0; t<T; t++) {
|
|
void*** start = starts + t*TraversalsPerThread;
|
|
done.push_back(
|
|
inThread<double>( [start,N2,TraversalsPerThread] () -> double {
|
|
void **p[MaxTraversalsPerThread];
|
|
for(int j=0; j<TraversalsPerThread; j++)
|
|
p[j] = start[j];
|
|
for(int i=0; i<N2; i++)
|
|
for(int j=0; j<TraversalsPerThread; j++) {
|
|
p[j] = (void**)*p[j];
|
|
if (TraversalsPerThread > 1)
|
|
_mm_prefetch( (const char*)p[j], _MM_HINT_T0 );
|
|
}
|
|
for(int j=0; j<TraversalsPerThread; j++)
|
|
if (p[j] == p[(j+1)%TraversalsPerThread])
|
|
std::cout << "N";
|
|
return timer();
|
|
}));
|
|
}
|
|
double firstEnd = 1e30;
|
|
for(int t=0; t<T; t++) {
|
|
done[t].getBlocking();
|
|
firstEnd = std::min(firstEnd, done[t].get());
|
|
}
|
|
double end = timer();
|
|
printf(" %2dx%2d traversals: %5.3fs, %6.1f M/sec, %4.1f%%\n", T, (int)TraversalsPerThread, end-start,
|
|
N2 / 1e6 * (T*TraversalsPerThread) / (end-start),
|
|
(firstEnd-start)/(end-start)*100.0);
|
|
}
|
|
}
|
|
|
|
//delete[] x; // TODO: Free large pages
|
|
}
|
|
#endif
|
|
|
|
ACTOR template <int N, class X>
|
|
[[flow_allow_discard]] Future<X> addN(Future<X> in) {
|
|
X i = wait(in);
|
|
return i + N;
|
|
}
|
|
|
|
ACTOR template <class A, class B>
|
|
[[flow_allow_discard]] Future<Void> switchTest(FutureStream<A> as, Future<B> oneb) {
|
|
loop choose {
|
|
when(A a = waitNext(as)) { std::cout << "A " << a << std::endl; }
|
|
when(B b = wait(oneb)) {
|
|
std::cout << "B " << b << std::endl;
|
|
break;
|
|
}
|
|
}
|
|
loop {
|
|
std::cout << "Done!" << std::endl;
|
|
return Void();
|
|
}
|
|
}
|
|
|
|
class TestBuffer : public ReferenceCounted<TestBuffer> {
|
|
public:
|
|
static TestBuffer* create(int length) {
|
|
#if defined(__INTEL_COMPILER)
|
|
return new TestBuffer(length);
|
|
#else
|
|
auto b = (TestBuffer*)new int[(length + 7) / 4];
|
|
new (b) TestBuffer(length);
|
|
return b;
|
|
#endif
|
|
}
|
|
#if !defined(__INTEL_COMPILER)
|
|
void operator delete(void* buf) {
|
|
std::cout << "Freeing buffer" << std::endl;
|
|
delete[](int*) buf;
|
|
}
|
|
#endif
|
|
|
|
int size() const { return length; }
|
|
uint8_t* begin() { return data; }
|
|
uint8_t* end() { return data + length; }
|
|
const uint8_t* begin() const { return data; }
|
|
const uint8_t* end() const { return data + length; }
|
|
|
|
private:
|
|
TestBuffer(int length) noexcept : length(length) {}
|
|
int length;
|
|
uint8_t data[1];
|
|
};
|
|
|
|
int fastKeyCount = 0;
|
|
|
|
class FastKey : public FastAllocated<FastKey>, public ReferenceCounted<FastKey> {
|
|
public:
|
|
FastKey() : length(0) {}
|
|
FastKey(char* b, int length) : length(length) {
|
|
ASSERT(length <= sizeof(data));
|
|
memcpy(data, b, length);
|
|
}
|
|
~FastKey() { fastKeyCount++; }
|
|
int size() const { return length; }
|
|
uint8_t* begin() { return data; }
|
|
uint8_t* end() { return data + length; }
|
|
const uint8_t* begin() const { return data; }
|
|
const uint8_t* end() const { return data + length; }
|
|
|
|
private:
|
|
int length;
|
|
uint8_t data[252];
|
|
};
|
|
|
|
struct TestB : FastAllocated<TestB> {
|
|
char x[65];
|
|
};
|
|
|
|
void fastAllocTest() {
|
|
double t;
|
|
|
|
std::vector<void*> d;
|
|
for (int i = 0; i < 1000000; i++) {
|
|
d.push_back(FastAllocator<64>::allocate());
|
|
int r = deterministicRandom()->randomInt(0, 1000000);
|
|
if (r < d.size()) {
|
|
FastAllocator<64>::release(d[r]);
|
|
d[r] = d.back();
|
|
d.pop_back();
|
|
}
|
|
}
|
|
std::sort(d.begin(), d.end());
|
|
if (std::unique(d.begin(), d.end()) != d.end())
|
|
std::cout << "Pointer returned twice!?" << std::endl;
|
|
|
|
for (int i = 0; i < 2; i++) {
|
|
void* p = FastAllocator<64>::allocate();
|
|
void* q = FastAllocator<64>::allocate();
|
|
std::cout << (intptr_t)p << " " << (intptr_t)q << std::endl;
|
|
FastAllocator<64>::release(p);
|
|
FastAllocator<64>::release(q);
|
|
}
|
|
|
|
t = timer();
|
|
for (int i = 0; i < 1000000; i++)
|
|
(void)FastAllocator<64>::allocate();
|
|
t = timer() - t;
|
|
std::cout << "Allocations: " << (1 / t) << "M/sec" << std::endl;
|
|
|
|
t = timer();
|
|
for (int i = 0; i < 1000000; i++)
|
|
FastAllocator<64>::release(FastAllocator<64>::allocate());
|
|
t = timer() - t;
|
|
std::cout << "Allocate/Release pairs: " << (1 / t) << "M/sec" << std::endl;
|
|
|
|
t = timer();
|
|
void* pp[100];
|
|
for (int i = 0; i < 10000; i++) {
|
|
for (int j = 0; j < 100; j++)
|
|
pp[j] = FastAllocator<64>::allocate();
|
|
for (int j = 0; j < 100; j++)
|
|
FastAllocator<64>::release(pp[j]);
|
|
}
|
|
t = timer() - t;
|
|
std::cout << "Allocate/Release interleaved(100): " << (1 / t) << "M/sec" << std::endl;
|
|
|
|
t = timer();
|
|
for (int i = 0; i < 1000000; i++)
|
|
delete new TestB;
|
|
t = timer() - t;
|
|
std::cout << "Allocate/Release TestB pairs: " << (1 / t) << "M/sec" << std::endl;
|
|
|
|
#if FLOW_THREAD_SAFE
|
|
t = timer();
|
|
std::vector<Future<bool>> results;
|
|
for (int i = 0; i < 4; i++)
|
|
results.push_back(inThread<bool>([]() -> bool {
|
|
TestB* pp[100];
|
|
for (int i = 0; i < 10000; i++) {
|
|
for (int j = 0; j < 100; j++)
|
|
pp[j] = new TestB;
|
|
for (int j = 0; j < 100; j++)
|
|
delete pp[j];
|
|
}
|
|
return true;
|
|
}));
|
|
waitForAll(results).getBlocking();
|
|
t = timer() - t;
|
|
std::cout << "Threaded Allocate/Release TestB interleaved (100): " << results.size() << " x " << (1 / t) << "M/sec"
|
|
<< std::endl;
|
|
#endif
|
|
|
|
volatile int32_t v = 0;
|
|
|
|
t = timer();
|
|
for (int i = 0; i < 10000000; i++)
|
|
interlockedIncrement(&v);
|
|
t = timer() - t;
|
|
std::cout << "interlocked increment: " << 10.0 / t << "M/sec " << v << std::endl;
|
|
|
|
v = 5;
|
|
t = timer();
|
|
for (int i = 0; i < 10000000; i++) {
|
|
interlockedCompareExchange(&v, 5, 5);
|
|
}
|
|
t = timer() - t;
|
|
std::cout << "1 state machine: " << 10.0 / t << "M/sec " << v << std::endl;
|
|
|
|
v = 0;
|
|
t = timer();
|
|
for (int i = 0; i < 10000000; i++)
|
|
v++;
|
|
t = timer() - t;
|
|
std::cout << "volatile increment: " << 10.0 / t << "M/sec " << v << std::endl;
|
|
|
|
{
|
|
Reference<TestBuffer> b(TestBuffer::create(1000));
|
|
memcpy(b->begin(), "Hello, world!", 14);
|
|
|
|
t = timer();
|
|
for (int i = 0; i < 10000000; i++) {
|
|
Reference<TestBuffer> r = std::move(b);
|
|
b = std::move(r);
|
|
}
|
|
t = timer() - t;
|
|
std::cout << "move Reference<Buffer>: " << 10.0 / t << "M/sec " << std::endl;
|
|
|
|
t = timer();
|
|
for (int i = 0; i < 10000000; i++) {
|
|
Reference<TestBuffer> r = b;
|
|
}
|
|
t = timer() - t;
|
|
std::cout << "copy (1) Reference<Buffer>: " << 10.0 / t << "M/sec " << std::endl;
|
|
|
|
Reference<TestBuffer> c = b;
|
|
t = timer();
|
|
for (int i = 0; i < 10000000; i++) {
|
|
Reference<TestBuffer> r = b;
|
|
}
|
|
t = timer() - t;
|
|
std::cout << "copy (2) Reference<Buffer>: " << 10.0 / t << "M/sec " << std::endl;
|
|
|
|
std::cout << (const char*)b->begin() << std::endl;
|
|
}
|
|
t = timer();
|
|
for (int i = 0; i < 10000000; i++) {
|
|
delete new FastKey;
|
|
}
|
|
t = timer() - t;
|
|
std::cout << "delete new FastKey: " << 10.0 / t << "M/sec " << fastKeyCount << std::endl;
|
|
|
|
t = timer();
|
|
for (int i = 0; i < 10000000; i++) {
|
|
Reference<FastKey> r(new FastKey);
|
|
}
|
|
t = timer() - t;
|
|
std::cout << "new Reference<FastKey>: " << 10.0 / t << "M/sec " << fastKeyCount << std::endl;
|
|
}
|
|
|
|
template <class PromiseT>
|
|
Future<Void> threadSafetySender(std::vector<PromiseT>& v, Event& start, Event& ready, int iterations) {
|
|
for (int i = 0; i < iterations; i++) {
|
|
start.block();
|
|
if (v.size() == 0)
|
|
return Void();
|
|
for (int i = 0; i < v.size(); i++)
|
|
v[i].send(Void());
|
|
ready.set();
|
|
}
|
|
return Void();
|
|
}
|
|
|
|
ACTOR [[flow_allow_discard]] void threadSafetyWaiter(Future<Void> f, int32_t* count) {
|
|
wait(f);
|
|
interlockedIncrement(count);
|
|
}
|
|
ACTOR [[flow_allow_discard]] void threadSafetyWaiter(FutureStream<Void> f, int n, int32_t* count) {
|
|
while (n--) {
|
|
waitNext(f);
|
|
interlockedIncrement(count);
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
void threadSafetyTest() {
|
|
double t = timer();
|
|
|
|
int N = 10000, V = 100;
|
|
|
|
std::vector<Promise<Void>> v;
|
|
Event start, ready;
|
|
Future<Void> sender = inThread<Void>( [&] { return threadSafetySender( v, start, ready, N ); } );
|
|
|
|
for(int i=0; i<N; i++) {
|
|
v.clear();
|
|
for (int j = 0; j < V; j++)
|
|
v.push_back(Promise<Void>());
|
|
std::vector<Future<Void>> f( v.size() );
|
|
for(int i=0; i<v.size(); i++)
|
|
f[i] = v[i].getFuture();
|
|
std::random_shuffle( f.begin(), f.end() );
|
|
|
|
start.set();
|
|
int32_t count = 0;
|
|
for(int i=0; i<f.size(); i++)
|
|
threadSafetyWaiter( f[i], &count );
|
|
ready.block();
|
|
|
|
if (count != V)
|
|
std::cout << "Thread safety error: " << count << std::endl;
|
|
}
|
|
|
|
t = timer()-t;
|
|
std::cout << "Thread safety test (2t): " << (V*N/1e6/t) << "M/sec" << std::endl;
|
|
}
|
|
|
|
void threadSafetyTest2() {
|
|
double t = timer();
|
|
|
|
int N = 1000, V = 100;
|
|
|
|
// std::vector<PromiseStream<Void>> streams( 100 );
|
|
std::vector<PromiseStream<Void>> streams;
|
|
for (int i = 0; i < 100; i++)
|
|
streams.push_back(PromiseStream<Void>());
|
|
std::vector<PromiseStream<Void>> v;
|
|
Event start, ready;
|
|
Future<Void> sender = inThread<Void>( [&] { return threadSafetySender( v, start, ready, N ); } );
|
|
|
|
for(int i=0; i<N; i++) {
|
|
std::vector<int> counts( streams.size() );
|
|
v.clear();
|
|
for(int k=0; k<V; k++) {
|
|
int i = deterministicRandom()->randomInt(0, (int)streams.size());
|
|
counts[i]++;
|
|
v.push_back( streams[i] );
|
|
}
|
|
|
|
start.set();
|
|
int32_t count = 0;
|
|
for(int i=0; i<streams.size(); i++)
|
|
threadSafetyWaiter( streams[i].getFuture(), counts[i], &count );
|
|
ready.block();
|
|
|
|
if (count != V)
|
|
std::cout << "Thread safety error: " << count << std::endl;
|
|
}
|
|
|
|
t = timer()-t;
|
|
std::cout << "Thread safety test 2 (2t): " << (V*N/1e6/t) << "M/sec" << std::endl;
|
|
}
|
|
|
|
volatile int32_t cancelled = 0, returned = 0;
|
|
|
|
ACTOR [[flow_allow_discard]] Future<Void> returnCancelRacer( Future<Void> f ) {
|
|
try {
|
|
wait(f);
|
|
} catch ( Error& ) {
|
|
interlockedIncrement( &cancelled );
|
|
throw;
|
|
}
|
|
interlockedIncrement( &returned );
|
|
return Void();
|
|
}
|
|
|
|
void returnCancelRaceTest() {
|
|
int N = 100, M = 100;
|
|
for(int i=0; i<N; i++) {
|
|
std::vector< Promise<Void> > promises;
|
|
std::vector< Future<Void> > futures;
|
|
for(int i=0; i < M; i++) {
|
|
promises.push_back( Promise<Void>() );
|
|
futures.push_back( returnCancelRacer( promises.back().getFuture() ) );
|
|
}
|
|
std::random_shuffle( futures.begin(), futures.end() );
|
|
|
|
// FIXME: Doesn't work as written with auto-reset
|
|
// events. Probably not particularly racy as written. Test may
|
|
// FAIL or PASS at whim.
|
|
|
|
Event ev1, ev2;
|
|
ThreadFuture<Void> b = inThread<Void>( [&] ()->Void {
|
|
ev1.block();
|
|
for(int i=0; i<promises.size(); i++)
|
|
futures[i] = Future<Void>();
|
|
return Void();
|
|
} );
|
|
ThreadFuture<Void> a = inThread<Void>([&]()->Void {
|
|
ev2.block();
|
|
for(int i=0; i<promises.size(); i++) {
|
|
promises[i].send(Void());
|
|
for( volatile int32_t dummy = 0; dummy < 10; dummy ++ );
|
|
}
|
|
return Void();
|
|
} );
|
|
ev1.set(); ev2.set();
|
|
a.getBlocking();
|
|
b.getBlocking();
|
|
}
|
|
|
|
bool ok = cancelled && returned && cancelled+returned == N*M;
|
|
printf("ReturnCancelRaceTest: %s\n", ok ? "PASS" : "FAIL");
|
|
printf(" %d cancelled, %d returned\n", cancelled, returned);
|
|
}
|
|
#endif
|
|
|
|
ACTOR [[flow_allow_discard]] Future<int> chooseTest(Future<int> a, Future<int> b) {
|
|
choose {
|
|
when(int A = wait(a)) { return A; }
|
|
when(int B = wait(b)) { return B; }
|
|
}
|
|
}
|
|
|
|
void showArena(ArenaBlock* a, ArenaBlock* parent) {
|
|
printf("ArenaBlock %p (<-%p): %d bytes, %d refs\n", a, parent, a->size(), a->debugGetReferenceCount());
|
|
if (!a->isTiny()) {
|
|
int o = a->nextBlockOffset;
|
|
while (o) {
|
|
ArenaBlockRef* r = (ArenaBlockRef*)((char*)a->getData() + o);
|
|
|
|
// If alignedBuffer is valid then print its pointer and size, else recurse
|
|
if (r->aligned4kBufferSize != 0) {
|
|
printf("AlignedBuffer %p (<-%p) %u bytes\n", r->aligned4kBuffer, a, r->aligned4kBufferSize);
|
|
} else {
|
|
showArena(r->next, a);
|
|
}
|
|
|
|
o = r->nextBlockOffset;
|
|
}
|
|
}
|
|
}
|
|
|
|
void arenaTest() {
|
|
BinaryWriter wr(AssumeVersion(g_network->protocolVersion()));
|
|
{
|
|
Arena arena;
|
|
VectorRef<StringRef> test;
|
|
test.push_back(arena, StringRef(arena, LiteralStringRef("Hello")));
|
|
test.push_back(arena, StringRef(arena, LiteralStringRef(", ")));
|
|
test.push_back(arena, StringRef(arena, LiteralStringRef("World!")));
|
|
|
|
for (auto i = test.begin(); i != test.end(); ++i)
|
|
for (auto j = i->begin(); j != i->end(); ++j)
|
|
std::cout << *j;
|
|
std::cout << std::endl;
|
|
|
|
wr << test;
|
|
}
|
|
{
|
|
Arena arena2;
|
|
VectorRef<StringRef> test2;
|
|
BinaryReader reader(wr.getData(), wr.getLength(), AssumeVersion(g_network->protocolVersion()));
|
|
reader >> test2 >> arena2;
|
|
|
|
for (auto i = test2.begin(); i != test2.end(); ++i)
|
|
for (auto j = i->begin(); j != i->end(); ++j)
|
|
std::cout << *j;
|
|
std::cout << std::endl;
|
|
}
|
|
|
|
double t = timer();
|
|
for (int i = 0; i < 100; i++) {
|
|
Arena ar;
|
|
for (int i = 0; i < 10000000; i++)
|
|
new (ar) char[10];
|
|
}
|
|
printf("100 x 10M x 10B allocated+freed from Arenas: %f sec\n", timer() - t);
|
|
|
|
// printf("100M x 8bytes allocations: %d bytes used\n", 0);//ar.getSize());
|
|
// showArena( ar.impl.getPtr(), 0 );
|
|
};
|
|
|
|
ACTOR [[flow_allow_discard]] void testStream(FutureStream<int> xs) {
|
|
loop {
|
|
int x = waitNext(xs);
|
|
std::cout << x << std::endl;
|
|
}
|
|
}
|
|
|
|
ACTOR [[flow_allow_discard]] Future<Void> actorTest1(bool b) {
|
|
printf("1");
|
|
if (b)
|
|
throw future_version();
|
|
return Void();
|
|
}
|
|
|
|
ACTOR [[flow_allow_discard]] void actorTest2(bool b) {
|
|
printf("2");
|
|
if (b)
|
|
throw future_version();
|
|
}
|
|
|
|
ACTOR [[flow_allow_discard]] Future<Void> actorTest3(bool b) {
|
|
try {
|
|
if (b)
|
|
throw future_version();
|
|
} catch (Error&) {
|
|
printf("3");
|
|
return Void();
|
|
}
|
|
printf("\nactorTest3 failed\n");
|
|
return Void();
|
|
}
|
|
|
|
ACTOR [[flow_allow_discard]] Future<Void> actorTest4(bool b) {
|
|
state double tstart = now();
|
|
try {
|
|
if (b)
|
|
throw operation_failed();
|
|
} catch (...) {
|
|
wait(delay(1));
|
|
}
|
|
if (now() < tstart + 1)
|
|
printf("actorTest4 failed");
|
|
else
|
|
printf("4");
|
|
return Void();
|
|
}
|
|
|
|
ACTOR [[flow_allow_discard]] Future<bool> actorTest5() {
|
|
state bool caught = false;
|
|
|
|
loop {
|
|
loop {
|
|
state bool inloop = false;
|
|
if (caught) {
|
|
printf("5");
|
|
return true;
|
|
}
|
|
try {
|
|
loop {
|
|
if (inloop) {
|
|
printf("\nactorTest5 failed\n");
|
|
return false;
|
|
}
|
|
inloop = true;
|
|
if (1)
|
|
throw operation_failed();
|
|
}
|
|
} catch (Error&) {
|
|
caught = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ACTOR [[flow_allow_discard]] Future<bool> actorTest6() {
|
|
state bool caught = false;
|
|
loop {
|
|
if (caught) {
|
|
printf("6");
|
|
return true;
|
|
}
|
|
try {
|
|
if (1)
|
|
throw operation_failed();
|
|
} catch (Error&) {
|
|
caught = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
ACTOR [[flow_allow_discard]] Future<bool> actorTest7() {
|
|
try {
|
|
loop {
|
|
loop {
|
|
if (1)
|
|
throw operation_failed();
|
|
if (1) {
|
|
printf("actorTest7 failed (1)\n");
|
|
return false;
|
|
}
|
|
if (0)
|
|
break;
|
|
}
|
|
if (1) {
|
|
printf("actorTest7 failed (2)\n");
|
|
return false;
|
|
}
|
|
}
|
|
} catch (Error&) {
|
|
printf("7");
|
|
return true;
|
|
}
|
|
}
|
|
|
|
ACTOR [[flow_allow_discard]] Future<bool> actorTest8() {
|
|
state bool caught = false;
|
|
state Future<bool> set = true;
|
|
|
|
loop {
|
|
state bool inloop = false;
|
|
if (caught) {
|
|
printf("8");
|
|
return true;
|
|
}
|
|
try {
|
|
loop {
|
|
if (inloop) {
|
|
printf("\nactorTest8 failed\n");
|
|
return false;
|
|
}
|
|
bool b = wait(set);
|
|
inloop = true;
|
|
if (1)
|
|
throw operation_failed();
|
|
}
|
|
} catch (Error&) {
|
|
caught = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
ACTOR [[flow_allow_discard]] Future<bool> actorTest9A(Future<Void> setAfterCalling) {
|
|
state int count = 0;
|
|
loop {
|
|
if (count == 4) {
|
|
printf("9");
|
|
return true;
|
|
}
|
|
if (count && count != 4) {
|
|
printf("\nactorTest9 failed\n");
|
|
return false;
|
|
}
|
|
loop {
|
|
loop {
|
|
wait(setAfterCalling);
|
|
loop {
|
|
loop {
|
|
count++;
|
|
break;
|
|
}
|
|
wait(Future<Void>(Void()));
|
|
count++;
|
|
break;
|
|
}
|
|
count++;
|
|
break;
|
|
}
|
|
count++;
|
|
break;
|
|
}
|
|
// loopDepth < 0 ???
|
|
}
|
|
}
|
|
|
|
Future<bool> actorTest9() {
|
|
Promise<Void> p;
|
|
Future<bool> f = actorTest9A(p.getFuture());
|
|
p.send(Void());
|
|
return f;
|
|
}
|
|
|
|
ACTOR [[flow_allow_discard]] Future<Void> actorTest10A(FutureStream<int> inputStream, Future<Void> go) {
|
|
state int i;
|
|
for (i = 0; i < 5; i++) {
|
|
wait(go);
|
|
int input = waitNext(inputStream);
|
|
}
|
|
return Void();
|
|
}
|
|
|
|
void actorTest10() {
|
|
PromiseStream<int> ins;
|
|
Promise<Void> go;
|
|
for (int x = 0; x < 2; x++)
|
|
ins.send(x);
|
|
Future<Void> a = actorTest10A(ins.getFuture(), go.getFuture());
|
|
go.send(Void());
|
|
for (int x = 0; x < 3; x++)
|
|
ins.send(x);
|
|
if (!a.isReady())
|
|
printf("\nactorTest10 failed\n");
|
|
else
|
|
printf("10");
|
|
}
|
|
|
|
ACTOR [[flow_allow_discard]] Future<Void> cancellable() {
|
|
wait(Never());
|
|
return Void();
|
|
}
|
|
|
|
ACTOR [[flow_allow_discard]] Future<Void> simple() {
|
|
return Void();
|
|
}
|
|
|
|
ACTOR [[flow_allow_discard]] Future<Void> simpleWait() {
|
|
wait(Future<Void>(Void()));
|
|
return Void();
|
|
}
|
|
|
|
ACTOR [[flow_allow_discard]] Future<int> simpleRet(Future<int> x) {
|
|
int i = wait(x);
|
|
return i;
|
|
}
|
|
|
|
template <int i>
|
|
Future<int> chain(Future<int> const& x);
|
|
|
|
ACTOR template <int i>
|
|
[[flow_allow_discard]] Future<int> achain(Future<int> x) {
|
|
int k = wait(chain<i>(x));
|
|
return k + 1;
|
|
}
|
|
|
|
template <int i>
|
|
Future<int> chain(Future<int> const& x) {
|
|
return achain<i - 1>(x);
|
|
}
|
|
|
|
template <>
|
|
Future<int> chain<0>(Future<int> const& x) {
|
|
return x;
|
|
}
|
|
|
|
ACTOR [[flow_allow_discard]] Future<int> chain2(Future<int> x, int i);
|
|
|
|
ACTOR [[flow_allow_discard]] Future<int> chain2(Future<int> x, int i) {
|
|
if (i > 1) {
|
|
int k = wait(chain2(x, i - 1));
|
|
return k + 1;
|
|
} else {
|
|
int k = wait(x);
|
|
return k + i;
|
|
}
|
|
}
|
|
|
|
ACTOR [[flow_allow_discard]] Future<Void> cancellable2() {
|
|
try {
|
|
wait(Never());
|
|
return Void();
|
|
} catch (Error& e) {
|
|
throw;
|
|
}
|
|
}
|
|
|
|
ACTOR [[flow_allow_discard]] Future<int> introLoadValueFromDisk(Future<std::string> filename) {
|
|
std::string file = wait(filename);
|
|
|
|
if (file == "/dev/threes")
|
|
return 3;
|
|
else
|
|
ASSERT(false);
|
|
return 0; // does not happen
|
|
}
|
|
|
|
ACTOR [[flow_allow_discard]] Future<int> introAdd(Future<int> a, Future<int> b) {
|
|
state int x = wait(a);
|
|
int y = wait(b);
|
|
return x + y; // x would be undefined here if it was not "state"
|
|
}
|
|
|
|
ACTOR [[flow_allow_discard]] Future<int> introFirst(Future<int> a, Future<int> b) {
|
|
choose {
|
|
when(int x = wait(a)) { return x; }
|
|
when(int x = wait(b)) { return x; }
|
|
}
|
|
}
|
|
|
|
struct AddReply {
|
|
int sum;
|
|
AddReply() {}
|
|
AddReply(int x) : sum(x) {}
|
|
|
|
template <class Ar>
|
|
void serialize(Ar& ar) {
|
|
serializer(ar, sum);
|
|
}
|
|
};
|
|
|
|
struct AddRequest {
|
|
int a, b;
|
|
Promise<AddReply> reply; // Self-addressed envelope
|
|
|
|
AddRequest() {}
|
|
AddRequest(int a, int b) : a(a), b(b) {}
|
|
|
|
template <class Ar>
|
|
void serialize(Ar& ar) {
|
|
serializer(ar, a, b, reply);
|
|
}
|
|
};
|
|
|
|
ACTOR [[flow_allow_discard]] void introAddServer(PromiseStream<AddRequest> add) {
|
|
loop choose {
|
|
when(AddRequest req = waitNext(add.getFuture())) {
|
|
printf("%d + %d = %d\n", req.a, req.b, req.a + req.b);
|
|
req.reply.send(req.a + req.b);
|
|
}
|
|
}
|
|
}
|
|
|
|
void introPromiseFuture() {
|
|
Promise<int> myPromise;
|
|
|
|
Future<int> myFuture = myPromise.getFuture();
|
|
|
|
myPromise.send(12345);
|
|
|
|
ASSERT(myFuture.isReady() && myFuture.get() == 12345);
|
|
}
|
|
|
|
void introActor() {
|
|
Future<int> f = introLoadValueFromDisk(std::string("/dev/threes"));
|
|
ASSERT(f.get() == 3);
|
|
|
|
Promise<int> a, b;
|
|
Future<int> sum = introAdd(a.getFuture(), b.getFuture());
|
|
b.send(3);
|
|
ASSERT(!sum.isReady());
|
|
a.send(2);
|
|
ASSERT(sum.get() == 5);
|
|
|
|
Promise<int> c, d;
|
|
Future<int> first = introFirst(c.getFuture(), d.getFuture());
|
|
ASSERT(!first.isReady());
|
|
// d.send(100);
|
|
d.sendError(operation_failed());
|
|
ASSERT(first.isError() && first.getError().code() == error_code_operation_failed);
|
|
// ASSERT( first.getBlocking() == 100 );
|
|
|
|
PromiseStream<AddRequest> addInterface;
|
|
introAddServer(addInterface);
|
|
|
|
Future<AddReply> reply = addInterface.getReply(AddRequest(5, 2));
|
|
ASSERT(reply.get().sum == 7);
|
|
|
|
printf("OK\n");
|
|
}
|
|
|
|
template <int N>
|
|
void chainTest() {
|
|
auto startt = timer();
|
|
for (int i = 0; i < 100000; i++) {
|
|
Promise<int> p;
|
|
Future<int> f = chain<N>(p.getFuture());
|
|
p.send(i);
|
|
ASSERT(f.get() == i + N);
|
|
}
|
|
auto endt = timer();
|
|
printf("chain<%d>: %0.3f M/sec\n", N, 0.1 / (endt - startt));
|
|
|
|
startt = timer();
|
|
for (int i = 0; i < 100000; i++) {
|
|
Promise<int> p;
|
|
Future<int> f = chain2(p.getFuture(), N);
|
|
p.send(i);
|
|
ASSERT(f.get() == i + N);
|
|
}
|
|
endt = timer();
|
|
printf("chain2<%d>: %0.3f M/sec\n", N, 0.1 / (endt - startt));
|
|
}
|
|
|
|
ACTOR [[flow_allow_discard]] void cycle(FutureStream<Void> in, PromiseStream<Void> out, int* ptotal) {
|
|
loop {
|
|
waitNext(in);
|
|
(*ptotal)++;
|
|
out.send(Void());
|
|
}
|
|
}
|
|
|
|
ACTOR [[flow_allow_discard]] Future<Void> cycleTime(int nodes, int times) {
|
|
state std::vector<PromiseStream<Void>> n(nodes);
|
|
state int total = 0;
|
|
|
|
// 1->2, 2->3, ..., n-1->0
|
|
for (int i = 1; i < nodes; i++)
|
|
cycle(n[i].getFuture(), n[(i + 1) % nodes], &total);
|
|
|
|
state double startT = timer();
|
|
n[1].send(Void());
|
|
loop {
|
|
waitNext(n[0].getFuture());
|
|
if (!--times)
|
|
break;
|
|
n[1].send(Void());
|
|
}
|
|
|
|
printf("Ring test: %d nodes, %d total ops, %.3f seconds\n", nodes, total, timer() - startT);
|
|
return Void();
|
|
}
|
|
|
|
void sleeptest() {
|
|
#ifdef __linux__
|
|
int times[] = { 0, 100, 500, 1000, 5000, 100000, 500000, 1000000 };
|
|
for (int j = 0; j < 8; j++) {
|
|
double b = timer();
|
|
int n = std::min(100, 4000000 / (1 + times[j]));
|
|
for (int i = 0; i < n; i++) {
|
|
timespec ts;
|
|
ts.tv_sec = times[j] / 1000000;
|
|
ts.tv_nsec = (times[j] % 1000000) * 1000;
|
|
clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, nullptr);
|
|
// nanosleep(&ts, nullptr);
|
|
}
|
|
double t = timer() - b;
|
|
printf("Sleep test (%dus x %d): %0.1f\n", times[j], n, double(t) / n * 1e6);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void asyncMapTest() {
|
|
Future<Void> c;
|
|
|
|
{
|
|
AsyncMap<int, int> m1;
|
|
m1.set(10, 1);
|
|
ASSERT(m1.get(10) == 1);
|
|
ASSERT(m1.get(20) == 0);
|
|
Future<Void> a = m1.onChange(10);
|
|
Future<Void> b = m1.onChange(20);
|
|
c = m1.onChange(30);
|
|
ASSERT(!a.isReady() && !b.isReady());
|
|
m1.set(10, 0);
|
|
ASSERT(a.isReady() && !a.isError() && !b.isReady() && m1.get(10) == 0);
|
|
m1.set(20, 5);
|
|
ASSERT(b.isReady() && !b.isError() && m1.get(20) == 5);
|
|
|
|
a = m1.onChange(10);
|
|
b = m1.onChange(20);
|
|
m1.triggerRange(15, 25);
|
|
ASSERT(!a.isReady() && b.isReady() && !b.isError() && m1.get(20) == 5);
|
|
}
|
|
ASSERT(c.isReady() && c.isError() && c.getError().code() == error_code_broken_promise);
|
|
|
|
printf("AsyncMap: OK\n");
|
|
|
|
double startt;
|
|
AsyncMap<int, int> m2;
|
|
startt = timer();
|
|
for (int i = 0; i < 1000000; i++) {
|
|
m2.set(5, 0);
|
|
m2.set(5, 1);
|
|
}
|
|
printf(" set(not present/present): %0.1fM/sec\n", 2.0 / (timer() - startt));
|
|
startt = timer();
|
|
for (int i = 0; i < 1000000; i++) {
|
|
m2.set(5, 1);
|
|
m2.set(5, 2);
|
|
}
|
|
printf(" set(present/present): %0.1fM/sec\n", 2.0 / (timer() - startt));
|
|
startt = timer();
|
|
for (int i = 0; i < 1000000; i++) {
|
|
m2.set(5, 1);
|
|
}
|
|
printf(" set(no change): %0.1fM/sec\n", 1.0 / (timer() - startt));
|
|
|
|
m2.set(5, 5);
|
|
startt = timer();
|
|
for (int i = 0; i < 1000000; i++)
|
|
m2.onChange(5);
|
|
printf(" onChange(present, cancelled): %0.1fM/sec\n", 1.0 / (timer() - startt));
|
|
startt = timer();
|
|
for (int i = 0; i < 1000000; i++)
|
|
m2.onChange(10);
|
|
printf(" onChange(not present, cancelled): %0.1fM/sec\n", 1.0 / (timer() - startt));
|
|
startt = timer();
|
|
for (int i = 0; i < 1000000; i++) {
|
|
auto f = m2.onChange(10);
|
|
m2.set(10, 1);
|
|
m2.set(10, 0);
|
|
}
|
|
printf(" onChange(not present, set): %0.1fM/sec\n", 1.0 / (timer() - startt));
|
|
startt = timer();
|
|
for (int i = 0; i < 1000000; i++) {
|
|
auto f = m2.onChange(5);
|
|
m2.set(5, i + 1);
|
|
}
|
|
printf(" onChange(present, set): %0.1fM/sec\n", 1.0 / (timer() - startt));
|
|
}
|
|
|
|
extern void net2_test();
|
|
|
|
void dsltest() {
|
|
double startt, endt;
|
|
|
|
setThreadLocalDeterministicRandomSeed(40);
|
|
|
|
asyncMapTest();
|
|
|
|
net2_test();
|
|
// sleeptest();
|
|
|
|
Future<Void> ctf = cycleTime(1000, 1000);
|
|
ctf.get();
|
|
|
|
introPromiseFuture();
|
|
introActor();
|
|
// return;
|
|
|
|
printf("Actor control flow tests: ");
|
|
actorTest1(true);
|
|
actorTest2(true);
|
|
actorTest3(true);
|
|
// if (g_network == &g_simulator)
|
|
// g_simulator.run( actorTest4(true) );
|
|
actorTest5();
|
|
actorTest6();
|
|
actorTest7();
|
|
actorTest8();
|
|
actorTest9();
|
|
actorTest10();
|
|
|
|
printf("\n");
|
|
|
|
printf("Running actor fuzz tests:\n");
|
|
// Only include this test outside of Windows because of MSVC compiler bug
|
|
#ifndef WIN32
|
|
auto afResults = actorFuzzTests();
|
|
#else
|
|
std::pair<int, int> afResults(0, 0);
|
|
#endif
|
|
printf("Actor fuzz tests: %d/%d passed\n", afResults.first, afResults.second);
|
|
startt = timer();
|
|
for (int i = 0; i < 1000000; i++)
|
|
deterministicRandom()->random01();
|
|
endt = timer();
|
|
printf("Random01: %0.2f M/sec\n", 1.0 / (endt - startt));
|
|
|
|
startt = timer();
|
|
for (int i = 0; i < 1000000; i++)
|
|
Promise<Void>();
|
|
endt = timer();
|
|
printf("Promises: %0.2f M/sec\n", 1.0 / (endt - startt));
|
|
|
|
startt = timer();
|
|
for (int i = 0; i < 1000000; i++)
|
|
Promise<Void>().send(Void());
|
|
endt = timer();
|
|
printf("Promises (with send): %0.2f M/sec\n", 1.0 / (endt - startt));
|
|
|
|
startt = timer();
|
|
for (int i = 0; i < 1000000; i++) {
|
|
Promise<Void> p;
|
|
Future<Void> f = p.getFuture();
|
|
p.send(Void());
|
|
f.get();
|
|
}
|
|
endt = timer();
|
|
printf("Promise/Future/send roundtrip: %0.2f M/sec\n", 1.0 / (endt - startt));
|
|
|
|
Promise<Void> p;
|
|
|
|
startt = timer();
|
|
for (int i = 0; i < 1000000; i++)
|
|
p.getFuture();
|
|
endt = timer();
|
|
printf("Futures: %0.2f M/sec\n", 1.0 / (endt - startt));
|
|
|
|
startt = timer();
|
|
for (int i = 0; i < 1000000; i++)
|
|
PromiseStream<Void>();
|
|
endt = timer();
|
|
printf("PromiseStreams: %0.2f M/sec\n", 1.0 / (endt - startt));
|
|
|
|
startt = timer();
|
|
for (int i = 0; i < 1000000; i++)
|
|
PromiseStream<Void>().send(Void());
|
|
endt = timer();
|
|
printf("PromiseStreams (with send): %0.2f M/sec\n", 1.0 / (endt - startt));
|
|
|
|
startt = timer();
|
|
for (int i = 0; i < 1000000; i++) {
|
|
PromiseStream<Void> p;
|
|
FutureStream<Void> f = p.getFuture();
|
|
p.send(Void());
|
|
f.pop();
|
|
}
|
|
endt = timer();
|
|
printf("PromiseStream/FutureStream/send/popBlocking roundtrip: %0.2f M/sec\n", 1.0 / (endt - startt));
|
|
|
|
startt = timer();
|
|
{
|
|
PromiseStream<int> ps;
|
|
for (int i = 0; i < 1000000; i++) {
|
|
ps.send(i);
|
|
}
|
|
}
|
|
endt = timer();
|
|
printf("PromiseStream queued send: %0.2f M/sec\n", 1.0 / (endt - startt));
|
|
|
|
startt = timer();
|
|
for (int i = 0; i < 1000000; i++)
|
|
cancellable();
|
|
endt = timer();
|
|
printf("Cancellations: %0.2f M/sec\n", 1.0 / (endt - startt));
|
|
|
|
startt = timer();
|
|
for (int i = 0; i < 1000000; i++)
|
|
cancellable2();
|
|
endt = timer();
|
|
printf("Cancellations with catch: %0.2f M/sec\n", 1.0 / (endt - startt));
|
|
|
|
startt = timer();
|
|
for (int i = 0; i < 1000000; i++)
|
|
simple();
|
|
endt = timer();
|
|
printf("Actor creation: %0.2f M/sec\n", 1.0 / (endt - startt));
|
|
|
|
startt = timer();
|
|
for (int i = 0; i < 1000000; i++)
|
|
simpleWait();
|
|
endt = timer();
|
|
printf("With trivial wait: %0.2f M/sec\n", 1.0 / (endt - startt));
|
|
|
|
startt = timer();
|
|
for (int i = 0; i < 1000000; i++) {
|
|
Promise<int> p;
|
|
Future<int> f = simpleRet(p.getFuture());
|
|
p.send(i);
|
|
ASSERT(f.get() == i);
|
|
}
|
|
endt = timer();
|
|
printf("Bounce int through actor: %0.2f M/sec\n", 1.0 / (endt - startt));
|
|
|
|
startt = timer();
|
|
for (int i = 0; i < 1000000; i++) {
|
|
Promise<int> p;
|
|
Future<int> f = simpleRet(p.getFuture());
|
|
Future<int> g = simpleRet(p.getFuture());
|
|
p.send(i);
|
|
ASSERT(f.get() == i);
|
|
ASSERT(g.get() == i);
|
|
}
|
|
endt = timer();
|
|
printf("Bounce int through two actors in parallel: %0.2f M/sec\n", 1.0 / (endt - startt));
|
|
|
|
/*chainTest<1>();
|
|
chainTest<4>();
|
|
chainTest<16>();
|
|
chainTest<64>();
|
|
|
|
startt = timer();
|
|
for(int i=0; i<1000000; i++)
|
|
try {
|
|
throw success();
|
|
} catch (Error&) {
|
|
}
|
|
endt = timer();
|
|
printf("C++ exception: %0.2f M/sec\n", 1.0/(endt-startt));*/
|
|
|
|
arenaTest();
|
|
|
|
{
|
|
Promise<int> a, b;
|
|
Future<int> c = chooseTest(a.getFuture(), b.getFuture());
|
|
a.send(1);
|
|
b.send(2);
|
|
std::cout << "c=" << c.get() << std::endl;
|
|
}
|
|
|
|
{
|
|
Promise<double> i;
|
|
Future<double> d = addN<20>(i.getFuture());
|
|
i.send(1.1);
|
|
std::cout << d.get() << std::endl;
|
|
}
|
|
|
|
{
|
|
Promise<double> i;
|
|
i.sendError(operation_failed());
|
|
Future<double> d = addN<20>(i.getFuture());
|
|
if (d.isError() && d.getError().code() == error_code_operation_failed)
|
|
std::cout << "Error transmitted OK" << std::endl;
|
|
else
|
|
std::cout << "Error not transmitted!" << std::endl;
|
|
}
|
|
|
|
/*{
|
|
int na = Actor::allActors.size();
|
|
PromiseStream<int> t;
|
|
testStream(t.getFuture());
|
|
if (Actor::allActors.size() != na+1)
|
|
std::cout << "Actor not created!" << std::endl;
|
|
t = PromiseStream<int>();
|
|
if (Actor::allActors.size() != na)
|
|
std::cout << "Actor not cleaned up!" << std::endl;
|
|
}*/
|
|
|
|
PromiseStream<int> as;
|
|
Promise<double> bs;
|
|
as.send(4);
|
|
Future<Void> sT = switchTest(as.getFuture(), bs.getFuture());
|
|
as.send(5);
|
|
// sT = move(Future<Void>());
|
|
as.send(6);
|
|
bs.send(10.1);
|
|
as.send(7);
|
|
|
|
fastAllocTest();
|
|
|
|
#if FLOW_THREAD_SAFE
|
|
returnCancelRaceTest();
|
|
threadSafetyTest();
|
|
threadSafetyTest2();
|
|
#else
|
|
printf("Thread safety disabled.\n");
|
|
#endif
|
|
}
|
|
|
|
/*ACTOR Future<Void> pingServer( FutureStream<Promise<bool>> requests, int rate ) {
|
|
state int count = 0;
|
|
loop {
|
|
Promise<bool> req = waitNext( requests );
|
|
req.send( (++count)%rate != 0 );
|
|
}
|
|
}
|
|
|
|
ACTOR Future<int> ping( PromiseStream<Promise<bool>> server ) {
|
|
state int count = 0;
|
|
loop {
|
|
bool result = wait( server.getReply<bool>() );
|
|
|
|
count++;
|
|
if (!result)
|
|
break;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
void pingtest() {
|
|
double start = timer();
|
|
PromiseStream<Promise<bool>> serverInterface;
|
|
Future<Void> pS = pingServer( serverInterface.getFuture(), 5000000 );
|
|
Future<int> count = ping( serverInterface );
|
|
double end = timer();
|
|
std::cout << count.get() << " pings completed in " << (end-start) << " sec" << std::endl;
|
|
}*/
|
|
|
|
void copyTest() {
|
|
double start, elapsed;
|
|
|
|
Arena arena;
|
|
StringRef s(new (arena) uint8_t[10 << 20], 10 << 20);
|
|
|
|
{
|
|
start = timer();
|
|
for (int i = 0; i < 100; i++) {
|
|
StringRef k = s;
|
|
(void)k;
|
|
}
|
|
elapsed = timer() - start;
|
|
|
|
printf("StringRef->StringRef: %fs/GB\n", elapsed);
|
|
}
|
|
|
|
{
|
|
start = timer();
|
|
for (int i = 0; i < 100; i++)
|
|
Standalone<StringRef> a = s;
|
|
elapsed = timer() - start;
|
|
|
|
printf("StringRef->Standalone: %fs/GB\n", elapsed);
|
|
}
|
|
|
|
{
|
|
Standalone<StringRef> sa = s;
|
|
start = timer();
|
|
for (int i = 0; i < 100; i++)
|
|
Standalone<StringRef> a = sa;
|
|
elapsed = timer() - start;
|
|
|
|
printf("Standalone->Standalone: %fs/GB\n", elapsed);
|
|
}
|
|
|
|
{
|
|
Standalone<StringRef> sa = s, sb;
|
|
start = timer();
|
|
for (int i = 0; i < 50; i++) {
|
|
sb = std::move(sa);
|
|
sa = std::move(sb);
|
|
}
|
|
elapsed = timer() - start;
|
|
printf("move(Standalone)->Standalone: %fs/GB\n", elapsed);
|
|
}
|
|
}
|
|
|
|
/*ACTOR void badTest( FutureStream<int> is ) {
|
|
state PromiseStream<int> js;
|
|
|
|
loop choose {
|
|
when( int j = waitNext( js.getFuture() ) ) {
|
|
std::cout << "J" << j << std::endl;
|
|
}
|
|
when( int i = waitNext( is ) ) {
|
|
std::cout << "I" << i << std::endl;
|
|
js.send( i );
|
|
std::cout << "-I" << i << std::endl;
|
|
}
|
|
}
|
|
}
|
|
|
|
void dsltest() {
|
|
PromiseStream<int> is;
|
|
badTest( is.getFuture() );
|
|
is.send(1);
|
|
is.send(2);
|
|
is.send(3);
|
|
throw not_implemented();
|
|
}
|
|
void pingtest() {}*/
|