|  | // 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 "src/lib/storage/vfs/cpp/lazy_dir.h" | 
|  |  | 
|  | #include <zircon/syscalls.h> | 
|  |  | 
|  | #include <random> | 
|  | #include <vector> | 
|  |  | 
|  | #include <fbl/ref_ptr.h> | 
|  | #include <fbl/string_printf.h> | 
|  | #include <perftest/perftest.h> | 
|  |  | 
|  | #include "assert.h" | 
|  | #include "src/lib/fxl/strings/string_printf.h" | 
|  | #include "src/lib/storage/vfs/cpp/vfs.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}); | 
|  | } | 
|  |  | 
|  | fs::VdirCookie cookie; | 
|  | while (state->KeepRunning()) { | 
|  | 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 |