Flags.hsc 15.4 KB
Newer Older
1 2 3 4 5 6 7 8
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE RecordWildCards   #-}

-- | Accessors to GHC RTS flags.
-- Descriptions of flags can be seen in
-- <https://www.haskell.org/ghc/docs/latest/html/users_guide/runtime-control.html GHC User's Guide>,
-- or by running RTS help message using @+RTS --help@.
--
9
-- @since 4.8.0.0
10 11
--
module GHC.RTS.Flags
12 13 14 15
  ( RtsTime
  , RtsNat
  , RTSFlags (..)
  , GiveGCStats (..)
16 17 18 19
  , GCFlags (..)
  , ConcFlags (..)
  , MiscFlags (..)
  , DebugFlags (..)
20
  , DoCostCentres (..)
21
  , CCFlags (..)
22
  , DoHeapProfile (..)
23
  , ProfFlags (..)
24
  , DoTrace (..)
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
  , TraceFlags (..)
  , TickyFlags (..)
  , getRTSFlags
  , getGCFlags
  , getConcFlags
  , getMiscFlags
  , getDebugFlags
  , getCCFlags
  , getProfFlags
  , getTraceFlags
  , getTickyFlags
  ) where

#include "Rts.h"
#include "rts/Flags.h"

import Control.Applicative
import Control.Monad

import Foreign.C.String    (peekCString)
import Foreign.C.Types     (CChar, CInt)
import Foreign.Ptr         (Ptr, nullPtr)
import Foreign.Storable    (peekByteOff)

import GHC.Base
import GHC.Enum
import GHC.IO
import GHC.Real
import GHC.Show
import GHC.Word

-- | @'Time'@ is defined as a @'StgWord64'@ in @stg/Types.h@
57
--
58
-- @since 4.8.2.0
59
type RtsTime = Word64
60 61

-- | @'nat'@ defined in @rts/Types.h@
62
--
63
-- @since 4.8.2.0
64
type RtsNat = #{type unsigned int}
65

66 67 68
-- | Should we produce a summary of the garbage collector statistics after the
-- program has exited?
--
69
-- @since 4.8.2.0
70 71 72 73 74 75 76 77
data GiveGCStats
    = NoGCStats
    | CollectGCStats
    | OneLineGCStats
    | SummaryGCStats
    | VerboseGCStats
    deriving (Show)

78
-- | @since 4.8.0.0
79 80 81 82 83 84 85 86 87 88 89 90
instance Enum GiveGCStats where
    fromEnum NoGCStats      = #{const NO_GC_STATS}
    fromEnum CollectGCStats = #{const COLLECT_GC_STATS}
    fromEnum OneLineGCStats = #{const ONELINE_GC_STATS}
    fromEnum SummaryGCStats = #{const SUMMARY_GC_STATS}
    fromEnum VerboseGCStats = #{const VERBOSE_GC_STATS}

    toEnum #{const NO_GC_STATS}      = NoGCStats
    toEnum #{const COLLECT_GC_STATS} = CollectGCStats
    toEnum #{const ONELINE_GC_STATS} = OneLineGCStats
    toEnum #{const SUMMARY_GC_STATS} = SummaryGCStats
    toEnum #{const VERBOSE_GC_STATS} = VerboseGCStats
Eric Seidel's avatar
Eric Seidel committed
91
    toEnum e = errorWithoutStackTrace ("invalid enum for GiveGCStats: " ++ show e)
92

93 94 95
-- | Parameters of the garbage collector.
--
-- @since 4.8.0.0
96 97 98
data GCFlags = GCFlags
    { statsFile             :: Maybe FilePath
    , giveStats             :: GiveGCStats
99 100 101 102 103 104 105 106
    , maxStkSize            :: RtsNat
    , initialStkSize        :: RtsNat
    , stkChunkSize          :: RtsNat
    , stkChunkBufferSize    :: RtsNat
    , maxHeapSize           :: RtsNat
    , minAllocAreaSize      :: RtsNat
    , minOldGenSize         :: RtsNat
    , heapSizeSuggestion    :: RtsNat
107
    , heapSizeSuggestionAuto :: Bool
108 109
    , oldGenFactor          :: Double
    , pcFreeHeap            :: Double
110 111
    , generations           :: RtsNat
    , steps                 :: RtsNat
112 113 114 115 116 117 118
    , squeezeUpdFrames      :: Bool
    , compact               :: Bool -- ^ True <=> "compact all the time"
    , compactThreshold      :: Double
    , sweep                 :: Bool
      -- ^ use "mostly mark-sweep" instead of copying for the oldest generation
    , ringBell              :: Bool
    , frontpanel            :: Bool
119
    , idleGCDelayTime       :: RtsTime
120 121 122 123 124
    , doIdleGC              :: Bool
    , heapBase              :: Word -- ^ address to ask the OS for memory
    , allocLimitGrace       :: Word
    } deriving (Show)

