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

import logging
import platform
import re

from telemetry import decorators
from telemetry.internal.platform import power_monitor


MSR_RAPL_POWER_UNIT = 0x606
MSR_PKG_ENERGY_STATUS = 0x611  # Whole package
MSR_PP0_ENERGY_STATUS = 0x639  # Core
MSR_PP1_ENERGY_STATUS = 0x641  # Uncore
MSR_DRAM_ENERGY_STATUS = 0x619
IA32_PACKAGE_THERM_STATUS = 0x1b1
IA32_TEMPERATURE_TARGET = 0x1a2


def _JoulesToMilliwattHours(value_joules):
  return value_joules * 1000 / 3600.


def _IsSandyBridgeOrLater(vendor, family, model):
  # Model numbers from:
  # https://software.intel.com/en-us/articles/intel-architecture-and-processor-identification-with-cpuid-model-and-family-numbers
  # http://www.speedtraq.com
  return ('Intel' in vendor and family == 6 and
          (model in (0x2A, 0x2D) or model >= 0x30))


class MsrPowerMonitor(power_monitor.PowerMonitor):
  def __init__(self, backend):
    super(MsrPowerMonitor, self).__init__()
    self._backend = backend
    self._start_energy_j = None
    self._start_temp_c = None

  def CanMonitorPower(self):
    raise NotImplementedError()

  def StartMonitoringPower(self, browser):
    assert self._start_energy_j is None and self._start_temp_c is None, (
        'Called StartMonitoringPower() twice.')
    self._start_energy_j = self._PackageEnergyJoules()
    self._start_temp_c = self._TemperatureCelsius()

  def StopMonitoringPower(self):
    assert not(self._start_energy_j is None or self._start_temp_c is None), (
        'Called StopMonitoringPower() before StartMonitoringPower().')

    energy_consumption_j = self._PackageEnergyJoules() - self._start_energy_j
    average_temp_c = (self._TemperatureCelsius() + self._start_temp_c) / 2.
    if energy_consumption_j < 0:  # Correct overflow.
      # The energy portion of the MSR is 4 bytes.
      energy_consumption_j += 2 ** 32 * self._EnergyMultiplier()

    self._start_energy_j = None
    self._start_temp_c = None

    return {
        'identifier': 'msr',
        'energy_consumption_mwh': _JoulesToMilliwattHours(energy_consumption_j),
        'platform_info': {
            'average_temperature_c': average_temp_c,
        },
    }

  @decorators.Cache
  def _EnergyMultiplier(self):
    return 0.5 ** self._backend.ReadMsr(MSR_RAPL_POWER_UNIT, 8, 5)

  def _PackageEnergyJoules(self):
    return (self._backend.ReadMsr(MSR_PKG_ENERGY_STATUS, 0, 32) *
            self._EnergyMultiplier())

  def _TemperatureCelsius(self):
    tcc_activation_temp = self._backend.ReadMsr(IA32_TEMPERATURE_TARGET, 16, 7)
    if tcc_activation_temp <= 0:
      tcc_activation_temp = 105
    package_temp_headroom = self._backend.ReadMsr(
        IA32_PACKAGE_THERM_STATUS, 16, 7)
    return tcc_activation_temp - package_temp_headroom

  def _CheckMSRs(self):
    try:
      if self._PackageEnergyJoules() <= 0:
        logging.info('Cannot monitor power: no energy readings.')
        return False

      if self._TemperatureCelsius() <= 0:
        logging.info('Cannot monitor power: no temperature readings.')
        return False
    except OSError as e:
      logging.info('Cannot monitor power: %s' % e)
      return False
    return True


class MsrPowerMonitorLinux(MsrPowerMonitor):
  def CanMonitorPower(self):
    vendor = None
    family = None
    model = None
    cpuinfo = open('/proc/cpuinfo').read().splitlines()
    for line in cpuinfo:
      if vendor and family and model:
        break
      if line.startswith('vendor_id'):
        vendor = line.split('\t')[1]
      elif line.startswith('cpu family'):
        family = int(line.split(' ')[2])
      elif line.startswith('model\t\t'):
        model = int(line.split(' ')[1])
    if not _IsSandyBridgeOrLater(vendor, family, model):
      logging.info('Cannot monitor power: pre-Sandy Bridge CPU.')
      return False

    if not self._CheckMSRs():
      logging.info('Try running tools/telemetry/build/linux_setup_msr.py.')
      return False

    return True


class MsrPowerMonitorWin(MsrPowerMonitor):
  def CanMonitorPower(self):
    family, model = map(int, re.match('.+ Family ([0-9]+) Model ([0-9]+)',
                        platform.processor()).groups())
    if not _IsSandyBridgeOrLater(platform.processor(), family, model):
      logging.info('Cannot monitor power: pre-Sandy Bridge CPU.')
      return False

    msr_return_value = self._CheckMSRs()
    # Since _CheckMSRs() starts the MSR server on win platform, we must close
    # it after checking to avoid leaking msr server process.
    self._backend.CloseMsrServer()
    return msr_return_value


  def StopMonitoringPower(self):
    power_statistics = super(MsrPowerMonitorWin, self).StopMonitoringPower()
    self._backend.CloseMsrServer()
    return power_statistics
