// Copyright 2020 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 "ram-info.h"

#include <lib/fdio/fdio.h>
#include <stdlib.h>

#include <fbl/unique_fd.h>
#include <soc/aml-common/aml-ram.h>

namespace ram_metrics = ::llcpp::fuchsia::hardware::ram::metrics;

namespace {

// TODO(fxbug.dev/48254): Get default channel information through the FIDL API.

constexpr ram_info::RamDeviceInfo kDevices[] = {
    {
        // Astro
        .devfs_path = "/dev/sys/platform/05:03:24/ram",
        .default_cycles_to_measure = 456000000 / 20,  // 456 Mhz, 50 ms.
        .default_channels =
            {
                [0] = {.name = "cpu", .mask = aml_ram::kDefaultChannelCpu},
                [1] = {.name = "gpu", .mask = aml_ram::kDefaultChannelGpu},
                [2] = {.name = "vdec", .mask = aml_ram::kDefaultChannelVDec},
                [3] = {.name = "vpu", .mask = aml_ram::kDefaultChannelVpu},
            },
    },
    {
        // Sherlock
        .devfs_path = "/dev/sys/platform/05:04:24/ram",
        .default_cycles_to_measure = 792000000 / 20,  // 792 Mhz, 50 ms.
        .default_channels =
            {
                [0] = {.name = "cpu", .mask = aml_ram::kDefaultChannelCpu},
                [1] = {.name = "gpu", .mask = aml_ram::kDefaultChannelGpu},
                [2] = {.name = "vdec", .mask = aml_ram::kDefaultChannelVDec},
                [3] = {.name = "vpu", .mask = aml_ram::kDefaultChannelVpu},
            },
    },
};

double CounterToBandwidthMBs(uint64_t cycles, uint64_t frequency, uint64_t cycles_measured,
                             uint64_t bytes_per_cycle) {
  double bandwidth_rw = static_cast<double>(cycles * frequency * bytes_per_cycle);
  bandwidth_rw /= static_cast<double>(cycles_measured);
  bandwidth_rw /= 1024.0 * 1024.0;
  return bandwidth_rw;
}

}  // namespace

namespace ram_info {

void DefaultPrinter::Print(const ram_metrics::BandwidthInfo& info) const {
  fprintf(file_, "channel \t\t usage (MB/s)  time: %lu ms\n", info.timestamp / ZX_MSEC(1));
  size_t ix = 0;
  double total_bandwidth_rw = 0;
  for (const auto& row : rows_) {
    if (row.empty()) {
      continue;
    }
    // We discard read-only and write-only counters as they are not supported
    // by current hardware.
    double bandwidth_rw = CounterToBandwidthMBs(info.channels[ix].readwrite_cycles, info.frequency,
                                                cycles_to_measure_, info.bytes_per_cycle);
    total_bandwidth_rw += bandwidth_rw;
    fprintf(file_, "%s (rw) \t\t %g\n", row.c_str(), bandwidth_rw);
    ++ix;
  }
  // Use total read-write cycles if supported.
  if (info.total.readwrite_cycles) {
    total_bandwidth_rw = CounterToBandwidthMBs(info.total.readwrite_cycles, info.frequency,
                                               cycles_to_measure_, info.bytes_per_cycle);
  }
  fprintf(file_, "total (rw) \t\t %g\n", total_bandwidth_rw);
}

void CsvPrinter::Print(const ram_metrics::BandwidthInfo& info) const {
  size_t row_count = 0;
  for (const auto& row : rows_) {
    if (!row.empty()) {
      row_count++;
    }
  }

  fprintf(file_, "time,");

  size_t ix = 0;
  for (const auto& row : rows_) {
    if (row.empty()) {
      continue;
    }

    fprintf(file_, "\"%s\"%s", row.c_str(), (ix < row_count - 1) ? "," : "");
    ix++;
  }

  fprintf(file_, "\n%lu,", info.timestamp / ZX_MSEC(1));

  ix = 0;
  for (const auto& row : rows_) {
    if (row.empty()) {
      continue;
    }

    double bandwidth_rw = CounterToBandwidthMBs(info.channels[ix].readwrite_cycles, info.frequency,
                                                cycles_to_measure_, info.bytes_per_cycle);
    fprintf(file_, "%g%s", bandwidth_rw, (ix < row_count - 1) ? "," : "\n");
    ix++;
  }
}

zx::status<std::array<uint64_t, ram_metrics::MAX_COUNT_CHANNELS>> ParseChannelString(
    std::string_view str) {
  if (str[0] == '\0') {
    return zx::error(ZX_ERR_INVALID_ARGS);
  }

  std::array<uint64_t, ram_metrics::MAX_COUNT_CHANNELS> channels = {};
  std::string_view next_channel = str;

  for (uint64_t& channel : channels) {
    errno = 0;
    char* endptr;
    channel = strtoul(next_channel.data(), &endptr, 0);
    if (endptr > &(*next_channel.cend())) {
      return zx::error_status(ZX_ERR_BAD_STATE);
    }

    next_channel = endptr;

    if (channel == ULONG_MAX && errno == ERANGE) {
      return zx::error(ZX_ERR_OUT_OF_RANGE);
    }

    if (next_channel[0] == '\0') {
      break;
    }

    // Only a comma separator is allowed.
    if (next_channel[0] != ',') {
      return zx::error_status(ZX_ERR_INVALID_ARGS);
    }

    next_channel = next_channel.data() + 1;
  }

  // Make sure there are no trailing characters.
  if (next_channel[0] != '\0') {
    return zx::error_status(ZX_ERR_INVALID_ARGS);
  }

  return zx::ok(channels);
}

std::tuple<zx::channel, ram_info::RamDeviceInfo> ConnectToRamDevice() {
  for (const auto& info : kDevices) {
    fbl::unique_fd fd(open(info.devfs_path, O_RDWR));
    if (fd.get() <= -1) {
      continue;
    }

    zx::channel handle;
    zx_status_t status = fdio_get_service_handle(fd.release(), handle.reset_and_get_address());
    if (status == ZX_OK) {
      return {std::move(handle), info};
    }
  }

  return {};
}

zx_status_t MeasureBandwith(const Printer* const printer, zx::channel channel,
                            const ram_metrics::BandwidthMeasurementConfig& config) {
  ram_metrics::Device::SyncClient client{std::move(channel)};
  auto info = client.MeasureBandwidth(config);
  if (!info.ok()) {
    return info.status();
  }
  if (info->result.is_err()) {
    return info->result.err();
  }

  printer->Print(info->result.response().info);
  return ZX_OK;
}

zx_status_t GetDdrWindowingResults(zx::channel channel) {
  ram_metrics::Device::SyncClient client{std::move(channel)};
  auto info = client.GetDdrWindowingResults();
  if (!info.ok()) {
    return info.status();
  }
  if (info->result.is_err()) {
    return info->result.err();
  }

  printf("register value: 0x%x\n", info->result.response().value);
  return ZX_OK;
}

}  // namespace ram_info