125 126 127
-- | Parameters concerning context switching
--
-- @since 4.8.0.0
128
data ConcFlags = ConcFlags
129
    { ctxtSwitchTime  :: RtsTime
130 131 132
    , ctxtSwitchTicks :: Int
    } deriving (Show)

133 134 135
-- | Miscellaneous parameters
--
-- @since 4.8.0.0
136
data MiscFlags = MiscFlags
137
    { tickInterval          :: RtsTime
138 139 140 141 142 143 144 145
    , installSignalHandlers :: Bool
    , machineReadable       :: Bool
    , linkerMemBase         :: Word
      -- ^ address to ask the OS for memory for the linker, 0 ==> off
    } deriving (Show)

-- | Flags to control debugging output & extra checking in various
-- subsystems.
146 147
--
-- @since 4.8.0.0
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
data DebugFlags = DebugFlags
    { scheduler   :: Bool -- ^ 's'
    , interpreter :: Bool -- ^ 'i'
    , weak        :: Bool -- ^ 'w'
    , gccafs      :: Bool -- ^ 'G'
    , gc          :: Bool -- ^ 'g'
    , block_alloc :: Bool -- ^ 'b'
    , sanity      :: Bool -- ^ 'S'
    , stable      :: Bool -- ^ 't'
    , prof        :: Bool -- ^ 'p'
    , linker      :: Bool -- ^ 'l' the object linker
    , apply       :: Bool -- ^ 'a'
    , stm         :: Bool -- ^ 'm'
    , squeeze     :: Bool -- ^ 'z' stack squeezing & lazy blackholing
    , hpc         :: Bool -- ^ 'c' coverage
    , sparks      :: Bool -- ^ 'r'
    } deriving (Show)

166 167
-- | Should the RTS produce a cost-center summary?
--
168
-- @since 4.8.2.0
169 170 171 172 173 174 175 176
data DoCostCentres
    = CostCentresNone
    | CostCentresSummary
    | CostCentresVerbose
    | CostCentresAll
    | CostCentresXML
    deriving (Show)

177
-- | @since 4.8.0.0
178 179 180 181 182 183 184 185 186 187 188 189
instance Enum DoCostCentres where
    fromEnum CostCentresNone    = #{const COST_CENTRES_NONE}
    fromEnum CostCentresSummary = #{const COST_CENTRES_SUMMARY}
    fromEnum CostCentresVerbose = #{const COST_CENTRES_VERBOSE}
    fromEnum CostCentresAll     = #{const COST_CENTRES_ALL}
    fromEnum CostCentresXML     = #{const COST_CENTRES_XML}

    toEnum #{const COST_CENTRES_NONE}    = CostCentresNone
    toEnum #{const COST_CENTRES_SUMMARY} = CostCentresSummary
    toEnum #{const COST_CENTRES_VERBOSE} = CostCentresVerbose
    toEnum #{const COST_CENTRES_ALL}     = CostCentresAll
    toEnum #{const COST_CENTRES_XML}     = CostCentresXML
Eric Seidel's avatar
Eric Seidel committed
190
    toEnum e = errorWithoutStackTrace ("invalid enum for DoCostCentres: " ++ show e)
191

192 193 194
-- | Parameters pertaining to the cost-center profiler.
--
-- @since 4.8.0.0
195 196 197 198 199 200
data CCFlags = CCFlags
    { doCostCentres :: DoCostCentres
    , profilerTicks :: Int
    , msecsPerTick  :: Int
    } deriving (Show)

201 202
-- | What sort of heap profile are we collecting?
--
203
-- @since 4.8.2.0
204 205 206 207 208 209 210 211 212 213 214
data DoHeapProfile
    = NoHeapProfiling
    | HeapByCCS
    | HeapByMod
    | HeapByDescr
    | HeapByType
    | HeapByRetainer
    | HeapByLDV
    | HeapByClosureType
    deriving (Show)

