Commit 67b9e3e6 authored by Valentin Reis's avatar Valentin Reis
Browse files

Merge branch 'sensor-fix' into HEAD

parents 27b4a010 a08e1db9
Pipeline #11746 failed with stages
in 31 seconds
......@@ -48,7 +48,7 @@ foreign export ccall verbosityExport :: Ex
foreign export ccall logfileExport :: Ex
foreign export ccall activeSensorFrequencyExport :: Ex
foreign export ccall passiveSensorFrequencyExport :: Ex
foreign export ccall upstreamRpcAddressExport :: Ex
......@@ -88,7 +88,7 @@ verbosityExport = exportIO E.verbosity
logfileExport = exportIO E.logfile
activeSensorFrequencyExport = exportIO E.activeSensorFrequency
passiveSensorFrequencyExport = exportIO E.passiveSensorFrequency
upstreamRpcAddressExport = exportIO E.upstreamRpcAddress
......
......@@ -21,7 +21,7 @@ in { verbose = t.Verbosity.Error
}
, hwmonCfg = { hwmonEnabled = True, hwmonPath = "/sys/class/hwmon" }
, controlCfg = t.ControlCfg.ControlOff
, activeSensorFrequency.hertz = 1.0
, passiveSensorFrequency.hertz = 1.0
, extraStaticPassiveSensors = [] : List t.PassiveSensorKV
, extraStaticActuators = [] : List t.StaticActuatorKV
}
......
......@@ -102,6 +102,7 @@ let ControlCfg =
-- ControlOff: bypass mode
< ControlCfg :
{ minimumControlInterval : types.Time
, minimumWaitInterval : types.Time
, staticPower : types.Power
, learnCfg : LearnCfg
, speedThreshold : Double
......@@ -129,7 +130,7 @@ let Cfg =
, raplCfg : Optional RaplCfg
, hwmonCfg : Hwmon
, controlCfg : ControlCfg
, activeSensorFrequency : types.Frequency
, passiveSensorFrequency : types.Frequency
, extraStaticPassiveSensors : List PassiveSensorKV
, extraStaticActuators : List StaticActuatorKV
}
......
......@@ -9,12 +9,12 @@
-- Maintainer : fre@freux.fr
module CPD.Integrated
( Integrator (..),
IntegratorMeta (..),
IntegratorAction (..),
MeasurementState (..),
M (..),
trapezoidArea,
initIntegrator,
throughTuple,
measureValue,
squeeze,
averageArea,
......@@ -25,6 +25,7 @@ import CPD.Core
import Control.Lens
import qualified Data.Aeson as A
import Data.Data
import Data.Functor (($>))
import Data.Generics.Labels ()
import Data.JSON.Schema
import qualified Data.Map as M
......@@ -36,9 +37,16 @@ import Protolude
data Integrator
= Integrator
{ tLast :: Time,
minimumControlInterval :: Time,
measured :: Map SensorID (MeasurementState M)
{ meta :: IntegratorMeta,
measured :: Map SensorID (MeasurementState M) -- measurement states
}
deriving (Generic)
data IntegratorMeta
= IntegratorMeta
{ tLast :: Time, -- time the last control loop was finished (init time)
minimumWaitInterval :: Time, -- wait period between measurement periods
minimumControlInterval :: Time -- delta min for measurement period
}
deriving (Generic)
......@@ -84,13 +92,20 @@ trapezoidArea (t1, v1) (t2, v2) =
where
deltaT = fromuS (t2 - t1)
measureValue :: Time -> (Time, Double) -> MeasurementState M -> MeasurementState M
measureValue delta (newTime, newValue) = \case
Never -> Discarded
measureValue ::
IntegratorMeta ->
(Time, Double) ->
MeasurementState M ->
MeasurementState M
measureValue meta (newTime, newValue) = \case
Never ->
if minimumWaitInterval meta + tLast meta <= newTime
then Discarded
else Never
Discarded -> Running initial
Done m -> Done $ measure m
Running m ->
( if newTime >= delta + firstTime m
( if newTime >= minimumControlInterval meta + firstTime m
then Done
else Running
)
......@@ -114,26 +129,23 @@ averageArea M {firstTime, lastTime, lastValue, area} =
where
deltaT = fromuS (lastTime - firstTime)
-- | Tries to 'squeeze' the sensors for values. A squeeze is only successfull
-- if all sensors are in the Done state.
squeeze ::
Time ->
Map SensorID (MeasurementState M) ->
Maybe (Map SensorID Double, Map SensorID (MeasurementState M))
squeeze _t mstM =
case traverse throughTuple (M.toList mstM) of
case traverse sequenceA (M.toList mstM) of
Done (M.fromList -> m) -> Just (m <&> averageArea, m $> Never)
_ -> Nothing
throughTuple :: Functor f => (a, f b) -> f (a, b)
throughTuple (id, m) = (id,) <$> m
initIntegrator ::
Time ->
Time ->
IntegratorMeta ->
[SensorID] ->
Integrator
initIntegrator t tmin sensorIDs =
initIntegrator meta sensorIDs =
Integrator
{ tLast = t,
minimumControlInterval = tmin,
{ meta = meta,
measured = M.fromList (sensorIDs <&> (,Never))
}
......@@ -216,7 +216,7 @@ nrm _callTime (ChildDied pid exitcode) = do
put $
st
& #slices
. at sliceID
. at sliceID
?~ (slice & #cmds . at cmdID ?~ cmd {processState = newPstate})
nrm callTime (DownstreamEvent clientid msg) =
nrmDownstreamEvent callTime clientid msg
......@@ -266,10 +266,11 @@ doControl input = do
( M.toList (lenses st) ::
[(ActuatorKey, ScopedLens NRMState A.Actuator)]
)
<&> \(k, ScopedLens l) -> CPD.Action
{ actuatorID = toS k,
actuatorValue = CPD.DiscreteDouble $ st ^. l . #referenceAction
}
<&> \(k, ScopedLens l) ->
CPD.Action
{ actuatorID = toS k,
actuatorValue = CPD.DiscreteDouble $ st ^. l . #referenceAction
}
else Nothing
in banditCartesianProductControl ccfg cpd input mRefActions >>= \case
DoNothing -> pass
......@@ -392,8 +393,9 @@ nrmDownstreamEvent callTime clientid = \case
Just c -> do
put $
Just
( c & #downstreamCmds
. at downstreamCmdID
( c
& #downstreamCmds
. at downstreamCmdID
.~ Nothing
)
log "downstream cmd un-registered."
......@@ -411,8 +413,9 @@ nrmDownstreamEvent callTime clientid = \case
Just c -> do
put $
Just
( c & #downstreamThreads
. at downstreamThreadID
( c
& #downstreamThreads
. at downstreamThreadID
.~ Nothing
)
log "downstream thread un-registered."
......
......@@ -33,12 +33,15 @@ toCPD cfg st = Problem {..}
where
sensors = cpdSensors st
actuators = cpdActuators st
(objectives, constraints) = fromMaybe ([], []) (throughputConstrained <$> mcfg cfg <*> Just st)
(objectives, constraints) =
fromMaybe
([], [])
(throughputConstrained <$> mcfg cfg <*> Just st)
mcfg jc@ControlCfg {} = Just jc
mcfg _ = Nothing
-- | This problem generator produces a global energy minimization problem under a
-- throughput constraint.
-- | This problem generator produces a global energy minimization problem under
-- a throughput constraint.
throughputConstrained ::
-- | Control configuration
ControlCfg ->
......@@ -63,13 +66,21 @@ throughputConstrained cfg st =
normalizedSumSlowdown :: Maybe OExpr
normalizedSumSlowdown =
nonEmpty (M.toList constrained) <&> \(fmap fst -> ids) ->
thresholded 0.5 1.5 (coerce (foldMap (OExprSum . sID) ids) \/ (coerce (foldMap (OExprSum . sRef) ids) \+ scalar 1))
thresholded
0.5
1.5
( coerce (foldMap (OExprSum . sRef) ids)
\/ (coerce (foldMap (OExprSum . sID) ids) \+ scalar 1)
)
idsToMinimize :: Maybe (NonEmpty SensorID)
idsToMinimize = nonEmpty (fst <$> M.toList toMinimize)
toMinimize :: Map SensorID SensorMeta
toMinimize = M.filterWithKey (\_ m -> TagPower `elem` S.tags m) allSensorMeta
constrained :: Map SensorID SensorMeta
constrained = M.filterWithKey (\_ m -> DownstreamCmdSignal `elem` S.tags m) allSensorMeta
constrained =
M.filterWithKey
(\_ m -> DownstreamCmdSignal `elem` S.tags m)
allSensorMeta
allSensorMeta :: Map SensorID S.SensorMeta
allSensorMeta =
M.fromList
......@@ -81,7 +92,9 @@ throughputConstrained cfg st =
-- | produces a sum objective normalized by #sensors
addAll :: NonEmpty SensorID -> OExpr
addAll ss = coerce (foldMap (OExprSum . sID) ss) \/ (scalar . fromIntegral $ length ss)
addAll ss =
coerce (foldMap (OExprSum . sID) ss)
\/ (scalar . fromIntegral $ length ss)
-- | Subtract two objectives, defaulting to either of them
-- if one is absent.
......
......@@ -52,8 +52,8 @@ banditCartesianProductControl ::
ControlM Decision
banditCartesianProductControl ccfg cpd (Reconfigure t) _ = do
pub (UPub.PubCPD t cpd)
minTime <- use $ #integrator . #minimumControlInterval
#integrator .= initIntegrator t minTime (M.keys $ sensors cpd)
meta <- use $ #integrator . #meta
#integrator .= initIntegrator meta (M.keys $ sensors cpd)
case (CPD.Core.objectives cpd, M.toList (actuators cpd)) of
([], _) -> reset
(_, l) ->
......@@ -138,13 +138,12 @@ banditCartesianProductControl ccfg cpd (NoEvent t) mRefActions =
banditCartesianProductControl ccfg cpd (Event t ms) mRefActions = do
forM_ ms $ \m@(Measurement sensorID sensorValue sensorTime) -> do
log $ "Processing measurement " <> show m
#integrator %= \(Integrator tlast delta measuredM) ->
Integrator
tlast
delta
( measuredM
& ix sensorID
%~ measureValue delta (sensorTime, sensorValue)
#integrator
%= execState
( do
meta <- use #meta
#measured . ix sensorID
%= measureValue meta (sensorTime, sensorValue)
)
tryControlStep ccfg cpd t mRefActions
......@@ -206,6 +205,7 @@ wrappedCStep cc stepObjectives stepConstraints sensorRanges t mRefActions = do
Just (measurements, newMeasured) -> do
-- squeeze was successfull: setting the new integrator state
logInfo "control: integrator squeeze success"
#integrator . #meta . #tLast .= t
#integrator . #measured .= newMeasured
-- acquiring fields
(counter :: Refined NonNegative Int) <-
......
......@@ -11,7 +11,7 @@ module NRM.Export
verbosity,
showConfiguration,
C.logfile,
activeSensorFrequency,
passiveSensorFrequency,
upstreamPubAddress,
upstreamRpcAddress,
downstreamEventAddress,
......@@ -46,9 +46,9 @@ import qualified NRM.Types.Configuration as C
DaemonVerbosity (..),
DownstreamCfg (..),
UpstreamCfg (..),
activeSensorFrequency,
logfile,
toFrequency,
passiveSensorFrequency,
verbose,
)
import qualified NRM.Types.Messaging.UpstreamRep as URep
......@@ -65,8 +65,8 @@ parseDaemon :: [Text] -> IO C.Cfg
parseDaemon = O.parseArgDaemonCli
-- | Parses Daemon CLI arguments
activeSensorFrequency :: C.Cfg -> Double
activeSensorFrequency = fromHz . C.toFrequency . C.activeSensorFrequency
passiveSensorFrequency :: C.Cfg -> Double
passiveSensorFrequency = fromHz . C.toFrequency . C.passiveSensorFrequency
-- | Queries configuration for 'verbose' verbosity
verbosity :: C.Cfg -> Int
......
......@@ -11,7 +11,7 @@ module NRM.ExportIO
verbosity,
showConfiguration,
logfile,
activeSensorFrequency,
passiveSensorFrequency,
upstreamPubAddress,
upstreamRpcAddress,
downstreamEventAddress,
......@@ -45,8 +45,8 @@ verbosity = return . E.verbosity
logfile :: C.Cfg -> IO Text
logfile = return . E.logfile
activeSensorFrequency :: C.Cfg -> IO Double
activeSensorFrequency = return . E.activeSensorFrequency
passiveSensorFrequency :: C.Cfg -> IO Double
passiveSensorFrequency = return . E.passiveSensorFrequency
upstreamPubAddress :: C.Cfg -> IO Text
upstreamPubAddress = return . E.upstreamPubAddress
......
......@@ -19,6 +19,7 @@ module NRM.State
)
where
import CPD.Integrated as I
import Control.Lens
import Data.Map as M
import Data.Map.Merge.Lazy
......@@ -66,7 +67,7 @@ initialState c time = do
updater _pkgid package (packageRaplConfig, packageRaplDir) =
package
{ rapl = Just Rapl
{ frequency = hz 3,
{ frequency = Cfg.toFrequency $ Cfg.passiveSensorFrequency c,
raplCfg = packageRaplConfig,
maxEnergyCounterValue = packageRaplDir ^. #maxEnergy,
max = watts 150,
......@@ -93,8 +94,11 @@ initialState c time = do
ccfg ->
Just $
initialController
time
(Cfg.toTime $ Cfg.minimumControlInterval ccfg)
IntegratorMeta
{ tLast = time,
I.minimumWaitInterval = Cfg.toTime $ Cfg.minimumWaitInterval ccfg,
I.minimumControlInterval =Cfg.toTime $ Cfg.minimumControlInterval ccfg
}
[],
slices = M.fromList [],
pus = M.fromList $ (,PU) <$> selectPUIDs hwl,
......@@ -121,7 +125,7 @@ initialState c time = do
& M.fromList
)
<&> concretizeExtraPassiveSensor
(Cfg.toFrequency $ Cfg.activeSensorFrequency c),
(Cfg.toFrequency $ Cfg.passiveSensorFrequency c),
..
}
......@@ -129,12 +133,13 @@ concretizeExtraPassiveSensor ::
Frequency ->
Cfg.ExtraPassiveSensor ->
NRMState.ExtraPassiveSensor
concretizeExtraPassiveSensor f x = NRMState.ExtraPassiveSensor
{ NRMState.extraPassiveSensor = x,
NRMState.history = [],
NRMState.lastRead = Nothing,
NRMState.frequency = f
}
concretizeExtraPassiveSensor f x =
NRMState.ExtraPassiveSensor
{ NRMState.extraPassiveSensor = x,
NRMState.history = [],
NRMState.lastRead = Nothing,
NRMState.frequency = f
}
-- | Removes a slice from the state
removeSlice :: SliceID -> NRMState -> (Maybe Slice, NRMState)
......
......@@ -521,4 +521,4 @@ deriving via (GenericJSON Cfg) instance ToJSON Cfg
deriving via (GenericJSON Cfg) instance JSONSchema Cfg
jsonOptions :: Options
jsonOptions = defaultOptions {omitNothingFields = True}
jsonOptions = defaultOptions {omitNothingFields = False}
......@@ -156,13 +156,12 @@ enqueueAll =
(zipWithMatched $ \_ a abuffer -> enqueue a abuffer)
initialController ::
Time ->
Time ->
IntegratorMeta ->
[SensorID] ->
Controller
initialController time minTime sensorIDs =
initialController integratorMeta sensorIDs =
Controller
{ integrator = initIntegrator time minTime sensorIDs,
{ integrator = initIntegrator integratorMeta sensorIDs,
lastA = Nothing,
bandit = Nothing,
armstats = M.empty,
......@@ -320,6 +319,12 @@ deriving via (GenericJSON Integrator) instance A.ToJSON Integrator
deriving via (GenericJSON Integrator) instance A.FromJSON Integrator
deriving via (GenericJSON IntegratorMeta) instance JSONSchema IntegratorMeta
deriving via (GenericJSON IntegratorMeta) instance A.ToJSON IntegratorMeta
deriving via (GenericJSON IntegratorMeta) instance A.FromJSON IntegratorMeta
deriving instance Show Integrator
deriving instance MessagePack Integrator
......@@ -328,6 +333,14 @@ deriving instance FromDhall Integrator
deriving instance ToDhall Integrator
deriving instance Show IntegratorMeta
deriving instance MessagePack IntegratorMeta
deriving instance FromDhall IntegratorMeta
deriving instance ToDhall IntegratorMeta
deriving via (GenericJSON (Arms [Action])) instance JSONSchema (Arms [Action])
deriving via (GenericJSON (Arms [Action])) instance A.ToJSON (Arms [Action])
......
......@@ -75,7 +75,7 @@ instance Default Manifest where
V.Success a -> a
jsonOptions :: Options
jsonOptions = defaultOptions {omitNothingFields = True}
jsonOptions = defaultOptions {omitNothingFields = False}
instance MessagePack Integer where
......
......@@ -74,6 +74,9 @@ newtype Energy = Energy {fromuJ :: Double}
deriving (Eq, Ord, Generic, Data, Inject, Interpret, MessagePack)
deriving (Show, Num, JSONSchema, ToJSON, FromJSON) via Double
mil :: Double
mil = 1000000
-- | Microjoule value constructor.
progress :: Int -> Progress
progress = Progress
......@@ -84,11 +87,11 @@ uJ = Energy
-- | Joule value accessor.
fromJoules :: Energy -> Double
fromJoules = (/ 1000000) . fromuJ
fromJoules = (/ mil) . fromuJ
-- | Watt value constructor.
joules :: Double -> Energy
joules = Energy . (* 1000000.0)
joules = Energy . (* mil)
-- | Microwatt value constructor.
uW :: Double -> Power
......@@ -96,11 +99,11 @@ uW = Power
-- | Watt value accessor.
fromWatts :: Power -> Double
fromWatts = (/ 1000000) . fromuW
fromWatts = (/ mil) . fromuW
-- | Watt value constructor.
watts :: Double -> Power
watts = Power . (* 1000000.0)
watts = Power . (* mil)
-- | Microsecond value constructor.
uS :: Double -> Time
......@@ -108,10 +111,10 @@ uS = Time
-- | Second value constructor.
seconds :: Double -> Time
seconds = Time . (* 1000000)
seconds = Time . (* mil)
fromSeconds :: Time -> Double
fromSeconds (Time t) = t / 1000000
fromSeconds (Time t) = t / mil
-- | Hertz value constructor.
hz :: Double -> Frequency
......
......@@ -63,7 +63,7 @@ class Daemon(object):
# setup periodic sensor updates
self.sensor_cb = ioloop.PeriodicCallback(
self.wrap("doSensor"), 1000 / self.lib.activeSensorFrequency(self.cfg)
self.wrap("doSensor"), 1000 / self.lib.passiveSensorFrequency(self.cfg)
)
self.sensor_cb.start()
......
......@@ -42,5 +42,8 @@
"hwmonCfg": {
"hwmonPath": "/sys/class/hwmon",
"hwmonEnabled": true
},
"passiveSensorFrequency": {
"fromHz": 1
}
}
\ No newline at end of file
}
......@@ -911,8 +911,7 @@
},
"integrator": {
"required": [
"tLast",
"minimumControlInterval",
"meta",
"measured"
],
"type": "object",
......@@ -1010,11 +1009,24 @@
},
"type": "object"
},
"minimumControlInterval": {
"type": "number"
},
"tLast": {
"type": "number"
"meta": {
"required": [
"tLast",
"minimumWaitInterval",
"minimumControlInterval"
],
"type": "object",
"properties": {
"minimumWaitInterval": {
"type": "number"
},
"minimumControlInterval": {
"type": "number"
},
"tLast": {
"type": "number"
}
}
}
}
},
......
......@@ -1063,7 +1063,15 @@
"pmpi_lib",
"singularity",
"upstreamCfg",
<<<<<<< HEAD:resources/schemas/upstream-rep.json
"verbose"
=======
"hwmonCfg",
"controlCfg",
"passiveSensorFrequency",
"extraStaticPassiveSensors",
"extraStaticActuators"
>>>>>>> sensor-fix:hsnrm/resources/upstreamRep.json
],
"type": "object",
"properties": {
......@@ -1220,7 +1228,13 @@
"properties": {
"controlCfg": {
"required": [
<<<<<<< HEAD:resources/schemas/upstream-rep.json
"hint",
=======
"minimumControlInterval",
"minimumWaitInterval",
"staticPower",
>>>>>>> sensor-fix:hsnrm/resources/upstreamRep.json
"learnCfg",
"minimumControlInterval",
"referenceMeasurementRoundInterval",
......@@ -1232,6 +1246,9 @@
"referenceMeasurementRoundInterval": {
"type": "number"
},
"minimumWaitInterval": {
"type": "number"
},
"hint": {
"oneOf": [
{
......@@ -1399,11 +1416,19 @@
},
{
"required": [