[Git][ghc/ghc][wip/ghc-dynamic-census] Profiling: Allow heap profiling to be controlled dynamically.
Matthew Pickering
gitlab at gitlab.haskell.org
Tue Dec 8 14:37:31 UTC 2020
Matthew Pickering pushed to branch wip/ghc-dynamic-census at Glasgow Haskell Compiler / GHC
Commits:
21285405 by Matthew Pickering at 2020-12-08T14:37:24+00:00
Profiling: Allow heap profiling to be controlled dynamically.
This patch exposes three new functions in `GHC.Profiling` which allow
heap profiling to be enabled and disabled dynamically.
1. startHeapProfTimer - Starts heap profiling with the given RTS options
2. stopHeapProfTimer - Stops heap profiling
3. requestHeapCensus - Perform a heap census on the next context
switch, regardless of whether the timer is enabled or not.
- - - - -
12 changed files:
- docs/users_guide/9.2.1-notes.rst
- docs/users_guide/profiling.rst
- includes/Rts.h
- includes/rts/Flags.h
- + includes/rts/prof/Heap.h
- libraries/base/GHC/Profiling.hs
- libraries/base/GHC/RTS/Flags.hsc
- rts/Proftimer.c
- rts/Proftimer.h
- rts/RtsFlags.c
- rts/Schedule.c
- rts/rts.cabal.in
Changes:
=====================================
docs/users_guide/9.2.1-notes.rst
=====================================
@@ -47,7 +47,13 @@ Compiler
- There is a significant refactoring in the solver; any type-checker plugins
will have to be updated, as GHC no longer uses flattening skolems or
flattening metavariables.
-
+
+- The heap profiler can now be controlled from within a Haskell program using
+ functions in ``GHC.Profiling``. Profiling can be started and stopped or a heap
+ census requested at a specific point in the program.
+ There is a new RTS flag :rts-flag:`--no-automatic-heap-samples` which can be
+ used to stop heap profiling starting when a program starts.
+
``ghc-prim`` library
~~~~~~~~~~~~~~~~~~~~
=====================================
docs/users_guide/profiling.rst
=====================================
@@ -459,7 +459,7 @@ compiled program.
:type: dynamic
Deprecated alias for :ghc-flag:`-fprof-auto-exported`
-
+
.. ghc-flag:: -caf-all
:shortdesc: *(deprecated)* Alias for :ghc-flag:`-fprof-cafs`
:type: dynamic
@@ -885,6 +885,13 @@ There are three more options which relate to heap profiling:
profiles are always sampled with the frequency of the RTS clock. See
:ref:`prof-time-options` for changing that.
+.. rts-flag:: --no-automatic-heap-samples
+ :since: 9.2.1
+
+ Don't start heap profiling from the start of program executation. If this
+ option is enabled, it's expected that the user will manually start heap
+ profiling or request specific samples using functions from ``GHC.Profiling``.
+
.. rts-flag:: -xt
Include the memory occupied by threads in a heap profile. Each
=====================================
includes/Rts.h
=====================================
@@ -194,6 +194,7 @@ void _assertFail(const char *filename, unsigned int linenum)
/* Profiling information */
#include "rts/prof/CCS.h"
+#include "rts/prof/Heap.h"
#include "rts/prof/LDV.h"
/* Parallel information */
=====================================
includes/rts/Flags.h
=====================================
@@ -145,6 +145,7 @@ typedef struct _PROFILING_FLAGS {
Time heapProfileInterval; /* time between samples */
uint32_t heapProfileIntervalTicks; /* ticks between samples (derived) */
bool includeTSOs;
+ bool startHeapProfileAtStartup; /* true if we start profiling from program startup */
bool showCCSOnException;
=====================================
includes/rts/prof/Heap.h
=====================================
@@ -0,0 +1,24 @@
+/* -----------------------------------------------------------------------------
+ *
+ * (c) The University of Glasgow, 2009
+ *
+ * Heap Census Profiling
+ *
+ * Do not #include this file directly: #include "Rts.h" instead.
+ *
+ * To understand the structure of the RTS headers, see the wiki:
+ * https://gitlab.haskell.org/ghc/ghc/wikis/commentary/source-tree/includes
+ *
+ * ---------------------------------------------------------------------------*/
+
+#pragma once
+
+/* -----------------------------------------------------------------------------
+ * Fine-grained control over heap census profiling which can be called from
+ * Haskell to restrict the profile to portion(s) of the execution.
+ * See the module GHC.Profiling.
+ * ---------------------------------------------------------------------------*/
+
+void requestHeapCensus ( void );
+void startHeapProfTimer ( void );
+void stopHeapProfTimer ( void );
=====================================
libraries/base/GHC/Profiling.hs
=====================================
@@ -2,7 +2,14 @@
{-# LANGUAGE NoImplicitPrelude #-}
-- | @since 4.7.0.0
-module GHC.Profiling where
+module GHC.Profiling ( -- * Cost Centre Profiling
+ startProfTimer
+ , stopProfTimer
+ -- * Heap Profiling
+ , startHeapProfTimer
+ , stopHeapProfTimer
+ , requestHeapCensus
+ )where
import GHC.Base
@@ -17,3 +24,20 @@ foreign import ccall stopProfTimer :: IO ()
--
-- @since 4.7.0.0
foreign import ccall startProfTimer :: IO ()
+
+-- | Request a heap census on the next context switch. The census can be
+-- requested whether or not the heap profiling timer is running.
+--
+-- @since 4.16.0.0
+foreign import ccall requestHeapCensus :: IO ()
+
+-- | Start heap profiling. This is called normally by the RTS on start-up,
+-- but can be disabled using the rts flag `--no-automatic-heap-samples`
+--
+-- @since 4.16.0.0
+foreign import ccall startHeapProfTimer :: IO ()
+
+-- | Stop heap profiling.
+--
+-- @since 4.16.0.0
+foreign import ccall stopHeapProfTimer :: IO ()
=====================================
libraries/base/GHC/RTS/Flags.hsc
=====================================
@@ -289,6 +289,7 @@ data ProfFlags = ProfFlags
, heapProfileInterval :: RtsTime -- ^ time between samples
, heapProfileIntervalTicks :: Word -- ^ ticks between samples (derived)
, includeTSOs :: Bool
+ , startHeapProfileAtStartup :: Bool
, showCCSOnException :: Bool
, maxRetainerSetSize :: Word
, ccsLength :: Word
@@ -586,6 +587,8 @@ getProfFlags = do
<*> #{peek PROFILING_FLAGS, heapProfileIntervalTicks} ptr
<*> (toBool <$>
(#{peek PROFILING_FLAGS, includeTSOs} ptr :: IO CBool))
+ <*> (toBool <$>
+ (#{peek PROFILING_FLAGS, startHeapProfileAtStartup} ptr :: IO CBool))
<*> (toBool <$>
(#{peek PROFILING_FLAGS, showCCSOnException} ptr :: IO CBool))
<*> #{peek PROFILING_FLAGS, maxRetainerSetSize} ptr
=====================================
rts/Proftimer.c
=====================================
@@ -18,7 +18,12 @@
static bool do_prof_ticks = false; // enable profiling ticks
#endif
-static bool do_heap_prof_ticks = false; // enable heap profiling ticks
+static bool do_heap_prof_ticks = false; // Whether the timer is currently ticking down
+static bool heap_prof_timer_active = false; // Whether the timer is enabled at all
+
+/* The heap_prof_timer_active flag controls whether heap profiling is enabled
+at all, once it is enabled, the `do_heap_prof_ticks` flag controls whether the
+counter is currently counting down. This is paused, for example, in Schedule.c. */
// Sampling of Ticky-Ticky profiler to eventlog
#if defined(TICKY_TICKY) && defined(TRACING)
@@ -51,18 +56,36 @@ startProfTimer( void )
void
stopHeapProfTimer( void )
{
- RELAXED_STORE(&do_heap_prof_ticks, false);
+ RELAXED_STORE(&heap_prof_timer_active, false);
+ pauseHeapProfTimer();
}
void
startHeapProfTimer( void )
{
+ RELAXED_STORE(&heap_prof_timer_active, true);
+ resumeHeapProfTimer();
+}
+
+void
+pauseHeapProfTimer ( void ) {
+ RELAXED_STORE(&do_heap_prof_ticks, false);
+}
+
+
+void
+resumeHeapProfTimer ( void ) {
if (RtsFlags.ProfFlags.doHeapProfile &&
RtsFlags.ProfFlags.heapProfileIntervalTicks > 0) {
- do_heap_prof_ticks = true;
+ RELAXED_STORE(&do_heap_prof_ticks, true);
}
}
+void
+requestHeapCensus( void ){
+ RELAXED_STORE(&performHeapProfile, true);
+}
+
void
initProfTimer( void )
{
@@ -70,7 +93,12 @@ initProfTimer( void )
ticks_to_heap_profile = RtsFlags.ProfFlags.heapProfileIntervalTicks;
- startHeapProfTimer();
+ /* This might look a bit strange but the heap profile timer can
+ be toggled on/off from within Haskell by calling the startHeapProf
+ function from within Haskell */
+ if (RtsFlags.ProfFlags.startHeapProfileAtStartup){
+ startHeapProfTimer();
+ }
}
uint32_t total_ticks = 0;
@@ -99,7 +127,7 @@ handleProfTick(void)
}
#endif
- if (RELAXED_LOAD(&do_heap_prof_ticks)) {
+ if (RELAXED_LOAD(&do_heap_prof_ticks) && RELAXED_LOAD(&heap_prof_timer_active)) {
ticks_to_heap_profile--;
if (ticks_to_heap_profile <= 0) {
ticks_to_heap_profile = RtsFlags.ProfFlags.heapProfileIntervalTicks;
=====================================
rts/Proftimer.h
=====================================
@@ -12,9 +12,8 @@
void initProfTimer ( void );
void handleProfTick ( void );
-
-void stopHeapProfTimer ( void );
-void startHeapProfTimer ( void );
+void pauseHeapProfTimer ( void );
+void resumeHeapProfTimer ( void );
extern bool performHeapProfile;
extern bool performTickySample;
=====================================
rts/RtsFlags.c
=====================================
@@ -211,6 +211,7 @@ void initRtsFlagsDefaults(void)
RtsFlags.ProfFlags.doHeapProfile = false;
RtsFlags.ProfFlags.heapProfileInterval = USToTime(100000); // 100ms
+ RtsFlags.ProfFlags.startHeapProfileAtStartup = true;
#if defined(PROFILING)
RtsFlags.ProfFlags.includeTSOs = false;
@@ -390,6 +391,10 @@ usage_text[] = {
" -hT Produce a heap profile grouped by closure type",
#endif /* PROFILING */
+" -i<sec> Time between heap profile samples (seconds, default: 0.1)",
+" --no-automatic-heap-samples Do not start the heap profile interval timer,",
+" rely on the user to trigger samples from their application",
+
#if defined(TRACING)
"",
" -ol<file> Send binary eventlog to <file> (default: <program>.eventlog)",
@@ -415,7 +420,6 @@ usage_text[] = {
" the initial enabled event classes are 'sgpu'",
#endif
-" -i<sec> Time between heap profile samples (seconds, default: 0.1)",
"",
#if defined(TICKY_TICKY)
" -r<file> Produce ticky-ticky statistics (with -rstderr for stderr)",
@@ -1080,6 +1084,12 @@ error = true;
}
break;
}
+ else if (strequal("no-automatic-heap-samples",
+ &rts_argv[arg][2])) {
+ OPTION_SAFE;
+ RtsFlags.ProfFlags.startHeapProfileAtStartup = false;
+ break;
+ }
else {
OPTION_SAFE;
errorBelch("unknown RTS option: %s",rts_argv[arg]);
=====================================
rts/Schedule.c
=====================================
@@ -415,7 +415,7 @@ run_thread:
// that.
cap->r.rCurrentTSO = t;
- startHeapProfTimer();
+ resumeHeapProfTimer();
// ----------------------------------------------------------------------
// Run the current thread
@@ -533,7 +533,7 @@ run_thread:
// ----------------------------------------------------------------------
// Costs for the scheduler are assigned to CCS_SYSTEM
- stopHeapProfTimer();
+ pauseHeapProfTimer();
#if defined(PROFILING)
cap->r.rCCCS = CCS_SYSTEM;
#endif
=====================================
rts/rts.cabal.in
=====================================
@@ -180,6 +180,7 @@ library
rts/Types.h
rts/Utils.h
rts/prof/CCS.h
+ rts/prof/Heap.h
rts/prof/LDV.h
rts/storage/Block.h
rts/storage/ClosureMacros.h
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/212854051c77dc40ba3bf10f897f20fb7eb669d8
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/212854051c77dc40ba3bf10f897f20fb7eb669d8
You're receiving this email because of your account on gitlab.haskell.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/ghc-commits/attachments/20201208/354150a4/attachment-0001.html>
More information about the ghc-commits
mailing list