Skip to content

Commit 6fa77a9

Browse files
authored
Merge pull request #5850 from IntersectMBO/nadia.chambers/txgen-mvar-004
tx-generator MVar deadlock reporting
2 parents 71f8c71 + dd32da1 commit 6fa77a9

File tree

22 files changed

+536
-223
lines changed

22 files changed

+536
-223
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ ps: ## Plain-text list of profiles
7575
## Profile-based cluster shells (autogenerated targets)
7676
##
7777
PROFILES_BASE := default default-p2p plutus plutus-secp-ecdsa plutus-secp-schnorr oldtracing idle tracer-only
78-
PROFILES_FAST := fast fast-p2p fast-plutus fast-notracer fast-oldtracing faststartup-24M
78+
PROFILES_FAST := fast fast-solo fast-p2p fast-plutus fast-notracer fast-oldtracing faststartup-24M
7979
PROFILES_CI_TEST := ci-test ci-test-p2p ci-test-plutus ci-test-notracer ci-test-rtview ci-test-dense10
8080
PROFILES_CI_BENCH := ci-bench ci-bench-p2p ci-bench-plutus ci-bench-plutus-secp-ecdsa ci-bench-plutus-secp-schnorr ci-bench-notracer ci-bench-rtview ci-bench-lmdb ci-bench-drep
8181
PROFILES_CI_BENCH += ci-bench-plutusv3-blst ci-bench-plutus24

bench/tx-generator/CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# ChangeLog
2+
3+
## 2.14.1 -- June 2024
4+
* A new NixSvcOptions field is introduced: `_nix_keepalive`
5+
and it's propagated down to the `kaClient` that does keepalives.
6+
This makes keepalive timeouts configurable.
7+
* The fast-solo profile is introduced for quick test runs.
8+
* A `CHANGELOG.md` is created for the tx-generator.

bench/tx-generator/src/Cardano/Benchmarking/Command.hs

