Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bca6c18a authored by Chienyuan's avatar Chienyuan Committed by android-build-merger
Browse files

Merge "Add benchmark for queue"

am: 3c3861fd

Change-Id: I9586994386bbf51fae402424b66c3fa955c29a76
parents eec11ee2 3c3861fd
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -27,5 +27,6 @@ filegroup {
    srcs: [
        "alarm_benchmark.cc",
        "thread_benchmark.cc",
        "queue_benchmark.cc",
    ]
}
+199 −0
Original line number Diff line number Diff line
/*
 * Copyright 2019 The Android Open Source Project
 *
 * 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 "benchmark/benchmark.h"

#include <future>

#include "os/handler.h"
#include "os/queue.h"
#include "os/thread.h"

using ::benchmark::State;

namespace bluetooth {
namespace os {

class BM_QueuePerformance : public ::benchmark::Fixture {
 protected:
  void SetUp(State& st) override {
    ::benchmark::Fixture::SetUp(st);
    enqueue_thread_ = new Thread("enqueue_thread", Thread::Priority::NORMAL);
    enqueue_handler_ = new Handler(enqueue_thread_);
    dequeue_thread_ = new Thread("dequeue_thread", Thread::Priority::NORMAL);
    dequeue_handler_ = new Handler(dequeue_thread_);
  }

  void TearDown(State& st) override {
    delete enqueue_handler_;
    delete enqueue_thread_;
    delete dequeue_handler_;
    delete dequeue_thread_;
    enqueue_handler_ = nullptr;
    enqueue_thread_ = nullptr;
    dequeue_handler_ = nullptr;
    dequeue_thread_ = nullptr;
    benchmark::Fixture::TearDown(st);
  }

  Thread* enqueue_thread_;
  Handler* enqueue_handler_;
  Thread* dequeue_thread_;
  Handler* dequeue_handler_;
};

class TestEnqueueEnd {
 public:
  explicit TestEnqueueEnd(int64_t count, Queue<std::string>* queue, Handler* handler, std::promise<void>* promise)
      : count_(count), handler_(handler), queue_(queue), promise_(promise) {}

  void RegisterEnqueue() {
    handler_->Post([this] { queue_->RegisterEnqueue(handler_, [this] { return EnqueueCallbackForTest(); }); });
  }

  void push(std::string data) {
    {
      std::lock_guard<std::mutex> lock(mutex_);
      buffer_.push(std::move(data));
    }
    if (buffer_.size() == 1) {
      RegisterEnqueue();
    }
  }

  std::unique_ptr<std::string> EnqueueCallbackForTest() {
    std::lock_guard<std::mutex> lock(mutex_);
    std::unique_ptr<std::string> data = std::make_unique<std::string>(std::move(buffer_.front()));
    buffer_.pop();

    if (buffer_.empty()) {
      queue_->UnregisterEnqueue();
    }

    count_--;
    if (count_ == 0) {
      promise_->set_value();
    }

    return data;
  }

  std::queue<std::string> buffer_;
  int64_t count_;

 private:
  Handler* handler_;
  Queue<std::string>* queue_;
  std::promise<void>* promise_;
  std::mutex mutex_;
};

class TestDequeueEnd {
 public:
  explicit TestDequeueEnd(int64_t count, Queue<std::string>* queue, Handler* handler, std::promise<void>* promise)
      : count_(count), handler_(handler), queue_(queue), promise_(promise) {}

  void RegisterDequeue() {
    handler_->Post([this] { queue_->RegisterDequeue(handler_, [this] { DequeueCallbackForTest(); }); });
  }

  void DequeueCallbackForTest() {
    std::string data = *(queue_->TryDequeue());
    buffer_.push(data);

    count_--;
    if (count_ == 0) {
      queue_->UnregisterDequeue();
      promise_->set_value();
    }
  }

  std::queue<std::string> buffer_;
  int64_t count_;

 private:
  Handler* handler_;
  Queue<std::string>* queue_;
  std::promise<void>* promise_;
};

BENCHMARK_DEFINE_F(BM_QueuePerformance, send_packet_vary_by_packet_num)(State& state) {
  for (auto _ : state) {
    int64_t num_data_to_send_ = state.range(0);
    Queue<std::string> queue(num_data_to_send_);

    // register dequeue
    std::promise<void> dequeue_promise;
    auto dequeue_future = dequeue_promise.get_future();
    TestDequeueEnd test_dequeue_end(num_data_to_send_, &queue, enqueue_handler_, &dequeue_promise);
    test_dequeue_end.RegisterDequeue();

    // Push data to enqueue end buffer and register enqueue
    std::promise<void> enqueue_promise;
    TestEnqueueEnd test_enqueue_end(num_data_to_send_, &queue, enqueue_handler_, &enqueue_promise);
    for (int i = 0; i < num_data_to_send_; i++) {
      std::string data = std::to_string(1);
      test_enqueue_end.push(std::move(data));
    }
    dequeue_future.wait();
  }

  state.SetBytesProcessed(static_cast<int_fast64_t>(state.iterations()) * state.range(0));
};

BENCHMARK_REGISTER_F(BM_QueuePerformance, send_packet_vary_by_packet_num)
    ->Arg(10)
    ->Arg(100)
    ->Arg(1000)
    ->Arg(10000)
    ->Arg(100000)
    ->Iterations(100)
    ->UseRealTime();

BENCHMARK_DEFINE_F(BM_QueuePerformance, send_10000_packet_vary_by_packet_size)(State& state) {
  for (auto _ : state) {
    int64_t num_data_to_send_ = 10000;
    int64_t packet_size = state.range(0);
    Queue<std::string> queue(num_data_to_send_);

    // register dequeue
    std::promise<void> dequeue_promise;
    auto dequeue_future = dequeue_promise.get_future();
    TestDequeueEnd test_dequeue_end(num_data_to_send_, &queue, enqueue_handler_, &dequeue_promise);
    test_dequeue_end.RegisterDequeue();

    // Push data to enqueue end buffer and register enqueue
    std::promise<void> enqueue_promise;
    TestEnqueueEnd test_enqueue_end(num_data_to_send_, &queue, enqueue_handler_, &enqueue_promise);
    for (int i = 0; i < num_data_to_send_; i++) {
      std::string data = std::string(packet_size, 'x');
      test_enqueue_end.push(std::move(data));
    }
    dequeue_future.wait();
  }

  state.SetBytesProcessed(static_cast<int_fast64_t>(state.iterations()) * state.range(0) * 10000);
};

BENCHMARK_REGISTER_F(BM_QueuePerformance, send_10000_packet_vary_by_packet_size)
    ->Arg(10)
    ->Arg(100)
    ->Arg(1000)
    ->Iterations(100)
    ->UseRealTime();

}  // namespace os
}  // namespace bluetooth
 No newline at end of file