// Copyright 2017 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 "garnet/bin/cpuperf_provider/app.h"

#include <iostream>
#include <limits>
#include <memory>

#include <lib/async/default.h>

#include "garnet/bin/cpuperf_provider/categories.h"
#include "garnet/bin/cpuperf_provider/importer.h"
#include "garnet/lib/cpuperf/controller.h"
#include "garnet/lib/cpuperf/reader.h"
#include "lib/fxl/command_line.h"
#include "lib/fxl/logging.h"
#include "lib/fxl/strings/string_number_conversions.h"

namespace cpuperf_provider {

namespace {

// If only fxl string/number conversions supported 0x.

bool ParseNumber(const char* name, const fxl::StringView& arg,
                 uint64_t* value) {
  if (arg.size() > 2 && arg[0] == '0' && (arg[1] == 'x' || arg[1] == 'X')) {
    if (!fxl::StringToNumberWithError<uint64_t>(arg.substr(2), value,
                                                fxl::Base::k16)) {
      FXL_LOG(ERROR) << "Invalid value for " << name << ": " << arg;
      return false;
    }
  } else {
    if (!fxl::StringToNumberWithError<uint64_t>(arg, value)) {
      FXL_LOG(ERROR) << "Invalid value for " << name << ": " << arg;
      return false;
    }
  }
  return true;
}

}  // namespace

App::App(const fxl::CommandLine& command_line)
    : startup_context_(component::StartupContext::CreateFromStartupInfo()) {
  if (command_line.HasOption("help")) {
    PrintHelp();
    exit(EXIT_SUCCESS);
  }

  std::string buffer_size_as_string;
  if (command_line.GetOptionValue("buffer-size", &buffer_size_as_string)) {
    uint64_t buffer_size;
    if (!ParseNumber("buffer-size", buffer_size_as_string, &buffer_size))
      exit(EXIT_FAILURE);
    if (buffer_size == 0) {
      FXL_LOG(ERROR) << "Buffer size cannot be zero";
      exit(EXIT_FAILURE);
    }
    if (buffer_size > kMaxBufferSizeInMb) {
      FXL_LOG(ERROR) << "Buffer size too large, max " << kMaxBufferSizeInMb;
      exit(EXIT_FAILURE);
    }
    buffer_size_in_mb_ = static_cast<uint32_t>(buffer_size);
  }

  trace_observer_.Start(async_get_default_dispatcher(),
                        [this] { UpdateState(); });
}

App::~App() {}

void App::PrintHelp() {
  std::cout << "cpuperf_provider [options]" << std::endl;
  std::cout << "Options:" << std::endl;
  std::cout << "  --help: Produce this help message" << std::endl;
  std::cout << "  --buffer-size=<size>: Trace data buffer size (MB) [default="
            << kDefaultBufferSizeInMb << "]" << std::endl;
}

void App::UpdateState() {
  if (trace_state() == TRACE_STARTED) {
    TraceConfig config;
    config.Update();
    if (trace_config_.Changed(config)) {
      StopTracing();
      if (config.is_enabled())
        StartTracing(config);
    }
  } else {
    StopTracing();
  }
}

void App::StartTracing(const TraceConfig& trace_config) {
  FXL_DCHECK(trace_config.is_enabled());
  FXL_DCHECK(!context_);
  FXL_DCHECK(!controller_);

  cpuperf_config_t device_config;
  if (!trace_config.TranslateToDeviceConfig(&device_config)) {
    FXL_LOG(ERROR) << "Error converting trace config to device config";
    return;
  }

  std::unique_ptr<cpuperf::Controller> controller;
  if (!cpuperf::Controller::Create(buffer_size_in_mb_, device_config,
                                   &controller)) {
    FXL_LOG(ERROR) << "Cpuperf controller failed to initialize";
    return;
  }

  context_ = trace_acquire_prolonged_context();
  if (!context_) {
    // Tracing was disabled in the meantime.
    return;
  }

  FXL_VLOG(1) << "Starting trace, config = " << trace_config.ToString();

  start_time_ = zx_ticks_get();
  if (!controller->Start())
    goto Fail;

  FXL_LOG(INFO) << "Started tracing";
  trace_config_ = trace_config;
  controller_.reset(controller.release());
  return;

Fail:
  trace_release_prolonged_context(context_);
  context_ = nullptr;
}

void App::StopTracing() {
  if (!context_) {
    return;  // not currently tracing
  }
  FXL_DCHECK(trace_config_.is_enabled());

  FXL_LOG(INFO) << "Stopping trace";

  controller_->Stop();

  stop_time_ = zx_ticks_get();

  // Acquire a context for writing to the trace buffer.
  auto buffer_context = trace_acquire_context();

  auto reader = controller_->GetReader();
  if (reader) {
    Importer importer(buffer_context, &trace_config_, start_time_, stop_time_);
    if (!importer.Import(*reader)) {
      FXL_LOG(ERROR) << "Errors encountered while importing cpuperf data";
    }
  } else {
    FXL_LOG(ERROR) << "Unable to initialize reader";
  }

  trace_release_context(buffer_context);
  trace_release_prolonged_context(context_);
  context_ = nullptr;
  trace_config_.Reset();
  controller_.reset();
}

}  // namespace cpuperf_provider
