packages feed

moonlight-triangulation-0.1.0.0: src-dcel/Moonlight/Triangulation/Internal/Probe.hs

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeFamilyDependencies #-}
{-# LANGUAGE TypeOperators #-}

-- | Compile-time instrumentation switch. The bulk board is the measuring
-- instrument, so per-candidate probe counters must not exist on its path at
-- all: gating behind a flag the compiler can eliminate is the only honest way
-- to have both one sweep implementation and an undistorted measurement. The
-- flag is a type, not a value: at 'ProbeOff the counter type is @()@, so no
-- arithmetic on it can survive in the worker — erasure is a property of the
-- kind, not of the optimizer's mood. The instrumented entry instantiates the
-- same code at 'ProbeOn and pays the cold counter writes itself.
module Moonlight.Triangulation.Internal.Probe
  ( Probe (..)
  , ProbeCounter
  , KnownProbe (..)
  ) where

import Control.Monad.ST (ST)
import Data.Kind (Type)
import Moonlight.Triangulation.Internal.OperationState
  ( Counter
  , OperationState
  , addCounter
  )

-- | The instrumentation switch, promoted to a kind by @DataKinds@.
data Probe = ProbeOff | ProbeOn

-- | The counter a probe site threads. At 'ProbeOff there is nothing to
-- thread; at 'ProbeOn it is a strict @Int@.
type family ProbeCounter (probe :: Probe) = (counter :: Type) | counter -> probe where
  ProbeCounter 'ProbeOff = ()
  ProbeCounter 'ProbeOn = Int

class KnownProbe probe where
  probeZero :: ProbeCounter probe
  probeBump :: ProbeCounter probe -> ProbeCounter probe
  -- | Charge one finished counter to the operation's diagnostic cell. At
  -- 'ProbeOff this is @pure ()@ and disappears with the dictionary; at
  -- 'ProbeOn it is one cold vector write per drain or probe site, on the
  -- instrumented entry that asked for it.
  probeCharge :: OperationState s -> Counter -> ProbeCounter probe -> ST s ()

instance KnownProbe 'ProbeOff where
  probeZero = ()
  probeBump = id
  probeCharge _ _ _ = pure ()
  {-# INLINE probeZero #-}
  {-# INLINE probeBump #-}
  {-# INLINE probeCharge #-}

instance KnownProbe 'ProbeOn where
  probeZero = 0
  probeBump counter = counter + 1
  probeCharge operation counter value = addCounter operation counter value
  {-# INLINE probeZero #-}
  {-# INLINE probeBump #-}
  {-# INLINE probeCharge #-}