diff options
Diffstat (limited to 'protocols/Telegram/tdlib/td/benchmark/bench_misc.cpp')
-rw-r--r-- | protocols/Telegram/tdlib/td/benchmark/bench_misc.cpp | 392 |
1 files changed, 392 insertions, 0 deletions
diff --git a/protocols/Telegram/tdlib/td/benchmark/bench_misc.cpp b/protocols/Telegram/tdlib/td/benchmark/bench_misc.cpp new file mode 100644 index 0000000000..bfbcea438b --- /dev/null +++ b/protocols/Telegram/tdlib/td/benchmark/bench_misc.cpp @@ -0,0 +1,392 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018 +// +// 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) +// +#include "td/utils/benchmark.h" +#include "td/utils/common.h" +#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" + +#include "td/telegram/telegram_api.h" +#include "td/telegram/telegram_api.hpp" + +#if !TD_WINDOWS +#include <unistd.h> +#include <utime.h> +#endif + +#if TD_LINUX || TD_ANDROID || TD_TIZEN +#include <semaphore.h> +#endif + +#include <atomic> +#include <cstdint> + +namespace td { + +class F { + uint32 ∑ + + public: + explicit F(uint32 &sum) : sum(sum) { + } + + template <class T> + void operator()(const T &x) const { + sum += static_cast<uint32>(x.get_id()); + } +}; + +BENCH(Call, "TL Call") { + tl_object_ptr<telegram_api::Function> x = make_tl_object<telegram_api::account_getWallPapers>(); + uint32 res = 0; + F f(res); + for (int i = 0; i < n; i++) { + downcast_call(*x, f); + } + do_not_optimize_away(res); +} + +#if !TD_EVENTFD_UNSUPPORTED +BENCH(EventFd, "EventFd") { + EventFd fd; + 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; + } + do_not_optimize_away(res); +} + +BENCH(NewObj, "new struct then delete") { + struct A { + int32 a = 0; + int32 b = 0; + int32 c = 0; + int32 d = 0; + }; + 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; + do_not_optimize_away(res); +} + +#if !TD_THREAD_UNSUPPORTED +BENCH(ThreadNew, "new struct then delete in several threads") { + td::NewObjBench a, b; + thread ta([&] { a.run(n / 2); }); + thread tb([&] { b.run(n - n / 2); }); + ta.join(); + tb.join(); +} +#endif + +// Too hard for android clang (?) +BENCH(Time, "Clocks::monotonic") { + double res = 0; + for (int i = 0; i < n; i++) { + res += Clocks::monotonic(); + } + do_not_optimize_away(res); +} + +#if !TD_WINDOWS +class PipeBench : public Benchmark { + public: + int p[2]; + + PipeBench() { + pipe(p); + } + + string get_description() const override { + return "pipe write + read int32"; + } + + void start_up() override { + pipe(p); + } + + void run(int n) override { + int res = 0; + for (int i = 0; i < n; i++) { + int val = 1; + write(p[1], &val, sizeof(val)); + read(p[0], &val, sizeof(val)); + res += val; + } + do_not_optimize_away(res); + } + + void tear_down() override { + close(p[0]); + close(p[1]); + } +}; +#endif + +#if TD_LINUX || TD_ANDROID || TD_TIZEN +class SemBench : public Benchmark { + sem_t sem; + + public: + string get_description() const override { + return "sem post + wait"; + } + + void start_up() override { + int err = sem_init(&sem, 0, 0); + CHECK(err != -1); + } + + void run(int n) override { + for (int i = 0; i < n; i++) { + sem_post(&sem); + sem_wait(&sem); + } + } + + void tear_down() override { + sem_destroy(&sem); + } +}; +#endif + +#if !TD_WINDOWS +class UtimeBench : public Benchmark { + public: + void start_up() override { + FileFd::open("test", FileFd::Flags::Create | FileFd::Flags::Write).move_as_ok().close(); + } + string get_description() const override { + return "utime"; + } + void run(int n) override { + 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") { + auto fd = FileFd::open("test", FileFd::Flags::Create | FileFd::Flags::Write).move_as_ok(); + for (int i = 0; i < n; i++) { + fd.pwrite("a", 0).ok(); + } + fd.close(); +} + +class CreateFileBench : public Benchmark { + string get_description() const override { + return "create_file"; + } + void start_up() override { + mkdir("A").ensure(); + } + void run(int n) override { + for (int i = 0; i < n; i++) { + FileFd::open("A/" + to_string(i), FileFd::Flags::Write | FileFd::Flags::Create).move_as_ok().close(); + } + } + void tear_down() override { + auto status = td::walk_path("A/", [&](CSlice path, bool is_dir) { + if (is_dir) { + rmdir(path).ignore(); + } else { + unlink(path).ignore(); + } + }); + } +}; +class WalkPathBench : public Benchmark { + string get_description() const override { + return "walk_path"; + } + void start_up_n(int n) override { + mkdir("A").ensure(); + for (int i = 0; i < n; i++) { + FileFd::open("A/" + to_string(i), FileFd::Flags::Write | FileFd::Flags::Create).move_as_ok().close(); + } + } + void run(int n) override { + int cnt = 0; + auto status = td::walk_path("A/", [&](CSlice path, bool is_dir) { + stat(path).ok(); + cnt++; + }); + } + void tear_down() override { + auto status = td::walk_path("A/", [&](CSlice path, bool is_dir) { + if (is_dir) { + rmdir(path).ignore(); + } else { + unlink(path).ignore(); + } + }); + } +}; + +#if !TD_THREAD_UNSUPPORTED +template <int ThreadN = 2> +class AtomicReleaseIncBench : public Benchmark { + string get_description() const override { + return PSTRING() << "AtomicReleaseInc" << ThreadN; + } + + static std::atomic<uint64> a_; + void run(int n) override { + std::vector<thread> threads; + 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> +std::atomic<uint64> AtomicReleaseIncBench<ThreadN>::a_; + +template <int ThreadN = 2> +class AtomicReleaseCasIncBench : public Benchmark { + string get_description() const override { + return PSTRING() << "AtomicReleaseCasInc" << ThreadN; + } + + static std::atomic<uint64> a_; + void run(int n) override { + std::vector<thread> threads; + 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> +std::atomic<uint64> AtomicReleaseCasIncBench<ThreadN>::a_; + +template <int ThreadN = 2> +class RwMutexReadBench : public Benchmark { + string get_description() const override { + return PSTRING() << "RwMutexRead" << ThreadN; + } + RwMutex mutex_; + void run(int n) override { + std::vector<thread> threads; + 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(); + } + } +}; +template <int ThreadN = 2> +class RwMutexWriteBench : public Benchmark { + string get_description() const override { + return PSTRING() << "RwMutexWrite" << ThreadN; + } + RwMutex mutex_; + void run(int n) override { + std::vector<thread> threads; + 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(); + } + } +}; +#endif +} // namespace td + +int main() { + SET_VERBOSITY_LEVEL(VERBOSITY_NAME(DEBUG)); +#if !TD_THREAD_UNSUPPORTED + td::bench(td::AtomicReleaseIncBench<1>()); + td::bench(td::AtomicReleaseIncBench<2>()); + td::bench(td::AtomicReleaseCasIncBench<1>()); + td::bench(td::AtomicReleaseCasIncBench<2>()); + td::bench(td::RwMutexWriteBench<1>()); + td::bench(td::RwMutexReadBench<1>()); + td::bench(td::RwMutexWriteBench<>()); + td::bench(td::RwMutexReadBench<>()); +#endif +#if !TD_WINDOWS + td::bench(td::UtimeBench()); +#endif + td::bench(td::WalkPathBench()); + td::bench(td::CreateFileBench()); + td::bench(td::PwriteBench()); + + td::bench(td::CallBench()); +#if !TD_THREAD_UNSUPPORTED + td::bench(td::ThreadNewBench()); +#endif +#if !TD_EVENTFD_UNSUPPORTED + td::bench(td::EventFdBench()); +#endif + td::bench(td::NewObjBench()); + td::bench(td::NewIntBench()); +#if !TD_WINDOWS + td::bench(td::PipeBench()); +#endif +#if TD_LINUX || TD_ANDROID || TD_TIZEN + td::bench(td::SemBench()); +#endif + return 0; +} |