2018-12-31 20:04:05 +01:00
|
|
|
//
|
2021-01-01 13:57:46 +01:00
|
|
|
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
|
2018-12-31 20:04:05 +01:00
|
|
|
//
|
|
|
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|
|
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
|
|
//
|
2021-09-18 23:47:05 +02:00
|
|
|
#include "td/telegram/telegram_api.h"
|
|
|
|
#include "td/telegram/telegram_api.hpp"
|
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
#include "td/utils/benchmark.h"
|
|
|
|
#include "td/utils/common.h"
|
2021-08-22 08:39:43 +02:00
|
|
|
#include "td/utils/format.h"
|
2018-12-31 20:04:05 +01:00
|
|
|
#include "td/utils/logging.h"
|
|
|
|
#include "td/utils/port/Clocks.h"
|
|
|
|
#include "td/utils/port/EventFd.h"
|
|
|
|
#include "td/utils/port/FileFd.h"
|
|
|
|
#include "td/utils/port/path.h"
|
|
|
|
#include "td/utils/port/RwMutex.h"
|
|
|
|
#include "td/utils/port/Stat.h"
|
|
|
|
#include "td/utils/port/thread.h"
|
|
|
|
#include "td/utils/Slice.h"
|
2021-05-17 14:21:11 +02:00
|
|
|
#include "td/utils/SliceBuilder.h"
|
2021-09-01 19:31:39 +02:00
|
|
|
#include "td/utils/Status.h"
|
2021-08-18 18:26:03 +02:00
|
|
|
#include "td/utils/ThreadSafeCounter.h"
|
2018-12-31 20:04:05 +01:00
|
|
|
|
|
|
|
#if !TD_WINDOWS
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <utime.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if TD_LINUX || TD_ANDROID || TD_TIZEN
|
|
|
|
#include <semaphore.h>
|
|
|
|
#endif
|
|
|
|
|
2021-08-22 09:49:40 +02:00
|
|
|
#include <algorithm>
|
|
|
|
#include <array>
|
2018-12-31 20:04:05 +01:00
|
|
|
#include <atomic>
|
|
|
|
#include <cstdint>
|
2021-08-22 08:39:43 +02:00
|
|
|
#include <set>
|
2018-12-31 20:04:05 +01:00
|
|
|
|
|
|
|
class F {
|
2021-08-18 17:22:41 +02:00
|
|
|
td::uint32 ∑
|
2018-12-31 20:04:05 +01:00
|
|
|
|
|
|
|
public:
|
2021-08-18 17:22:41 +02:00
|
|
|
explicit F(td::uint32 &sum) : sum(sum) {
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
void operator()(const T &x) const {
|
2021-08-18 17:22:41 +02:00
|
|
|
sum += static_cast<td::uint32>(x.get_id());
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
BENCH(Call, "TL Call") {
|
2021-08-18 17:22:41 +02:00
|
|
|
td::tl_object_ptr<td::telegram_api::Function> x = td::make_tl_object<td::telegram_api::account_getWallPapers>(0);
|
|
|
|
td::uint32 res = 0;
|
2018-12-31 20:04:05 +01:00
|
|
|
F f(res);
|
|
|
|
for (int i = 0; i < n; i++) {
|
|
|
|
downcast_call(*x, f);
|
|
|
|
}
|
2021-08-18 17:22:41 +02:00
|
|
|
td::do_not_optimize_away(res);
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#if !TD_EVENTFD_UNSUPPORTED
|
|
|
|
BENCH(EventFd, "EventFd") {
|
2021-08-18 17:22:41 +02:00
|
|
|
td::EventFd fd;
|
2018-12-31 20:04:05 +01:00
|
|
|
fd.init();
|
|
|
|
for (int i = 0; i < n; i++) {
|
|
|
|
fd.release();
|
|
|
|
fd.acquire();
|
|
|
|
}
|
|
|
|
fd.close();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
BENCH(NewInt, "new int + delete") {
|
|
|
|
std::uintptr_t res = 0;
|
|
|
|
for (int i = 0; i < n; i++) {
|
|
|
|
int *x = new int;
|
|
|
|
res += reinterpret_cast<std::uintptr_t>(x);
|
|
|
|
delete x;
|
|
|
|
}
|
2021-08-18 17:22:41 +02:00
|
|
|
td::do_not_optimize_away(res);
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
|
2019-10-19 20:20:16 +02:00
|
|
|
BENCH(NewObj, "new struct, then delete") {
|
2018-12-31 20:04:05 +01:00
|
|
|
struct A {
|
2021-08-18 17:22:41 +02:00
|
|
|
td::int32 a = 0;
|
|
|
|
td::int32 b = 0;
|
|
|
|
td::int32 c = 0;
|
|
|
|
td::int32 d = 0;
|
2018-12-31 20:04:05 +01:00
|
|
|
};
|
|
|
|
std::uintptr_t res = 0;
|
|
|
|
A **ptr = new A *[n];
|
|
|
|
for (int i = 0; i < n; i++) {
|
|
|
|
ptr[i] = new A();
|
|
|
|
res += reinterpret_cast<std::uintptr_t>(ptr[i]);
|
|
|
|
}
|
|
|
|
for (int i = 0; i < n; i++) {
|
|
|
|
delete ptr[i];
|
|
|
|
}
|
|
|
|
delete[] ptr;
|
2021-08-18 17:22:41 +02:00
|
|
|
td::do_not_optimize_away(res);
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#if !TD_THREAD_UNSUPPORTED
|
2021-08-22 10:47:57 +02:00
|
|
|
BENCH(ThreadNew, "new struct, then delete in 2 threads") {
|
2021-08-18 17:22:41 +02:00
|
|
|
NewObjBench a, b;
|
|
|
|
td::thread ta([&] { a.run(n / 2); });
|
|
|
|
td::thread tb([&] { b.run(n - n / 2); });
|
2018-12-31 20:04:05 +01:00
|
|
|
ta.join();
|
|
|
|
tb.join();
|
|
|
|
}
|
|
|
|
#endif
|
2018-03-28 00:13:04 +02:00
|
|
|
/*
|
|
|
|
// Too hard for clang (?)
|
2018-12-31 20:04:05 +01:00
|
|
|
BENCH(Time, "Clocks::monotonic") {
|
|
|
|
double res = 0;
|
|
|
|
for (int i = 0; i < n; i++) {
|
2021-08-18 17:22:41 +02:00
|
|
|
res += td::Clocks::monotonic();
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
2021-08-18 17:22:41 +02:00
|
|
|
td::do_not_optimize_away(res);
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
2018-03-28 00:13:04 +02:00
|
|
|
*/
|
2018-12-31 20:04:05 +01:00
|
|
|
#if !TD_WINDOWS
|
2021-08-18 17:22:41 +02:00
|
|
|
class PipeBench final : public td::Benchmark {
|
2018-12-31 20:04:05 +01:00
|
|
|
public:
|
|
|
|
int p[2];
|
|
|
|
|
2021-08-18 17:22:41 +02:00
|
|
|
td::string get_description() const final {
|
2018-12-31 20:04:05 +01:00
|
|
|
return "pipe write + read int32";
|
|
|
|
}
|
|
|
|
|
2021-07-03 22:51:36 +02:00
|
|
|
void start_up() final {
|
2018-10-25 17:48:17 +02:00
|
|
|
int res = pipe(p);
|
|
|
|
CHECK(res == 0);
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
|
2021-07-03 22:51:36 +02:00
|
|
|
void run(int n) final {
|
2018-12-31 20:04:05 +01:00
|
|
|
int res = 0;
|
|
|
|
for (int i = 0; i < n; i++) {
|
|
|
|
int val = 1;
|
2018-10-25 17:48:17 +02:00
|
|
|
auto write_len = write(p[1], &val, sizeof(val));
|
|
|
|
CHECK(write_len == sizeof(val));
|
|
|
|
auto read_len = read(p[0], &val, sizeof(val));
|
|
|
|
CHECK(read_len == sizeof(val));
|
2018-12-31 20:04:05 +01:00
|
|
|
res += val;
|
|
|
|
}
|
2021-08-18 17:22:41 +02:00
|
|
|
td::do_not_optimize_away(res);
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
|
2021-07-03 22:51:36 +02:00
|
|
|
void tear_down() final {
|
2018-12-31 20:04:05 +01:00
|
|
|
close(p[0]);
|
|
|
|
close(p[1]);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if TD_LINUX || TD_ANDROID || TD_TIZEN
|
2021-08-18 17:22:41 +02:00
|
|
|
class SemBench final : public td::Benchmark {
|
2018-12-31 20:04:05 +01:00
|
|
|
sem_t sem;
|
|
|
|
|
|
|
|
public:
|
2021-08-18 17:22:41 +02:00
|
|
|
td::string get_description() const final {
|
2018-12-31 20:04:05 +01:00
|
|
|
return "sem post + wait";
|
|
|
|
}
|
|
|
|
|
2021-07-03 22:51:36 +02:00
|
|
|
void start_up() final {
|
2018-12-31 20:04:05 +01:00
|
|
|
int err = sem_init(&sem, 0, 0);
|
|
|
|
CHECK(err != -1);
|
|
|
|
}
|
|
|
|
|
2021-07-03 22:51:36 +02:00
|
|
|
void run(int n) final {
|
2018-12-31 20:04:05 +01:00
|
|
|
for (int i = 0; i < n; i++) {
|
|
|
|
sem_post(&sem);
|
|
|
|
sem_wait(&sem);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-03 22:51:36 +02:00
|
|
|
void tear_down() final {
|
2018-12-31 20:04:05 +01:00
|
|
|
sem_destroy(&sem);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if !TD_WINDOWS
|
2021-08-18 17:22:41 +02:00
|
|
|
class UtimeBench final : public td::Benchmark {
|
2018-12-31 20:04:05 +01:00
|
|
|
public:
|
2021-07-03 22:51:36 +02:00
|
|
|
void start_up() final {
|
2021-08-18 17:22:41 +02:00
|
|
|
td::FileFd::open("test", td::FileFd::Create | td::FileFd::Write).move_as_ok().close();
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
2021-08-18 17:22:41 +02:00
|
|
|
td::string get_description() const final {
|
2018-12-31 20:04:05 +01:00
|
|
|
return "utime";
|
|
|
|
}
|
2021-07-03 22:51:36 +02:00
|
|
|
void run(int n) final {
|
2018-12-31 20:04:05 +01:00
|
|
|
for (int i = 0; i < n; i++) {
|
|
|
|
int err = utime("test", nullptr);
|
|
|
|
CHECK(err >= 0);
|
|
|
|
utimbuf buf;
|
|
|
|
buf.modtime = 123;
|
|
|
|
buf.actime = 321;
|
|
|
|
err = utime("test", &buf);
|
|
|
|
CHECK(err >= 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
|
|
|
BENCH(Pwrite, "pwrite") {
|
2021-08-18 17:22:41 +02:00
|
|
|
auto fd = td::FileFd::open("test", td::FileFd::Create | td::FileFd::Write).move_as_ok();
|
2018-12-31 20:04:05 +01:00
|
|
|
for (int i = 0; i < n; i++) {
|
|
|
|
fd.pwrite("a", 0).ok();
|
|
|
|
}
|
|
|
|
fd.close();
|
|
|
|
}
|
|
|
|
|
2021-08-18 17:22:41 +02:00
|
|
|
class CreateFileBench final : public td::Benchmark {
|
|
|
|
td::string get_description() const final {
|
2018-12-31 20:04:05 +01:00
|
|
|
return "create_file";
|
|
|
|
}
|
2021-07-03 22:51:36 +02:00
|
|
|
void start_up() final {
|
2021-08-18 17:22:41 +02:00
|
|
|
td::mkdir("A").ensure();
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
2021-07-03 22:51:36 +02:00
|
|
|
void run(int n) final {
|
2018-12-31 20:04:05 +01:00
|
|
|
for (int i = 0; i < n; i++) {
|
2021-08-18 17:22:41 +02:00
|
|
|
td::FileFd::open(PSLICE() << "A/" << i, td::FileFd::Write | td::FileFd::Create).move_as_ok().close();
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
}
|
2021-07-03 22:51:36 +02:00
|
|
|
void tear_down() final {
|
2021-08-18 17:22:41 +02:00
|
|
|
td::walk_path("A/", [&](td::CSlice path, auto type) {
|
2019-09-28 04:14:21 +02:00
|
|
|
if (type == td::WalkPath::Type::ExitDir) {
|
2021-08-18 17:22:41 +02:00
|
|
|
td::rmdir(path).ignore();
|
2019-09-28 04:14:21 +02:00
|
|
|
} else if (type == td::WalkPath::Type::NotDir) {
|
2021-08-18 17:22:41 +02:00
|
|
|
td::unlink(path).ignore();
|
2019-09-28 04:14:21 +02:00
|
|
|
}
|
|
|
|
}).ignore();
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
};
|
2018-07-08 01:47:46 +02:00
|
|
|
|
2021-08-18 17:22:41 +02:00
|
|
|
class WalkPathBench final : public td::Benchmark {
|
|
|
|
td::string get_description() const final {
|
2018-12-31 20:04:05 +01:00
|
|
|
return "walk_path";
|
|
|
|
}
|
2021-07-03 22:51:36 +02:00
|
|
|
void start_up_n(int n) final {
|
2021-08-18 17:22:41 +02:00
|
|
|
td::mkdir("A").ensure();
|
2018-12-31 20:04:05 +01:00
|
|
|
for (int i = 0; i < n; i++) {
|
2021-08-18 17:22:41 +02:00
|
|
|
td::FileFd::open(PSLICE() << "A/" << i, td::FileFd::Write | td::FileFd::Create).move_as_ok().close();
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
}
|
2021-07-03 22:51:36 +02:00
|
|
|
void run(int n) final {
|
2018-12-31 20:04:05 +01:00
|
|
|
int cnt = 0;
|
2021-08-18 17:22:41 +02:00
|
|
|
td::walk_path("A/", [&](td::CSlice path, auto type) {
|
2019-09-28 04:14:21 +02:00
|
|
|
if (type == td::WalkPath::Type::EnterDir) {
|
|
|
|
return;
|
|
|
|
}
|
2021-08-18 17:22:41 +02:00
|
|
|
td::stat(path).ok();
|
2019-09-28 04:14:21 +02:00
|
|
|
cnt++;
|
|
|
|
}).ignore();
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
2021-07-03 22:51:36 +02:00
|
|
|
void tear_down() final {
|
2021-08-18 17:22:41 +02:00
|
|
|
td::walk_path("A/", [&](td::CSlice path, auto type) {
|
2019-09-28 04:14:21 +02:00
|
|
|
if (type == td::WalkPath::Type::ExitDir) {
|
2021-08-18 17:22:41 +02:00
|
|
|
td::rmdir(path).ignore();
|
2019-09-28 04:14:21 +02:00
|
|
|
} else if (type == td::WalkPath::Type::NotDir) {
|
2021-08-18 17:22:41 +02:00
|
|
|
td::unlink(path).ignore();
|
2019-09-28 04:14:21 +02:00
|
|
|
}
|
|
|
|
}).ignore();
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
#if !TD_THREAD_UNSUPPORTED
|
|
|
|
template <int ThreadN = 2>
|
2021-08-18 17:22:41 +02:00
|
|
|
class AtomicReleaseIncBench final : public td::Benchmark {
|
|
|
|
td::string get_description() const final {
|
2018-12-31 20:04:05 +01:00
|
|
|
return PSTRING() << "AtomicReleaseInc" << ThreadN;
|
|
|
|
}
|
|
|
|
|
2021-08-18 17:22:41 +02:00
|
|
|
static std::atomic<td::uint64> a_;
|
2021-07-03 22:51:36 +02:00
|
|
|
void run(int n) final {
|
2021-08-18 17:22:41 +02:00
|
|
|
td::vector<td::thread> threads;
|
2018-12-31 20:04:05 +01:00
|
|
|
for (int i = 0; i < ThreadN; i++) {
|
|
|
|
threads.emplace_back([&] {
|
|
|
|
for (int i = 0; i < n / ThreadN; i++) {
|
|
|
|
a_.fetch_add(1, std::memory_order_release);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
for (auto &thread : threads) {
|
|
|
|
thread.join();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
template <int ThreadN>
|
2021-08-18 17:22:41 +02:00
|
|
|
std::atomic<td::uint64> AtomicReleaseIncBench<ThreadN>::a_;
|
2018-12-31 20:04:05 +01:00
|
|
|
|
|
|
|
template <int ThreadN = 2>
|
2021-08-18 17:22:41 +02:00
|
|
|
class AtomicReleaseCasIncBench final : public td::Benchmark {
|
|
|
|
td::string get_description() const final {
|
2018-12-31 20:04:05 +01:00
|
|
|
return PSTRING() << "AtomicReleaseCasInc" << ThreadN;
|
|
|
|
}
|
|
|
|
|
2021-08-18 17:22:41 +02:00
|
|
|
static std::atomic<td::uint64> a_;
|
2021-07-03 22:51:36 +02:00
|
|
|
void run(int n) final {
|
2021-08-18 17:22:41 +02:00
|
|
|
td::vector<td::thread> threads;
|
2018-12-31 20:04:05 +01:00
|
|
|
for (int i = 0; i < ThreadN; i++) {
|
|
|
|
threads.emplace_back([&] {
|
|
|
|
for (int i = 0; i < n / ThreadN; i++) {
|
|
|
|
auto value = a_.load(std::memory_order_relaxed);
|
|
|
|
while (!a_.compare_exchange_strong(value, value + 1, std::memory_order_release, std::memory_order_relaxed)) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
for (auto &thread : threads) {
|
|
|
|
thread.join();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
template <int ThreadN>
|
2021-08-18 17:22:41 +02:00
|
|
|
std::atomic<td::uint64> AtomicReleaseCasIncBench<ThreadN>::a_;
|
2018-12-31 20:04:05 +01:00
|
|
|
|
2021-08-18 18:26:03 +02:00
|
|
|
template <int ThreadN>
|
2021-08-18 17:22:41 +02:00
|
|
|
class RwMutexReadBench final : public td::Benchmark {
|
|
|
|
td::string get_description() const final {
|
2018-12-31 20:04:05 +01:00
|
|
|
return PSTRING() << "RwMutexRead" << ThreadN;
|
|
|
|
}
|
2021-08-18 17:22:41 +02:00
|
|
|
td::RwMutex mutex_;
|
2021-07-03 22:51:36 +02:00
|
|
|
void run(int n) final {
|
2021-08-18 17:22:41 +02:00
|
|
|
td::vector<td::thread> threads;
|
2018-12-31 20:04:05 +01:00
|
|
|
for (int i = 0; i < ThreadN; i++) {
|
|
|
|
threads.emplace_back([&] {
|
|
|
|
for (int i = 0; i < n / ThreadN; i++) {
|
|
|
|
mutex_.lock_read().ensure();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
for (auto &thread : threads) {
|
|
|
|
thread.join();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2021-08-18 18:26:03 +02:00
|
|
|
|
|
|
|
template <int ThreadN>
|
2021-08-18 17:22:41 +02:00
|
|
|
class RwMutexWriteBench final : public td::Benchmark {
|
|
|
|
td::string get_description() const final {
|
2018-12-31 20:04:05 +01:00
|
|
|
return PSTRING() << "RwMutexWrite" << ThreadN;
|
|
|
|
}
|
2021-08-18 17:22:41 +02:00
|
|
|
td::RwMutex mutex_;
|
2021-07-03 22:51:36 +02:00
|
|
|
void run(int n) final {
|
2021-08-18 17:22:41 +02:00
|
|
|
td::vector<td::thread> threads;
|
2018-12-31 20:04:05 +01:00
|
|
|
for (int i = 0; i < ThreadN; i++) {
|
|
|
|
threads.emplace_back([&] {
|
|
|
|
for (int i = 0; i < n / ThreadN; i++) {
|
|
|
|
mutex_.lock_write().ensure();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
for (auto &thread : threads) {
|
|
|
|
thread.join();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2021-08-18 18:26:03 +02:00
|
|
|
|
|
|
|
class ThreadSafeCounterBench final : public td::Benchmark {
|
|
|
|
static td::ThreadSafeCounter counter_;
|
|
|
|
int thread_count_;
|
|
|
|
|
|
|
|
td::string get_description() const final {
|
|
|
|
return PSTRING() << "ThreadSafeCounter" << thread_count_;
|
|
|
|
}
|
|
|
|
void run(int n) final {
|
|
|
|
counter_.clear();
|
|
|
|
td::vector<td::thread> threads;
|
|
|
|
for (int i = 0; i < thread_count_; i++) {
|
|
|
|
threads.emplace_back([n] {
|
|
|
|
for (int i = 0; i < n; i++) {
|
|
|
|
counter_.add(1);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
for (auto &thread : threads) {
|
|
|
|
thread.join();
|
|
|
|
}
|
|
|
|
CHECK(counter_.sum() == n * thread_count_);
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
explicit ThreadSafeCounterBench(int thread_count) : thread_count_(thread_count) {
|
|
|
|
}
|
|
|
|
};
|
|
|
|
td::ThreadSafeCounter ThreadSafeCounterBench::counter_;
|
|
|
|
|
|
|
|
template <bool StrictOrder>
|
|
|
|
class AtomicCounterBench final : public td::Benchmark {
|
|
|
|
static std::atomic<td::int64> counter_;
|
|
|
|
int thread_count_;
|
|
|
|
|
|
|
|
td::string get_description() const final {
|
|
|
|
return PSTRING() << "AtomicCounter" << thread_count_;
|
|
|
|
}
|
|
|
|
void run(int n) final {
|
|
|
|
counter_.store(0);
|
|
|
|
td::vector<td::thread> threads;
|
|
|
|
for (int i = 0; i < thread_count_; i++) {
|
|
|
|
threads.emplace_back([n] {
|
|
|
|
for (int i = 0; i < n; i++) {
|
|
|
|
counter_.fetch_add(1, StrictOrder ? std::memory_order_seq_cst : std::memory_order_relaxed);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
for (auto &thread : threads) {
|
|
|
|
thread.join();
|
|
|
|
}
|
|
|
|
CHECK(counter_.load() == n * thread_count_);
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
explicit AtomicCounterBench(int thread_count) : thread_count_(thread_count) {
|
|
|
|
}
|
|
|
|
};
|
|
|
|
template <bool StrictOrder>
|
|
|
|
std::atomic<td::int64> AtomicCounterBench<StrictOrder>::counter_;
|
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
#endif
|
|
|
|
|
2021-09-01 19:31:39 +02:00
|
|
|
class IdDuplicateCheckerOld {
|
2021-08-22 08:39:43 +02:00
|
|
|
public:
|
|
|
|
static td::string get_description() {
|
|
|
|
return "Old";
|
|
|
|
}
|
|
|
|
td::Status check(td::int64 message_id) {
|
|
|
|
if (saved_message_ids_.size() == MAX_SAVED_MESSAGE_IDS) {
|
|
|
|
auto oldest_message_id = *saved_message_ids_.begin();
|
|
|
|
if (message_id < oldest_message_id) {
|
|
|
|
return td::Status::Error(2, PSLICE() << "Ignore very old message_id "
|
|
|
|
<< td::tag("oldest message_id", oldest_message_id)
|
|
|
|
<< td::tag("got message_id", message_id));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (saved_message_ids_.count(message_id) != 0) {
|
|
|
|
return td::Status::Error(1, PSLICE() << "Ignore duplicated message_id " << td::tag("message_id", message_id));
|
|
|
|
}
|
|
|
|
|
|
|
|
saved_message_ids_.insert(message_id);
|
|
|
|
if (saved_message_ids_.size() > MAX_SAVED_MESSAGE_IDS) {
|
|
|
|
saved_message_ids_.erase(saved_message_ids_.begin());
|
|
|
|
}
|
|
|
|
return td::Status::OK();
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
static constexpr size_t MAX_SAVED_MESSAGE_IDS = 1000;
|
|
|
|
std::set<td::int64> saved_message_ids_;
|
|
|
|
};
|
|
|
|
|
2021-08-22 09:25:11 +02:00
|
|
|
template <size_t MAX_SAVED_MESSAGE_IDS>
|
2021-09-01 19:31:39 +02:00
|
|
|
class IdDuplicateCheckerNew {
|
2021-08-22 08:39:43 +02:00
|
|
|
public:
|
|
|
|
static td::string get_description() {
|
|
|
|
return PSTRING() << "New" << MAX_SAVED_MESSAGE_IDS;
|
|
|
|
}
|
|
|
|
td::Status check(td::int64 message_id) {
|
|
|
|
auto insert_result = saved_message_ids_.insert(message_id);
|
|
|
|
if (!insert_result.second) {
|
|
|
|
return td::Status::Error(1, PSLICE() << "Ignore duplicated message_id " << td::tag("message_id", message_id));
|
|
|
|
}
|
|
|
|
if (saved_message_ids_.size() == MAX_SAVED_MESSAGE_IDS + 1) {
|
|
|
|
auto begin_it = saved_message_ids_.begin();
|
|
|
|
bool is_very_old = begin_it == insert_result.first;
|
|
|
|
saved_message_ids_.erase(begin_it);
|
|
|
|
if (is_very_old) {
|
|
|
|
return td::Status::Error(2, PSLICE() << "Ignore very old message_id "
|
|
|
|
<< td::tag("oldest message_id", *saved_message_ids_.begin())
|
|
|
|
<< td::tag("got message_id", message_id));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return td::Status::OK();
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
std::set<td::int64> saved_message_ids_;
|
|
|
|
};
|
|
|
|
|
2021-09-01 19:31:39 +02:00
|
|
|
class IdDuplicateCheckerNewOther {
|
2021-08-22 08:39:43 +02:00
|
|
|
public:
|
|
|
|
static td::string get_description() {
|
|
|
|
return "NewOther";
|
|
|
|
}
|
|
|
|
td::Status check(td::int64 message_id) {
|
|
|
|
if (!saved_message_ids_.insert(message_id).second) {
|
|
|
|
return td::Status::Error(1, PSLICE() << "Ignore duplicated message_id " << td::tag("message_id", message_id));
|
|
|
|
}
|
|
|
|
if (saved_message_ids_.size() == MAX_SAVED_MESSAGE_IDS + 1) {
|
|
|
|
auto begin_it = saved_message_ids_.begin();
|
|
|
|
bool is_very_old = *begin_it == message_id;
|
|
|
|
saved_message_ids_.erase(begin_it);
|
|
|
|
if (is_very_old) {
|
|
|
|
return td::Status::Error(2, PSLICE() << "Ignore very old message_id "
|
|
|
|
<< td::tag("oldest message_id", *saved_message_ids_.begin())
|
|
|
|
<< td::tag("got message_id", message_id));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return td::Status::OK();
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
static constexpr size_t MAX_SAVED_MESSAGE_IDS = 1000;
|
|
|
|
std::set<td::int64> saved_message_ids_;
|
|
|
|
};
|
|
|
|
|
2021-09-01 19:31:39 +02:00
|
|
|
class IdDuplicateCheckerNewSimple {
|
2021-08-22 08:39:43 +02:00
|
|
|
public:
|
|
|
|
static td::string get_description() {
|
|
|
|
return "NewSimple";
|
|
|
|
}
|
|
|
|
td::Status check(td::int64 message_id) {
|
|
|
|
auto insert_result = saved_message_ids_.insert(message_id);
|
|
|
|
if (!insert_result.second) {
|
|
|
|
return td::Status::Error(1, "Ignore duplicated message_id");
|
|
|
|
}
|
|
|
|
if (saved_message_ids_.size() == MAX_SAVED_MESSAGE_IDS + 1) {
|
|
|
|
auto begin_it = saved_message_ids_.begin();
|
|
|
|
bool is_very_old = begin_it == insert_result.first;
|
|
|
|
saved_message_ids_.erase(begin_it);
|
|
|
|
if (is_very_old) {
|
|
|
|
return td::Status::Error(2, "Ignore very old message_id");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return td::Status::OK();
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
static constexpr size_t MAX_SAVED_MESSAGE_IDS = 1000;
|
|
|
|
std::set<td::int64> saved_message_ids_;
|
|
|
|
};
|
|
|
|
|
2021-08-22 21:08:46 +02:00
|
|
|
template <size_t max_size>
|
2021-09-01 19:31:39 +02:00
|
|
|
class IdDuplicateCheckerArray {
|
2021-08-22 09:49:40 +02:00
|
|
|
public:
|
|
|
|
static td::string get_description() {
|
2021-08-22 21:08:46 +02:00
|
|
|
return PSTRING() << "Array" << max_size;
|
2021-08-22 09:49:40 +02:00
|
|
|
}
|
|
|
|
td::Status check(td::int64 message_id) {
|
2021-08-22 21:08:46 +02:00
|
|
|
if (end_pos_ == 2 * max_size) {
|
|
|
|
std::copy_n(&saved_message_ids_[max_size], max_size, &saved_message_ids_[0]);
|
|
|
|
end_pos_ = max_size;
|
2021-08-22 09:49:40 +02:00
|
|
|
}
|
2021-08-22 21:08:46 +02:00
|
|
|
if (end_pos_ == 0 || message_id > saved_message_ids_[end_pos_ - 1]) {
|
2021-08-22 09:49:40 +02:00
|
|
|
// fast path
|
2021-08-22 21:08:46 +02:00
|
|
|
saved_message_ids_[end_pos_++] = message_id;
|
2021-08-22 09:49:40 +02:00
|
|
|
return td::Status::OK();
|
|
|
|
}
|
2021-08-22 21:08:46 +02:00
|
|
|
if (end_pos_ >= max_size && message_id < saved_message_ids_[0]) {
|
2021-08-22 09:49:40 +02:00
|
|
|
return td::Status::Error(2, PSLICE() << "Ignore very old message_id "
|
|
|
|
<< td::tag("oldest message_id", saved_message_ids_[0])
|
|
|
|
<< td::tag("got message_id", message_id));
|
|
|
|
}
|
2021-08-22 21:08:46 +02:00
|
|
|
auto it = std::lower_bound(&saved_message_ids_[0], &saved_message_ids_[end_pos_], message_id);
|
2021-08-22 09:49:40 +02:00
|
|
|
if (*it == message_id) {
|
|
|
|
return td::Status::Error(1, PSLICE() << "Ignore duplicated message_id " << td::tag("message_id", message_id));
|
|
|
|
}
|
2021-08-22 21:08:46 +02:00
|
|
|
std::copy_backward(it, &saved_message_ids_[end_pos_], &saved_message_ids_[end_pos_ + 1]);
|
2021-08-22 09:49:40 +02:00
|
|
|
*it = message_id;
|
2021-08-22 21:08:46 +02:00
|
|
|
++end_pos_;
|
2021-08-22 09:49:40 +02:00
|
|
|
return td::Status::OK();
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2021-08-22 21:08:46 +02:00
|
|
|
std::array<td::int64, 2 * max_size> saved_message_ids_;
|
|
|
|
std::size_t end_pos_ = 0;
|
2021-08-22 09:49:40 +02:00
|
|
|
};
|
|
|
|
|
2021-08-22 08:39:43 +02:00
|
|
|
template <class T>
|
|
|
|
class DuplicateCheckerBench final : public td::Benchmark {
|
|
|
|
td::string get_description() const final {
|
|
|
|
return PSTRING() << "DuplicateCheckerBench" << T::get_description();
|
|
|
|
}
|
|
|
|
void run(int n) final {
|
|
|
|
T checker_;
|
|
|
|
for (int i = 0; i < n; i++) {
|
|
|
|
checker_.check(i).ensure();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2021-08-22 09:25:11 +02:00
|
|
|
template <class T>
|
|
|
|
class DuplicateCheckerBenchRepeat final : public td::Benchmark {
|
|
|
|
td::string get_description() const final {
|
|
|
|
return PSTRING() << "DuplicateCheckerBenchRepeat" << T::get_description();
|
|
|
|
}
|
|
|
|
void run(int n) final {
|
|
|
|
T checker_;
|
|
|
|
for (int i = 0; i < n; i++) {
|
|
|
|
auto iter = i >> 10;
|
|
|
|
auto pos = i - (iter << 10);
|
|
|
|
if (pos < 768) {
|
2021-08-22 10:47:57 +02:00
|
|
|
if (iter >= 3 && pos == 0) {
|
|
|
|
auto error = checker_.check((iter - 3) * 768 + pos);
|
|
|
|
CHECK(error.error().code() == 2);
|
|
|
|
}
|
2021-08-22 09:25:11 +02:00
|
|
|
checker_.check(iter * 768 + pos).ensure();
|
|
|
|
} else {
|
|
|
|
checker_.check(iter * 768 + pos - 256).ensure_error();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2021-08-22 09:59:50 +02:00
|
|
|
template <class T>
|
|
|
|
class DuplicateCheckerBenchRepeatOnly final : public td::Benchmark {
|
|
|
|
td::string get_description() const final {
|
|
|
|
return PSTRING() << "DuplicateCheckerBenchRepeatOnly" << T::get_description();
|
|
|
|
}
|
|
|
|
void run(int n) final {
|
|
|
|
T checker_;
|
|
|
|
for (int i = 0; i < n; i++) {
|
|
|
|
auto result = checker_.check(i & 255);
|
2021-08-22 10:01:49 +02:00
|
|
|
CHECK(result.is_error() == (i >= 256));
|
2021-08-22 09:59:50 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
class DuplicateCheckerBenchReverse final : public td::Benchmark {
|
|
|
|
td::string get_description() const final {
|
|
|
|
return PSTRING() << "DuplicateCheckerBenchReverseAdd" << T::get_description();
|
|
|
|
}
|
|
|
|
void run(int n) final {
|
|
|
|
T checker_;
|
|
|
|
for (int i = 0; i < n; i++) {
|
|
|
|
auto pos = i & 255;
|
|
|
|
checker_.check(i - pos + (255 - pos)).ensure();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2021-08-23 10:17:25 +02:00
|
|
|
template <class T>
|
|
|
|
class DuplicateCheckerBenchEvenOdd final : public td::Benchmark {
|
|
|
|
td::string get_description() const final {
|
|
|
|
return PSTRING() << "DuplicateCheckerBenchEvenOdd" << T::get_description();
|
|
|
|
}
|
|
|
|
void run(int n) final {
|
|
|
|
T checker_;
|
|
|
|
for (int i = 0; i < n; i++) {
|
|
|
|
auto pos = i & 255;
|
|
|
|
checker_.check(i - pos + (pos * 2) % 256 + (pos * 2) / 256).ensure();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
int main() {
|
|
|
|
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(DEBUG));
|
2021-08-22 08:39:43 +02:00
|
|
|
|
2021-09-01 19:31:39 +02:00
|
|
|
td::bench(DuplicateCheckerBenchEvenOdd<IdDuplicateCheckerNew<1000>>());
|
|
|
|
td::bench(DuplicateCheckerBenchEvenOdd<IdDuplicateCheckerNew<300>>());
|
|
|
|
td::bench(DuplicateCheckerBenchEvenOdd<IdDuplicateCheckerArray<1000>>());
|
|
|
|
td::bench(DuplicateCheckerBenchEvenOdd<IdDuplicateCheckerArray<300>>());
|
|
|
|
|
|
|
|
td::bench(DuplicateCheckerBenchReverse<IdDuplicateCheckerNew<1000>>());
|
|
|
|
td::bench(DuplicateCheckerBenchReverse<IdDuplicateCheckerNew<300>>());
|
|
|
|
td::bench(DuplicateCheckerBenchReverse<IdDuplicateCheckerArray<1000>>());
|
|
|
|
td::bench(DuplicateCheckerBenchReverse<IdDuplicateCheckerArray<300>>());
|
|
|
|
|
|
|
|
td::bench(DuplicateCheckerBenchRepeatOnly<IdDuplicateCheckerNew<1000>>());
|
|
|
|
td::bench(DuplicateCheckerBenchRepeatOnly<IdDuplicateCheckerNew<300>>());
|
|
|
|
td::bench(DuplicateCheckerBenchRepeatOnly<IdDuplicateCheckerArray<1000>>());
|
|
|
|
td::bench(DuplicateCheckerBenchRepeatOnly<IdDuplicateCheckerArray<300>>());
|
|
|
|
|
|
|
|
td::bench(DuplicateCheckerBenchRepeat<IdDuplicateCheckerOld>());
|
|
|
|
td::bench(DuplicateCheckerBenchRepeat<IdDuplicateCheckerNew<1000>>());
|
|
|
|
td::bench(DuplicateCheckerBenchRepeat<IdDuplicateCheckerNewOther>());
|
|
|
|
td::bench(DuplicateCheckerBenchRepeat<IdDuplicateCheckerNewSimple>());
|
|
|
|
td::bench(DuplicateCheckerBenchRepeat<IdDuplicateCheckerNew<300>>());
|
|
|
|
td::bench(DuplicateCheckerBenchRepeat<IdDuplicateCheckerArray<1000>>());
|
|
|
|
td::bench(DuplicateCheckerBenchRepeat<IdDuplicateCheckerArray<300>>());
|
|
|
|
|
|
|
|
td::bench(DuplicateCheckerBench<IdDuplicateCheckerOld>());
|
|
|
|
td::bench(DuplicateCheckerBench<IdDuplicateCheckerNew<1000>>());
|
|
|
|
td::bench(DuplicateCheckerBench<IdDuplicateCheckerNewOther>());
|
|
|
|
td::bench(DuplicateCheckerBench<IdDuplicateCheckerNewSimple>());
|
|
|
|
td::bench(DuplicateCheckerBench<IdDuplicateCheckerNew<300>>());
|
|
|
|
td::bench(DuplicateCheckerBench<IdDuplicateCheckerNew<100>>());
|
|
|
|
td::bench(DuplicateCheckerBench<IdDuplicateCheckerNew<10>>());
|
|
|
|
td::bench(DuplicateCheckerBench<IdDuplicateCheckerArray<1000>>());
|
|
|
|
td::bench(DuplicateCheckerBench<IdDuplicateCheckerArray<300>>());
|
2021-08-22 08:39:43 +02:00
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
#if !TD_THREAD_UNSUPPORTED
|
2021-08-18 18:26:03 +02:00
|
|
|
for (int i = 1; i <= 16; i *= 2) {
|
|
|
|
td::bench(ThreadSafeCounterBench(i));
|
|
|
|
td::bench(AtomicCounterBench<false>(i));
|
|
|
|
td::bench(AtomicCounterBench<true>(i));
|
|
|
|
}
|
|
|
|
|
2021-08-18 17:22:41 +02:00
|
|
|
td::bench(AtomicReleaseIncBench<1>());
|
|
|
|
td::bench(AtomicReleaseIncBench<2>());
|
|
|
|
td::bench(AtomicReleaseCasIncBench<1>());
|
|
|
|
td::bench(AtomicReleaseCasIncBench<2>());
|
|
|
|
td::bench(RwMutexWriteBench<1>());
|
|
|
|
td::bench(RwMutexReadBench<1>());
|
2021-08-18 18:26:03 +02:00
|
|
|
td::bench(RwMutexWriteBench<2>());
|
|
|
|
td::bench(RwMutexReadBench<2>());
|
2018-12-31 20:04:05 +01:00
|
|
|
#endif
|
|
|
|
#if !TD_WINDOWS
|
2021-08-18 17:22:41 +02:00
|
|
|
td::bench(UtimeBench());
|
2018-12-31 20:04:05 +01:00
|
|
|
#endif
|
2021-08-18 17:22:41 +02:00
|
|
|
td::bench(WalkPathBench());
|
|
|
|
td::bench(CreateFileBench());
|
|
|
|
td::bench(PwriteBench());
|
2018-12-31 20:04:05 +01:00
|
|
|
|
2021-08-18 17:22:41 +02:00
|
|
|
td::bench(CallBench());
|
2018-12-31 20:04:05 +01:00
|
|
|
#if !TD_THREAD_UNSUPPORTED
|
2021-08-18 17:22:41 +02:00
|
|
|
td::bench(ThreadNewBench());
|
2018-12-31 20:04:05 +01:00
|
|
|
#endif
|
|
|
|
#if !TD_EVENTFD_UNSUPPORTED
|
2021-08-18 17:22:41 +02:00
|
|
|
td::bench(EventFdBench());
|
2018-12-31 20:04:05 +01:00
|
|
|
#endif
|
2021-08-18 17:22:41 +02:00
|
|
|
td::bench(NewObjBench());
|
|
|
|
td::bench(NewIntBench());
|
2018-12-31 20:04:05 +01:00
|
|
|
#if !TD_WINDOWS
|
2021-08-18 17:22:41 +02:00
|
|
|
td::bench(PipeBench());
|
2018-12-31 20:04:05 +01:00
|
|
|
#endif
|
|
|
|
#if TD_LINUX || TD_ANDROID || TD_TIZEN
|
2021-08-18 17:22:41 +02:00
|
|
|
td::bench(SemBench());
|
2018-12-31 20:04:05 +01:00
|
|
|
#endif
|
|
|
|
}
|