/*
 * Copyright 2020 Bloomberg Finance LP
 *
 * 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 <buildboxcommon_fslocalcas.h>

#include <buildboxcommon_digestgenerator.h>
#include <buildboxcommon_temporarydirectory.h>

#include <ctime>
#include <random>

using namespace buildboxcommon;

class FsLocalCasFixture : public benchmark::Fixture {
  protected:
    FsLocalCasFixture() : fs_local_cas(storage_root.name()), rng(rd()) {}

    Digest generateRandomDigest()
    {
        return DigestGenerator::hash("Blob #" +
                                     std::to_string(distributed(rng)));
    }

    TemporaryDirectory storage_root;
    FsLocalCas fs_local_cas;

  private:
    std::random_device rd;
    std::mt19937 rng;
    std::uniform_int_distribution<int> distributed;
};

BENCHMARK_DEFINE_F(FsLocalCasFixture, HasMissingBlobRandomDigests)
(benchmark::State &state)
{
    for (auto _ : state) {
        (void)_;
        state.PauseTiming();
        const Digest digest = generateRandomDigest();
        state.ResumeTiming();

        fs_local_cas.hasBlob(digest);
    }
}

BENCHMARK_DEFINE_F(FsLocalCasFixture, ReadMissingBlobRandomDigests)
(benchmark::State &state)
{
    for (auto _ : state) {
        (void)_;
        state.PauseTiming();
        const Digest digest = generateRandomDigest();
        state.ResumeTiming();

        fs_local_cas.readBlob(digest);
    }
}

BENCHMARK_DEFINE_F(FsLocalCasFixture, HasMissingBlobFixedDigest)
(benchmark::State &state)
{
    const Digest digest = generateRandomDigest();

    for (auto _ : state) {
        (void)_;
        fs_local_cas.hasBlob(digest);
    }
}

BENCHMARK_DEFINE_F(FsLocalCasFixture, ReadMissingBlobFixedDigest)
(benchmark::State &state)
{
    const Digest digest = generateRandomDigest();

    for (auto _ : state) {
        (void)_;
        fs_local_cas.readBlob(digest);
    }
}

int main(int argc, char **argv)
{
    // Don't use BENCHMARK_REGISTER_F macro outside main() to
    // avoid static initialization order fiasco.
    // https://github.com/google/benchmark/issues/498

    BENCHMARK_REGISTER_F(FsLocalCasFixture, HasMissingBlobRandomDigests)
        ->Unit(benchmark::kMicrosecond);

    BENCHMARK_REGISTER_F(FsLocalCasFixture, HasMissingBlobFixedDigest)
        ->Unit(benchmark::kMicrosecond);

    BENCHMARK_REGISTER_F(FsLocalCasFixture, ReadMissingBlobRandomDigests)
        ->Unit(benchmark::kMicrosecond);

    BENCHMARK_REGISTER_F(FsLocalCasFixture, ReadMissingBlobFixedDigest)
        ->Unit(benchmark::kMicrosecond);

    benchmark::Initialize(&argc, argv);
    if (benchmark::ReportUnrecognizedArguments(argc, argv)) {
        return 1;
    }

    benchmark::RunSpecifiedBenchmarks();
}
