ghc-heap-view-0.6.0: Extract the heap representation of Haskell values and thunks

Copyright(c) 2012-2019 Joachim Breitner
LicenseBSD3
MaintainerJoachim Breitner <mail@joachim-breitner.de>
Safe HaskellNone
LanguageHaskell2010

GHC.HeapView

Contents

Description

With this module, you can investigate the heap representation of Haskell values, i.e. to investigate sharing and lazy evaluation.

Synopsis

Heap data types

data GenClosure b #

This is the representation of a Haskell value on the heap. It reflects http://hackage.haskell.org/trac/ghc/browser/includes/rts/storage/Closures.h

The data type is parametrized by the type to store references in. Usually this is a Box with the type synonym Closure.

All Heap objects have the same basic layout. A header containing a pointer to the info table and a payload with various fields. The info field below always refers to the info table pointed to by the header. The remaining fields are the payload.

See https://ghc.haskell.org/trac/ghc/wiki/Commentary/Rts/Storage/HeapObjects for more information.

Constructors

ConstrClosure

A data constructor

Fields

FunClosure

A function

Fields

ThunkClosure

A thunk, an expression not obviously in head normal form

Fields

SelectorClosure

A thunk which performs a simple selection operation

Fields

PAPClosure

An unsaturated function application

Fields

APClosure

A function application

Fields

APStackClosure

A suspended thunk evaluation

Fields

IndClosure

A pointer to another closure, introduced when a thunk is updated to point at its value

Fields

BCOClosure

A byte-code object (BCO) which can be interpreted by GHC's byte-code interpreter (e.g. as used by GHCi)

Fields

  • info :: !StgInfoTable
     
  • instrs :: !b

    A pointer to an ArrWords of instructions

  • literals :: !b

    A pointer to an ArrWords of literals

  • bcoptrs :: !b

    A pointer to an ArrWords of byte code objects

  • arity :: !HalfWord

    Arity of the partial application

  • size :: !HalfWord

    The size of this BCO in words

  • bitmap :: ![Word]

    An StgLargeBitmap describing the pointerhood of its args/free vars

BlackholeClosure

A thunk under evaluation by another thread

Fields

ArrWordsClosure

A ByteArray#

Fields

MutArrClosure

A MutableByteArray#

Fields

MVarClosure

An MVar#, with a queue of thread state objects blocking on them

Fields

MutVarClosure

A MutVar#

Fields

BlockingQueueClosure

An STM blocking queue.

Fields

IntClosure

Primitive Int

Fields

WordClosure

Primitive Word

Fields

Int64Closure

Primitive Int64

Fields

Word64Closure

Primitive Word64

Fields

AddrClosure

Primitive Addr

Fields

FloatClosure

Primitive Float

Fields

DoubleClosure

Primitive Double

Fields

OtherClosure

Another kind of closure

Fields

UnsupportedClosure 

Fields

Instances
Functor GenClosure Source # 
Instance details

Defined in GHC.HeapView

Methods

fmap :: (a -> b) -> GenClosure a -> GenClosure b #

(<$) :: a -> GenClosure b -> GenClosure a #

Foldable GenClosure Source # 
Instance details

Defined in GHC.HeapView

Methods

fold :: Monoid m => GenClosure m -> m #

foldMap :: Monoid m => (a -> m) -> GenClosure a -> m #

foldr :: (a -> b -> b) -> b -> GenClosure a -> b #

foldr' :: (a -> b -> b) -> b -> GenClosure a -> b #

foldl :: (b -> a -> b) -> b -> GenClosure a -> b #

foldl' :: (b -> a -> b) -> b -> GenClosure a -> b #

foldr1 :: (a -> a -> a) -> GenClosure a -> a #

foldl1 :: (a -> a -> a) -> GenClosure a -> a #

toList :: GenClosure a -> [a] #

null :: GenClosure a -> Bool #

length :: GenClosure a -> Int #

elem :: Eq a => a -> GenClosure a -> Bool #

maximum :: Ord a => GenClosure a -> a #

minimum :: Ord a => GenClosure a -> a #

sum :: Num a => GenClosure a -> a #

product :: Num a => GenClosure a -> a #

Traversable GenClosure Source # 
Instance details

Defined in GHC.HeapView

Methods

traverse :: Applicative f => (a -> f b) -> GenClosure a -> f (GenClosure b) #