215
-- | @since 4.8.0.0
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
instance Enum DoHeapProfile where
    fromEnum NoHeapProfiling   = #{const NO_HEAP_PROFILING}
    fromEnum HeapByCCS         = #{const HEAP_BY_CCS}
    fromEnum HeapByMod         = #{const HEAP_BY_MOD}
    fromEnum HeapByDescr       = #{const HEAP_BY_DESCR}
    fromEnum HeapByType        = #{const HEAP_BY_TYPE}
    fromEnum HeapByRetainer    = #{const HEAP_BY_RETAINER}
    fromEnum HeapByLDV         = #{const HEAP_BY_LDV}
    fromEnum HeapByClosureType = #{const HEAP_BY_CLOSURE_TYPE}

    toEnum #{const NO_HEAP_PROFILING}    = NoHeapProfiling
    toEnum #{const HEAP_BY_CCS}          = HeapByCCS
    toEnum #{const HEAP_BY_MOD}          = HeapByMod
    toEnum #{const HEAP_BY_DESCR}        = HeapByDescr
    toEnum #{const HEAP_BY_TYPE}         = HeapByType
    toEnum #{const HEAP_BY_RETAINER}     = HeapByRetainer
    toEnum #{const HEAP_BY_LDV}          = HeapByLDV
    toEnum #{const HEAP_BY_CLOSURE_TYPE} = HeapByClosureType
Eric Seidel's avatar
Eric Seidel committed
234
    toEnum e = errorWithoutStackTrace ("invalid enum for DoHeapProfile: " ++ show e)
235

236 237 238
-- | Parameters of the cost-center profiler
--
-- @since 4.8.0.0
239 240
data ProfFlags = ProfFlags
    { doHeapProfile            :: DoHeapProfile
241 242
    , heapProfileInterval      :: RtsTime -- ^ time between samples
    , heapProfileIntervalTicks :: Word    -- ^ ticks between samples (derived)
243 244 245 246 247 248 249 250 251 252 253 254 255
    , includeTSOs              :: Bool
    , showCCSOnException       :: Bool
    , maxRetainerSetSize       :: Word
    , ccsLength                :: Word
    , modSelector              :: Maybe String
    , descrSelector            :: Maybe String
    , typeSelector             :: Maybe String
    , ccSelector               :: Maybe String
    , ccsSelector              :: Maybe String
    , retainerSelector         :: Maybe String
    , bioSelector              :: Maybe String
    } deriving (Show)

256 257
-- | Is event tracing enabled?
--
258
-- @since 4.8.2.0
259
data DoTrace
260 261 262
    = TraceNone      -- ^ no tracing
    | TraceEventLog  -- ^ send tracing events to the event log
    | TraceStderr    -- ^ send tracing events to @stderr@
263 264
    deriving (Show)

265
-- | @since 4.8.0.0
266 267 268 269 270 271 272 273
instance Enum DoTrace where
    fromEnum TraceNone     = #{const TRACE_NONE}
    fromEnum TraceEventLog = #{const TRACE_EVENTLOG}
    fromEnum TraceStderr   = #{const TRACE_STDERR}

    toEnum #{const TRACE_NONE}     = TraceNone
    toEnum #{const TRACE_EVENTLOG} = TraceEventLog
    toEnum #{const TRACE_STDERR}   = TraceStderr
Eric Seidel's avatar
Eric Seidel committed
274
    toEnum e = errorWithoutStackTrace ("invalid enum for DoTrace: " ++ show e)
275

276 277 278
-- | Parameters pertaining to event tracing
--
-- @since 4.8.0.0
279 280 281 282 283 284 285 286 287 288
data TraceFlags = TraceFlags
    { tracing        :: DoTrace
    , timestamp      :: Bool -- ^ show timestamp in stderr output
    , traceScheduler :: Bool -- ^ trace scheduler events
    , traceGc        :: Bool -- ^ trace GC events
    , sparksSampled  :: Bool -- ^ trace spark events by a sampled method
    , sparksFull     :: Bool -- ^ trace spark events 100% accurately
    , user           :: Bool -- ^ trace user events (emitted from Haskell code)
    } deriving (Show)

289 290 291
-- | Parameters pertaining to ticky-ticky profiler
--
-- @since 4.8.0.0
292 293 294 295 296
data TickyFlags = TickyFlags
    { showTickyStats :: Bool
    , tickyFile      :: Maybe FilePath
    } deriving (Show)

