// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <zircon/syscalls.h>

#include <random>
#include <vector>

#include <fbl/ref_ptr.h>
#include <fbl/string_printf.h>
#include <fs/lazy_dir.h>
#include <fs/vfs.h>
#include <perftest/perftest.h>

#include "assert.h"
#include "src/lib/fxl/strings/string_printf.h"
#include "util.h"

namespace {

class TestLazyDir : public fs::LazyDir {
 public:
  void AddEntry(LazyEntry entry) { entries_.push_back(std::move(entry)); }

 protected:
  void GetContents(LazyEntryVector* out_vector) override {
    out_vector->reserve(entries_.size());
    for (const auto& entry : entries_) {
      out_vector->push_back(entry);
    }
  }

  zx_status_t GetFile(fbl::RefPtr<Vnode>* out_vnode, uint64_t id, fbl::String name) override {
    // Do nothing to benchmark obtaining id and name.
    return ZX_OK;
  }

  fbl::Vector<LazyEntry> entries_;
};

// Measure the time taken to create an empty LazyDir.
bool TestCreate(perftest::RepeatState* state) {
  while (state->KeepRunning()) {
    ZX_ASSERT(fbl::AdoptRef<TestLazyDir>(new TestLazyDir()) != nullptr);
  }
  return true;
}

// Measure the time taken to look up an entry in a LazyDir of a given size.
bool TestLookup(perftest::RepeatState* state, size_t file_count) {
  auto file_names = util::MakeDeterministicNamesList(file_count);

  auto dir = fbl::AdoptRef(new TestLazyDir());

  uint64_t id = 1;
  for (const auto& name : file_names) {
    dir->AddEntry({id++, name, V_TYPE_FILE});
  }

  int i = 0;
  while (state->KeepRunning()) {
    fbl::RefPtr<fs::Vnode> out;
    ASSERT_OK(dir->Lookup(file_names[i], &out));
    i = (i + 1) % file_names.size();
  }
  return true;
}

// Measure the time taken to read directory entries from a LazyDir of
// a given size using a given sized buffer.
bool TestReaddir(perftest::RepeatState* state, size_t file_count, size_t buffer_size) {
  auto file_names = util::MakeDeterministicNamesList(file_count);
  std::vector<char> buffer(buffer_size);

  auto dir = fbl::AdoptRef(new TestLazyDir());

  uint64_t id = 1;
  for (const auto& name : file_names) {
    dir->AddEntry({id++, name, V_TYPE_FILE});
  }

  while (state->KeepRunning()) {
    fs::vdircookie_t cookie;
    size_t real_len = 0;
    while (dir->Readdir(&cookie, buffer.data(), buffer_size, &real_len) != ZX_OK) {
      ZX_ASSERT(real_len != 0);
    }
  }
  return true;
}

void RegisterTests() {
  static const size_t kSizes[] = {1, 8, 64, 512, 4 * 1024, 16 * 1024};
  static const size_t kBuffers[] = {1024, 4 * 1024, 16 * 1024, 64 * 1024};
  perftest::RegisterTest("LazyDir/Create", TestCreate);
  for (auto size : kSizes) {
    auto name = fbl::StringPrintf("LazyDir/Lookup/size:%zd", size);
    perftest::RegisterTest(name.c_str(), TestLookup, size);
  }

  for (auto size : kSizes) {
    for (auto buffer : kBuffers) {
      auto name = fbl::StringPrintf("LazyDir/Readdir/size:%zd/buf:%zd", size, buffer);
      perftest::RegisterTest(name.c_str(), TestReaddir, size, buffer);
    }
  }
}
PERFTEST_CTOR(RegisterTests);

}  // namespace