Lines changed: 121 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1+
{-# LANGUAGE BlockArguments #-}
2+
{-# LANGUAGE CPP #-}
13
{-# LANGUAGE GADTs #-}
24
{-# LANGUAGE LambdaCase #-}
35
{-# LANGUAGE NamedFieldPuns #-}
6+
{-# LANGUAGE RecordWildCards #-}
47
{-# LANGUAGE ScopedTypeVariables #-}
5-
8+
{-# LANGUAGE StandaloneDeriving #-}
69
{-# OPTIONS_GHC -Wno-all-missed-specialisations -Wno-orphans #-}
710

811
module Cardano.Benchmarking.Command
@@ -12,26 +15,58 @@ module Cardano.Benchmarking.Command
1215
)
1316
where
1417

18+
#if !defined(mingw32_HOST_OS)
19+
#define UNIX
20+
#endif
21+
1522
import Cardano.Benchmarking.Compiler (compileOptions)
23+
import Cardano.Benchmarking.LogTypes (AsyncBenchmarkControl (..), BenchTracers (..),
24+
EnvConsts (..), TraceBenchTxSubmit (..))
1625
import Cardano.Benchmarking.Script (parseScriptFileAeson, runScript)
1726
import Cardano.Benchmarking.Script.Aeson (parseJSONFile, prettyPrint)
27+
import Cardano.Benchmarking.Script.Env as Env (emptyEnv, newEnvConsts)
1828
import Cardano.Benchmarking.Script.Selftest (runSelftest)
1929
import Cardano.Benchmarking.Version as Version
2030
import Cardano.TxGenerator.PlutusContext (readScriptData)
2131
import Cardano.TxGenerator.Setup.NixService
2232
import Cardano.TxGenerator.Types (TxGenPlutusParams (..))
23-
import Ouroboros.Network.NodeToClient (withIOManager)
24-
25-
import Prelude
26-
2733
import Data.Aeson (fromJSON)
2834
import Data.ByteString.Lazy as BSL
2935
import Data.Foldable (for_)
3036
import Data.Maybe (catMaybes)
37+
import Data.Text as T
3138
import Data.Text.IO as T
3239
import Options.Applicative as Opt
40+
import Ouroboros.Network.NodeToClient (IOManager, withIOManager)
41+
3342
import System.Exit
3443

44+
#ifdef UNIX
45+
import Cardano.Logging as Tracer (traceWith)
46+
import Control.Concurrent as Conc (killThread, myThreadId)
47+
import Control.Concurrent as Weak (mkWeakThreadId)
48+
import Control.Concurrent.Async as Async (cancelWith)
49+
import Control.Concurrent.STM as STM (readTVar)
50+
import Control.Monad.STM as STM (atomically)
51+
import Data.Foldable as Fold (forM_)
52+
import Data.List as List (unwords)
53+
import Data.Time.Format as Time (defaultTimeLocale, formatTime)
54+
import Data.Time.Clock.System as Time (getSystemTime, systemToUTCTime)
55+
import GHC.Weak as Weak (deRefWeak)
56+
57+
import System.Posix.Signals as Sig (Handler (CatchInfo),
58+
SignalInfo (..), SignalSpecificInfo (..), installHandler,
59+
sigINT, sigTERM)
60+
#if MIN_VERSION_base(4,18,0)
61+
import Data.Maybe as Maybe (fromMaybe)
62+
import GHC.Conc.Sync as Conc (threadLabel)
63+
#endif
64+
#endif
65+
66+
#ifdef UNIX
67+
deriving instance Show SignalInfo
68+
deriving instance Show SignalSpecificInfo
69+
#endif
3570

3671
data Command
3772
= Json FilePath
@@ -41,17 +76,22 @@ data Command
4176
| VersionCmd
4277

4378
runCommand :: IO ()
44-
runCommand = withIOManager $ \iocp -> do
79+
runCommand = withIOManager runCommand'
80+
81+
runCommand' :: IOManager -> IO ()
82+
runCommand' iocp = do
83+
envConsts <- installSignalHandler
4584
cmd <- customExecParser
4685
(prefs showHelpOnEmpty)
4786
(info commandParser mempty)
4887
case cmd of
49-
Json file -> do
50-
script <- parseScriptFileAeson file
51-
runScript script iocp >>= handleError
52-
JsonHL file nodeConfigOverwrite cardanoTracerOverwrite -> do
53-
opts <- parseJSONFile fromJSON file
88+
Json actionFile -> do
89+
script <- parseScriptFileAeson actionFile
90+
runScript emptyEnv script envConsts >>= handleError . fst
91+
JsonHL nixSvcOptsFile nodeConfigOverwrite cardanoTracerOverwrite -> do
92+
opts <- parseJSONFile fromJSON nixSvcOptsFile
5493
finalOpts <- mangleTracerConfig cardanoTracerOverwrite <$> mangleNodeConfig nodeConfigOverwrite opts
94+
let consts = envConsts { envNixSvcOpts = Just finalOpts }
5595

5696
Prelude.putStrLn $
5797
"--> initial options:\n" ++ show opts ++
@@ -60,20 +100,85 @@ runCommand = withIOManager $ \iocp -> do
60100
quickTestPlutusDataOrDie finalOpts
61101

62102
case compileOptions finalOpts of
63-
Right script -> runScript script iocp >>= handleError
64-
err -> handleError err
103+
Right script -> runScript emptyEnv script consts >>= handleError . fst
104+
err -> die $ "tx-generator:Cardano.Command.runCommand JsonHL: " ++ show err
65105
Compile file -> do
66106
o <- parseJSONFile fromJSON file
67107
case compileOptions o of
68108
Right script -> BSL.putStr $ prettyPrint script
69-
err -> handleError err
70-
Selftest outFile -> runSelftest iocp outFile >>= handleError
109+
Left err -> die $ "tx-generator:Cardano.Command.runCommand Compile: " ++ show err
110+
Selftest outFile -> runSelftest emptyEnv envConsts outFile >>= handleError
71111
VersionCmd -> runVersionCommand
72112
where
73113
handleError :: Show a => Either a b -> IO ()
74114
handleError = \case
75115
Right _ -> exitSuccess
76-
Left err -> die $ show err
116+
Left err -> die $ "tx-generator:Cardano.Command.runCommand handleError: " ++ show err
117+
installSignalHandler :: IO EnvConsts
118+
installSignalHandler = do
119+
-- The main thread does not appear in the set of asyncs.
120+
wkMainTID <- Weak.mkWeakThreadId =<< myThreadId
121+
envConsts@EnvConsts { .. } <- STM.atomically $ newEnvConsts iocp Nothing
122+
abc <- STM.atomically $ STM.readTVar envThreads
123+
_ <- pure (abc, wkMainTID)
124+
#ifdef UNIX
125+
let signalHandler = Sig.CatchInfo signalHandler'
126+
signalHandler' sigInfo = do
127+
tid <- Conc.myThreadId
128+
utcTime <- Time.systemToUTCTime <$> Time.getSystemTime
129+
-- It's meant to match Cardano.Tracers.Handlers.Logs.Utils
130+
-- The hope was to avoid the package dependency.
131+
let formatTimeStamp = formatTime' "%Y-%m-%dT%H-%M-%S"
132+
formatTime' = Time.formatTime Time.defaultTimeLocale
133+
timeStamp = formatTimeStamp utcTime
134+
#if MIN_VERSION_base(4,18,0)
135+
maybeLabel <- Conc.threadLabel tid
136+
let labelStr' :: String
137+
labelStr' = fromMaybe "(thread label unset)" maybeLabel
138+
#else
139+
labelStr' = "(base version insufficient to read thread label)"
140+
#endif
141+
labelStr :: String
142+
labelStr = List.unwords [ timeStamp
143+
, labelStr'
144+
, show tid
145+
, "received signal"
146+
, show sigInfo ]
147+
errorToThrow :: IOError
148+
errorToThrow = userError labelStr
149+
tag = TraceBenchTxSubError . T.pack
150+
traceWith' msg = do
151+
mBenchTracer <- STM.atomically do readTVar benchTracers
152+
case mBenchTracer of
153+
Nothing -> pure ()
154+
Just tracers -> do
155+
let wrappedMsg = tag msg
156+
submittedTracers = btTxSubmit_ tracers
157+
Tracer.traceWith submittedTracers wrappedMsg
158+
159+
Prelude.putStrLn labelStr
160+
traceWith' labelStr
161+
mABC <- STM.atomically $ STM.readTVar envThreads
162+
case mABC of
163+
Nothing -> do
164+
-- Catching a signal at this point makes it a higher than
165+
-- average risk of the tracer not being initialized, so
166+
-- this pursues some alternatives.
167+
let errMsg = "Signal received before AsyncBenchmarkControl creation."
168+
Prelude.putStrLn errMsg
169+
traceWith' errMsg
170+
Just AsyncBenchmarkControl { .. } -> do
171+
abcFeeder `Async.cancelWith` errorToThrow
172+
Fold.forM_ abcWorkers \work -> do
173+
work `Async.cancelWith` errorToThrow
174+
-- The main thread does __NOT__ appear in the above list.
175+
-- In order to kill that off, this, or some equivalent,
176+
-- absolutely /must/ be done separately.
177+
mapM_ Conc.killThread =<< Weak.deRefWeak wkMainTID
178+
Fold.forM_ [Sig.sigINT, Sig.sigTERM] $ \sig ->
179+
Sig.installHandler sig signalHandler Nothing
180+
#endif
181+
pure envConsts
77182

78183
mangleNodeConfig :: Maybe FilePath -> NixServiceOptions -> IO NixServiceOptions
79184
mangleNodeConfig fp opts = case (getNodeConfigFile opts, fp) of

bench/tx-generator/src/Cardano/Benchmarking/Compiler.hs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -201,11 +201,11 @@ benchmarkingPhase wallet collateralWallet = do
201201
payMode = PayToAddr keyNameBenchmarkDone doneWallet
202202
submitMode = if debugMode
203203
then LocalSocket
204-
else Benchmark targetNodes "tx-submit-benchmark" tps txCount
204+
else Benchmark targetNodes tps txCount
205205
generator = Take txCount $ Cycle $ NtoM wallet payMode inputs outputs (Just $ txParamAddTxSize txParams) collateralWallet
206206
emit $ Submit era submitMode txParams generator
207207
unless debugMode $ do
208-
emit $ WaitBenchmark "tx-submit-benchmark"
208+
emit WaitBenchmark
209209
return doneWallet
210210

211211
data Fees = Fees {

0 commit comments

Comments
 (0)