297 298 299
-- | Parameters of the runtime system
--
-- @since 4.8.0.0
300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360
data RTSFlags = RTSFlags
    { gcFlags         :: GCFlags
    , concurrentFlags :: ConcFlags
    , miscFlags       :: MiscFlags
    , debugFlags      :: DebugFlags
    , costCentreFlags :: CCFlags
    , profilingFlags  :: ProfFlags
    , traceFlags      :: TraceFlags
    , tickyFlags      :: TickyFlags
    } deriving (Show)

foreign import ccall safe "getGcFlags"
  getGcFlagsPtr :: IO (Ptr ())

foreign import ccall safe "getConcFlags"
  getConcFlagsPtr :: IO (Ptr ())

foreign import ccall safe "getMiscFlags"
  getMiscFlagsPtr :: IO (Ptr ())

foreign import ccall safe "getDebugFlags"
  getDebugFlagsPtr :: IO (Ptr ())

foreign import ccall safe "getCcFlags"
  getCcFlagsPtr :: IO (Ptr ())

foreign import ccall safe "getProfFlags" getProfFlagsPtr :: IO (Ptr ())

foreign import ccall safe "getTraceFlags"
  getTraceFlagsPtr :: IO (Ptr ())

foreign import ccall safe "getTickyFlags"
  getTickyFlagsPtr :: IO (Ptr ())

getRTSFlags :: IO RTSFlags
getRTSFlags = do
  RTSFlags <$> getGCFlags
           <*> getConcFlags
           <*> getMiscFlags
           <*> getDebugFlags
           <*> getCCFlags
           <*> getProfFlags
           <*> getTraceFlags
           <*> getTickyFlags

peekFilePath :: Ptr () -> IO (Maybe FilePath)
peekFilePath ptr
  | ptr == nullPtr = return Nothing
  | otherwise      = return (Just "<filepath>")

-- | Read a NUL terminated string. Return Nothing in case of a NULL pointer.
peekCStringOpt :: Ptr CChar -> IO (Maybe String)
peekCStringOpt ptr
  | ptr == nullPtr = return Nothing
  | otherwise      = Just <$> peekCString ptr

