Flags.hsc 15.3 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 78 79 80 81 82 83 84 85 86 87 88 89
data GiveGCStats
    = NoGCStats
    | CollectGCStats
    | OneLineGCStats
    | SummaryGCStats
    | VerboseGCStats
    deriving (Show)

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
90
    toEnum e = errorWithoutStackTrace ("invalid enum for GiveGCStats: " ++ show e)
91

92 93 94
-- | Parameters of the garbage collector.
--
-- @since 4.8.0.0
95 96 97
data GCFlags = GCFlags
    { statsFile             :: Maybe FilePath
    , giveStats             :: GiveGCStats
98 99 100 101 102 103 104 105
    , maxStkSize            :: RtsNat
    , initialStkSize        :: RtsNat
    , stkChunkSize          :: RtsNat
    , stkChunkBufferSize    :: RtsNat
    , maxHeapSize           :: RtsNat
    , minAllocAreaSize      :: RtsNat
    , minOldGenSize         :: RtsNat
    , heapSizeSuggestion    :: RtsNat
106
    , heapSizeSuggestionAuto :: Bool
107 108
    , oldGenFactor          :: Double
    , pcFreeHeap            :: Double
109 110
    , generations           :: RtsNat
    , steps                 :: RtsNat
111 112 113 114 115 116 117
    , 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
118
    , idleGCDelayTime       :: RtsTime
119 120 121 122 123
    , doIdleGC              :: Bool
    , heapBase              :: Word -- ^ address to ask the OS for memory
    , allocLimitGrace       :: Word
    } deriving (Show)

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

132 133 134
-- | Miscellaneous parameters
--
-- @since 4.8.0.0
135
data MiscFlags = MiscFlags
136
    { tickInterval          :: RtsTime
137 138 139 140 141 142 143 144
    , 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.
145 146
--
-- @since 4.8.0.0
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
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)

165 166
-- | Should the RTS produce a cost-center summary?
--
167
-- @since 4.8.2.0
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
data DoCostCentres
    = CostCentresNone
    | CostCentresSummary
    | CostCentresVerbose
    | CostCentresAll
    | CostCentresXML
    deriving (Show)

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
188
    toEnum e = errorWithoutStackTrace ("invalid enum for DoCostCentres: " ++ show e)
189

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

199 200
-- | What sort of heap profile are we collecting?
--
201
-- @since 4.8.2.0
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
data DoHeapProfile
    = NoHeapProfiling
    | HeapByCCS
    | HeapByMod
    | HeapByDescr
    | HeapByType
    | HeapByRetainer
    | HeapByLDV
    | HeapByClosureType
    deriving (Show)

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
231
    toEnum e = errorWithoutStackTrace ("invalid enum for DoHeapProfile: " ++ show e)
232

233 234 235
-- | Parameters of the cost-center profiler
--
-- @since 4.8.0.0
236 237
data ProfFlags = ProfFlags
    { doHeapProfile            :: DoHeapProfile
238 239
    , heapProfileInterval      :: RtsTime -- ^ time between samples
    , heapProfileIntervalTicks :: Word    -- ^ ticks between samples (derived)
240 241 242 243 244 245 246 247 248 249 250 251 252
    , 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)

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

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
270
    toEnum e = errorWithoutStackTrace ("invalid enum for DoTrace: " ++ show e)
271

272 273 274
-- | Parameters pertaining to event tracing
--
-- @since 4.8.0.0
275 276 277 278 279 280 281 282 283 284
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)

285 286 287
-- | Parameters pertaining to ticky-ticky profiler
--
-- @since 4.8.0.0
288 289 290 291 292
data TickyFlags = TickyFlags
    { showTickyStats :: Bool
    , tickyFile      :: Maybe FilePath
    } deriving (Show)

293 294 295
-- | Parameters of the runtime system
--
-- @since 4.8.0.0
296 297 298 299 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
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 <$>
357
                (#{peek GC_FLAGS, giveStats} ptr :: IO RtsNat))
358 359 360 361 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
          <*> #{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
419
                <$> (#{peek COST_CENTRE_FLAGS, doCostCentres} ptr :: IO RtsNat))
420 421 422 423 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
          <*> #{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)