Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
NanuIjaz committed Jan 13, 2024
2 parents 0d2800c + 072ae58 commit 6466d21
Show file tree
Hide file tree
Showing 28 changed files with 3,169 additions and 945 deletions.
9 changes: 8 additions & 1 deletion .github/workflows/haskell.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,16 @@ jobs:
strategy:
fail-fast: false
matrix:
# If you edit these versions, make sure the version in the lonely macos-latest job below is updated accordingly
ghc: ["9.2.8", "9.6.3"]
cabal: ["3.10.2.1"]
os: [macos-latest, windows-latest, ubuntu-latest]
os: [windows-latest, ubuntu-latest]
include:
# Using include, to make sure only be one macOS job, even if the matrix gets expanded later on.
# We want a single job, because macOS runners are scarce.
- os: macos-latest
cabal: "3.10.2.1"
ghc: "9.6.3"

env:
# Modify this value to "invalidate" the cabal cache.
Expand Down
197 changes: 197 additions & 0 deletions bench/cardano-topology/app/cardano-topology.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TupleSections #-}
{-# OPTIONS_GHC -Wno-partial-fields -Wno-name-shadowing #-}

{- HLINT ignore "Redundant id" -}
{- HLINT ignore "Use concatMap" -}

--------------------------------------------------------------------------------

import Prelude hiding (id)

import qualified Data.Aeson as Aeson
import qualified Data.ByteString.Lazy.Char8 as LBS
import qualified Data.GraphViz as G
import qualified Data.GraphViz.Attributes.Complete as G
import qualified Data.GraphViz.Printing as G
import qualified Data.Text.Lazy.IO as T
import Options.Applicative

import qualified Cardano.Benchmarking.Topology as Topo

--------------------------------------------------------------------------------

main :: IO ()
main = do
(coreNodesParams, topoJson, topoDot, withExplorer) <- execParser cliOpts
let cores = Topo.mkCoreNodes coreNodesParams
relays = [
Topo.mkExplorer (Topo.AWS Topo.EU_CENTRAL_1) cores
| withExplorer
]
writeTopo cores relays topoJson
maybe (pure ()) (writeDot cores) topoDot

--------------------------------------------------------------------------------

-- | Locations from the CLI are parsed first using the "legacy mode" for
-- backward compatiblity, in this mode locations have a default AWS region that
-- are the ones cardano-ops is using. The new format is either "loopback" or a
-- supported AWS Region.
cliLocation :: String -> Either String Topo.Location
cliLocation = \case
-- Legacy mode.
"LO" -> Right Topo.Loopback
"AP" -> Right (Topo.AWS Topo.AP_SOUTHEAST_2)
"EU" -> Right (Topo.AWS Topo.EU_CENTRAL_1)
"US" -> Right (Topo.AWS Topo.US_EAST_2)
-- New format.
str -> Aeson.eitherDecode
-- Make the string JSON valid by enclosing it with quotes.
(LBS.pack $ "\"" ++ str ++ "\"")


cliOpts :: ParserInfo (Topo.CoreNodesParams, FilePath, Maybe FilePath, Bool)
cliOpts = info (cliParser <**> helper)
( fullDesc
<> progDesc "Cardano topology generator"
<> header "make-topology - generate Cardano node topologies" )
where
cliParser :: Parser (Topo.CoreNodesParams, FilePath, Maybe FilePath, Bool)
cliParser =
(,,,)
<$> subparser coreNodesParamsParser
<*> strOption
( long "topology-output"
<> help "Topology file to write"
<> metavar "OUTFILE" )
<*> optional
(strOption
( long "dot-output"
<> help "Dot file to write"
<> metavar "OUTFILE" ))
<*> flag False True
( long "with-explorer"
<> help "Add an explorer to the topology")

coreNodesParamsParser =
command "line"
(info
(Topo.Line
<$> parseSize
<*> parseLocation
<*> parseRoleSelector)
(progDesc "Line"
<> fullDesc
<> header "Generate a line topology"))
<>
command "uni-circle"
(info
(Topo.UniCircle
<$> parseSize
<*> parseLocation
<*> parseRoleSelector)
(progDesc "Unidirectional circle"
<> fullDesc
<> header "Generate a unidirectional circle topology"))
<>
command "torus"
(info
(Topo.Torus
<$> parseSize
<*> some parseLocation
<*> parseRoleSelector)
(progDesc "Toroidal mesh"
<> fullDesc
<> header "Generate a toroidal mesh topology"))
<>
command "torus-dense"
(info
(Topo.TorusDense
<$> parseSize
<*> some parseLocation
<*> parseRoleSelector)
(progDesc "Toroidal mesh (dense)"
<> fullDesc
<> header "Generate a toroidal mesh topology (dense)"))

parseSize =
option auto
( long "size"
<> metavar "SIZE"
<> help "Node count" )

parseLocation =
option (eitherReader cliLocation)
( long "loc"
<> help "Region (at least one)"
<> metavar "LOCNAME" )

parseRoleSelector =
roleSelector <$>
flag False True
( long "with-bft-node-0"
<> help "Include a BFT node-0")

roleSelector withBft = \case
-- TODO: prepare for deprecation of BFT nodes by switching 1 & 0
1 -> Just 1 -- Normal pools are just that -- a single pool
0 -> if withBft
then Nothing -- The BFT node has no pools
else Just 1 -- Dense pools are denoted by any amount >1
_ -> Just 2

--------------------------------------------------------------------------------

--- * To JSON topology
---
writeTopo :: [Topo.Node] -> [Topo.Node] -> FilePath -> IO ()
writeTopo cores relays f = Aeson.encodeFile f (Topo.Topology cores relays)

--------------------------------------------------------------------------------

--- * To Graphviz
---
writeDot :: [Topo.Node] -> FilePath -> IO ()
writeDot topo f =
T.writeFile f $
G.renderDot $ G.toDot $
uncurry (G.graphElemsToDot params) (toGV topo)
where
params = G.nonClusteredParams
{ G.globalAttributes =
[ G.GraphAttrs
[G.Scale $ G.DVal 5]
]
, G.fmtNode =
\(_, Topo.Node{..})->
[ G.FillColor . G.toColorList . (:[]) $
case nodeId of
0 -> G.RGB 250 250 150
1 -> G.RGB 150 250 250
_ -> locationColor region
, G.Style [G.SItem G.Filled []]
]
}

toGV :: [Topo.Node] -> ([(String, Topo.Node)], [(String, String, String)])
toGV xs = (,)
((\n@Topo.Node{..} -> ("node-" <> show nodeId, n)) <$> xs)
(concat $
(\Topo.Node{..} ->
("node-" <> show nodeId, , "")
. ("node-" <>)
. show <$> producers
)
<$>
xs
)

locationColor :: Topo.Location -> G.Color
locationColor = \case
(Topo.AWS Topo.AP_SOUTHEAST_2) -> G.RGB 250 200 200
(Topo.AWS Topo.EU_CENTRAL_1) -> G.RGB 200 200 250
(Topo.AWS Topo.US_EAST_1) -> G.RGB 200 250 200
(Topo.AWS Topo.US_EAST_2) -> G.RGB 200 250 200
Topo.Loopback -> G.RGB 200 200 250
40 changes: 39 additions & 1 deletion bench/cardano-topology/cardano-topology.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@ license: Apache-2.0
license-files: LICENSE
NOTICE
build-type: Simple
extra-source-files: README.md
data-files: data/bench-torus-52.json
data/bench-torus-dense-52.json
data/ci-test-nomadcwqa.json
data/ci-test-nomadperf.json
data/ci-test.json
data/default-nomadcwqa.json
data/default-nomadperf.json
data/default.json

common project-config
build-depends: base >= 4.14 && < 5
Expand All @@ -25,10 +34,21 @@ common project-config
-Wno-unticked-promoted-constructors
-Wpartial-fields
-Wredundant-constraints
-Wwarn=deprecations

library
import: project-config
hs-source-dirs: src
exposed-modules: Cardano.Benchmarking.Topology
, Cardano.Benchmarking.Topology.Types
build-depends: base >=4.12 && <5
, aeson
, bytestring
, text

executable cardano-topology
import: project-config
hs-source-dirs: .
hs-source-dirs: app/
main-is: cardano-topology.hs
ghc-options: -threaded
-rtsopts
Expand All @@ -40,3 +60,21 @@ executable cardano-topology
, optparse-applicative-fork
, split
, text
, cardano-topology

test-suite cardano-topology-test
import: project-config
hs-source-dirs: test/
main-is: Main.hs
type: exitcode-stdio-1.0
other-modules: Paths_cardano_topology
autogen-modules: Paths_cardano_topology
build-depends: base
, aeson
, bytestring
, tasty
, tasty-hunit
, cardano-topology
ghc-options: -threaded
-rtsopts
"-with-rtsopts=-T"
Loading

0 comments on commit 6466d21

Please sign in to comment.