// Copyright (C) 2018 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 <random>

#include <benchmark/benchmark.h>

#include "perfetto/base/time.h"
#include "perfetto/ext/traced/traced.h"
#include "perfetto/ext/tracing/core/trace_packet.h"
#include "perfetto/tracing/core/trace_config.h"
#include "src/base/test/test_task_runner.h"
#include "test/gtest_and_gmock.h"
#include "test/task_runner_thread.h"
#include "test/task_runner_thread_delegates.h"
#include "test/test_helper.h"

#include "protos/perfetto/config/test_config.gen.h"
#include "protos/perfetto/trace/test_event.gen.h"
#include "protos/perfetto/trace/trace_packet.pbzero.h"

namespace perfetto {

namespace {

bool IsBenchmarkFunctionalOnly() {
  return getenv("BENCHMARK_FUNCTIONAL_TEST_ONLY") != nullptr;
}

void BenchmarkProducer(benchmark::State& state) {
  base::TestTaskRunner task_runner;

  TestHelper helper(&task_runner);
  helper.StartServiceIfRequired();

  FakeProducer* producer = helper.ConnectFakeProducer();
  helper.ConnectConsumer();
  helper.WaitForConsumerConnect();

  TraceConfig trace_config;
  trace_config.add_buffers()->set_size_kb(512);

  auto* ds_config = trace_config.add_data_sources()->mutable_config();
  ds_config->set_name("android.perfetto.FakeProducer");
  ds_config->set_target_buffer(0);

  static constexpr uint32_t kRandomSeed = 42;
  uint32_t message_count = static_cast<uint32_t>(state.range(0));
  uint32_t message_bytes = static_cast<uint32_t>(state.range(1));
  uint32_t mb_per_s = static_cast<uint32_t>(state.range(2));

  uint32_t messages_per_s = mb_per_s * 1024 * 1024 / message_bytes;
  uint32_t time_for_messages_ms =
      10000 + (messages_per_s == 0 ? 0 : message_count * 1000 / messages_per_s);

  ds_config->mutable_for_testing()->set_seed(kRandomSeed);
  ds_config->mutable_for_testing()->set_message_count(message_count);
  ds_config->mutable_for_testing()->set_message_size(message_bytes);
  ds_config->mutable_for_testing()->set_max_messages_per_second(messages_per_s);

  helper.StartTracing(trace_config);
  helper.WaitForProducerEnabled();

  uint64_t wall_start_ns = static_cast<uint64_t>(base::GetWallTimeNs().count());
  uint64_t service_start_ns = helper.service_thread()->GetThreadCPUTimeNs();
  uint64_t producer_start_ns = helper.producer_thread()->GetThreadCPUTimeNs();
  uint32_t iterations = 0;
  for (auto _ : state) {
    auto cname = "produced.and.committed." + std::to_string(iterations++);
    auto on_produced_and_committed = task_runner.CreateCheckpoint(cname);
    producer->ProduceEventBatch(helper.WrapTask(on_produced_and_committed));
    task_runner.RunUntilCheckpoint(cname, time_for_messages_ms);
  }
  uint64_t service_ns =
      helper.service_thread()->GetThreadCPUTimeNs() - service_start_ns;
  uint64_t producer_ns =
      helper.producer_thread()->GetThreadCPUTimeNs() - producer_start_ns;
  uint64_t wall_ns =
      static_cast<uint64_t>(base::GetWallTimeNs().count()) - wall_start_ns;

  state.counters["Ser CPU"] = benchmark::Counter(100.0 * service_ns / wall_ns);
  state.counters["Ser ns/m"] =
      benchmark::Counter(1.0 * service_ns / message_count);
  state.counters["Pro CPU"] = benchmark::Counter(100.0 * producer_ns / wall_ns);
  state.SetBytesProcessed(iterations * message_bytes * message_count);

  // Read back the buffer just to check correctness.
  helper.ReadData();
  helper.WaitForReadData();

  bool is_first_packet = true;
  std::minstd_rand0 rnd_engine(kRandomSeed);
  for (const auto& packet : helper.trace()) {
    ASSERT_TRUE(packet.has_for_testing());
    if (is_first_packet) {
      rnd_engine = std::minstd_rand0(packet.for_testing().seq_value());
      is_first_packet = false;
    } else {
      ASSERT_EQ(packet.for_testing().seq_value(), rnd_engine());
    }
  }
}

static void BenchmarkConsumer(benchmark::State& state) {
  base::TestTaskRunner task_runner;

  TestHelper helper(&task_runner);
  helper.StartServiceIfRequired();

  FakeProducer* producer = helper.ConnectFakeProducer();
  helper.ConnectConsumer();
  helper.WaitForConsumerConnect();

  TraceConfig trace_config;

  static const uint32_t kBufferSizeBytes =
      IsBenchmarkFunctionalOnly() ? 16 * 1024 : 2 * 1024 * 1024;
  trace_config.add_buffers()->set_size_kb(kBufferSizeBytes / 1024);

  static constexpr uint32_t kRandomSeed = 42;
  uint32_t message_bytes = static_cast<uint32_t>(state.range(0));
  uint32_t mb_per_s = static_cast<uint32_t>(state.range(1));
  bool is_saturated_producer = mb_per_s == 0;

  uint32_t message_count = kBufferSizeBytes / message_bytes;
  uint32_t messages_per_s = mb_per_s * 1024 * 1024 / message_bytes;
  uint32_t number_of_batches =
      is_saturated_producer ? 0 : std::max(1u, message_count / messages_per_s);

  auto* ds_config = trace_config.add_data_sources()->mutable_config();
  ds_config->set_name("android.perfetto.FakeProducer");
  ds_config->set_target_buffer(0);
  ds_config->mutable_for_testing()->set_seed(kRandomSeed);
  ds_config->mutable_for_testing()->set_message_count(message_count);
  ds_config->mutable_for_testing()->set_message_size(message_bytes);
  ds_config->mutable_for_testing()->set_max_messages_per_second(messages_per_s);

  helper.StartTracing(trace_config);
  helper.WaitForProducerEnabled();

  uint64_t wall_start_ns = static_cast<uint64_t>(base::GetWallTimeNs().count());
  uint64_t service_start_ns =
      static_cast<uint64_t>(helper.service_thread()->GetThreadCPUTimeNs());
  uint64_t consumer_start_ns =
      static_cast<uint64_t>(base::GetThreadCPUTimeNs().count());
  uint64_t read_time_taken_ns = 0;

  uint64_t iterations = 0;
  uint32_t counter = 0;
  for (auto _ : state) {
    auto cname = "produced.and.committed." + std::to_string(iterations++);
    auto on_produced_and_committed = task_runner.CreateCheckpoint(cname);
    producer->ProduceEventBatch(helper.WrapTask(on_produced_and_committed));

    if (is_saturated_producer) {
      // If the producer is running in saturated mode, wait until it flushes
      // data.
      task_runner.RunUntilCheckpoint(cname);

      // Then time how long it takes to read back the data.
      int64_t start = base::GetWallTimeNs().count();
      helper.ReadData(counter);
      helper.WaitForReadData(counter++);
      read_time_taken_ns +=
          static_cast<uint64_t>(base::GetWallTimeNs().count() - start);
    } else {
      // If the producer is not running in saturated mode, every second the
      // producer will send a batch of data over. Wait for a second before
      // performing readback; do this for each batch the producer sends.
      for (uint32_t i = 0; i < number_of_batches; i++) {
        auto batch_cname = "batch.checkpoint." + std::to_string(counter);
        auto batch_checkpoint = task_runner.CreateCheckpoint(batch_cname);
        task_runner.PostDelayedTask(batch_checkpoint, 1000);
        task_runner.RunUntilCheckpoint(batch_cname);

        int64_t start = base::GetWallTimeNs().count();
        helper.ReadData(counter);
        helper.WaitForReadData(counter++);
        read_time_taken_ns +=
            static_cast<uint64_t>(base::GetWallTimeNs().count() - start);
      }
    }
  }
  uint64_t service_ns =
      helper.service_thread()->GetThreadCPUTimeNs() - service_start_ns;
  uint64_t consumer_ns =
      static_cast<uint64_t>(base::GetThreadCPUTimeNs().count()) -
      consumer_start_ns;
  uint64_t wall_ns =
      static_cast<uint64_t>(base::GetWallTimeNs().count()) - wall_start_ns;

  state.counters["Ser CPU"] = benchmark::Counter(100.0 * service_ns / wall_ns);
  state.counters["Ser ns/m"] =
      benchmark::Counter(1.0 * service_ns / message_count);
  state.counters["Con CPU"] = benchmark::Counter(100.0 * consumer_ns / wall_ns);
  state.counters["Con Speed"] =
      benchmark::Counter(iterations * 1000.0 * 1000 * 1000 * kBufferSizeBytes /
                         read_time_taken_ns);
}

void SaturateCpuProducerArgs(benchmark::internal::Benchmark* b) {
  int min_message_count = 16;
  int max_message_count = IsBenchmarkFunctionalOnly() ? 16 : 1024 * 1024;
  int min_payload = 8;
  int max_payload = IsBenchmarkFunctionalOnly() ? 8 : 2048;
  for (int count = min_message_count; count <= max_message_count; count *= 2) {
    for (int bytes = min_payload; bytes <= max_payload; bytes *= 2) {
      b->Args({count, bytes, 0 /* speed */});
    }
  }
}

void ConstantRateProducerArgs(benchmark::internal::Benchmark* b) {
  int message_count = IsBenchmarkFunctionalOnly() ? 2 * 1024 : 128 * 1024;
  int min_speed = IsBenchmarkFunctionalOnly() ? 64 : 8;
  int max_speed = 128;
  for (int speed = min_speed; speed <= max_speed; speed *= 2) {
    b->Args({message_count, 128, speed});
    b->Args({message_count, 256, speed});
  }
}

void SaturateCpuConsumerArgs(benchmark::internal::Benchmark* b) {
  int min_payload = 8;
  int max_payload = IsBenchmarkFunctionalOnly() ? 16 : 64 * 1024;
  for (int bytes = min_payload; bytes <= max_payload; bytes *= 2) {
    b->Args({bytes, 0 /* speed */});
  }
}

void ConstantRateConsumerArgs(benchmark::internal::Benchmark* b) {
  int min_speed = IsBenchmarkFunctionalOnly() ? 128 : 1;
  int max_speed = IsBenchmarkFunctionalOnly() ? 128 : 2;
  for (int speed = min_speed; speed <= max_speed; speed *= 2) {
    b->Args({2, speed});
    b->Args({4, speed});
  }
}

}  // namespace

static void BM_EndToEnd_Producer_SaturateCpu(benchmark::State& state) {
  BenchmarkProducer(state);
}

BENCHMARK(BM_EndToEnd_Producer_SaturateCpu)
    ->Unit(benchmark::kMicrosecond)
    ->UseRealTime()
    ->Apply(SaturateCpuProducerArgs);

static void BM_EndToEnd_Producer_ConstantRate(benchmark::State& state) {
  BenchmarkProducer(state);
}

BENCHMARK(BM_EndToEnd_Producer_ConstantRate)
    ->Unit(benchmark::kMicrosecond)
    ->UseRealTime()
    ->Apply(ConstantRateProducerArgs);

static void BM_EndToEnd_Consumer_SaturateCpu(benchmark::State& state) {
  BenchmarkConsumer(state);
}

BENCHMARK(BM_EndToEnd_Consumer_SaturateCpu)
    ->Unit(benchmark::kMicrosecond)
    ->UseRealTime()
    ->Apply(SaturateCpuConsumerArgs);

static void BM_EndToEnd_Consumer_ConstantRate(benchmark::State& state) {
  BenchmarkConsumer(state);
}

BENCHMARK(BM_EndToEnd_Consumer_ConstantRate)
    ->Unit(benchmark::kMillisecond)
    ->UseRealTime()
    ->Apply(ConstantRateConsumerArgs);

}  // namespace perfetto
