[Git][ghc/ghc][master] 5 commits: rts: Add IPE event class for -l
Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC Commits: 41c2448b by Wen Kokke at 2026-05-19T12:44:53-04:00 rts: Add IPE event class for -l This commit adds a new IPE event class to the -l RTS flag. Previously, IPE events were enabled unconditionally. However, the IPE events can easily grow to hundreds or thousands of megabytes. With the new event class you can pass, e.g., -l-I to disable IPE events. - - - - - 62536551 by Wen Kokke at 2026-05-19T12:44:53-04:00 ghc-internal: Add TraceFlags.traceIPE - - - - - e45312d1 by Wen Kokke at 2026-05-19T12:44:53-04:00 testsuite: Add test for TraceFlags.traceIpe - - - - - 4768d9aa by Wen Kokke at 2026-05-19T12:44:53-04:00 ghc-internal: Add DebugFlags.ipe - - - - - bc1b5c69 by Wen Kokke at 2026-05-19T12:44:53-04:00 testsuite: Add test for DebugFlags.ipe - - - - - 18 changed files: - + changelog.d/ipe-event-class - docs/users_guide/runtime_control.rst - libraries/ghc-internal/src/GHC/Internal/RTS/Flags.hsc - rts/IPE.c - rts/RtsFlags.c - rts/Trace.c - rts/Trace.h - rts/include/rts/EventLogWriter.h - rts/include/rts/Flags.h - testsuite/tests/interface-stability/ghc-experimental-exports.stdout - testsuite/tests/interface-stability/ghc-experimental-exports.stdout-mingw32 - + testsuite/tests/rts/T25275/DebugIpe.hs - + testsuite/tests/rts/T25275/T25275_A.stdout - + testsuite/tests/rts/T25275/T25275_B.stdout - + testsuite/tests/rts/T25275/T25275_C.stdout - + testsuite/tests/rts/T25275/T25275_D.stdout - + testsuite/tests/rts/T25275/TraceIpe.hs - + testsuite/tests/rts/T25275/all.T Changes: ===================================== changelog.d/ipe-event-class ===================================== @@ -0,0 +1,9 @@ +section: compiler +synopsis: Add eventlog flag -lI to enable/disable IPE tracing +issues: #27239 +mrs: !16004 + +description: { + The RTS `-l` flag now accepts the new event class `I`, + which controls whether or not IPE events are emitted. +} ===================================== docs/users_guide/runtime_control.rst ===================================== @@ -1304,6 +1304,9 @@ When the program is linked with the :ghc-flag:`-eventlog` option - ``u`` — user events. These are events emitted from Haskell code using functions such as ``Debug.Trace.traceEvent``. Enabled by default. + - ``I`` — IPE events. These events describe source position information + for info tables. See :ghc-flag:`-finfo-table-map`. + You can disable specific classes, or enable/disable all classes at once: ===================================== libraries/ghc-internal/src/GHC/Internal/RTS/Flags.hsc ===================================== @@ -211,6 +211,8 @@ data DebugFlags = DebugFlags , squeeze :: Bool -- ^ @z@ stack squeezing & lazy blackholing , hpc :: Bool -- ^ @c@ coverage , sparks :: Bool -- ^ @r@ + , ipe :: Bool -- ^ @I@ + -- @since ghc-experimental-10.0.0 } deriving ( Show -- ^ @since base-4.8.0.0 , Generic -- ^ @since base-4.15.0.0 ) @@ -359,6 +361,8 @@ data TraceFlags = TraceFlags , 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) + , traceIpe :: Bool -- ^ trace IPE events + -- @since ghc-experimental-10.0.0 } deriving ( Show -- ^ @since base-4.8.0.0 , Generic -- ^ @since base-4.15.0.0 ) @@ -588,6 +592,8 @@ getDebugFlags = do (#{peek DEBUG_FLAGS, hpc} ptr :: IO CBool)) <*> (toBool <$> (#{peek DEBUG_FLAGS, sparks} ptr :: IO CBool)) + <*> (toBool <$> + (#{peek DEBUG_FLAGS, ipe} ptr :: IO CBool)) getCCFlags :: IO CCFlags getCCFlags = do @@ -628,7 +634,7 @@ getTraceFlags :: IO TraceFlags getTraceFlags = do #if defined(javascript_HOST_ARCH) -- The JS backend does not currently have trace flags - return (TraceFlags TraceNone False False False False False False False) + return (TraceFlags TraceNone False False False False False False False False) #else let ptr = (#ptr RTS_FLAGS, TraceFlags) rtsFlagsPtr TraceFlags <$> (toEnum . fromIntegral @@ -647,6 +653,8 @@ getTraceFlags = do (#{peek TRACE_FLAGS, sparks_full} ptr :: IO CBool)) <*> (toBool <$> (#{peek TRACE_FLAGS, user} ptr :: IO CBool)) + <*> (toBool <$> + (#{peek TRACE_FLAGS, ipe} ptr :: IO CBool)) #endif getTickyFlags :: IO TickyFlags ===================================== rts/IPE.c ===================================== @@ -165,26 +165,46 @@ static void traceIPEFromHashTable(void *data STG_UNUSED, StgWord key STG_UNUSED, } void dumpIPEToEventLog(void) { - // Dump pending entries - IpeBufferListNode *node = RELAXED_LOAD(&ipeBufferList); - while (node != NULL) { - if (ipe_node_valid(node)){ - decompressIPEBufferListNodeIfCompressed(node); - - for (uint32_t i = 0; i < node->count; i++) { - const InfoProvEnt ent = ipeBufferEntryToIpe(node, i); - traceIPE(&ent); - } + /* + Usually, traceX functions are defined as a pair of a traceX_ function that + traces unconditionally and a traceX functional macro that performs the test + for the relevant TRACE_x flag. + + This function is the only function that calls traceIPE, but it takes a lot + of work just to prepare the IPE information. If traceIPE does not trace that + IPE information, all that work is wasted. Hence, the test of TRACE_ipe is + performed in this function instead. + + This function is called via traceInitEvent in RtsStartup.c, which registers + it as an init event handler. It is important that this happens regardless + of whether or not IPE tracing is enabled at startup, since IPE tracing can + be started/stopped at runtime using the dynamic trace flags API. + + IPE tracing is enabled whenever IPE debug printing is enabled via -DI, so + this test does not prevent IPE debug printing. + */ + if (RTS_UNLIKELY(TRACE_ipe)) { + // Dump pending entries + IpeBufferListNode *node = RELAXED_LOAD(&ipeBufferList); + while (node != NULL) { + if (ipe_node_valid(node)){ + decompressIPEBufferListNodeIfCompressed(node); + + for (uint32_t i = 0; i < node->count; i++) { + const InfoProvEnt ent = ipeBufferEntryToIpe(node, i); + traceIPE(&ent); + } + } + node = node->next; } - node = node->next; - } - // Dump entries already in hashmap - ACQUIRE_LOCK(&ipeMapLock); - if (ipeMap != NULL) { - mapHashTable(ipeMap, NULL, &traceIPEFromHashTable); + // Dump entries already in hashmap + ACQUIRE_LOCK(&ipeMapLock); + if (ipeMap != NULL) { + mapHashTable(ipeMap, NULL, &traceIPEFromHashTable); + } + RELEASE_LOCK(&ipeMapLock); } - RELEASE_LOCK(&ipeMapLock); } ===================================== rts/RtsFlags.c ===================================== @@ -249,6 +249,7 @@ void initRtsFlagsDefaults(void) RtsFlags.TraceFlags.sparks_sampled= false; RtsFlags.TraceFlags.sparks_full = false; RtsFlags.TraceFlags.user = false; + RtsFlags.TraceFlags.ipe = false; RtsFlags.TraceFlags.ticky = false; RtsFlags.TraceFlags.trace_output = NULL; # if defined(THREADED_RTS) @@ -449,6 +450,7 @@ usage_text[] = { " p par spark events (sampled)", " f par spark events (full detail)", " u user events (emitted from Haskell code)", +" I IPE events", #if defined(TICKY_TICKY) " T ticky-ticky counter samples", #endif @@ -457,7 +459,7 @@ usage_text[] = { " t add time stamps (only useful with -v)", # endif " -x disable an event class, for any flag above", -" the initial enabled event classes are 'sgpu'", +" the initial enabled event classes are 'sgIpu'", # if defined(THREADED_RTS) " --eventlog-flush-interval=<secs>", " Periodically flush the eventlog at the specified interval.", @@ -2528,6 +2530,7 @@ static void read_trace_flags(const char *arg) RtsFlags.TraceFlags.gc = true; RtsFlags.TraceFlags.sparks_sampled = true; RtsFlags.TraceFlags.user = true; + RtsFlags.TraceFlags.ipe = true; for (c = arg; *c != '\0'; c++) { switch(*c) { @@ -2541,8 +2544,9 @@ static void read_trace_flags(const char *arg) RtsFlags.TraceFlags.gc = enabled; RtsFlags.TraceFlags.sparks_sampled = enabled; RtsFlags.TraceFlags.sparks_full = enabled; - RtsFlags.TraceFlags.user = enabled; RtsFlags.TraceFlags.nonmoving_gc = enabled; + RtsFlags.TraceFlags.user = enabled; + RtsFlags.TraceFlags.ipe = enabled; #if defined(TICKY_TICKY) RtsFlags.TraceFlags.ticky = enabled; #endif @@ -2577,6 +2581,10 @@ static void read_trace_flags(const char *arg) RtsFlags.TraceFlags.user = enabled; enabled = true; break; + case 'I': + RtsFlags.TraceFlags.ipe = enabled; + enabled = true; + break; case 'T': #if defined(TICKY_TICKY) RtsFlags.TraceFlags.ticky = enabled; ===================================== rts/Trace.c ===================================== @@ -47,6 +47,8 @@ bool getTraceFlag(RUNTIME_TRACE_FLAG flag) { return RuntimeTraceFlagCache.user; case TRACE_CAP: return RuntimeTraceFlagCache.cap; + case TRACE_IPE: + return RuntimeTraceFlagCache.ipe; default: return false; } @@ -75,6 +77,9 @@ void setTraceFlag(RUNTIME_TRACE_FLAG flag, bool value) { case TRACE_CAP: RuntimeTraceFlagCache.cap = value; break; + case TRACE_IPE: + RuntimeTraceFlagCache.ipe = value; + break; } } @@ -119,13 +124,19 @@ static void updateTraceFlagCache(void) { RuntimeTraceFlagCache.user = RtsFlags.TraceFlags.user; + // -DI turns on IPE tracing too + RuntimeTraceFlagCache.ipe = + RtsFlags.TraceFlags.ipe || + RtsFlags.DebugFlags.ipe; + // We trace cap events if we're tracing anything else RuntimeTraceFlagCache.cap = TRACE_sched || TRACE_gc || TRACE_spark_sampled || TRACE_spark_full || - TRACE_user; + TRACE_user || + TRACE_ipe; } void initTracing (void) @@ -720,6 +731,7 @@ void traceHeapProfSampleString(const char *label, StgWord residency) } } +// The TRACE_ipe test happens in dumpIPEToEventLog. void traceIPE(const InfoProvEnt *ipe) { #if defined(DEBUG) ===================================== rts/Trace.h ===================================== @@ -79,6 +79,7 @@ enum CapsetType { CapsetTypeCustom = CAPSET_TYPE_CUSTOM, #define TRACE_spark_full ((const bool)RuntimeTraceFlagCache.spark_full) #define TRACE_user ((const bool)RuntimeTraceFlagCache.user) #define TRACE_cap ((const bool)RuntimeTraceFlagCache.cap) +#define TRACE_ipe ((const bool)RuntimeTraceFlagCache.ipe) /* * Runtime trace flags. @@ -91,6 +92,7 @@ typedef struct { bool spark_full; bool user; bool cap; + bool ipe; } RUNTIME_TRACE_FLAG_CACHE; /* ===================================== rts/include/rts/EventLogWriter.h ===================================== @@ -90,6 +90,7 @@ typedef enum { TRACE_SPARK_FULL, TRACE_USER, TRACE_CAP, + TRACE_IPE, } RUNTIME_TRACE_FLAG; /* ===================================== rts/include/rts/Flags.h ===================================== @@ -191,6 +191,7 @@ typedef struct _TRACE_FLAGS { bool sparks_full; /* trace spark events 100% accurately */ bool ticky; /* trace ticky-ticky samples */ bool user; /* trace user events (emitted from Haskell code) */ + bool ipe; /* trace IPE events */ #if defined(THREADED_RTS) /* Time between force eventlog flushes (or 0 if disabled) */ Time eventlogFlushTime; ===================================== testsuite/tests/interface-stability/ghc-experimental-exports.stdout ===================================== @@ -7812,7 +7812,7 @@ module GHC.RTS.Flags.Experimental where type ConcFlags :: * data ConcFlags = ConcFlags {ctxtSwitchTime :: RtsTime, ctxtSwitchTicks :: GHC.Internal.Types.Int} type DebugFlags :: * - data DebugFlags = DebugFlags {scheduler :: GHC.Internal.Types.Bool, interpreter :: GHC.Internal.Types.Bool, weak :: GHC.Internal.Types.Bool, gccafs :: GHC.Internal.Types.Bool, gc :: GHC.Internal.Types.Bool, nonmoving_gc :: GHC.Internal.Types.Bool, block_alloc :: GHC.Internal.Types.Bool, sanity :: GHC.Internal.Types.Bool, stable :: GHC.Internal.Types.Bool, prof :: GHC.Internal.Types.Bool, linker :: GHC.Internal.Types.Bool, apply :: GHC.Internal.Types.Bool, stm :: GHC.Internal.Types.Bool, squeeze :: GHC.Internal.Types.Bool, hpc :: GHC.Internal.Types.Bool, sparks :: GHC.Internal.Types.Bool} + data DebugFlags = DebugFlags {scheduler :: GHC.Internal.Types.Bool, interpreter :: GHC.Internal.Types.Bool, weak :: GHC.Internal.Types.Bool, gccafs :: GHC.Internal.Types.Bool, gc :: GHC.Internal.Types.Bool, nonmoving_gc :: GHC.Internal.Types.Bool, block_alloc :: GHC.Internal.Types.Bool, sanity :: GHC.Internal.Types.Bool, stable :: GHC.Internal.Types.Bool, prof :: GHC.Internal.Types.Bool, linker :: GHC.Internal.Types.Bool, apply :: GHC.Internal.Types.Bool, stm :: GHC.Internal.Types.Bool, squeeze :: GHC.Internal.Types.Bool, hpc :: GHC.Internal.Types.Bool, sparks :: GHC.Internal.Types.Bool, ipe :: GHC.Internal.Types.Bool} type DoCostCentres :: * data DoCostCentres = CostCentresNone | CostCentresSummary | CostCentresVerbose | CostCentresAll | CostCentresJSON type DoHeapProfile :: * @@ -7889,7 +7889,7 @@ module GHC.RTS.Flags.Experimental where type TickyFlags :: * data TickyFlags = TickyFlags {showTickyStats :: GHC.Internal.Types.Bool, tickyFile :: GHC.Internal.Maybe.Maybe GHC.Internal.IO.FilePath} type TraceFlags :: * - data TraceFlags = TraceFlags {tracing :: DoTrace, timestamp :: GHC.Internal.Types.Bool, traceScheduler :: GHC.Internal.Types.Bool, traceGc :: GHC.Internal.Types.Bool, traceNonmovingGc :: GHC.Internal.Types.Bool, sparksSampled :: GHC.Internal.Types.Bool, sparksFull :: GHC.Internal.Types.Bool, user :: GHC.Internal.Types.Bool} + data TraceFlags = TraceFlags {tracing :: DoTrace, timestamp :: GHC.Internal.Types.Bool, traceScheduler :: GHC.Internal.Types.Bool, traceGc :: GHC.Internal.Types.Bool, traceNonmovingGc :: GHC.Internal.Types.Bool, sparksSampled :: GHC.Internal.Types.Bool, sparksFull :: GHC.Internal.Types.Bool, user :: GHC.Internal.Types.Bool, traceIpe :: GHC.Internal.Types.Bool} getCCFlags :: GHC.Internal.Types.IO CCFlags getConcFlags :: GHC.Internal.Types.IO ConcFlags getDebugFlags :: GHC.Internal.Types.IO DebugFlags ===================================== testsuite/tests/interface-stability/ghc-experimental-exports.stdout-mingw32 ===================================== @@ -7815,7 +7815,7 @@ module GHC.RTS.Flags.Experimental where type ConcFlags :: * data ConcFlags = ConcFlags {ctxtSwitchTime :: RtsTime, ctxtSwitchTicks :: GHC.Internal.Types.Int} type DebugFlags :: * - data DebugFlags = DebugFlags {scheduler :: GHC.Internal.Types.Bool, interpreter :: GHC.Internal.Types.Bool, weak :: GHC.Internal.Types.Bool, gccafs :: GHC.Internal.Types.Bool, gc :: GHC.Internal.Types.Bool, nonmoving_gc :: GHC.Internal.Types.Bool, block_alloc :: GHC.Internal.Types.Bool, sanity :: GHC.Internal.Types.Bool, stable :: GHC.Internal.Types.Bool, prof :: GHC.Internal.Types.Bool, linker :: GHC.Internal.Types.Bool, apply :: GHC.Internal.Types.Bool, stm :: GHC.Internal.Types.Bool, squeeze :: GHC.Internal.Types.Bool, hpc :: GHC.Internal.Types.Bool, sparks :: GHC.Internal.Types.Bool} + data DebugFlags = DebugFlags {scheduler :: GHC.Internal.Types.Bool, interpreter :: GHC.Internal.Types.Bool, weak :: GHC.Internal.Types.Bool, gccafs :: GHC.Internal.Types.Bool, gc :: GHC.Internal.Types.Bool, nonmoving_gc :: GHC.Internal.Types.Bool, block_alloc :: GHC.Internal.Types.Bool, sanity :: GHC.Internal.Types.Bool, stable :: GHC.Internal.Types.Bool, prof :: GHC.Internal.Types.Bool, linker :: GHC.Internal.Types.Bool, apply :: GHC.Internal.Types.Bool, stm :: GHC.Internal.Types.Bool, squeeze :: GHC.Internal.Types.Bool, hpc :: GHC.Internal.Types.Bool, sparks :: GHC.Internal.Types.Bool, ipe :: GHC.Internal.Types.Bool} type DoCostCentres :: * data DoCostCentres = CostCentresNone | CostCentresSummary | CostCentresVerbose | CostCentresAll | CostCentresJSON type DoHeapProfile :: * @@ -7892,7 +7892,7 @@ module GHC.RTS.Flags.Experimental where type TickyFlags :: * data TickyFlags = TickyFlags {showTickyStats :: GHC.Internal.Types.Bool, tickyFile :: GHC.Internal.Maybe.Maybe GHC.Internal.IO.FilePath} type TraceFlags :: * - data TraceFlags = TraceFlags {tracing :: DoTrace, timestamp :: GHC.Internal.Types.Bool, traceScheduler :: GHC.Internal.Types.Bool, traceGc :: GHC.Internal.Types.Bool, traceNonmovingGc :: GHC.Internal.Types.Bool, sparksSampled :: GHC.Internal.Types.Bool, sparksFull :: GHC.Internal.Types.Bool, user :: GHC.Internal.Types.Bool} + data TraceFlags = TraceFlags {tracing :: DoTrace, timestamp :: GHC.Internal.Types.Bool, traceScheduler :: GHC.Internal.Types.Bool, traceGc :: GHC.Internal.Types.Bool, traceNonmovingGc :: GHC.Internal.Types.Bool, sparksSampled :: GHC.Internal.Types.Bool, sparksFull :: GHC.Internal.Types.Bool, user :: GHC.Internal.Types.Bool, traceIpe :: GHC.Internal.Types.Bool} getCCFlags :: GHC.Internal.Types.IO CCFlags getConcFlags :: GHC.Internal.Types.IO ConcFlags getDebugFlags :: GHC.Internal.Types.IO DebugFlags ===================================== testsuite/tests/rts/T25275/DebugIpe.hs ===================================== @@ -0,0 +1,6 @@ +module Main where + +import GHC.RTS.Flags.Experimental (DebugFlags (..), getDebugFlags) + +main :: IO () +main = print . ipe =<< getDebugFlags ===================================== testsuite/tests/rts/T25275/T25275_A.stdout ===================================== @@ -0,0 +1 @@ +False \ No newline at end of file ===================================== testsuite/tests/rts/T25275/T25275_B.stdout ===================================== @@ -0,0 +1 @@ +True \ No newline at end of file ===================================== testsuite/tests/rts/T25275/T25275_C.stdout ===================================== @@ -0,0 +1 @@ +False \ No newline at end of file ===================================== testsuite/tests/rts/T25275/T25275_D.stdout ===================================== @@ -0,0 +1 @@ +True \ No newline at end of file ===================================== testsuite/tests/rts/T25275/TraceIpe.hs ===================================== @@ -0,0 +1,6 @@ +module Main where + +import GHC.RTS.Flags.Experimental (TraceFlags (..), getTraceFlags) + +main :: IO () +main = print . traceIpe =<< getTraceFlags ===================================== testsuite/tests/rts/T25275/all.T ===================================== @@ -0,0 +1,45 @@ +# Compile and run with default RTS options +test( + 'T25275_A', + [ + extra_files(['TraceIpe.hs']), + js_skip + ], + multimod_compile_and_run, + ['TraceIpe', ''], +) + +# Compile and run with -lI +test( + 'T25275_B', + [ + extra_files(['TraceIpe.hs']), + extra_run_opts('+RTS -lI -RTS'), + js_skip + ], + multimod_compile_and_run, + ['TraceIpe', ''], +) + +# Compile and run with default RTS options +test( + 'T25275_C', + [ + only_ways(['debug']), + extra_files(['DebugIpe.hs']), + ], + multimod_compile_and_run, + ['DebugIpe', ''], +) + +# Compile and run with -DI +test( + 'T25275_D', + [ + only_ways(['debug']), + extra_files(['DebugIpe.hs']), + extra_run_opts('+RTS -DI -RTS'), + ], + multimod_compile_and_run, + ['DebugIpe', ''], +) View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/28666fbfc33ddf932d73191fde40068... -- View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/28666fbfc33ddf932d73191fde40068... You're receiving this email because of your account on gitlab.haskell.org.
participants (1)
-
Marge Bot (@marge-bot)