getGCFlags :: IO GCFlags
getGCFlags = do
  ptr <- getGcFlagsPtr
  GCFlags <$> (peekFilePath =<< #{peek GC_FLAGS, statsFile} ptr)
          <*> (toEnum . fromIntegral <$>
361
                (#{peek GC_FLAGS, giveStats} ptr :: IO RtsNat))
362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422
          <*> #{peek GC_FLAGS, maxStkSize} ptr
          <*> #{peek GC_FLAGS, initialStkSize} ptr
          <*> #{peek GC_FLAGS, stkChunkSize} ptr
          <*> #{peek GC_FLAGS, stkChunkBufferSize} ptr
          <*> #{peek GC_FLAGS, maxHeapSize} ptr
          <*> #{peek GC_FLAGS, minAllocAreaSize} ptr
          <*> #{peek GC_FLAGS, minOldGenSize} ptr
          <*> #{peek GC_FLAGS, heapSizeSuggestion} ptr
          <*> #{peek GC_FLAGS, heapSizeSuggestionAuto} ptr
          <*> #{peek GC_FLAGS, oldGenFactor} ptr
          <*> #{peek GC_FLAGS, pcFreeHeap} ptr
          <*> #{peek GC_FLAGS, generations} ptr
          <*> #{peek GC_FLAGS, steps} ptr
          <*> #{peek GC_FLAGS, squeezeUpdFrames} ptr
          <*> #{peek GC_FLAGS, compact} ptr
          <*> #{peek GC_FLAGS, compactThreshold} ptr
          <*> #{peek GC_FLAGS, sweep} ptr
          <*> #{peek GC_FLAGS, ringBell} ptr
          <*> #{peek GC_FLAGS, frontpanel} ptr
          <*> #{peek GC_FLAGS, idleGCDelayTime} ptr
          <*> #{peek GC_FLAGS, doIdleGC} ptr
          <*> #{peek GC_FLAGS, heapBase} ptr
          <*> #{peek GC_FLAGS, allocLimitGrace} ptr

getConcFlags :: IO ConcFlags
getConcFlags = do
  ptr <- getConcFlagsPtr
  ConcFlags <$> #{peek CONCURRENT_FLAGS, ctxtSwitchTime} ptr
            <*> #{peek CONCURRENT_FLAGS, ctxtSwitchTicks} ptr

getMiscFlags :: IO MiscFlags
getMiscFlags = do
  ptr <- getMiscFlagsPtr
  MiscFlags <$> #{peek MISC_FLAGS, tickInterval} ptr
            <*> #{peek MISC_FLAGS, install_signal_handlers} ptr
            <*> #{peek MISC_FLAGS, machineReadable} ptr
            <*> #{peek MISC_FLAGS, linkerMemBase} ptr

getDebugFlags :: IO DebugFlags
getDebugFlags = do
  ptr <- getDebugFlagsPtr
  DebugFlags <$> #{peek DEBUG_FLAGS, scheduler} ptr
             <*> #{peek DEBUG_FLAGS, interpreter} ptr
             <*> #{peek DEBUG_FLAGS, weak} ptr
             <*> #{peek DEBUG_FLAGS, gccafs} ptr
             <*> #{peek DEBUG_FLAGS, gc} ptr
             <*> #{peek DEBUG_FLAGS, block_alloc} ptr
             <*> #{peek DEBUG_FLAGS, sanity} ptr
             <*> #{peek DEBUG_FLAGS, stable} ptr
             <*> #{peek DEBUG_FLAGS, prof} ptr
             <*> #{peek DEBUG_FLAGS, linker} ptr
             <*> #{peek DEBUG_FLAGS, apply} ptr
             <*> #{peek DEBUG_FLAGS, stm} ptr
             <*> #{peek DEBUG_FLAGS, squeeze} ptr
             <*> #{peek DEBUG_FLAGS, hpc} ptr
             <*> #{peek DEBUG_FLAGS, sparks} ptr

getCCFlags :: IO CCFlags
getCCFlags = do
  ptr <- getCcFlagsPtr
  CCFlags <$> (toEnum . fromIntegral
423
                <$> (#{peek COST_CENTRE_FLAGS, doCostCentres} ptr :: IO RtsNat))
424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461
          <*> #{peek COST_CENTRE_FLAGS, profilerTicks} ptr
          <*> #{peek COST_CENTRE_FLAGS, msecsPerTick} ptr

getProfFlags :: IO ProfFlags
getProfFlags = do
  ptr <- getProfFlagsPtr
  ProfFlags <$> (toEnum <$> #{peek PROFILING_FLAGS, doHeapProfile} ptr)
            <*> #{peek PROFILING_FLAGS, heapProfileInterval} ptr
            <*> #{peek PROFILING_FLAGS, heapProfileIntervalTicks} ptr
            <*> #{peek PROFILING_FLAGS, includeTSOs} ptr
            <*> #{peek PROFILING_FLAGS, showCCSOnException} ptr
            <*> #{peek PROFILING_FLAGS, maxRetainerSetSize} ptr
            <*> #{peek PROFILING_FLAGS, ccsLength} ptr
            <*> (peekCStringOpt =<< #{peek PROFILING_FLAGS, modSelector} ptr)
            <*> (peekCStringOpt =<< #{peek PROFILING_FLAGS, descrSelector} ptr)
            <*> (peekCStringOpt =<< #{peek PROFILING_FLAGS, typeSelector} ptr)
            <*> (peekCStringOpt =<< #{peek PROFILING_FLAGS, ccSelector} ptr)
            <*> (peekCStringOpt =<< #{peek PROFILING_FLAGS, ccsSelector} ptr)
            <*> (peekCStringOpt =<< #{peek PROFILING_FLAGS, retainerSelector} ptr)
            <*> (peekCStringOpt =<< #{peek PROFILING_FLAGS, bioSelector} ptr)

getTraceFlags :: IO TraceFlags
getTraceFlags = do
  ptr <- getTraceFlagsPtr
  TraceFlags <$> (toEnum . fromIntegral
                   <$> (#{peek TRACE_FLAGS, tracing} ptr :: IO CInt))
             <*> #{peek TRACE_FLAGS, timestamp} ptr
             <*> #{peek TRACE_FLAGS, scheduler} ptr
             <*> #{peek TRACE_FLAGS, gc} ptr
             <*> #{peek TRACE_FLAGS, sparks_sampled} ptr
             <*> #{peek TRACE_FLAGS, sparks_full} ptr
             <*> #{peek TRACE_FLAGS, user} ptr

getTickyFlags :: IO TickyFlags
getTickyFlags = do
  ptr <- getTickyFlagsPtr
  TickyFlags <$> #{peek TICKY_FLAGS, showTickyStats} ptr
             <*> (peekFilePath =<< #{peek TICKY_FLAGS, tickyFile} ptr)