Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cardano-node/cardano-node.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ library
Cardano.Node.TraceConstraints
Cardano.Node.Tracing
Cardano.Node.Tracing.API
Cardano.Node.Tracing.Cdf
Cardano.Node.Tracing.Consistency
Cardano.Node.Tracing.DefaultTraceConfig
Cardano.Node.Tracing.Documentation
Expand Down
106 changes: 106 additions & 0 deletions cardano-node/src/Cardano/Node/Tracing/Cdf.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ScopedTypeVariables #-}

-- | CDFs
--
-- This module should be imported qualified.
--
module Cardano.Node.Tracing.Cdf
( Counter (..)
, Config (..)
, State
, size
, null
, empty
, minPriority
, defaultConfig
, processDataPoint
) where

import Prelude hiding (null)
import Data.Int (Int64)
import Data.IntPSQ (IntPSQ)
import qualified Data.IntPSQ as Pq
import Data.Time (NominalDiffTime)

data Counter = Counter {
limit :: !Double
, counter :: !Int64
}

decCdf :: Double -> Counter -> Counter
decCdf v cdf@Counter{..}
| v < limit = cdf {counter = counter - 1}
| otherwise = cdf

incCdf :: Double -> Counter -> Counter
incCdf v cdf@Counter{..}
| v < limit = cdf {counter = counter + 1}
| otherwise = cdf


newtype State p = State { cdfState :: IntPSQ p NominalDiffTime }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a comment explaining why a Cdf needs a notion of priority?


empty :: State p
empty = State Pq.empty

null :: State p -> Bool
null = Pq.null . cdfState

size :: State p -> Int
size = Pq.size . cdfState

minPriority :: Ord p => State p -> Maybe p
minPriority State { cdfState } = case Pq.minView cdfState of
Nothing -> Nothing
Just (_, p, _, _) -> Just p

data Config = Config { numOfDataPoints :: Int }

Check warning on line 59 in cardano-node/src/Cardano/Node/Tracing/Cdf.hs

View workflow job for this annotation

GitHub Actions / build

Suggestion in Config in module Cardano.Node.Tracing.Cdf: Use newtype instead of data ▫︎ Found: "data Config = Config {numOfDataPoints :: Int}" ▫︎ Perhaps: "newtype Config = Config {numOfDataPoints :: Int}" ▫︎ Note: decreases laziness

-- | Default `Config` keeps `k/2` data points.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The proportionality to k is easier to justify for some CDFs than for others, but it's probably fine for most?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But one other option is to just force each callers to choose a number

defaultConfig :: Config
defaultConfig = Config { numOfDataPoints = 1080 }


processDataPoint
:: forall f p.
( Ord p
, Functor f
)
=> Config
-> (Int, p, NominalDiffTime)
-- ^ index, priority, value
-> State p
-> f Counter
-> (f Counter, State p, Bool)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple questions that a comment should answer:

  • What does the Bool mean?
  • Why do we need to maintain the Counter and the State as separate things?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's only two call sites to this function and they both ignore the return value when the returned Bool is False.

So return Maybe (f Counter, State p) instead?

processDataPoint Config { numOfDataPoints } (idx, p, delay) s@(State m) cdfs
| idx `Pq.member` m
= nothingToDo

| otherwise
= if Pq.size m' > numOfDataPoints
then
case Pq.minView m' of
Nothing -> (cdfs, s, False)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use nothingToDo here too?

Just (_, minVal, minDelay, m'')
| minVal == p
-> nothingToDo

| otherwise
-> (adjustCdf (realToFrac minDelay) <$> cdfs, State m'', True)
else
(updateCdf <$> cdfs, State m', True)
where
nothingToDo = (cdfs, s, False)

delay_ :: Double

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just inline this as (realToFrac delay :: Double)?

delay_ = realToFrac delay

m' = Pq.insert idx p delay m

updateCdf :: Counter -> Counter
updateCdf = incCdf delay_

adjustCdf :: Double -> Counter -> Counter
adjustCdf d = updateCdf . decCdf d
12 changes: 12 additions & 0 deletions cardano-node/src/Cardano/Node/Tracing/Tracers.hs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ import qualified Ouroboros.Network.BlockFetch.ClientState as BlockFetch
import Ouroboros.Network.ConnectionId (ConnectionId)
import qualified Ouroboros.Network.Diffusion as Diffusion

import LeiosDemoTypes (TraceLeiosKernel (..))

import Codec.CBOR.Read (DeserialiseFailure)
import Control.Monad (unless)
import "contra-tracer" Control.Tracer (mkTracer)
Expand Down Expand Up @@ -360,6 +362,15 @@ mkConsensusTracers configReflection trBase trForward mbTrEKG _trDataPoint trConf
["Consensus", "LeiosKernel"]
configureTracers configReflection trConfig [leiosKernelTr]

!leiosMetricsTr <- do

@nfrisby nfrisby Aug 5, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 Matches the extant pattern, eg:

-- Special blockFetch client metrics, send directly to EKG
!blockFetchClientMetricsTr <- do
tr1 <- foldTraceM (\cm lc -> pure . calculateBlockFetchClientMetrics cm lc) initialClientMetrics
(metricsFormatter
(mkMetricsTracer mbTrEKG))
pure $ filterTrace (\ (_, TraceLabelPeer _ m) -> case m of
BlockFetch.CompletedBlockFetch {} -> True
_ -> False)
tr1

tr1 <- foldTraceM (\cm lc -> pure . calculateLeiosMetrics cm lc) initialLeiosMetrics
(metricsFormatter
(mkMetricsTracer mbTrEKG))
pure $ filterTrace (\(_, msg) -> case msg of
TraceLeiosAnnouncementAccepted{} -> True
_ -> False)
tr1

!leiosPeerTr <- mkCardanoTracer
trBase trForward mbTrEKG
["Consensus", "LeiosPeer"]
Expand Down Expand Up @@ -421,6 +432,7 @@ mkConsensusTracers configReflection trBase trForward mbTrEKG _trDataPoint trConf
traceWith txCountersTracer
, Consensus.leiosKernelTracer = mkTracer $
traceWith leiosKernelTr
<> traceWith leiosMetricsTr
, Consensus.leiosPeerTracer = mkTracer $
traceWith leiosPeerTr
}
Expand Down
Loading
Loading