Files
oceanbase/deps/oblib/unittest/lib/coro/testing.h
gm 4a92b6d7df reformat source code
according to code styles, 'AccessModifierOffset' should be -2.
2021-06-17 10:40:36 +08:00

206 lines
5.0 KiB
C++

/**
* Copyright (c) 2021 OceanBase
* OceanBase CE is licensed under Mulan PubL v2.
* You can use this software according to the terms and conditions of the Mulan PubL v2.
* You may obtain a copy of Mulan PubL v2 at:
* http://license.coscl.org.cn/MulanPubL-2.0
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PubL v2 for more details.
*/
#ifndef CORO_TESTING_H
#define CORO_TESTING_H
#include "lib/coro/co.h"
#include "lib/coro/co_set_sched.h"
#include "lib/thread/thread_pool.h"
#include <functional>
#include <vector>
using namespace oceanbase::lib;
using namespace oceanbase::common;
namespace cotesting {
using VoidFuncT = std::function<void()>;
using Idx1FuncT = std::function<void(int)>; // (grp_th_idx)
using Idx2FuncT = std::function<void(int, int)>; // (grp_th_idx, grp_co_idx)
//// Worker Definition
//
struct WorkerIndex {
WorkerIndex()
: th_idx_(0), // thread index of all thread
co_idx_(0), // routine index of all co-routine
grp_idx_(0), // group index
grp_th_idx_(0), // thread index of current group
grp_co_idx_(0), // routine index of current group
th_co_idx_(0) // routine index of current thread
{}
int th_idx_;
int co_idx_;
int grp_idx_;
int grp_th_idx_;
int grp_co_idx_;
int th_co_idx_;
};
class SimpleWorker : public CoSetSched::Worker {
public:
SimpleWorker(CoSetSched& sched, VoidFuncT func) : CoSetSched::Worker(sched, func)
{}
SimpleWorker(CoSetSched& sched, Idx1FuncT func) : CoSetSched::Worker(sched, [this, func] { func(wi_.grp_co_idx_); })
{}
SimpleWorker(CoSetSched& sched, Idx2FuncT func)
: CoSetSched::Worker(sched, [this, func] { func(wi_.grp_th_idx_, wi_.grp_co_idx_); })
{}
public:
WorkerIndex wi_;
};
//// Single Thread Scheduler definition
//
class SimpleSched : public CoSetSched {
using WorkerT = SimpleWorker;
public:
template <class FuncT>
SimpleSched(FuncT func, int cnt, WorkerIndex& wi) : cnt_(cnt), workers_(), wi_(wi)
{
for (int i = 0; i < cnt_; i++) {
auto w = new WorkerT(*this, func);
workers_.push_back(w);
w->wi_ = wi_;
wi_.co_idx_++;
wi_.grp_co_idx_++;
wi_.th_co_idx_++;
}
wi_.th_co_idx_ = 0;
}
~SimpleSched()
{
destroy();
for (auto w : workers_) {
delete w;
}
}
int start(bool wait = true)
{
int ret = OB_SUCCESS;
if (OB_FAIL(CoSetSched::start())) {
} else if (wait) {
CoSetSched::wait();
}
return ret;
}
private:
int prepare() final
{
int ret = CoSetSched::create_set(0);
for (int i = 0; OB_SUCC(ret) && i < cnt_; i++) {
ret = workers_[i]->init();
}
return ret;
}
private:
int cnt_;
std::vector<WorkerT*> workers_;
WorkerIndex& wi_;
};
//// Flexible worker pool
//
class FlexPool {
using Sched = SimpleSched;
public:
FlexPool()
{}
template <class FuncT>
FlexPool(FuncT func, int thes, int coros = 1)
{
create(func, thes, coros);
}
~FlexPool()
{
for (auto th : th_pools_) {
delete th;
}
}
template <class FuncT>
FlexPool& create(FuncT func, int thes, int coros = 1)
{
for (int i = 0; i < thes; i++) {
th_pools_.push_back(new Sched(func, coros, wi_));
wi_.grp_th_idx_++;
wi_.th_idx_++;
}
wi_.grp_idx_++;
wi_.grp_th_idx_ = 0;
wi_.grp_co_idx_ = 0;
return *this;
}
void start(bool wait = true)
{
for (auto th : th_pools_) {
th->start(false);
}
if (wait) {
this->wait();
}
}
void wait()
{
for (auto th : th_pools_) {
th->wait();
}
}
private:
std::vector<Sched*> th_pools_;
WorkerIndex wi_;
};
// Mock lib::ThreadPool
using DefaultRunnable = ThreadPool;
// Give an assurance that executing time of the given function must
// less than specific time.
//
// Use macro instead of function because error message in function can
// only contain the most inner function location and outsider location
// would been ignored. It's not acceptable when many TIME_LESS
// functions exist outside.
#define TIME_LESS(time, func) \
({ \
const auto start_ts = co_current_time(); \
{ \
func(); \
} \
const auto end_ts = co_current_time(); \
EXPECT_LT(end_ts - start_ts, (time)); \
})
#define TIME_MORE(time, func) \
({ \
const auto start_ts = co_current_time(); \
{ \
func(); \
} \
const auto end_ts = co_current_time(); \
EXPECT_GT(end_ts - start_ts, (time)); \
})
} // namespace cotesting
#endif /* CORO_TESTING_H */