{-# LINE 1 "src/System/LibCPUID.hsc" #-}
-----------------------------------------------------------------------------
-- |
-- Module      :  System.LibCPUID
-- Copyright   :  (c) Daniel Taskoff, 2020
-- License     :  MIT
--
-- Maintainer  :  daniel.taskoff@gmail.com
-- Stability   :  experimental
--
-- Bindings to https://github.com/anrieff/libcpuid.
--
-- Currently implemented:
--
-- * getting CPU vendor and brand strings, TSC availability, number of physical, and logical cores
-- * measuring CPU clock frequency using a time-stamp counter and time intervals
-- * getting CPU clock frequency as reported by the OS
-- * measuring CPU clock frequency using a busy-wait cycle
-----------------------------------------------------------------------------

module System.LibCPUID
  (
  -- * LibCPUID utilities
    getTotalLogicalCores
  , clockByOS
  , clockMeasure, ShouldQuadCheck(..)
  , clock
  -- * Reexports from "System.LibCPUID.CPUID"
  , module System.LibCPUID.CPUID
  -- * Reexports from "System.LibCPUID.TSC"
  , module System.LibCPUID.TSC
  ) where

import Foreign.C.Types (CInt(..))
import System.LibCPUID.CPUID (CPUID(..), cpuid)
import System.LibCPUID.TSC (TSCMark, initialise, mark, unmark, clockBy)




-- | Get the total number of logical cores (even if CPUID is not present).
-- If CPUID is present, the following is true:
--
-- * @'getTotalLogicalCores' = 'totalLogicalCores' '<$>' 'cpuid'@
getTotalLogicalCores :: IO Int
getTotalLogicalCores = fromIntegral <$> c_cpuid_get_total_cpus

foreign import ccall "cpuid_get_total_cpus"
  c_cpuid_get_total_cpus :: IO CInt

-- | Get the CPU clock frequency in MHz, as reported by the OS (which may differ from the true clock).
-- If the OS is not supported, the result will be -1.
clockByOS :: IO Int
clockByOS = fromIntegral <$> c_cpu_clock_by_os

foreign import ccall "cpu_clock_by_os"
  c_cpu_clock_by_os :: IO CInt

-- | Get the CPU clock frequency in MHz, after performing a busy-wait cycle for the given time in ms.
-- If RDTSC is not supported, the result will be -1.
clockMeasure :: Int -> ShouldQuadCheck -> IO Int
clockMeasure time (ShouldQuadCheck shouldQuadCheck) =
  fromIntegral <$> c_cpu_clock_measure (fromIntegral time) if shouldQuadCheck then 1 else 0

-- | Should 'clockMeasure' do a more thorough measurement (quadruple checking).
newtype ShouldQuadCheck = ShouldQuadCheck Bool

foreign import ccall "cpu_clock_measure"
  c_cpu_clock_measure :: CInt -> CInt -> IO CInt

-- | Get the CPU clock frequency in MHz, by trying all available methods.
-- If all of them fail, the result will be -1.
clock :: IO Int
clock = fromIntegral <$> c_cpu_clock

foreign import ccall "cpu_clock"
  c_cpu_clock :: IO CInt