sequenceA :: Applicative f => GenClosure (f a) -> f (GenClosure a) #

mapM :: Monad m => (a -> m b) -> GenClosure a -> m (GenClosure b) #

sequence :: Monad m => GenClosure (m a) -> m (GenClosure a) #

Show b => Show (GenClosure b) 
Instance details

Defined in GHC.Exts.Heap.Closures

allClosures :: GenClosure b -> [b] #

For generic code, this function returns all referenced closures.

data ClosureType #

Reading from the heap

getBoxedClosureData :: Box -> IO Closure #

Like getClosureData, but taking a Box, so it is easier to work with.

getClosureRaw :: a -> IO (Ptr StgInfoTable, [Word], [Box]) Source #

This returns the raw representation of the given argument. The second component of the triple are the words on the heap, and the third component are those words that are actually pointers. Once back in Haskell word, the Word may be outdated after a garbage collector run, but the corresponding Box will still point to the correct value.

Pretty printing

ppClosure :: (Int -> b -> String) -> Int -> GenClosure b -> String Source #

A pretty-printer that tries to generate valid Haskell for evalutated data. It assumes that for the included boxes, you already replaced them by Strings using map or, if you need to do IO, mapM.

The parameter gives the precedendence, to avoid avoidable parenthesises.

Heap maps

For more global views of the heap, you can use heap maps. These come in variations, either a trees or as graphs, depending on whether you want to detect cycles and sharing or not.

The entries of a HeapGraph can be annotated with arbitrary values. Most operations expect this to be in the Monoid class: They use mempty to annotate closures added because the passed values reference them, and they use mappend to combine the annotations when two values conincide, e.g. during updateHeapGraph.

data HeapTree Source #

Heap maps as tree, i.e. no sharing, no cycles.

buildHeapTree :: Int -> Box -> IO HeapTree Source #

Constructing an HeapTree from a boxed value. It takes a depth parameter that prevents it from running ad infinitum for cyclic or infinite structures.

ppHeapTree :: HeapTree -> String Source #

Pretty-Printing a heap Tree

Example output for [Just 4, Nothing, *something*], where *something* is an unevaluated expression depending on the command line argument.

