summaryrefslogtreecommitdiff
path: root/protocols/Telegram/tdlib/td/benchmark/bench_misc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'protocols/Telegram/tdlib/td/benchmark/bench_misc.cpp')
-rw-r--r--protocols/Telegram/tdlib/td/benchmark/bench_misc.cpp392
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 &sum;
+
+ 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;
+}