[Just (I# 4),Nothing,Just (_thunk ["arg1","arg2"])]

data HeapGraphEntry a Source #

For heap graphs, i.e. data structures that also represent sharing and cyclic structures, these are the entries. If the referenced value is Nothing, then we do not have that value in the map, most likely due to exceeding the recursion bound passed to buildHeapGraph.

Besides a pointer to the stored value and the closure representation we also keep track of whether the value was still alive at the last update of the heap graph. In addition we have a slot for arbitrary data, for the user's convenience.

Instances
Functor HeapGraphEntry Source # 
Instance details

Defined in GHC.HeapView

Methods

fmap :: (a -> b) -> HeapGraphEntry a -> HeapGraphEntry b #

(<$) :: a -> HeapGraphEntry b -> HeapGraphEntry a #

Show a => Show (HeapGraphEntry a) Source # 
Instance details

Defined in GHC.HeapView

newtype HeapGraph a Source #

The whole graph. The suggested interface is to only use lookupHeapGraph, as the internal representation may change. Nevertheless, we export it here: Sometimes the user knows better what he needs than we do.

Constructors

HeapGraph (IntMap (HeapGraphEntry a)) 
Instances
Show a => Show (HeapGraph a) Source # 
Instance details

Defined in GHC.HeapView

buildHeapGraph Source #

Arguments

:: Monoid a 
=> Int

Search limit

-> a

Data value for the root

-> Box

The value to start with

-> IO (HeapGraph a) 

Creates a HeapGraph for the value in the box, but not recursing further than the given limit. The initial value has index heapGraphRoot.

multiBuildHeapGraph Source #

Arguments

:: Monoid a 
=> Int

Search limit

-> [(a, Box)]

Starting values with associated data entry

-> IO (HeapGraph a, [(a, HeapGraphIndex)]) 

Creates a HeapGraph for the values in multiple boxes, but not recursing further than the given limit.

Returns the HeapGraph and the indices of initial values. The arbitrary type a can be used to make the connection between the input and the resulting list of indices, and to store additional data.

addHeapGraph Source #

Arguments

:: Monoid a 
=> Int

Search limit

-> a

Data to be stored with the added value

-> Box

Value to add to the graph

-> HeapGraph a

Graph to extend

-> IO (HeapGraphIndex, HeapGraph a) 

Adds an entry to an existing HeapGraph.

Returns the updated HeapGraph and the index of the added value.

annotateHeapGraph :: Monoid a => a -> HeapGraphIndex -> HeapGraph a -> HeapGraph a Source #

Adds the given annotation to the entry at the given index, using the mappend operation of its Monoid instance.

updateHeapGraph :: Monoid a => Int -> HeapGraph a -> IO (HeapGraph a, HeapGraphIndex -> HeapGraphIndex) Source #

This function updates a heap graph to reflect the current state of closures on the heap, conforming to the following specification.

  • Every entry whose value has been garbage collected by now is marked as dead by setting hgeLive to False
  • Every entry whose value is still live gets the hgeClosure field updated and newly referenced closures are, up to the given depth, added to the graph.
  • A map mapping previous indicies to the corresponding new indicies is returned as well.
  • The closure at heapGraphRoot stays at heapGraphRoot

ppHeapGraph :: HeapGraph a -> String Source #

Pretty-prints a HeapGraph. The resulting string contains newlines. Example for let s = "Ki" in (s, s, cycle "Ho"):

let x1 = "Ki"
    x6 = C# 'H' : C# 'o' : x6
in (x1,x1,x6)

Boxes

data Box #

An arbitrary Haskell value in a safe Box. The point is that even unevaluated thunks can safely be moved around inside the Box, and when required, e.g. in getBoxedClosureData, the function knows how far it has to evaluate the argument.

Constructors

Box (Any :: Type) 
Instances
Show Box 
Instance details

Defined in GHC.Exts.Heap.Closures

Methods

showsPrec :: Int -> Box -> ShowS #

show :: Box -> String #

showList :: [Box] -> ShowS #

asBox :: a -> Box #

This takes an arbitrary value and puts it into a box. Note that calls like

asBox (head list)

will put the thunk "head list" into the box, not the element at the head of the list. For that, use careful case expressions:

case list of x:_ -> asBox x

areBoxesEqual :: Box -> Box -> IO Bool #

Boxes can be compared, but this is not pure, as different heap objects can, after garbage collection, become the same object.

Disassembler

disassembleBCO :: (a -> Maybe (GenClosure b)) -> GenClosure a -> Maybe [BCI b] Source #

This function integrates the disassembler in GHC.Disassembler. The first argument should a function that dereferences the pointer in the closure to a closure.

If any of these return Nothing, then disassembleBCO returns Nothing

Orphan instances

Functor GenClosure Source # 
Instance details

Methods

fmap :: (a -> b) -> GenClosure a -> GenClosure b #

(<$) :: a -> GenClosure b -> GenClosure a #

Foldable GenClosure Source # 
Instance details

Methods

fold :: Monoid m => GenClosure m -> m #

foldMap :: Monoid m => (a -> m) -> GenClosure a -> m #

foldr :: (a -> b -> b) -> b -> GenClosure a -> b #

foldr' :: (a -> b -> b) -> b -> GenClosure a -> b #

foldl :: (b -> a -> b) -> b -> GenClosure a -> b #

foldl' :: (b -> a -> b) -> b -> GenClosure a -> b #

foldr1 :: (a -> a -> a) -> GenClosure a -> a #

foldl1 :: (a -> a -> a) -> GenClosure a -> a #

toList :: GenClosure a -> [a] #

null :: GenClosure a -> Bool #

length :: GenClosure a -> Int #

elem :: Eq a => a -> GenClosure a -> Bool #

maximum :: Ord a => GenClosure a -> a #

minimum :: Ord a => GenClosure a -> a #

sum :: Num a => GenClosure a -> a #

product :: Num a => GenClosure a -> a #

Traversable GenClosure Source # 
Instance details

Methods

traverse :: Applicative f => (a -> f b) -> GenClosure a -> f (GenClosure b) #

sequenceA :: Applicative f => GenClosure (f a) -> f (GenClosure a) #

mapM :: Monad m => (a -> m b) -> GenClosure a -> m (GenClosure b) #

sequence :: Monad m => GenClosure (m a) -> m (GenClosure a) #

Storable StgInfoTable Source # 
Instance details