ghc-events-0.4.4.0/0000755000000000000000000000000012520426612012106 5ustar0000000000000000ghc-events-0.4.4.0/GhcEvents.hs0000644000000000000000000002322012520426612014327 0ustar0000000000000000{-# LANGUAGE CPP #-} module Main where import GHC.RTS.Events import GHC.RTS.Events.Merge import GHC.RTS.Events.Analysis import GHC.RTS.Events.Analysis.SparkThread import GHC.RTS.Events.Analysis.Thread import GHC.RTS.Events.Analysis.Capability import System.Environment import Text.Printf import Data.List import Data.Either (rights) import Data.Function import Data.IntMap (IntMap) import Data.Map (Map) import qualified Data.Map as M import Data.Maybe import System.IO import System.Exit main = getArgs >>= command command ["--help"] = do putStr usage command ["show", file] = do log <- readLogOrDie file putStrLn $ ppEventLog log command ["show", "threads", file] = do eventLog <- readLogOrDie file let eventTypeMap = buildEventTypeMap . eventTypes . header $ eventLog let capEvents = sortEvents . events . dat $ eventLog let mappings = rights . validates capabilityThreadRunMachine $ capEvents let indexes = map (uncurry capabilityThreadIndexer) $ zip mappings capEvents let threadMap = M.fromListWith (++) . reverse $ zip indexes (map return capEvents) putStrLn "Event Types:" putStrLn . unlines . map ppEventType . eventTypes . header $ eventLog putStrLn "Thread Indexed Events:" putStrLn . showMap ((++ "\n") . show) (unlines . map ((" " ++) . ppEvent eventTypeMap)) $ threadMap command ["show", "caps", file] = do eventLog <- readLogOrDie file let eventTypeMap = buildEventTypeMap . eventTypes . header $ eventLog let capEvents = sortEvents . events . dat $ eventLog let indexes = map ce_cap capEvents let capMap = M.fromListWith (++) . reverse $ zip indexes (map return capEvents) putStrLn "Event Types:" putStrLn . unlines . map ppEventType . eventTypes . header $ eventLog putStrLn "Cap Indexed Events:" putStrLn . showMap ((++ "\n") . show) (unlines . map ((" " ++) . ppEvent eventTypeMap)) $ capMap command ["merge", out, file1, file2] = do log1 <- readLogOrDie file1 log2 <- readLogOrDie file2 let m = mergeEventLogs log1 log2 writeEventLogToFile out m command ["validate", "threads", file] = do eventLog <- readLogOrDie file let capEvents = sortEvents . events . dat $ eventLog let result = validate (routeM capabilityThreadRunMachine capabilityThreadIndexer (refineM (spec . ce_event) threadMachine)) capEvents putStrLn $ showValidate (\(m, n) -> "\nThread States:\n" ++ showIndexed show show m ++ "\nCap States:\n" ++ showIndexed show show n) show result command ["validate", "threadpool", file] = do eventLog <- readLogOrDie file let capEvents = sortEvents . events . dat $ eventLog let result = validate capabilityThreadPoolMachine capEvents putStrLn $ showValidate show show result command ["validate", "threadrun", file] = do eventLog <- readLogOrDie file let capEvents = sortEvents . events . dat $ eventLog let result = validate capabilityThreadRunMachine capEvents putStrLn $ showValidate show show result command ["validate", "taskpool", file] = do eventLog <- readLogOrDie file let capEvents = sortEvents . events . dat $ eventLog let result = validate capabilityTaskPoolMachine capEvents putStrLn $ showValidate show show result command ["validate", "tasks", file] = do eventLog <- readLogOrDie file let capEvents = sortEvents . events . dat $ eventLog let result = validate capabilityTaskOSMachine capEvents putStrLn $ showValidate show show result command ["validate", "sparks", file] = do eventLog <- readLogOrDie file let capEvents = sortEvents . events . dat $ eventLog let result = validate (routeM capabilitySparkThreadMachine capabilitySparkThreadIndexer (refineM (spec . ce_event) sparkThreadMachine)) capEvents putStrLn $ showValidate show show result command ["simulate", "threads", file] = do eventLog <- readLogOrDie file let capEvents = sortEvents . events . dat $ eventLog let result = simulate (routeM capabilityThreadRunMachine capabilityThreadIndexer (refineM (spec . ce_event) threadMachine)) capEvents putStrLn . showProcess $ result command ["simulate", "threadpool", file] = do eventLog <- readLogOrDie file let capEvents = sortEvents . events . dat $ eventLog let result = simulate capabilityThreadPoolMachine capEvents putStrLn . showProcess $ result command ["simulate", "threadrun", file] = do eventLog <- readLogOrDie file let capEvents = sortEvents . events . dat $ eventLog let result = simulate capabilityThreadRunMachine capEvents putStrLn . showProcess $ result command ["simulate", "taskpool", file] = do eventLog <- readLogOrDie file let capEvents = sortEvents . events . dat $ eventLog let result = simulate capabilityTaskPoolMachine capEvents putStrLn . showProcess $ result command ["simulate", "tasks", file] = do eventLog <- readLogOrDie file let capEvents = sortEvents . events . dat $ eventLog let result = simulate capabilityTaskOSMachine capEvents putStrLn . showProcess $ result command ["simulate", "sparks", file] = do eventLog <- readLogOrDie file let capEvents = sortEvents . events . dat $ eventLog let result = simulate (routeM capabilitySparkThreadMachine capabilitySparkThreadIndexer (refineM (spec . ce_event) sparkThreadMachine)) capEvents putStrLn . showProcess $ result command ["profile", "threads", file] = do eventLog <- readLogOrDie file let capEvents = sortEvents . events . dat $ eventLog let result = profileRouted (refineM (spec. ce_event) threadMachine) capabilityThreadRunMachine capabilityThreadIndexer (time . ce_event) capEvents putStrLn . showProcess $ result command ["profile", "sparks", file] = do eventLog <- readLogOrDie file let capEvents = sortEvents . events . dat $ eventLog let result = profileRouted (refineM (spec . ce_event) sparkThreadMachine) capabilitySparkThreadMachine capabilitySparkThreadIndexer (time . ce_event) capEvents putStrLn . showProcess $ result command _ = putStr usage >> die "Unrecognized command" usage = unlines $ map pad strings where align = 4 + (maximum . map (length . fst) $ strings) pad (x, y) = zipWith const (x ++ repeat ' ') (replicate align ()) ++ y strings = [ ("ghc-events --help:", "Display this help.") , ("ghc-events show :", "Pretty print an event log.") , ("ghc-events show threads :", "Pretty print an event log, ordered by threads.") , ("ghc-events show caps :", "Pretty print an event log, ordered by capabilities.") , ("ghc-events merge :", "Merge two event logs.") , ("ghc-events sparks-csv :", "Print spark information in CSV.") , ("ghc-events validate threads :", "Validate thread states.") , ("ghc-events validate threadpool :", "Validate thread pool state.") , ("ghc-events validate threadrun :", "Validate thread running state.") , ("ghc-events validate tasks :", "Validate task states.") , ("ghc-events validate sparks :", "Validate spark thread states.") , ("ghc-events simulate threads :", "Simulate thread states.") , ("ghc-events simulate threadpool :", "Simulate thread pool state.") , ("ghc-events simulate threadrun :", "Simulate thread running state.") , ("ghc-events simulate tasks :", "Simulate task states.") , ("ghc-events simulate sparks :", "Simulate spark thread states.") , ("ghc-events profile threads :", "Profile thread states.") , ("ghc-events profile sparks :", "Profile spark thread states.") ] readLogOrDie file = do e <- readEventLogFromFile file case e of Left s -> die ("Failed to parse " ++ file ++ ": " ++ s) Right log -> return log #if ! MIN_VERSION_base(4,8,0) die s = do hPutStrLn stderr s; exitWith (ExitFailure 1) #endif showValidate :: (s -> String) -> (i -> String) -> Either (s, i) s -> String showValidate showState showInput (Left (state, input)) = "Invalid eventlog:" ++ "\nState:\n" ++ ( showState state ) ++ "\nInput:\n" ++ ( showInput input ) showValidate showState _ (Right state) = "Valid eventlog: " ++ ( showState state ) showProcess :: (Show e, Show a) => Process e a -> String showProcess process = "Trace:\n" ++ (unlines . map show . toList) process ++ "\n" ++ (maybe "Valid." (("Invalid:\n" ++) . show) . toMaybe) process showIndexed :: (k -> String) -> (v -> String) -> Map k v -> String showIndexed showKey showValue m | M.null m = "Empty map\n" | otherwise = "Indexed output:\n" ++ concatMap (\(k, v) -> "Key: " ++ ( showKey k ) ++ ", Value: " ++ ( showValue v ) ++ "\n") (M.toList m) showMap :: Ord k => (k -> String) -> (a -> String) -> M.Map k a -> String showMap showKey showValue m = concat $ zipWith (++) (map showKey . M.keys $ m :: [String]) (map (showValue . (M.!) m) . M.keys $ m :: [String]) ghc-events-0.4.4.0/Setup.lhs0000644000000000000000000000011512520426612013713 0ustar0000000000000000#!/usr/bin/env runhaskell > import Distribution.Simple > main = defaultMain ghc-events-0.4.4.0/LICENSE0000644000000000000000000000312712520426612013116 0ustar0000000000000000The Glasgow Haskell Compiler License Copyright 2002-2012, The University Court of the University of Glasgow and others. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - Neither name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY COURT OF THE UNIVERSITY OF GLASGOW AND THE CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY COURT OF THE UNIVERSITY OF GLASGOW OR THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ghc-events-0.4.4.0/ghc-events.cabal0000644000000000000000000000522412520426612015140 0ustar0000000000000000name: ghc-events version: 0.4.4.0 synopsis: Library and tool for parsing .eventlog files from GHC description: Parses .eventlog files emitted by GHC 6.12.1 and later. Includes the ghc-events tool permitting, in particular, to dump an event log file as text. category: Development, GHC, Debug, Profiling, Trace license: BSD3 license-file: LICENSE author: Donnie Jones , Simon Marlow , Paul Bone , Mischa Dieterle , Thomas Horstmeyer , Duncan Coutts , Nicolas Wu , Jost Berthold Mikolaj Konarski maintainer: Simon Marlow bug-reports: https://github.com/haskell/ThreadScope/issues build-type: Simple tested-with: GHC == 6.12.3, GHC == 7.4.1, GHC == 7.6.1, GHC == 7.6.3, GHC == 7.8.2, GHC == 7.8.3, GHC == 7.10.1 cabal-version: >= 1.8 extra-source-files: GHC/RTS/EventLogFormat.h, test/*.eventlog test/stop.hs source-repository head type: git location: git@github.com:haskell/ghc-events.git library build-depends: base == 4.*, mtl >= 2.2.1 && < 3.0, containers >= 0.2 && < 0.6, binary >= 0.5 && < 0.8, bytestring >= 0.9.0, array >= 0.2 && < 0.6 exposed-modules: GHC.RTS.Events, GHC.RTS.Events.Merge GHC.RTS.Events.Analysis GHC.RTS.Events.Analysis.Capability GHC.RTS.Events.Analysis.SparkThread GHC.RTS.Events.Analysis.Thread other-modules: GHC.RTS.EventParserUtils, GHC.RTS.EventTypes include-dirs: GHC/RTS extensions: RecordWildCards, NamedFieldPuns, BangPatterns, PatternGuards other-extensions: FlexibleContexts, CPP executable ghc-events main-is: GhcEvents.hs build-depends: base, mtl, containers, binary, bytestring, array extensions: RecordWildCards, NamedFieldPuns, BangPatterns, PatternGuards test-suite test-versions type: exitcode-stdio-1.0 main-is: test/TestVersions.hs build-depends: base, mtl, containers, binary, bytestring, array extensions: RecordWildCards, NamedFieldPuns, BangPatterns, PatternGuards ghc-events-0.4.4.0/test/0000755000000000000000000000000012520426612013065 5ustar0000000000000000ghc-events-0.4.4.0/test/stop.hs0000644000000000000000000000235312520426612014411 0ustar0000000000000000-- This test program triggers different thread stop encodings in -- eventlogs, depending on GHC version (black hole, mvar read, mvar) module Main where import Control.Concurrent import Debug.Trace import GHC.Conc main = do putStrLn "suggest to run with +RTS -lsu-g-p -K80m -k10m -H200m -C1s" -- define some time-consuming computation let stuff = ack 3 10 -- create MVars to block on v1 <- newMVar "full" v2 <- newEmptyMVar -- create a thread which blackholes something, and re-fills the MVar traceEventIO "forking child thread" forkIO (do traceEventIO "child" putStrLn ("child thread sez " ++ show stuff) traceEventIO "filling full MVar" putMVar v1 "filled full var" yield traceEventIO "filling empty MVar" putMVar v2 "filled empty var" yield traceEventIO "child finished" ) yield putStrLn ("and the main thread sez " ++ show stuff) traceEventIO "emptying full MVar" s1 <- takeMVar v1 putStrLn ("from MVar: " ++ s1) traceEventIO "reading empty MVar" s2 <- readMVar v2 putStrLn ("from MVar: " ++ s2) ack :: Integer -> Integer -> Integer ack 0 m = m+1 ack n 0 = ack (n-1) 1 ack n m = ack (n-1) (ack n (m-1)) ghc-events-0.4.4.0/test/pre77stop.eventlog0000644000000000000000000001456012520426612016512 0ustar0000000000000000hdrbhetbetb Create threadeteetb Run threadeteetb Stop threadeteetbThread runnableeteetbMigrate threadeteetb Wakeup threadeteetb Starting GCeteetb Finished GCeteetb Request sequential GCeteetb Request parallel GCeteetbCreate spark threadeteetb Log messageeteetbCreate capabilitieseteetb Block markereteetb User messageeteetbGC idleeteetb GC workingeteetbGC doneeteetbVersioneteetbProgram invocationeteetbCreate capability seteteetbDelete capability seteteetb Add capability to capability seteteetb%Remove capability from capability seteteetbRTS name and versioneteetbProgram argumentseteetbProgram environment variableseteetb  Process IDeteetb!Parent process IDeteetb"8Spark counterseteetb# Spark createeteetb$ Spark dudeteetb%Spark overfloweteetb& Spark runeteetb' Spark stealeteetb( Spark fizzleeteetb)Spark GCeteetb+Wall clock timeeteetb, Thread labeleteetb-Create capabilityeteetb.Delete capabilityeteetb/Disable capabilityeteetb0Enable capabilityeteetb1 Total heap mem ever allocatedeteetb2 Current heap sizeeteetb3 Current heap live dataeteetb4&Heap static parameterseteetb52 GC statisticseteetb6Synchronise stop-the-world GCeteetb<Starting message receivaleteetb=Finished message receivaleteetb>Creating Processeteetb?Killing Processeteetb@Assigning thread to processeteetbA Creating machineeteetbBKilling machineeteetbCSending messageeteetbDReceiving messageeteetbESending/Receiving local messageetehetehdredatbi5B0ݭ>  q !@.BBD.forking child threadFFFFUUFchildK"O~P- T ]UTA[ U\p'#Hc#O+JX+R0ò000Ʃfilling full MVar0000B0emptying full MVar00'0))0Ppreading empty MVar0T0U~0Vc0WW0aYfilling empty MVar0b0d50e0q0r0Ő0>00$0!07Rchild finished090;0Xg 0ݳk-v+St[ M!ImаGHC-7.6.3 rts_l:;./wrongeventlog2+RTS-lsu-g-p-K80m-k10m-H200m-C1s =SSH_AGENT_PID=1817PVM_RSH=/usr/bin/sshGPG_AGENT_INFO=/tmp/keyring-yTUMmt/gpg:0:1TERM=xtermSHELL=/bin/bashXDG_SESSION_COOKIE=acf1c79e0e2de67643be755c00000003-1405160974.283591-1531347675WINDOWID=58743399OLDPWD=/opt/Eden/edentv/fixFor783/BLD-ghc-events-parallelGNOME_KEYRING_CONTROL=/tmp/keyring-yTUMmtUSER=jostLS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lz=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.axa=00;36:*.oga=00;36:*.spx=00;36:*.xspf=00;36:XDG_SESSION_PATH=/org/freedesktop/DisplayManager/Session0XDG_SEAT_PATH=/org/freedesktop/DisplayManager/Seat0PVM_ROOT=/usr/lib/pvm3SSH_AUTH_SOCK=/tmp/keyring-yTUMmt/sshSESSION_MANAGER=local/onAir:@/tmp/.ICE-unix/1781,unix/onAir:/tmp/.ICE-unix/1781DEFAULTS_PATH=/usr/share/gconf/gnome-fallback.default.pathPVM_ARCH=LINUX64XDG_CONFIG_DIRS=/etc/xdg/xdg-gnome-fallback:/etc/xdgPATH=/home/jost/bin:/home/jost/bin:/usr/lib/lightdm/lightdm:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/home/jost/.cabal/binDESKTOP_SESSION=gnome-fallbackPWD=/opt/Eden/edentv/fixFor783GNOME_KEYRING_PID=1770LANG=en_US.UTF-8MANDATORY_PATH=/usr/share/gconf/gnome-fallback.mandatory.pathUBUNTU_MENUPROXY=libappmenu.soGDMSESSION=gnome-fallbackSHLVL=1HOME=/home/jostLANGUAGE=en_US:enGNOME_DESKTOP_SESSION_ID=this-is-deprecatedLOGNAME=jostPVM_EXPORT=DISPLAYXDG_DATA_DIRS=/usr/share/gnome-fallback:/usr/share/gnome:/usr/local/share/:/usr/share/DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-Mviy2n6D5M,guid=3677210ad991dc7e0dc3a1ae00000012LESSOPEN=| /usr/bin/lesspipe %sDISPLAY=:0.0XDG_CURRENT_DESKTOP=GNOMELESSCLOSE=/usr/bin/lesspipe %s %sCOLORTERM=gnome-terminalXAUTHORITY=/home/jost/.Xauthority_=./wrongeventlog20ݏ0ݐ7.0ݑO0ݑ0ݑghc-events-0.4.4.0/test/783stop.eventlog0000644000000000000000000001515212520426612016065 0ustar0000000000000000hdrbhetbetb Create threadeteetb Run threadeteetb Stop threadeteetbThread runnableeteetbMigrate threadeteetb Wakeup threadeteetb Starting GCeteetb Finished GCeteetb Request sequential GCeteetb Request parallel GCeteetbCreate spark threadeteetb Log messageeteetbCreate capabilitieseteetb Block markereteetb User messageeteetbGC idleeteetb GC workingeteetbGC doneeteetbVersioneteetbProgram invocationeteetbCreate capability seteteetbDelete capability seteteetb Add capability to capability seteteetb%Remove capability from capability seteteetbRTS name and versioneteetbProgram argumentseteetbProgram environment variableseteetb  Process IDeteetb!Parent process IDeteetb"8Spark counterseteetb# Spark createeteetb$ Spark dudeteetb%Spark overfloweteetb& Spark runeteetb' Spark stealeteetb( Spark fizzleeteetb)Spark GCeteetb+Wall clock timeeteetb, Thread labeleteetb-Create capabilityeteetb.Delete capabilityeteetb/Disable capabilityeteetb0Enable capabilityeteetb1 Total heap mem ever allocatedeteetb2 Current heap sizeeteetb3 Current heap live dataeteetb4&Heap static parameterseteetb52 GC statisticseteetb6Synchronise stop-the-world GCeteetb7 Task createeteetb8 Task migrateeteetb9 Task deleteeteetb: User markereteetb;Empty event for bug #9003eteetb<Starting message receivaleteetb=Finished message receivaleteetb>Creating Processeteetb?Killing Processeteetb@Assigning thread to processeteetbA Creating machineeteetbBKilling machineeteetbCSending messageeteetbDReceiving messageeteetbESending/Receiving local messageetehetehdredatbB2+ -  H NI: M%M/Nforking child threadO4OcO O9dćechild"'GG  6s׬!^($SW1$[,} *,22O2T2filling full MVar2y2222Aemptying full MVar2C2U12V2preading empty MVar2222]2؇filling empty MVar2W22292t22021262^2t;child finished2w2y2L 2+ 61-ֱ[+<S KP N!UImGHC-7.8.3 rts_l85./wrong783+RTS-lsu-g-p-K80m-k10m-H200m-C1sO 7SSH_AGENT_PID=1817PVM_RSH=/usr/bin/sshGPG_AGENT_INFO=/tmp/keyring-yTUMmt/gpg:0:1TERM=xtermSHELL=/bin/bashXDG_SESSION_COOKIE=acf1c79e0e2de67643be755c00000003-1405160974.283591-1531347675WINDOWID=58743399OLDPWD=/opt/Eden/edentv/fixFor783/BLD-ghc-events-parallelGNOME_KEYRING_CONTROL=/tmp/keyring-yTUMmtUSER=jostLS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lz=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.axa=00;36:*.oga=00;36:*.spx=00;36:*.xspf=00;36:XDG_SESSION_PATH=/org/freedesktop/DisplayManager/Session0XDG_SEAT_PATH=/org/freedesktop/DisplayManager/Seat0PVM_ROOT=/usr/lib/pvm3SSH_AUTH_SOCK=/tmp/keyring-yTUMmt/sshSESSION_MANAGER=local/onAir:@/tmp/.ICE-unix/1781,unix/onAir:/tmp/.ICE-unix/1781DEFAULTS_PATH=/usr/share/gconf/gnome-fallback.default.pathPVM_ARCH=LINUX64XDG_CONFIG_DIRS=/etc/xdg/xdg-gnome-fallback:/etc/xdgPATH=/home/jost/bin:/home/jost/bin:/usr/lib/lightdm/lightdm:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/home/jost/.cabal/binDESKTOP_SESSION=gnome-fallbackPWD=/opt/Eden/edentv/fixFor783GNOME_KEYRING_PID=1770LANG=en_US.UTF-8MANDATORY_PATH=/usr/share/gconf/gnome-fallback.mandatory.pathUBUNTU_MENUPROXY=libappmenu.soGDMSESSION=gnome-fallbackSHLVL=1HOME=/home/jostLANGUAGE=en_US:enGNOME_DESKTOP_SESSION_ID=this-is-deprecatedLOGNAME=jostPVM_EXPORT=DISPLAYXDG_DATA_DIRS=/usr/share/gnome-fallback:/usr/share/gnome:/usr/local/share/:/usr/share/DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-Mviy2n6D5M,guid=3677210ad991dc7e0dc3a1ae00000012LESSOPEN=| /usr/bin/lesspipe %sDISPLAY=:0.0XDG_CURRENT_DESKTOP=GNOMELESSCLOSE=/usr/bin/lesspipe %s %sCOLORTERM=gnome-terminalXAUTHORITY=/home/jost/.Xauthority_=./wrong7837 .pN92 .p72.pN925.p2+v2+.2+2+/2+Űghc-events-0.4.4.0/test/mdlLogMPI1.eventlog0000644000000000000000000020371212520426612016504 0ustar0000000000000000hdrbhetbetb Create threadeteetb Run threadeteetb Stop threadeteetbThread runnableeteetbMigrate threadeteetbShutdowneteetb Wakeup threadeteetb Starting GCeteetb Finished GCeteetb Request sequential GCeteetb Request parallel GCeteetbCreate spark threadeteetb Log messageeteetbStartupeteetb Block markereteetb User messageeteetbGC idleeteetb GC workingeteetbGC doneeteetbVersioneteetbProgram invocationeteetbCreate capability seteteetbDelete capability seteteetb Add capability to capability seteteetb%Remove capability from capability seteteetbRTS name and versioneteetbProgram argumentseteetbProgram environment variableseteetb  Process IDeteetb!Parent process IDeteetb"8Spark counterseteetb# Spark createeteetb$ Spark dudeteetb%Spark overfloweteetb& Spark runeteetb' Spark stealeteetb( Spark fizzleeteetb)Spark GCeteetb+Wall clock timeeteetb, Thread labeleteetb<Starting message receivaleteetb=Finished message receivaleteetb>Creating Processeteetb?Killing Processeteetb@Assigning thread to processeteetbA Creating machineeteetbBKilling machineeteetbCSending messageeteetbDReceiving messageeteetbESending/Receiving local messageetehetehdredatb)̢ D,/@,N,10@13܀@3P3@44 `@404<4aPD4mU&4@@4D5 HW =5 5(555(55h5 5566Qh<6d=6l6p??H@ @gp<@w=Bg(BnHHWZp Wb@WgPg gggxg`gg he<@DHXDgXD XDXD)XD(XDFXDLhX9DXDaxX=m0u x  P   ˨ x H    XH  8 x H   0+3pJRZbPj q`0Xϰ׀Px H[gxw~p@ '8''!')'1x'5`'=0'A 'd@'o+4+@+HX+P(+[+c+++P+, ,x,H,',.,6,>p,F@,N,U,ih,q8,y,,,0,00Ƙ0h0 001?1Kh1S81[1j1v`1~01111p1@111h181111H266586=6D<7D9hX=9' 9.9699h9 999`909999X9(9::h:! :(:0:8:H0:S=Up =]@=hAAxA0AAAAAp AٰA8C<C1pDDb XwDE`X=FF FFpF'@F/FFFXF(FFÀFPF FFFxFHG GG%(G,G8G@GHPGWG_KKKKXL(LLhLtL@LLLLPL LL¨LxLHLLLpL@MM MM$PM0Qb@QqQyQ<TxDV(XDWX=WW֘WhXOX[hXc8XnX`X0XXXXXX(XX̰XhXXXY`Y 0YY"]]X](]]]]^^X^(^+^3^;P^C ^J^R^Z^b`^j0^r^^X^(^^^h^ _x _0`peeff Pf fff" fBfUirh<iDjݰXDlsX=l{ll`llllmm`m0m#m+m3Xm;(mBmJmVm^Pmf mmm}mHmmmmXm(qrr rpr@r!rg`rsrzrr@rrrrrPr rrrܐrrrssXss*ww`w0w<y`D{AX={P{Xp{`@{<{D|X4=|ø|ˈ|X|(|||P} } }}!x})H}1}8}Lp}T@}\}c}k}{P}  `p@( x!<9PDX=xHpHT`\0dwX(P H( aXi(pxPҠX( (,x80@GOWpjrzh8`"%1<eD?XDBX=N`^iX   < H` P0 X _ k sX {(      x H    h 8 ' 2 6   h 8  COXW(^fnzP HĈ(\ d+.:>FhN8VY y0p<DYXDXX= 8&p@{ x`ٸ@  h 8  ;` C0&*&6&>p&F@&N&U&&&&p&&&ڰ&h&P&'' x'H<'SD(րX=(8( ()`) 0)))0X)8(00)01P09 <0LD1HX=111242@2Hx2T02c2k2sp2(2222h28222`20222X2(8 88??%p?-@?5?8?@?H?L ?o?0AP <AgDBX=BCC pC@C C(CsC~CCXCCCC8C CCԨCxCHCCDpD@DDD2hD:8K?KJKRKZpKb@KjKHKKK˸K@KKKKLPL LLL%L9L@LHLPLXXLkLwSS=SESM<V/DWXDYDX=YPYXxY`HYYPYYY`Y0YYYZpZ@ZZZ#Z38Z;ZFZNZRxZfZmcz8 cc0hhhhxiHiii i3iFie<iy`DjX=jhj8jjjj`k:kFPkN kUkekqHkykkkk@kkkkPkkkިkxkkwow{Pw8wwwwww8xx<x#HDy0X=yyyyXy(yyyyhy8zz zHzz&z6zB@f흀8<`DSX=Zbjp0ߠp h8")5=`E0M`hXp(w8(%<5hDPX= %18@HPx\0`ks{p@h `0N8 V;CxKHSZ^fnp 8h<)DrX=yPP)1x9HAHPX`Xh({8xH'p'$'+'3';'CP'p'@'''h'8+++P+++è+x+H+++p+@, ,,,- ,8LLhL8L<MHDNz`XDOHX=OPP P^PjxPv0P~PpP@PPPP PPߨPxPHPQ QpQ@Q"Q)Q=hQE8aa#a+a3Xa;(aBa0aaaa(aa˰aӀaPa aaab`bbb-Xb5(b<bL<b\8DcPX=ccs sxs~~~~%~-P~18~9~< ~`~w#h<6DopX={(P ( '.:>xFHRYaipq@P `0xp@ WHfnv<D X= P( /7CxKHSZbP xJV^`f0nu Ϩx<(DypX=(h8`( P @*6>hN<]DX=ؐ`0 X(&6P> IQYxip  7сXщ(ѐјќѤѬPѰ8 `B<VDԖhX=Ԣ ԩԱԹH8#.6F0QYaiXq(xՀՈՔPգկշxտHڠpX塰婀PX&.P6 AEQxYHahpX曰检 `0<DX=( X'/7?PG NV^f`n0X(P+;@CJ<ZDhX=8 7 > J Rh b i q }` H    p @  ǘ h 8   x 2  : ]Ĩ`H "h<.@DXXD X=!!!!@!$!+!z!!!X!!!!8!!!ۨ!x!H!""p"("!")"9h"A8/x/)/1/9/E@/I(/`////X///ٰ//P/ /0000#0+030;X0J0V;`;;;<;@D=r(X==y====߈=X=(>> >P> >!>)>1>9`>A0>I>\>dX>l(>s>{>P> E E&EIJ?JChJO JSJZJ^JfJn` JJ@M(<M)DNXDOX{=OOOO@PP PVPaPiPqpPPPPhP8PPPPxP0PPPXP(QQQhX-X9XApXM(XTX\XXXXXXXݰ^Hh^X^c<ihDk XDly8X=llll`l0llllllllPmm |||x|H||} }"}*}2x}B}I}Q}]p}e@}m}t}|} }}x}H}}}θ}@} Šp@ 8 <D'XU=.6>pJ(QYp@ڰ8  xH08pKS[k8s'3;XC(JRpטh8x0!)1p9@AP\hȀ <`DZX=jxrHzP<D7hX=GNV^xryɁɍXɑ@ɜɤɬɴhɼ8א`0 X(<PDp(X=w䇘݈X(P '/7`?0JZbXnuyP   `H  4HY<mxD~XT=p@X(*2>PF MU]e`m0uXP !0!!޸!p!@!"@`"S"["gp"w<"D#pX=#(##$$ h$8$$ $($0x$D$K$W$_X$g($v$~EE(E%E-<E=hDFX=FFFFGpG(GG-G5PG= GDGLGTG`HGd0GlGwGXG(GGGG Ghh>XhF(hM<h]DiX=iXi@ihj*j6@j>jEjYhja8jijpjxj`j0jjjj@jjjΘjhjjSbjrXz(0߸r}h8xHנp@ h70 ?fS[Pc jnv~x` < DS0XDXn=h88$3?`G0OV^fpn@vh 0ҰXҿϘh8%1@9@P\8dks{xӃHӋӒӚӮ@ӶӽŰ̀ $4<`D0<SD X=x< PDMX=Y@](hpPxH¸ʈhPXP<D(X=%o{X(P x`@ +P3 LlhLLLH<LDMX=NN`N0Nh8NsNNxNNNpN@NNN՘NhN8NOO`O0OOO/pO;(OR OZhOHWXW@WWWWWPW8 W`Ww(ww٘wP<wDy-pXz=y5@y=yDyyyyXyyɰyрyPy yyyz`z zz'pz>zFzNz^ zi ,4`@GO`̸ԈX(h 8&.`60>Qa(<D0X= X(%p0{(8HP`<cDPX= xH@ h,8x`㛈<(D`X= Q\dl`凸又X(岰嶘P xH X` 0XM8U\dlxp`x0| @K <^DX=P +3h;8RZxbHjq}p@h8ϨH8V8f8n`8v0<8D9Xr=99P9 :X:(:#:+:;P:C :J:R:Z:fH:n:u:}::::::P::c;hcRc^cf`<cvDdX{=dPd de(ee#e+e; eFeNeVxe^Hefemeue}eXeeehe8e e˨exP͐<0D Xw=%PowXP xH@' 2xH .6>`Q<epD8Xs=`0X( P "*>E  x,04~8<DXi=hPx 0(/7?pG@OV^r8z퍐`  " ) 1 AX I( P X d hh  @    P      x H  # + ;X C( N V ^ n  }  `  " "Ɛ "` "0 " " " " #< #(8D $QXm= $X $` KH K K Kp< L D MXB= M Mh M&8 MtX M|( M M MP M M M Mx MH M M M Mp M N N Nh N 8 N/ N7 s s s tp t @ t t]H ti tp tx t@ t t t th t8 t t tʨ tx t t t tp u@ u u   H  < 'D `X{= k o wx  h 8   ` 0    #X '@ 2 : Jh R8 ] e m }0  0  ƈ @< D HX= & - 5    `    X (  ݰ  P   x H  ' 7 ?X h - 4 << LHD X= P   @      $ , 4 <` H O S _ gX v Ⴐ ኀ P   ᱐   ; JH R Y a e mp u@ y( P  < hD SXD X=     Έ X   ,H 4 ; Op W@ _ f n zh 8    0   Ġ p    (8 0 7 C Gx  h 8   ` / 0X 0 ( 0 0 0' 0/P 07  0> 0F 0ZH 0b 0i 0q 0y 0 0 QcP Qo Qv Q~< Q0D RX|= Rʰ RҀ Rh S$ S,X S8 S? SO SWP S_  Sj Sn Szx SH S S S SX S S SȘ Sh S< SD U?X= UO8 UW tѠ tX t( t t u uJ uR uZX ub( uu u} uP u  u u ux uH u u uψ uX u u u vP v   X %( ,< @D X=  p @ x 0   p (  ( 0 8h @8 H O W k0 s z  p    $ G `( d k s { h 8  0  < 6D XD PX=   ި x 0  H  O [ cx s ~  p @     P  ب ` 0   p ܘ ܣ ܫ ܳ` ܻ0  P   $ 80 @ G O Wp _@ g n v ݂h ݒ ݙ ݥ ݭ` ݵ0  ̠    < ,(D \X{= h lx tH  8   ` 0    p ( $ + 7 G8 O Z b j` z  Ϡ @  < D V@X= a i m  à X (   h      !` )0 1 D LX T( [ g wP  ;< ;D =X= = p =@ = =" =. =2 = =p =( = = =h =8 = = =֐ =` =0 = = >p >( > >  >( >88 >@ ? ? ?= F F Fx FH F F F FǠ F Fh N < ND OjX= OvH Oz0 O O O OX Ox OH O P Pp P@ b+X b: bF< bVPD c(X= c c cŀ cP c c c cx d d  d dX d#@ d6 d> w wH x x < x pD y`X= ylx yp` yx0 yh y  y y y` y z z z zX z$ z+ z3 z; zK  zV z^ zfx znH z} z P    x H X `P l s x H    p @   Ͱ P    x      J N V ^X f( j q y  H < 8D shX=      ` 0 8    #0 + 2 > Bp N( ] a mh< }D X=  x  & . 6p >@ Q Y 9 E8 M T \ dx   8  ٨ x 0    p @  # 7h ?8 G N V fH r P   < 0D X= h P   g@ o z  8    x  Ԡ p @   h 8   2` :0        #p 'X /( 6 V8 i P< D zXD @X=   ( 0h 88 @ (      ̨ x H    p @  " *h 28 : I U`  ژ h 8   8X D K _h g8 z Ȃ Ȋ` Ȓ0 Ț ȡ ȵX   h     x   " * 6@ :( I U Yh a8 i p ɀx ɈH ɐ ɗ ɟ ɧ ɷ( ɾ  Θ h 8   x H   ,X< ;D txX= ˀ0 ˈ ˏ ˗< ˣXD 8W=    H     X / ; ? Gh O8 W f r` vH ~ ̉ ̍ ̝X ̩ ̬ ̴ ̼ h    x H    X "( ) 1 Ah I8 Q X ` hx x  ͇ ͏ ͗X ͟( Ͳ ͺ P    H     Ε@ Π ר @ p  \x l Ϗ@ ӊ ӎ ӞP Ӣ8 Ӫ ӱ ӵ ӽ )xX4 2)A hx) 7.5.20111229)P)jost=mdlLogMPI 2 +RTS -l -RTS 10 200 200 ))))`+)O+4kp )'~!)p'}*!GHC-7.5.20111229 rts_debug_pm*+jost=mdlLogMPI+RTS-l-RTS10200200*hOMPI_MCA_orte_precondition_transports=a26f2412209a61f5-364fa122416e260cORBIT_SOCKETDIR=/tmp/orbit-jostATISTREAMSDKSAMPLEROOT=/opt/ati-stream-sdk-v2.3-lnx32GPG_AGENT_INFO=/tmp/seahorse-BYAiMn/S.gpg-agent:1893:1PVM_RSH=sshSHELL=/bin/bashTERM=xtermXDG_SESSION_COOKIE=ffab047df008bf9112f4eb2549e523e1-1325866751.93800-1887441509CUDASDKROOT=/opt/Cuda-openCL-misc/Cuda-SDK-ubuntu/cudaGLOBUS_LOCATION=/opt/globusWINDOWID=71303172GNOME_KEYRING_CONTROL=/tmp/keyring-XnV3KiPABLO_ROOT=/opt/EdenGHC/PabloGTK_MODULES=canberra-gtk-moduleUSER=jostLS_COLORS=rs=0:di=01;34:ln=01;36:hl=44;37:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.lzma=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.rar=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.axa=00;36:*.oga=00;36:*.spx=00;36:*.xspf=00;36:LD_LIBRARY_PATH=/opt/Cuda-openCL-misc/Cuda-SDK-ubuntu/cuda/lib:/opt/ati-stream-sdk-v2.3-lnx32/lib/x86:/opt/globus/libEC2_HOME=/opt/ec2-api-tools-1.3-34128SSH_AUTH_SOCK=/tmp/keyring-XnV3Ki/sshPVM_ROOT=/opt/EdenGHC/pvm3USERNAME=jostSESSION_MANAGER=local/ibm-jost:@/tmp/.ICE-unix/1849,unix/ibm-jost:/tmp/.ICE-unix/1849DEFAULTS_PATH=/usr/share/gconf/gnome.default.pathATISTREAMSDKROOT=/opt/ati-stream-sdk-v2.3-lnx32PVM_ARCH=LINUXXDG_CONFIG_DIRS=/etc/xdg/xdg-gnome:/etc/xdgPATH=/opt/Cuda-openCL-misc/Cuda-SDK-ubuntu/cuda/bin:/home/jost/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/opt/bin:/home/jost/.cabal/binDESKTOP_SESSION=gnome_=./mdlLogMPIPWD=/opt2/EdenGHC/darcs-edentestJAVA_HOME=/usr/lib/jvm/java-6-sunGDM_KEYBOARD_LAYOUT=dkGNOME_KEYRING_PID=1831LANG=en_DK.utf8GDM_LANG=en_DK.utf8MANDATORY_PATH=/usr/share/gconf/gnome.mandatory.pathGDMSESSION=gnomeHISTCONTROL=ignorebothSPEECHD_PORT=7560TEXINPUTS=/home/jost/texmf:HOME=/home/jostSHLVL=1GNOME_DESKTOP_SESSION_ID=this-is-deprecatedLOGNAME=jostDBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-2FumsJTp4s,guid=4ba373624b700fa54dbcc0394f071effXDG_DATA_DIRS=/usr/share/gnome:/usr/local/share/:/usr/share/DARCS_EDITOR=emacsLESSOPEN=| /usr/bin/lesspipe %sDISPLAY=:0.0EC2_PRIVATE_KEY=/home/jost/.amazon-keys/amazon-pk-MA6BWW7H6T6IGTAV5QIWU54PQDET2A7U.pemLESSCLOSE=/usr/bin/lesspipe %s %sCOLORTERM=gnome-terminalXAUTHORITY=/var/run/gdm/auth-for-jost-bN54Qk/databaseEC2_CERT=/home/jost/.amazon-keys/amazon-cert-MA6BWW7H6T6IGTAV5QIWU54PQDET2A7U.pemOMPI_MCA_orte_local_daemon_uri=1342570496.0;tcp://127.0.0.1:44967OMPI_MCA_orte_hnp_uri=1342570496.0;tcp://127.0.0.1:44967OMPI_MCA_mpi_yield_when_idle=0OMPI_MCA_orte_app_num=0OMPI_UNIVERSE_SIZE=1OMPI_MCA_ess=envOMPI_MCA_orte_ess_num_procs=2OMPI_COMM_WORLD_SIZE=2OMPI_COMM_WORLD_LOCAL_SIZE=2OMPI_MCA_orte_ess_jobid=1342570497OMPI_MCA_orte_ess_vpid=0OMPI_COMM_WORLD_RANK=0OMPI_COMM_WORLD_LOCAL_RANK=0OMPI_MCA_opal_cr_is_tool=0OPAL_OUTPUT_STDERR_FD=18>,G0'newInport(1,1,1), blackhole 0xb1d03514 0p'newInport(1,1,2), blackhole 0xb1d0351c C1U1p'newInport(1,1,3), blackhole 0xb1d03924 1@'newInport(1,1,4), blackhole 0xb1d0392c C3԰U>458(%connectTSO (1,_,2) to inport (2,1,1) C5nV5`'newInport(1,2,5), blackhole 0xb1d07d14 60%connectTSO (1,_,6) to inport (1,1,4) E6W6.@%connectTSO (1,_,6) to inport (1,1,3) C6EVC7XC85XC8XC8XC9XXC9j`XC9XC:XC?:XC?8X?%connectTSO (1,_,3) to inport (1,2,5) C?(VE@XE@hXE@8XE@%XE@0XE@8XE@@`XE@LXE@SXE@[XBOCOMM CHECK FAILED EHxXEMo`XER]XExXEXEPXEaXE`XE¸XExXEXEPXEoHXE+)XC+XE,aXE0XC13XE1XE6XC9XE: XEC `XCFXEGXXEKHXCLaXELXEQVXCXCXEX8XE]{XC]XE^}XEifXCl XEmuXEq`XCr[XErHXEwXC{XE}DXE(XCTXEMpXCPJ`XEPXCXHXE^ ? dH  p @ B ԫghc-events-0.4.4.0/test/mandelbrot-mmc-2011-06-14.eventlog0000644000000000000000000031336612520426612020575 0ustar0000000000000000hdrbhetbetbStartup (num_engines)eteetbShutdowneteetb8A block of events generated by a specific engine followseteetbA context is created or re-usedeteetb,The context is being placed on the run queueeteetb Run a spark from the local stacketeetb &Run a spark stolen from another engineeteetb Run contexteteetbContext stoppedeteetb&Create a context for executing a sparketeetbA user-provided log messageeteetb Start GCeteetb Stop GCeteetb'Register an id->string mappingeteetb(About to call main/2eteetbCreate an engine seteteetbDetete an engine seteteetbAdd an engine to an engine seteteetbAdd an engine to an engine seteteetb.The type of the runtime system for this capseteteetb*The command line arguments of this processeteetb0The environment variables this process inheritedeteetb &The pid and parent pid of this processeteetbg A spark is being createdeteetbd 0Start a parallel conjunction (dyn id, static id)eteetbe#End a parallel conjunction (dyn id)eteetbf End a parallel conjunct (dyn id)eteetbh Create a future (future id)eteetbi/Wait on a future without suspending (future id)eteetbj6Wait on a future by suspending this thread (future id)eteetbkSignal a future (future id)eteetbl.Engine begins looking for a context to executeeteetbm#Engine begins attempt to steal worketeetbn-Release this context to the free context pooletehetehdredatb mmc-DEV'STATE_VARIABLE_Acc_19'f9|Qhm99uAfC]QimC^bC_:CfM\QjpmM]M]FfWOQkmWQqWSIfaQlmaaKfk#QmpmkkNfu!Qnmu<uQf%"Qom&&Sf6QppmI3Vf QqmYf2Qrm23[f5Qspm ^fQtm6afQumcf˼Qvpm̐hffb8QwmceifsQxmT:kf6Qypm7y8Vnf-QzmqEqfQ{msfIQ|pm%vfAyQ}mC)D yf*HQ~m*?*{f8.`Qpm8/n80F~fEؐQmE EfeQmeefȻQm:fRQmT)UfV QpmVWfpQ0mqsfQmffQmfQPmF=f.APQpm.B5.C fHQmHDHf\RuQm\T*\Vf|ϣQm||fQmfCkQmDEfu=Q0muTuf oQPm  fQpmafQm&&fCQm*f ҰQm Ҳl ҳqf S@Qm S S|f <Qm  fqQ0muAwfbCQPmbbfPNQpmPOPQAf3Qm5fNQmNNfQmf0Qm35&fQmff!Q0m!!f$1QPm$$f'Qpm''6f*Z|Qm*\*`If.,Qm.,0.,Շf1w Qm1w61wmf5&MQm5&\5&$f8Qm8q8f=<Q0m=?=CdfA6\QPmA6_6A6afEQpmEEfIQmIIL> L> LJ{LKfO%QmO% O%(fTUQmTYTT]zfY%QmY%Y%@ f^Qm^A^  fcQ0mcbcfhQPmhhfnQpmnnfs Qms s fyQmyyWf~lQm~qV~u"fGkQmG2G"fQmV%fϺPQ0mϼϿ{(f(QPm06>+f-Qpm.fЀQmЃІ1fKzQðmKK4fWQmZN\7fQm!&:f/bQm//>f\QȐm\p\NAfǥ4QɰmǥǥDfQmGf8KQm8M8OJf}XQm}[;}]JMfxQ0mz}Pf,UQPm,Yq,\&SfNQpmQSVfDw7QѐmD}DXfQPmy![fQpm}_fQm=bf Qm  KefQ0mhfhQPm !xjfB@QmBG4BNlf#Qm#I#of)C-Qm)C)Crf.Qm..uf4Q0m4j4pyf:gQްm:g:gf|f@$cQm@$f%@$hfE^2QmEeEnfK3QmKKfQԽQ0mQ"QݢfWÈjQPmWÊWÌf]Qpm] ] *fcۂQmcc/fiBQmiDiFfp%k&Qmp%m0p%o~fvQQmvQvQ(f|Qm||yf^mQ0m^p^s=flQPmnqfTC1QpmTETIfVQmYZfF/=QmF0F2kfQm}foǥQmoɢof^Qm^^7f_.Q0m_5_=f`*uQPm`2g`<-fJQmQYfuQ0mZf5QPm8W:ftQpmf#XQm#t#f#Qm%'fYQ0m f -QPm / 1YfRpm^f7SRm7V 7Wf BRm  fRmfVRmV6Vf#FRm##:f+Q#R0m+Q$+Q&f38!RPm38=38f;_:R pm;_-fR"0m/fOR"mz2f"eR$m$&6f/R%m//9fx'R&mxxq<f ơ-R'm ƨ Ʊ>f)cR(m)cQ)cAf1l&R)m1qL1wDf:cR*m::GfBruR+mBr'Br|JfJKR-mJ3JMfSuLWR.0mSuNSuQPf[ R/Pm[[Sfd^iR0pmd^ld^oVflrR1mllHYfv U{R2mv ]%v fz\f~R3m~~_fR4mEbfbjR6mbb6ef"sR70m""?hfǀR8PmDŽLJkfy%R9pm|nfBR:mB9BVqf[KR;m[QL[Utf6R<m6E6wfR=mizf@R?mD;G}f©R@0mf5LFRAPm5N5PyfiRBmkPm~fRCm>f-wREm-{ -|fRF0m #faQ:RGPmaSDaUnf#;RHpm#?#@f,RIm,,f6FSRJm6FU6FWf?RKm? ?fIIRLmIIfSRNmSLSf]YRO0m]]h]^ffAt=RPPmfAvfAxfo}+RQpo}.o}DGno}Mo}Qeo}RRQpfo}TRQeo}TRQfo}URPeo}V>RPfo}VRPPeo}WgRPPfo}WROeo}XqROfo}YMROeo}ZROfo}[&RO0eo}[RO0fo}JRNeo}RNfo}RNpeo}9RNpfo}'RNeo}RNfo}}RMeo}RMfo}RMPeo} RMPfo}RLeo}RLfo}RLeo}RLfo}RL0eo}RL0fo}RKeo}"RKfo}RKpeo}"RKpfo}RKeo}]RKfo}RJeo}^RJfo}RJPeo}^RJPfo}RIeo}RIfo}RRIeo}RIfo}RRI0eo}RI0fo}WRHeo}RHfo}XRHpeo}RHpfo}aRHeo}RHfo}]RGeo}URGfo}RGPeo}ZRGPfo}QRFeo}RFfo}RRFeo}RFfo}WRF0eo}RF0fo}WREeo}REfo}\REpeo}REpfo}]REeo}REfo}fRDeo}RDfo}bRDPeo}RDPfo}cRCeo}RCfo}cRCeo}RCfo}_RC0eo}RC0fo}dRBeo}RBfo}eRBpeo}RBpfo}jRBeo}RBfo}fRAeo}RAfo}oRAPeo}RAPfo}tR@eo}R@fo}yR@eo}R@fo}~R@0eo}R@0fo}vR?eo}R?fo}R?peo}R?pfo}R?eo}R?fo}#R>eo}R>fo}R>Peo}R>Pfo}R=eo}ÝR=fo} R=eo}ĞR=fo}%R=0eo}ţR=0fo}%R<eo}ƟR<fo}&R'Rfo~>Reo~?0Rfo~?RPeo~@5RPfo~@Reo~A6Rfo~AReo~B6Rfo~BR0eo~C@R0fo~CReo~DRfo~ERpeo~FRpfo~G"Reo~GRfo~H0Reo~HRfo~I,RPeo~IRPfo~J1R eo~JR fo~K-R eo~KR fo~L2R 0eo~LR 0fo~M7R eo~MR fo~N<R peo~NR pfo~OFR eo~OR fo~PFR eo~PR fo~QPR Peo~QR Pfo~RUR eo~RR fo~SUR eo~SR fo~T_R 0eo~TR 0fo~U[R eo~UR fo~VdR peo~VR pfo~W`R eo~WR fo~XnReo~XRfo~YjRPeo~YRPfo~ZoReo~ZRfo~[pReo~[Rfo~\pR0eo~\R0fo~]uReo~]Rfo~^qRpeo~^Rpfo~_vReo~_Rfo~`{Reo~aRfo~aRPeo~bRPfo~bReo~cRfo~cReo~d Rfo~dR0eo~eR0fo~eReo~fRfo~fRpeo~gRpfo~gReo~hRfo~hReo~iERfo~iRPeo~jARPfo~jReo~kBRfo~kReo~lBRfo~lR0eo~mLR0fo~mReo~nHRfo~nRpeo~oqRpfo~oReo~phRfo~qQeo~rQfo~sXQPeo~tBQPfo~tQeo~uGQfo~uQeo~vLQfo~vQ0eo~wQQ0fo~wQeo~xVQfo~xQpeo~y[Qpfo~yQeo~z`Qfo~zQeo~{`Qfo~{QPeo~|aQPfo~|Qeo~}aQfo~}Qeo~~bQfo~~Q0eo~gQ0fo~Qeo~cQfo~Qpeo~hQpfo~Qeo~dQfo~Qeo~rQfo~QPeo~rQPfo~Qeo~sQfo~Qeo~xQfo~Q0eo~Q0fo~Qeo~Qfo~Qpeo~Qpfo~Qeo~Qfo~ Qeo~Qfo~QPeo~QPfo~ Qeo~Qfo~ Qeo~Qfo~Q0eo~Q0fo~Qeo~Qfo~Qpeo~Qpfo~ Qeo~Qfo~ Qeo~Qfo~QPeo~QPfo~!Qeo~Qfo~!Qeo~Qfo~Q0eo~Q0fo~Qeo~Qfo~Qpeo~Qpfo~Qeo~Qfo~Qeo~Qfo~QPeo~QPfo~Qeo~wQfo~Qeo~|Qfo~ Q0eo~Q0fo~Qeo~Qfo~Qpeo~Qpfo~Qeo~Qfo~Qeo~Qfo~QPeo~!QPfo~Qeo~&Qfo~Qeo~+Qfo~Q0eo~9Q0fo~Qeo~>Qfo~Qpeo~CQpfo~Qeo~CQfo~Qeo~DQfo~QPeo~DQPfo~Qeo~EQfo~Qeo~EQfo~Q0eo~JQ0fo~Qeo~FQfo~Qpeo~PQpfo~Qeo~PQfo~Qeo~ZQfo~QPeo~ZQPfo~Qeo~_Qfo~Qeo~dQfo~Q0eo~nQ0fo~Qeo~wQfo~Qpeo~xQpfo~Qeo~}Qfo~Qeo~}Qfo~QPeo~тQPfo~Qeo~҃Qfo~Qeo~ӃQfo~Q0eo~ԈQ0fo~Qeo~ՄQfo~Qpeo~։Qpfo~ Qeo~דQfo~Qeo~ؘQfo~QPeo~ٔQPfo~Qeo~ڙQfo~Qeo~۞Qfo~ Q0eo~ܚQ0fo~Qeo~&Qfo~Qpeo~ Qpfo~Qeo~Qfo~Qްeo~Qްfo~QPeo~QPfo~Qeo~Qfo~Qݐeo~Qݐfo~Q0eo~Q0fo~Qeo~Qfo~Qpeo~Qpfo~Qeo~Qfo~Q۰eo~#Q۰fo~QPeo~#QPfo~Qeo~$Qfo~Qڐeo~)Qڐfo~Q0eo~.Q0fo~Qeo~3Qfo~Qpeo~8Qpfo~Qeo~=Qfo~Qذeo~=Qذfo~QPeo~>QPfo~Qeo~>Qfo~Qאeo~:Qאfo~Q0eo~?Q0fo~Qeo~;Qfo~Qpeo~@Qpfo~Qeo~EQfo~Qհeo~JQհfo~QPeo~OQPfo~Qeo~PQfo~QԐeo~PQԐfo~Q0eo~UQ0fo~Qeo~ZQfo~Qpeo[QpfoQeodQfoQҰeoeQҰfoQPeoeQPfoQeoaQfoQѐeobQѐfoQ0eogQ0foQeocQfoQpeolQpfoQeo hQfo [Qϰeo Qϰfo wQPeo XQPfo Qeo]QfoQΐeobQΐfoQ0eogQ0foQeoqQfoQpeoqQpfoQeovQfoQ̰eowQ̰foQPeowQPfoQeoxQfoQːeotQːfoQ0eoyQ0foQeouQfoQpeo~QpfoQeozQfoQɰeoQɰfoQPeoQPfo QeoQfoQȐeoQȐfo Q0eo Q0fo! Qeo" Qfo"Qpeo# Qpfo#Qeo$vQfo$Qưeo%vQưfo%QPeo&rQPfo&Qeo'sQfo'QŐeo(sQŐfo(Q0eo)xQ0fo)Qeo*tQfo*Qpeo+yQpfo+Qeo,zQfo,Qðeo-Qðfo.QPeo.QPfo/Qeo/Qfo0Qeo0Qfo1 Q0eo1Q0fo2Qeo2Qfo3Qpeo3Qpfo4 Qeo4Qfo5Qeo6Qfo6QPeo7QPfo7Qeo8nQfo8Qeo9nQfo9Q0eo:xQ0fo:Qeo;tQfo;Qpeo~Qfo?QPeo?QPfo@Qeo@QfoAQeoAQfoBQ0eoBQ0foC QeoCQfoDQpeoDQpfoE QeoEQfoFQeoFQfoGQPeoGQPfoHQeoHQfoIQeoIQfoJQ0eoJQ0foKQeoKQfoLQpeoLQpfoMQeoMQfoNQeoNQfoOQPeoOQPfoP$QeoPQfoQ%QeoQQfoRWQ0eoRQ0foSWQeoSQfoTQpeoUQpfoUQeoV5QfoVQeoWYQfoWQPeoX^QPfoXQeoYcQfoYQeoZdQfoZQ0eo[mQ0fo[Qeo\nQfo\Qpeo]wQpfo]Qeo^|Qfo^Qeo_Qfo`QPeo`QPfoaQeoaQfobQeobQfocQ0eocQ0fodQeoeQfof QpeofQpfog|QeohQfohQeohQfoi}QPeojQPfoj~QeojQfok~QeokQfolQ0eolQ0fomQeomQfonQpeooQpfooQeopQfopQeoqQfoqQPeorQPforQeos QfosQeotQfotQ0eou Q0fouQeov%QfovQpeow&QpfowQeox/QfoxQeoy0QfoyQPeoz0QPfozQeo{1Qfo{Qeo|1Qfo|Q0eo}2Q0fo}Qeo~2Qfo~Qpeo3QpfoQeo3QfoQeo=QfoQPeoBQPfoQeoGQfoQeoLQfoQ0eoQQ0foQeoZQfoQpeo[QpfoQeo`QfoQeoQfo QPeoQPfoQeoQfoQeoQfoQ0eoQ0foQeoQfoQpeoQpfoQeoQfoQeoQfoQPeoQPfo]QeoQfo]QeoQfogQ0eoQ0fogQeoQfoqQpeoQpfoqQeo`QfoQeo`QfoQPeoQPfoOQeoQfoPQeoQfoGQ0eoQ0foLQeoQfoHQpeoQpfoMQeoQfoIQeoQfoSQPeoQPfoXQeoQfoXQeoQfobQ0eoQ0fobQeoQfogQpeoQpfocQeoQfomQeoQfoiQPeoQPfoiQeoQfojQeoQfofQ0eoQ0fofQeoQfogQpeoQpfolQeoQfoqQeoQfozQPeoQPfoQeoQfoQeo QfoQ0eoQ0foQeoQfoQpeoQpfoQeoQfoQeoQfo QPeoQPfoQeoQfo{QeoQfoQ0eo Q0foeQeoQfoaQpeoQpfooQeoQfokQeoQfouQPeoQPfozQeoQfozQeoQfoQ0eoQ0fo{QeoQfoۅQpeoQpfo܁QeoQfo݆QeoQfoނQPeoQPfo߇QeoQfoQeoQfoQ0eoQ0foQeoQfoQpeoQpfoQeoQfoQeo QfoQPeo QPfoQeoQfoQeoQfoQ0eoQ0foQeo%QfoQpeo&QpfoQeo+QfoQeo'QfoQPeo'QPfoQeo(QfoQeo(QfoQ0eo$Q0foQeo QfoQpeo%QpfoQeo*QfoQeo/QfoQPeo0QPfoQeo5QfoQeo5QfoQ0eo1Q0foQeoQfoQpeoQpfo*QeoQfo4Q~eoQ~fo0Q~PeoQ~Pfo5Q}eoQ}fo5Q}eoQ}fo6Q}0eoQ}0fo6Q|eoQ|fo7Q|peoQ|pfoEQ|eoQ|foAQ{eoQ{foFQ{PeoQ{Pfo KQzeo Qzfo KQzeo Qzfo UQz0eo Qz0fo QQyeo Qyfo ZQypeo Qypfo[QyeoQyfo`QxeoQxfo\QxPeoQxPfoeQweoQwfoaQweoQwfobQw0eoQw0fogQveoQvfogQvpeoQvpfoqQveoQvfomQueoQufovQuPeoQuPfo{QteoQtfo|QteoQtfoQt0eoQt0foQseoQsfoQspeo QspfoQseoQsfoQreo Qrfo QrPeo!QrPfo"Qqeo"Qqfo#sQqeo#Qqfo$xQq0eo$Qq0fo%xQpeo%Qpfo&}Qppeo'Qppfo'Qpeo'Qpfo(Qoeo*Qofo*QoPeo+SQoPfo+Qneo,XQnfo,Qneo-]Qnfo-Qn0eo.bQn0fo.Qmeo/gQmfo/Qmpeo0gQmpfo0Qmeo1lQmfo1Qleo2hQlfo2QlPeo3iQlPfo3Qkeo4iQkfo4Qkeo5jQkfo5Qk0eo6oQk0fo6Qjeo7kQjfo7Qjpeo8pQjpfo8Qjeo9pQjfo9Qieo:zQifo:QiPeo;zQiPfo<Qheo<{Qhfo=Qheo=Qhfo>Qh0eo>Qh0fo?Qgeo?Qgfo@ Qgpeo@QgpfoA QgeoAQgfoBQfeoBQffoCQfPeoCQfPfoDQeeoDQefoEQeeoEQefoFQe0eoFQe0foGQdeoGQdfoHQdpeoHQdpfoIQdeoIQdfoJQceoJQcfoK$QcPeoKQcPfoL)QbeoLQbfoM)QbeoMQbfoN3Qb0eoNQb0foO3QaeoOQafoPAQapeoPQapfoQBQaeoQQafoRPQ`eoS:Q`foSQ`PeoT6Q`PfoTQ_eoUQ_foV.Q_eoVQ_foW7Q_0eoWQ_0foX8Q^eoXQ^foY=Q^peoYQ^pfoZBQ^eoZQ^fo[GQ]eo[Q]fo\PQ]Peo\Q]Pfo]UQ\eo]Q\fo^VQ\eo^Q\fo_hQ\0eo_Q\0fo`iQ[eo`Q[foanQ[peoaQ[pfobnQ[eobQ[focxQZeocQZfodtQZPeodQZPfoeyQYeoeQYfofuQYeofQYfoguQY0eogQY0fohvQXeohQXfoirQXpeoiQXpfoj{QXeojQXfok|QWeokQWfolQWPeolQWPfomQVeonQVfonQVeoo QVfooQV0eopQV0fopQUeoqQUfoqQUpeor@QUpforQUeosnQUfotQTeotQTfouQTPeouQTPfov#QSeovQSfow#QSeowQSfox$QS0eoxQS0foy)QReoyQRfoz)QRpeozQRpfo{3QReo{QRfo|3QQeo|QQfo}=QQPeo}QQPzzlz7mz:z;z=a"z>Tz=-,Vz@yl-m/md9<f˒ QQPm˕˙v-j]fo_QRmog4onrfyLQSmyMyO7 fLQUmR fQV0mfQVmfQXmf_QY0m`axfQYmfEQ[mFHf{2Q\0m||f̗Q\m̘̙"f<Q^m "X%foQ_0mpq'fiQ_mJ́*fQam@-f.YQb0m/60l/fuQbm[32fEQdmFH_5foQe0mP֋7f"Qem"":f,BQgm,D,F=f6PQh0m6Q6S?f@OQhm@P@RZBfJQjmJJ-EfTQk0mTTGf^{Qkm^|^}zJfh.QmmhhMfrQn0mrrOf|Qnm||RfQpmUf8[Qq0m9<:WfQqm+]Zf Qsm " ]fWQt0m8n_ffQtmghbfxQvmef-Qw0mEgfVQwmWXjfQym_軨mfeQz0mizmJpfrQ{Pmt4u}rf TQ|m  uf=Q}0m?qA\xf*%Q~Pm**zf6hQm6{6}fCQ0mCCfTQPmTQT)fwQmw$wfQ0m%fQmQfIQmKqMWfQmf:Qm鿐dfQ0m!f}Qmf!zQm!!\f8uQ0m8w8xfN)QPmNqNIfu"#Qmu$u(f?QmAzCfGQmfD$QmD&D)fƺaQmƻƽUf=Qm>fV{Q0mV}OVf7QPm7!7xf NbQpm NC Nf 9Qm  f 44DQm 47 49f /Qm 1 3[f1FQm35gfX {QmX ]Xfo Q0mo8o jfQPmnpfXQpmY[fSYQmS،SھfQmmJf0Qm# f"c_Qm"ca["cc<f%RfQm%R%Rf(f.Q0m(f+(ff+ +QPm+G+Vf.*Qpm..f22ذQm2222Of5-Qm5S5}f9Qm99f="Qm=$=&fAQmA !A"fF$Q0mF$F$fJA*QmJBiJDxL?LnfOaSQmOg2OjfTi+Q0mTi.$Ti/fYi+QPmYqYy f`aϜQpm`aO`aޟff%pQmf%f%vfk+<Qmk+AAk+FMfp@QeQ0mp@Tp@XvfuQPmuufzAEQpmzCzEfp^'Qmp`pb!f\Qm^ga%$fY_Qm\J_>'fQm')*f tQm'"--fuQ0mu;u0f]bQPm]]3feQpme#e6fQŐmC̚9fQưmDr<f߈Qm?f,cQm,^,pBfWQmƐEfNQ0mPRHfQPmKfQpm  XNfUQΐmnQf-Qϰm5=;UfliQ0ml0lYfOQҰmR1S\fsQmv\x^ftQԐmt,taf \ Qհm \/ \dfuQmuugfI8QmI IQkfAQpmDH)nf%=Qڐm%>%>qf*kQ۰m**mtf/*Qm/-J//0wf5]i{Qm5]k/5]lszf:ؔ=Qm:ؕ:ؗ}f@d_Q0m@da@dcfHUQPmH_SHdfNQpmNNfT\jQmT\xT\fZ#QmZZ)f_%Qm__䊥fe͚Qme͜ e͝mfkQmkukfq,Q0mq.nq/fwCQPmw)w*f}IQpm}K0}LfPQm;fI) QmI+I,ff3Qm5>6fkQmnLpvfQm-fAQpmAA8f7Qm(fVQmY'\uf+Qm.0f Qm  nfBQpmBB f Qmsf"Qm$%dfӴ;Qmӷӹf⧝=Qm⧠⧤NfY ;QmY YPf?QmfHQm f}Rmfv+R0mv-v0Vf b-RPm b b$fJVRpmJJfjFRmjIjL7f KCRm O` Rf'MRm'i'f/PgRm/PM/PWf7! R m7!7!Af?y0R 0m?y9?yBfI0(R PmI7I?fR"!R pmR#^R# fZO¸R mZOIZOfbzWRmbzbzfjRmjjfuZRmuPuf~rtRm~r~r[fR0mfi#RPmmo fiRpmiicfKb RmKdKfLfBRmEGQftR0mx{{]fORmfUh6RmUkUmf̹R0m̺^̺  f>RPm#fG9RpmG$Gv&flRmI)fnR mnn,fz R!m}-0fR#Pm3fޢR$pmޤާ5f=R%0m@B8fk$OR&Pmk+%k2;f"|R'pm""W?f* MR(m**XBf2R*m22IEf::R+0m:<:>HfEh{R,PmEh%Eh.LfM:R-mM<M>NfUR.mUBUQf^.R/m^1^3lTffO%R0mfOGfOWfq0.R1mq0q0G[fzyR3pmzz^fDR4mFHaf)[R5m+"-dfxR6mx4xUgfڭR7mڰEڲ|if@R8m@H@ lf{R9mԠof&6R:m&:n&= rfR<mOPuf=y}R=0m={H=}xfOR>PmRNS{fk4(R?pmk5k6~fzR@mfiRAmlEp9fzRBpmfBERCmBHBK_fQRDmV[f REm Z f1RFm116f (KRHm - 2f)RI0m))f31RJPm31+31ffqQS0mq^qif=QTPm@0Bu fQUm fQWPm:f\QXm^af'QZPm),$fFQ[mHK' f Q]Pm$f)RQ^m+-(foQ`Pmqt>,fQam0f ^QcPm R 4fQdm8f(/QfPm(0(<f7B.Qgm7D+7F}@fEFQiPmEkEDfUQjmU"U%nHfd.QlPmdOdKLfs\Qmms_@saPffQoPmhkITf(QpmXfQrPm \f7Qsm\`fIQuPmKN6df6Qvm8H:hfQxPmlfUQymofQzm.tfqrQ|msouwf-d3Q}m-f0-h|f=!Qm=#=%sfURMQmUSUUfxQpmx9xfj3Qmkmf\=QPm]_fQmfPHQmQSfۗQPmۙۛfQpmXf 1Qm  f Qm X f7Qm7}7^fZ+QmZ ZfoQpmo ofKQ0m?fQPmڠf+cQpm+e%+ff?QmAC?fX QmXXf%aQm%%ϯf'Qm)L+qf Qm \ f FQ0m Fu Ff ՏQPm Ց< Ւf zjQpm zl zn|f?,Qm??fQm fQm t"?fWbQmWWfQm߮fDQ0mعڄfz3jQPmz5z6fQpm1f!Qm!!Uf$CAQm$D$Gf')Qm'+'-f+F Qm+F+Ff.Qm.&.f1[Q0m1]c1_f5 ,QPm5 ?5 f9Qpm99f=!Qm==fAqQmAt:Av.fF& \QmF& TF&fJQPmJJL?{L fPQpmPPfTQmTfTp fZ!QmZZ f_tQm_?_fdDQmdDdD fijnQmijp%ijrfn|Qmnn .ft Qmt t KfyQmyy֋f2;Q0m22 fnQPmor#f3Qpm&f]?Qm] ])f4"Qm44,f+TQm+W +Y/fLQmL+LT2ftQmtt5f":Q0m#%8fQPmUz;f'Qpm''=fHN9Q0mHPHQ@fz/MQPmz0z3 Cfͱ0QpmͱͱMFf. Qːm02FIf4Q̰m44fLfuQmuuZOf2QmNFRf8Qm4Tfm Qmm mWfQmZfQmk]f Q0m  -`f 1QPm 1 1|cf/2Qpm//!ff%IQאm'{)ifkQذmkkEmf#Q0m#!i##pf)S$QPm)S)S sf.fQpm..vf4qpQݐm4q64qxf: QPm: : {f?gQpm??~fE}QmE}?E}fKNQmKNKNfQ";QmQ"=cQ"?RfW0QmWWlf\ <Qm\ \fcQ0mcWcficQPmii%fo@Qpmo@Eo@fuebQmuedueef{Qm{{f]Qm_a:fnGQmngnҰfQm?fEQ0mLoSf.QPmyf)1 Q0m)2)4fQPm GfVQpmXaZfQmLfQm~fǫoQmǫ Cǫ _fαQmα1αf?QmAoBf̙Q0m̝̚fQPmf6fQpm66RfQmf@bQmADvfhFRmjlf ̆Rm + f3Rm9?lfݴR0mKf RPm if&Rpm&E&f.rWRm.rY.r[f6`Rm6`6`3f>R m>>ufFΖR mFΘ~FΚvfO/R mO/#O/SfWy,R 0mWzW|f_>RPm_As_CfhRiRpmhRjhRlfpRmpĆp-fy7jRmy7Uy7_fRmտfKRmKFK ftRm fx$R0mx&<x(jfY+RPm[k]lf=Rpm?!Afj Rmj j0fORmQxRfƫz]Rmƫ|ƫ~dfѻ RmѻڽѻU"f:Rm::%fmR0morI(f;cR Pm=@A+fR!pm&.fRR"mUwW1fUR#mWaXx4f 4R$m 4 4 7fYR%mYY7:f1R'mq=f#|^R(0m#~#ÂX@f, R)Pm, , Cf4TR*pm4Ti4TœFf"Rm``|fByR?mBdBfV,RR@mV-V/sfŽRBmǚ/fRC0mBfRDPm7f0l6REpm0m0o{fxURFm|f.RGm.%.,6f'LRHm'N'Q`f1X~RIm1X>1Xf:lRKm:%:JfDr۬RL0mDrDrGfNRMPmNZN`fWRNpmW;Wf`cROm`r`ホfj\RPmjljNnzJZzR5zS"zTzT_@Czy@@X(d2MQQPg9 QQPd^QQQg_QQdp^QRgq QRdzQRpg{zQRpd|QRg}QRdQS0gQS0d QSghQSdzQSgQSdQTPg2QTPdߺQTgQT dQUg]QU dxQUpg5QUp dUQUgQU dQV0gQV0 dQVgQVdQVgQVdQWPgkQWPd~QWg5#QWd6pQXg7$QXd8[QXpg9QXpd:QXg:QXd;QY0g<QY0d=QYg>QYd?QYg@ZQYdAhQZPgBQZPdCNQZgDQZdEQ[gEQ[dFQ[pgGQ[pdHQ[gI~Q[dJQ\0gKdQ\0dLQ\gM8Q\dNTQ\gO Q\dP(Q]PgPQ]P dRQ]gl3Q]!dmQ^gnQ^"doQ^pgpQ^p#dqQ^grqQ^$dsQ_0gtIQ_0%dueQ_gv&Q_&dwFQ_gxQ_'dy,Q`PgyQ`P(d{Q`g{Q`)d|Qag}Qa*d~QapgnQap+dQagGQa,d^Qb0gQb0-d2QbgQb.dQbgQb/dQcPgwQcP0dQcgBQc1dLQdgQd2d QdpgQdp3dQdgQd4dQe0gQe05dQegkQe6dtQeg:Qe7dVQfPgQfP8d3QfgQf9dQggQg:dQgpg}Qgp;dQggQQg<dhQh0g;Qh0=dRQhgQh>d"QhgQh?dQiPgQiP@dQigRQiAdT%QjgTQjBdV QjpgVQjpCdWQjgXQjDdYQk0gZQk0Ed[Qkg\ZQkFd]mQkg^3QkGd_EQlPg_QlPHda'QlgaQlIdcQmgcQmJddQmpgeQmpKdfQmggmQmLdhQn0giJQn0MdjTQngkQnNdl,QnglQnOdmQoPgnQoPPdoQogpQoQdqQpgrnQpRdsQppgtYQppSdubQpgv$QpTdw6Qq0gwQq0UdyQqgyQqVdzQqg{QqWd|QrPg}}QrPXd~Qrg^QrYdqQsg;QsZdRQspg!Qsp[dQsgoQs\dxQt0gQt0]dQtgQt^d%QtgQt_dQuPgQuP`dQugQuadQvg^QvbduQvpg7Qvpcd7QvgQvddQw0gQw0edQwgQwfdQwgpQwgdQxPg;QxPhdWQxgQxid4QygQyjdQypgQypkd QygQyldQz0gQz0mdQzgNQzndeQzg0Qzod0Q{PgQ{PpdQ{gQ{qdQ|gQ|rdQ|pgQ|psdQ|gjQ|tdxQ}0gCQ}0udcQ}g Q}vd.Q}gQ}wd Q~PgQ~PxdQ~gQ~ydQgbQzdpQpg2Qp{d[QgQ|dSQ0g/Q0}daQgQ~dPQgQd QPgQPdQgQdDQg Qd<QpgQpd QgQdQ0gQ0d Qg!Qd"Qg#qQd$QPg%QPd&Qg'sQd(Qg)>Qd*Qpg+Qpd,Qg-Qd.Q0g/wQ0d0Qg19Qd2UQg3 Qd4QPg4QPd5Qg6Qd7Qg8sQd9Qpg:]Qpd;gQg<-Qd=QQ0g>Q0d?*Qg?Qd@QgAQdBQPgCxQPdDQgElQdFQgGIQdH`QpgI!QpdJ8QgJQdLQ0gLQ0dMQgNQdOQgPQdQQPgR<QPdSJQgT QdUQgUQdWQpgWQpdXQgYQdZQ0g[SQ0d\wQg]OQd^Qg_YQd`pQPga-QPdbMQgcQdd QgdQdeQpgfQpdgQghQdiQ0gjhQ0dkvQgl*QdmNQgnQdoQPgoQPdpQgqQdrQgsuQdtQpguQpdvQgwQdxQ0gyQ0dzQg{ZQd|cQg};Qd~[QPgQPdQgQdQgQdQpgQpd QgQdQ0gQ0dQgoQdQgHQdMQPgQPd*QgQdQgQdQpgQpdQgUQduQ0g;Q0dRQg QdQgQdQPgQPdUQgQd%QgQdQpgQpdQgQdQ0gUQ0dlQg$Qd@QgQdQPgQPdQgQdQgQdQpgvQpdQgNQdeQ0g+Q0dKQgQdQgQdQPgQPdQgQdQgTQdkQpg(Qpd?QgQdQ0gQ0dQgǒQdȭQgjQdtQPg(QPd:QgQdQgQdQpgФQpdѲQg|QdӥQ0ggQ0dՇQg;QdDQgQdQPgQPdQgۥQdܮQgtQd1QpgQpdlQgQdQ0g!Q0dQgSQdQgQdKQPgQPdxQgQdQg$QdQpgZQpd QgQd@Q0gQ0dQgQdQg'QdQPg YQPd Qg Qd LQg Qd _Qpg QpdNQgQd9Q0gQ0dtQgQdQg$QdQPgQQPdQgpQdqQgrEQdsQpgsQpdtFQgtQduQ0gv1Q0dvQgwlQdx)QgxQdydQPgz QPdzQg{WQ d| Qg|Q d}BQpg}Qp d~xQg~Q dQ0g?Q0 dQgqQd7QgQdmQPgQPdQg/QdQgXQdQpgQpdGQgQdQ0g Q0dVQgQdQgAQdQPgsQPd9QgQdyQgQdQpgDQpdQgzQd.Q0gQ0dnQgQdQg'QdQPgTQP d QgQ!dLQgQ"dQpgQp#dQgNQ$dQ0gQ0%dQg"Q&dYQgQ'dQPgQP(dQgVQ)dQgQ*d<QpgQp+dnQgQ,dQ0gQ0-dQgGQ.dkQgQ/dQPg QP0dQðg@Qð1dQgiQ2dQpgQp3dQgKQ4d Q0gQ05dYQŐgQŐ6dQgQ7dQPgDQP8dQưgQư9d<QgQ:dnQpgQp;dQgQ<dQ0gYQ0=d QȐgQȐ>d;QgQ?dmQPgQP@d£Qɰg&QɰAdQg\QBdQpgŗQpCdKQgQDddžQ0g Q0EdQːg?QːFdQgmQGd!QPg˚QPHdWQ̰gQ̰Id͎Qg QJdQpgTQpKdQgЋQLdCQ0gQ0Md~QΐgQΐNdӰQg.QOdQPg`QPPdQϰg֛QϰQdQgTQRdQpg٦QpSdZQgQTdەQ0gQ0UdQѐgIQѐVdQgހQWd4QPg߭QPXdjQҰgQҰYdQgQZd~QpgQp[dQg7Q\dQ0grQ0]d&QԐgQԐ^deQgQ_dQPgQP`dQհgYQհadQgQbd_QpgQpcdQgQddQ0gSQ0edQאgQאfd9QgQgdtQPgQPhdQذg$QذidQgMQjdQpgQpkd<QgQldiQ0gQ0mdQڐg"QڐndQg]QodQPgQPpd?Q۰gQ۰qdzQgQrd@QpgQpsdrQgQtdQ0gQ0udQݐgCQݐvdQgyQwd;QPgQPxd Qްg Qްyd Qg <Qzd Qpg sQp{d QgQ|dUQ0gQ0}dQg Q~dQgDQdQPgrQPd3QgQdnQgQdQpg0QpdQgQdCQ0gQ0d~QgQdIQgQdQPg+QPdQgoQd Qg Qd!PQpg!Qpd"Qg#Qd#Q0g$DQ0d$Qg%rQd&/Qg&Qd'aQPg'QPd(Qg)Qd)Qg*LQd+ Qpg+Qpd,;Qg,Qd-vQ0g-Q0d.Qg//Qd/Qg0eQd1QPg1QPd2kQg2Qd3Qg4$Qd4Qpg5VQpd6Qg6Qd7<Q0g7Q0d8nQg8Qd9Qg:'Qd:QPg;TQPd< Qg<Qd=CQg=Qd>zQpg?Qpd?Qg@@QdAQ0gAQ0dB=QgBQdDQgDQdELQPgEQPdFQgGQdGQgHvQdI*QpgIQpdJnQgJQdKQ0gL+Q0dLQgMbQdNQgNQdOUQPgOQPdPQgQ QdQQgR7QdSNQpgSQpdT|QgTQdUQ0gV'Q0dVQgWYQdX QgXQdYDQPgYQPdZQg[Qd[Qg\8Qd\Qpg]|Qpd^4Qg^Qd_bQ0g_Q0d`QgaQdaQgbQQdcQPgczQPdd.QgdQdeWQgeQdfQpggQpdgQghBQdhQ0giQ0djCQgjQdklQgkQdlQPgm%QPdmQgnnQdoQgoQdpOQpgpQpdqQgrQdrQ0gsHQ0dtQgtzQdu2QguQdv`QPgwJQPdxwQgxQdzRg{Rd{Rpg|HRpd|Rg}uRd~.R0g~R0dvRgRdeRgRdRPg#RPdRgbRd RgRdDRpgRpdzRgRdR0g/R0dRgXRdRgRdBRPgRPdpRgRdRgRdRpg_Rpd RgRdSR0gR0dRgRdRgBRdRPg}RPd?RgRduR gR dR pg*R pdR g`R dR 0gR 0dKR gR d}R gR dR Pg-R PdR g_R dR gR dIR pgR pdR gR dR 0gBR 0dR gxR d1R gR dpRPgRPdRg)RdRgRRd RpgRpdRgKRdR0gR0dRgCRdRgRd2RPgRPddRgzqRd{`Rg{Rd|Rpg}4Rpd}Rg~sRd5R0gR0dtRgRdRg6RdRPgvRPdIRgR dRgR dRpgORp dRgR dGR0gR0 dRg RdRgMRdERPgRPdwRgRdRg"RdRpgkRpd#RgRdUR0gR0dRg.RdRgiRd=RPgRPdRgRdRg>RdRpgyRpd6RgRdvR0gR0dRg*RdRgjRdRPgRP dKRgR!dRg R"dRpgDRp#dRgvR$d.R0gR0%diRgR&d+RgR'dkR PgR P(dR g-R )dR!gcR!*d R!pgR!p+dmR!gR!,dR"0gR"0-dBR"gR".dyR"gR"/dR#Pg%R#P0dR#g[R#1dR$gR$2dFR$pgR$p3d|R$gR$4dR%0g:R%05dR%g~R%6d;R%gR%7dˆR&PgR&P8dR&gER&9dR'g|R':d4R'pgƲR'p;dxR'gR'<dȯR(0g:R(0=dR(ghR(>d%R(g˧R(?dWR)PgR)P@d4R)gβR)AdfR*gR*BdМR*pgR*pCdR*gQR*Dd R+0gӌR+0EdMR+gR+FdՄR+gR+GdR,PgJR,PHdR,gؠR,IdPR-gR-JdڔR-pgR-pKdR-gVR-LdR.0gݚR.0MdRR.gR.Nd߉R.g R.OdR/Pg4R/PPdR/gR/QdR0g6R0RdR0pgzR0pSd2R0gR0TdvR10gR10UdR1g/R1VdR1gxR1Wd,R2PgR2PXdkR2gR2YdR3g R3ZdR3pgR3p[dR3gAR3\dR40gR40]d4R4gR4^doR4gR4_dR5PgR5P`dR5gVR5adR6gR6bdIR6pgR6pcdR6gR6ddR70gaR70ed#R7gR7fdYR7gR7gdR8PgR8PhdR8gMR8idR9gR9jd8R9pgR9pkd|R9gR9ldR:0g5R:0mdR:g^R:ndR:gR:od QR;Pg R;Ppd R;g R;qd R<g JR<rd RPgR>PxdR>gR>ydR?g8R?zdR?pgsR?p{dR?g>R?|dR@0g~R@0}d7R@gR@~dmR@gR@dRAPg&RAPdRAg aRAd!RBg!RBd"GRBpg"RBpd#RBg$2RBd$RC0g%zRC0d&<RCg&RCd'eRCg'RCd(RDPg)ORDPd*RDg*RDd+YREg,uREd-)REpg-REpd0REg0REd1JRF0g1RF0d2RFg3RFd3RFg4>RFd4RGPg5pRGPd6$RGg6RGd7_RHg7RHd8RHpg9*RHpd9RHg:nRHd;4RI0g;RI0d:RId>RJPg?lRJPd@)RJg@RJdA[RKgARKdBRKpgCRKpdCRKgDFRKdDRL0gERL0dF:RLgFRLdGyRLgGRLdHRMPgI%RMPdIRMgJ`RMdKRNgKRNdLJRNpgLRNpdMRNgN RNdNRO0gOPRO0dP ROgPROdRROgS%ROdSRPPgT`RPPdU"RPgURPdVXRQgVRQdWRQpgXRQpdXRQgYHRQdZRR0gZRR0d[;RRg[RRd\rRRg\RRd]RSPg^&RSPd^RSg_aRSd`RTg`RTdaURTpgaRTpdbRTgcRTdcRU0gdRRU0deRUgeRUdfARUgfRUdgRVPggRVPdhRVgiKRVdiRWgjyRWdk1RWpgkRWpdllRWglRWdmRX0gn*RX0dnRXgo\RXdp/RXgpRXdqfRYPgqRYPdrRYgs,RYdsRZgtcRZdu)RZpguRZpdv_RZgvRZdwR[0gx!R[0dxR[gy\R[dzR[gzR[d{TR\Pg{R\Pd|R\g}R\d}R]g~MR]dR]pgR]pdIR]gR]dR^0g R^0dR^gFR^dR^gR^dPR_PgR_Pd)R_gR_dR`gNR`dR`pgR`pdAR`gR`d|Ra0gRa0dRag:RaduRagRadRbPg2RbPdRbgmRbd!RcgRcdXRcpgRcpdRcgRcdLRd0gRd0dRdgRddRdg;RddRePgdRePdRegRedSRfgRfdRfpgRfpdRfgPRfdRg0gRg0dVRggRgdRggRgd`RhPgRhPdRhgRhdYRigRidRipg RipdRig?RidRj0gzRj0d.RjgRjdnRjgRjdRkPg'RkPdRkgkRkd#RlgRldZRlpgRlpdRlgRldRm0gRRm0dRmgRmdARmgRmdxRnPgRnPdRng1RndRogZRodRopgRopdRRogRodRp0g&Rp0dRpg\RpdRpg—RpdKRqPgRqPdyRqgRqdůRrg)RrdRrpgdRrpdRrgRrd{Rs0gRs0dʶRsg0RsdRsgoRsdRtPgRtPdΐRtgRt dRug@Ru dRupg{Rup d3RugҭRu deRv0gRv0 dԩRvg#RvdRvgbRvdRwPgיRwPdHRwgRwdRxgRxdڱRxpg8RxpdRxgjRxdݥRy0g#Ry0dRyg^RydRygRydQRzPgRzPdRzgRzdR{g<R{dR{pgwR{pd4R{gR{dbR|0gR|0dR|g$R|dR|gqR|fR|׵j1df SR|e R|f fR| fWR|eXR|fYR|0[SfR|0eR|0fճR{׫f)hR{e)iR{f)jsR{p)lf3R{pe3nR{pf3R{3f=R{e=OR{f= Rz=fG(jRzeG)5RzfG*gRzPG+pL?VL fRRzPeRRzPfRRyR7f\Rye\Ryf\|Ry\}ff]RyefURyffċRy0fŕfp |Ry0ep |Ry0fp 9Rxp f{''Rxe{'Rxf{4Rxp{6AfARxpeRxpfTRxf#Rxe%/Rxf%Rw'fr8Rwer9HRwfr9RwPr;[fGRwPeGfRwPfGRvGfRveKRvfRv1f jRveRvf>Rv0 f*Rv0eRv0fRuܠ fʿQRueʿDRufʿRupʿ fԑ%Rupeԑ`RupfԑRuԑ f^pYRue^q(Ruf^qRt^sm f)Rte)Rtf)tRtP)f8RtPe9RtPf:Rs<ffRseBRsfRsf,PRse-^Rsf.Rs0/fWRs0eWRs0fWRrW2f"HRre"Rrf"Rrp"Nf"Rrpe"Rrpf"3Rr"f,PRre,RRrf,RRq,T~f6s.Rqe6sRqf6sRqP6sf@7bRqPe@7$RqPf@7Rp@7fJRpeJRpfJ;RpJdfS&RpeSRpfSRp0Sf],WRp0e]-"Rp0f]-Ro]/]fg"Roeg0RofgKRopgfqLRopeqMaRopfqNRoqO5f{_Roe{_Rof{_lRn{_f_CRne_EiRnf_FRnP_G+fgRnPegRnPfgZRmgfn5Rmen8 Rmfn:&Rmn>fwRmewRmfwRm0wfvRm0eRm0fJRlf'*Rle(jRlf)Rlp+PfRlpeeRlpfRlYf˥a$Rle˥aRlf˥bRk˥cfշRkeշCRkfշcRkPշfRkPeRkPfgRjfxiRje{Rjf}RjӁfðRjeRjfRj0̓f{Rj0e{Rj0f|aRi~xf&Rie'Rif(>Rip)fRipeRipfCRi@f=Rie=9Rif=Rh=Of+oiTRhe+oiRhf+oj}RhP+okf5fubRhPe5fvRhPf5fvRg5fxMf?MRge?MMRgf?MRg?MefIRgeI RgfIRg0IfSdyRg0eSdCRg0fSdZRfSd f]6Rfe]6Rff]6Rfp]6ff"RfpefRfpffRfffpRfepRffpRepfzSfReezSgRefzShRePzSifWMRePeX7RePfYRd[afRdemRdfRdfRdeRdfPRd05f:Rd0eRd0fyRcqf93Rce9Rcf9fRcp9f1Rcpe28Rcpf3aRc4xf]Rce]{Rcf]Rb]fRbeĢRbf$RbPưff=RbPef2RbPff7Raf^fE{RaeERafERaE $fk+RaekRafmRa0nfGyRa0eGzRa0fG{}R`G|fR`eR`fR`pfCR`peCR`pfCgR`Cf R`e R`f R_ f놻R_e뇆R_f,R_PfjR_PejmR_PfjR^jf%ҁ'R^e%҂R^f%҃R^%҄f/V:8R^e/V;TR^f/V;R^0/V<f8R^0e8R^0f8R]8fBuER]eBu/R]fBuR]pBufKR]peKlR]pfK_R]K%PfUR]eUR]fUR\Uf_R\e_R\f_|R\P_xfhؕR\Peh.R\PfhER[hۉfqRR[eqSiR[fqTR[qUsf{ZR[e{ZR[f{ZiR[0{ZfR[0eR[0f=RZfRZeRZfRZpfx.RZpexRZpfxڑRZxۿf5RZe6lRZf7)RY8*f&RRYe&!RYf&RYP&f|RYPe|RYPf|̵RX|fRXeCRXfRXf:yRXe:zRXf:{RX0:}fϙ iRX0eϙ RX0fϙ eRWϙ fPRWePRWfQORWpRfC~RWpeC;RWpfCRWCfvRWew=RWfwRVyGf8RVe9^RVf:(RVP;qfRVPeRVPf{RU"fY(RUeY)RUfY*RUY+frRUeXRUfRU0҄fc:RU0efRU0fhRTn%f#1eRTe#1ARTf#1XRTp#1f,s}sRTpe,s~oRTpf,sRT,sf5RTe5NRTf5RS5Tf>RSe>XRSf>RSP>0fH'qRSPeH'rRSPfH'sRRH'ufQiRReQiORRfQiRRQi fZ}RReZRRfZRR0Z fcpRR0ecqQRR0fcqRQcrfmRQemRQfmRQpmmmlm>zjz{zz"zzVzBghc-events-0.4.4.0/test/TestVersions.hs0000644000000000000000000000444112520426612016074 0ustar0000000000000000{- This test parses sample event logs from each major GHC version and compares the pretty printed output with reference output. When tests fail, use a diff tool to compare the output of "ghc-events show" with the reference file. Resolve the differences in either the library code or the reference file, and 'darcs record' the changes. Steps to produce event log and reference output: $ ghc --make queens.hs -o queens-ghc-$VERSION -threaded -eventlog $ queens-ghc-$VERSION 8 +RTS -N4 -ls $ ghc-events show queens-ghc-$VERSION.eventlog > queens-ghc-$VERSION.eventlog.reference Where queens.hs is http://darcs.haskell.org/nofib/parallel/queens/Main.hs -} import GHC.RTS.Events import System.Exit files :: [FilePath] files = map ("test/"++) [ "queens-ghc-6.12.1.eventlog" , "queens-ghc-7.0.2.eventlog" , "mandelbrot-mmc-2011-06-14.eventlog" , "mdlLogMPI1.eventlog" , "pre77stop.eventlog", "782stop.eventlog", "783stop.eventlog" ] -- returns True on success testFile :: FilePath -> IO Bool testFile f = do e <- readEventLogFromFile f let oops s = putStrLn (f ++ ": failure" ++ s) >> return False case e of Left m -> oops m Right newlogdata -> do oldlog <- readFile (f ++ ".reference") let newlog = ppEventLog newlogdata ++ "\n" in if oldlog == newlog then putStrLn (f ++ ": success") >> return True else do putStrLn $ diffLines oldlog newlog oops "pretty print output does not match" main = do successes <- mapM testFile files if and successes then return () else exitFailure -- -- Code to help print the differences between a working test and a failing test. -- diffLines o n = diff 1 (lines o) (lines n) diff :: Int -> [String] -> [String] -> String diff _ [] [] = "Logs match" diff l [] (n:ns) = "Extra lines in new log at line " ++ show l ++ ":\n" ++ (unlines (n:ns)) diff l (o:os) [] = "Missing lines in new log at line " ++ show l ++ ":\n" ++ (unlines (o:os)) diff l (o:os) (n:ns) = if (o == n) then diff (l+1) os ns else "Different lines at line " ++ show l ++ ":\n" ++ "Original: " ++ o ++ "\n" ++ "New: " ++ n ghc-events-0.4.4.0/test/782stop.eventlog0000644000000000000000000001510412520426612016061 0ustar0000000000000000hdrbhetbetb Create threadeteetb Run threadeteetb Stop threadeteetbThread runnableeteetbMigrate threadeteetb Wakeup threadeteetb Starting GCeteetb Finished GCeteetb Request sequential GCeteetb Request parallel GCeteetbCreate spark threadeteetb Log messageeteetbCreate capabilitieseteetb Block markereteetb User messageeteetbGC idleeteetb GC workingeteetbGC doneeteetbVersioneteetbProgram invocationeteetbCreate capability seteteetbDelete capability seteteetb Add capability to capability seteteetb%Remove capability from capability seteteetbRTS name and versioneteetbProgram argumentseteetbProgram environment variableseteetb  Process IDeteetb!Parent process IDeteetb"8Spark counterseteetb# Spark createeteetb$ Spark dudeteetb%Spark overfloweteetb& Spark runeteetb' Spark stealeteetb( Spark fizzleeteetb)Spark GCeteetb+Wall clock timeeteetb, Thread labeleteetb-Create capabilityeteetb.Delete capabilityeteetb/Disable capabilityeteetb0Enable capabilityeteetb1 Total heap mem ever allocatedeteetb2 Current heap sizeeteetb3 Current heap live dataeteetb4&Heap static parameterseteetb52 GC statisticseteetb6Synchronise stop-the-world GCeteetb7 Task createeteetb8 Task migrateeteetb9 Task deleteeteetb: User markereteetb<Starting message receivaleteetb=Finished message receivaleteetb>Creating Processeteetb?Killing Processeteetb@Assigning thread to processeteetbA Creating machineeteetbBKilling machineeteetbCSending messageeteetbDReceiving messageeteetbESending/Receiving local messageetehetehdredatbB2 9   H]}L$L#M?forking child threadNCcNJNPNjXJDXychildD  P OF ?ɬL3~q$+ $3x,S,,[x11.g14 1ffilling full MVar11i111emptying full MVar11%1&1reading empty MVar141@11X1filling empty MVar11111111111child finished1U11 & 2 @n-N+ђSs VM!۬ImGHC-7.8.20140411 rts_l 5./wrong782+RTS-lsu-g-p-K80m-k10m-H200m-C1s$ 7SSH_AGENT_PID=1817PVM_RSH=/usr/bin/sshGPG_AGENT_INFO=/tmp/keyring-yTUMmt/gpg:0:1TERM=xtermSHELL=/bin/bashXDG_SESSION_COOKIE=acf1c79e0e2de67643be755c00000003-1405160974.283591-1531347675WINDOWID=58743399OLDPWD=/opt/Eden/edentv/fixFor783/BLD-ghc-events-parallelGNOME_KEYRING_CONTROL=/tmp/keyring-yTUMmtUSER=jostLS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lz=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.axa=00;36:*.oga=00;36:*.spx=00;36:*.xspf=00;36:XDG_SESSION_PATH=/org/freedesktop/DisplayManager/Session0XDG_SEAT_PATH=/org/freedesktop/DisplayManager/Seat0PVM_ROOT=/usr/lib/pvm3SSH_AUTH_SOCK=/tmp/keyring-yTUMmt/sshSESSION_MANAGER=local/onAir:@/tmp/.ICE-unix/1781,unix/onAir:/tmp/.ICE-unix/1781DEFAULTS_PATH=/usr/share/gconf/gnome-fallback.default.pathPVM_ARCH=LINUX64XDG_CONFIG_DIRS=/etc/xdg/xdg-gnome-fallback:/etc/xdgPATH=/home/jost/bin:/home/jost/bin:/usr/lib/lightdm/lightdm:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/home/jost/.cabal/binDESKTOP_SESSION=gnome-fallbackPWD=/opt/Eden/edentv/fixFor783GNOME_KEYRING_PID=1770LANG=en_US.UTF-8MANDATORY_PATH=/usr/share/gconf/gnome-fallback.mandatory.pathUBUNTU_MENUPROXY=libappmenu.soGDMSESSION=gnome-fallbackSHLVL=1HOME=/home/jostLANGUAGE=en_US:enGNOME_DESKTOP_SESSION_ID=this-is-deprecatedLOGNAME=jostPVM_EXPORT=DISPLAYXDG_DATA_DIRS=/usr/share/gnome-fallback:/usr/share/gnome:/usr/local/share/:/usr/share/DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-Mviy2n6D5M,guid=3677210ad991dc7e0dc3a1ae00000012LESSOPEN=| /usr/bin/lesspipe %sDISPLAY=:0.0XDG_CURRENT_DESKTOP=GNOMELESSCLOSE=/usr/bin/lesspipe %s %sCOLORTERM=gnome-terminalXAUTHORITY=/home/jost/.Xauthority_=./wrong7827 =V0M91ˁ071]0M91!02 T2 _.2 $2 2 ghc-events-0.4.4.0/GHC/0000755000000000000000000000000012520426612012507 5ustar0000000000000000ghc-events-0.4.4.0/GHC/RTS/0000755000000000000000000000000012520426612013157 5ustar0000000000000000ghc-events-0.4.4.0/GHC/RTS/EventParserUtils.hs0000644000000000000000000001617612520426612017005 0ustar0000000000000000{-# LANGUAGE CPP #-} {-# LANGUAGE FlexibleContexts #-} {-# OPTIONS_GHC -fwarn-incomplete-patterns #-} module GHC.RTS.EventParserUtils ( EventParser(..), EventParsers(..), GetEvents, GetHeader, getE, getH, getString, mkEventTypeParsers, simpleEvent, skip, ) where import Control.Monad import Control.Monad.Except import Control.Monad.Reader import Data.Array import Data.Binary import Data.Binary.Get hiding (skip) import qualified Data.Binary.Get as G import Data.Binary.Put import Data.Char import Data.Function import Data.IntMap (IntMap) import qualified Data.IntMap as M import Data.List #define EVENTLOG_CONSTANTS_ONLY #include "EventLogFormat.h" import GHC.RTS.EventTypes -- reader/Get monad that passes around the event types type GetEvents a = ReaderT EventParsers (ExceptT String Get) a newtype EventParsers = EventParsers (Array Int (GetEvents EventInfo)) type GetHeader a = ExceptT String Get a getH :: Binary a => GetHeader a getH = lift get getE :: Binary a => GetEvents a getE = lift $ lift get nBytes :: Integral a => a -> GetEvents [Word8] nBytes n = replicateM (fromIntegral n) getE getString :: Integral a => a -> GetEvents String getString len = do bytes <- nBytes len return $ map (chr . fromIntegral) bytes skip :: Integral a => a -> GetEvents () skip n = lift $ lift $ G.skip (fromIntegral n) -- -- Code to build the event parser table. -- -- -- Event parser data. Parsers are either fixed or vairable size. -- data EventParser a = FixedSizeParser { fsp_type :: Int, fsp_size :: EventTypeSize, fsp_parser :: GetEvents a } | VariableSizeParser { vsp_type :: Int, vsp_parser :: GetEvents a } get_parser (FixedSizeParser _ _ p) = p get_parser (VariableSizeParser _ p) = p get_type (FixedSizeParser t _ _) = t get_type (VariableSizeParser t _) = t isFixedSize (FixedSizeParser {}) = True isFixedSize (VariableSizeParser {}) = False simpleEvent :: Int -> a -> EventParser a simpleEvent t p = FixedSizeParser t 0 (return p) -- Our event log format allows new fields to be added to events over -- time. This means that our parser must be able to handle: -- -- * old versions of an event, with fewer fields than expected, -- * new versions of an event, with more fields than expected -- -- The event log file declares the size for each event type, so we can -- select the correct parser for the event type based on its size. We -- do this once after parsing the header: given the EventTypes, we build -- an array of event parsers indexed by event type. -- -- For each event type, we may have multiple parsers for different -- versions of the event, indexed by size. These are listed in the -- eventTypeParsers list below. For the given log file we select the -- parser for the most recent version (largest size less than the size -- declared in the header). If this is a newer version of the event -- than we understand, there may be extra bytes that we have to read -- and discard in the parser for this event type. -- -- Summary: -- if size is smaller that we expect: -- parse the earier version, or ignore the event -- if size is just right: -- parse it -- if size is too big: -- parse the bits we understand and discard the rest mkEventTypeParsers :: IntMap EventType -> [EventParser EventInfo] -> Array Int (GetEvents EventInfo) mkEventTypeParsers etypes event_parsers = accumArray (flip const) undefined (0, max_event_num) [ (num, parser num) | num <- [0..max_event_num] ] --([ (num, undeclared_etype num) | num <- [0..max_event_num] ] ++ -- [ (num, parser num etype) | (num, etype) <- M.toList etypes ]) where max_event_num = maximum (M.keys etypes) undeclared_etype num = throwError ("undeclared event type: " ++ show num) parser_map = makeParserMap event_parsers parser num = -- Get the event's size from the header, -- the first Maybe describes whether the event was declared in the header. -- the second Maybe selects between variable and fixed size events. let mb_mb_et_size = do et <- M.lookup num etypes return $ size et -- Find a parser for the event with the given size. maybe_parser mb_et_size = do possible <- M.lookup num parser_map best_parser <- case mb_et_size of Nothing -> getVariableParser possible Just et_size -> getFixedParser et_size possible return $ get_parser best_parser in case mb_mb_et_size of -- This event is declared in the log file's header Just mb_et_size -> case maybe_parser mb_et_size of -- And we have a valid parser for it. Just p -> p -- But we don't have a valid parser for it. Nothing -> noEventTypeParser num mb_et_size -- This event is not declared in the log file's header Nothing -> undeclared_etype num -- Find the first variable length parser. getVariableParser :: [EventParser a] -> Maybe (EventParser a) getVariableParser [] = Nothing getVariableParser (x:xs) = case x of FixedSizeParser _ _ _ -> getVariableParser xs VariableSizeParser _ _ -> Just x -- Find the best fixed size parser, that is to say, the parser for the largest -- event that does not exceed the size of the event as declared in the log -- file's header. getFixedParser :: EventTypeSize -> [EventParser a] -> Maybe (EventParser a) getFixedParser size parsers = do parser <- ((filter isFixedSize) `pipe` (filter (\x -> (fsp_size x) <= size)) `pipe` (sortBy descending_size) `pipe` maybe_head) parsers return $ padParser size parser where pipe f g = g . f descending_size (FixedSizeParser _ s1 _) (FixedSizeParser _ s2 _) = compare s2 s1 descending_size _ _ = undefined maybe_head [] = Nothing maybe_head (x:xs) = Just x padParser :: EventTypeSize -> (EventParser a) -> (EventParser a) padParser size (VariableSizeParser t p) = VariableSizeParser t p padParser size (FixedSizeParser t orig_size orig_p) = FixedSizeParser t size p where p = if (size == orig_size) then orig_p else do d <- orig_p skip (size - orig_size) return d makeParserMap :: [EventParser a] -> IntMap [EventParser a] makeParserMap = foldl buildParserMap M.empty where buildParserMap map parser = M.alter (addParser parser) (get_type parser) map addParser p Nothing = Just [p] addParser p (Just ps) = Just (p:ps) noEventTypeParser :: Int -> Maybe EventTypeSize -> GetEvents EventInfo noEventTypeParser num mb_size = do bytes <- case mb_size of Just n -> return n Nothing -> getE :: GetEvents Word16 skip bytes return UnknownEvent{ ref = fromIntegral num } ghc-events-0.4.4.0/GHC/RTS/EventTypes.hs0000644000000000000000000004112412520426612015623 0ustar0000000000000000{-# OPTIONS_GHC -fwarn-incomplete-patterns #-} module GHC.RTS.EventTypes where import Data.Word (Word8, Word16, Word32, Word64) import Data.Binary -- EventType. type EventTypeNum = Word16 type EventTypeDescLen = Word32 type EventTypeDesc = String type EventTypeSize = Word16 -- Event. type EventDescription = String type Timestamp = Word64 type ThreadId = Word32 type CapNo = Word16 type Marker = Word32 type BlockSize = Word32 type RawThreadStopStatus = Word16 type StringId = Word32 type Capset = Word32 type PerfEventTypeNum = Word32 type TaskId = Word64 type PID = Word32 newtype KernelThreadId = KernelThreadId { kernelThreadId :: Word64 } deriving (Eq, Ord, Show) instance Binary KernelThreadId where put (KernelThreadId tid) = put tid get = fmap KernelThreadId get -- Types for Parallel-RTS Extension type ProcessId = Word32 type MachineId = Word16 type PortId = ThreadId type MessageSize = Word32 type RawMsgTag = Word8 -- These types are used by Mercury events. type ParConjDynId = Word64 type ParConjStaticId = StringId type SparkId = Word32 type FutureId = Word64 sz_event_type_num :: EventTypeSize sz_event_type_num = 2 sz_cap :: EventTypeSize sz_cap = 2 sz_time :: EventTypeSize sz_time = 8 sz_tid :: EventTypeSize sz_tid = 4 sz_old_tid :: EventTypeSize sz_old_tid = 8 -- GHC 6.12 was using 8 for ThreadID when declaring the size -- of events, but was actually using 32 bits for ThreadIDs sz_capset :: EventTypeSize sz_capset = 4 sz_capset_type :: EventTypeSize sz_capset_type = 2 sz_block_size :: EventTypeSize sz_block_size = 4 sz_block_event :: EventTypeSize sz_block_event = fromIntegral (sz_event_type_num + sz_time + sz_block_size + sz_time + sz_cap) sz_pid :: EventTypeSize sz_pid = 4 sz_taskid :: EventTypeSize sz_taskid = 8 sz_kernel_tid :: EventTypeSize sz_kernel_tid = 8 sz_th_stop_status :: EventTypeSize sz_th_stop_status = 2 sz_string_id :: EventTypeSize sz_string_id = 4 sz_perf_num :: EventTypeSize sz_perf_num = 4 -- Sizes for Parallel-RTS event fields sz_procid, sz_mid, sz_mes, sz_realtime, sz_msgtag :: EventTypeSize sz_procid = 4 sz_mid = 2 sz_mes = 4 sz_realtime = 8 sz_msgtag = 1 -- Sizes for Mercury event fields. sz_par_conj_dyn_id :: EventTypeSize sz_par_conj_dyn_id = 8 sz_par_conj_static_id :: EventTypeSize sz_par_conj_static_id = sz_string_id sz_spark_id :: EventTypeSize sz_spark_id = 4 sz_future_id :: EventTypeSize sz_future_id = 8 {- - Data type delcarations to build the GHC RTS data format, - which is a (header, data) pair. - - Header contains EventTypes. - Data contains Events. -} data EventLog = EventLog { header :: Header, dat :: Data } deriving Show newtype Header = Header { eventTypes :: [EventType] } deriving (Show, Eq) data Data = Data { events :: [Event] } deriving Show data EventType = EventType { num :: EventTypeNum, desc :: EventTypeDesc, size :: Maybe EventTypeSize -- ^ 'Nothing' indicates variable size } deriving (Show, Eq) data Event = Event { time :: {-# UNPACK #-}!Timestamp, spec :: EventInfo } deriving Show data EventInfo -- pseudo events = EventBlock { end_time :: Timestamp, cap :: Int, block_events :: [Event] } | UnknownEvent { ref :: {-# UNPACK #-}!EventTypeNum } -- init and shutdown | Startup { n_caps :: Int } -- EVENT_SHUTDOWN is replaced by EVENT_CAP_DELETE and GHC 7.6+ -- no longer generate the event; should be removed at some point | Shutdown { } -- thread scheduling | CreateThread { thread :: {-# UNPACK #-}!ThreadId } | RunThread { thread :: {-# UNPACK #-}!ThreadId } | StopThread { thread :: {-# UNPACK #-}!ThreadId, status :: ThreadStopStatus } | ThreadRunnable { thread :: {-# UNPACK #-}!ThreadId } | MigrateThread { thread :: {-# UNPACK #-}!ThreadId, newCap :: {-# UNPACK #-}!Int } | WakeupThread { thread :: {-# UNPACK #-}!ThreadId, otherCap :: {-# UNPACK #-}!Int } | ThreadLabel { thread :: {-# UNPACK #-}!ThreadId, threadlabel :: String } -- par sparks | CreateSparkThread { sparkThread :: {-# UNPACK #-}!ThreadId } | SparkCounters { sparksCreated, sparksDud, sparksOverflowed, sparksConverted, sparksFizzled, sparksGCd, sparksRemaining :: {-# UNPACK #-}! Word64 } | SparkCreate { } | SparkDud { } | SparkOverflow { } | SparkRun { } | SparkSteal { victimCap :: {-# UNPACK #-}!Int } | SparkFizzle { } | SparkGC { } -- tasks | TaskCreate { taskId :: TaskId, cap :: {-# UNPACK #-}!Int, tid :: {-# UNPACK #-}!KernelThreadId } | TaskMigrate { taskId :: TaskId, cap :: {-# UNPACK #-}!Int, new_cap :: {-# UNPACK #-}!Int } | TaskDelete { taskId :: TaskId } -- garbage collection | RequestSeqGC { } | RequestParGC { } | StartGC { } | GCWork { } | GCIdle { } | GCDone { } | EndGC { } | GlobalSyncGC { } | GCStatsGHC { heapCapset :: {-# UNPACK #-}!Capset , gen :: {-# UNPACK #-}!Int , copied :: {-# UNPACK #-}!Word64 , slop, frag :: {-# UNPACK #-}!Word64 , parNThreads :: {-# UNPACK #-}!Int , parMaxCopied :: {-# UNPACK #-}!Word64 , parTotCopied :: {-# UNPACK #-}!Word64 } -- heap statistics | HeapAllocated { heapCapset :: {-# UNPACK #-}!Capset , allocBytes :: {-# UNPACK #-}!Word64 } | HeapSize { heapCapset :: {-# UNPACK #-}!Capset , sizeBytes :: {-# UNPACK #-}!Word64 } | HeapLive { heapCapset :: {-# UNPACK #-}!Capset , liveBytes :: {-# UNPACK #-}!Word64 } | HeapInfoGHC { heapCapset :: {-# UNPACK #-}!Capset , gens :: {-# UNPACK #-}!Int , maxHeapSize :: {-# UNPACK #-}!Word64 , allocAreaSize :: {-# UNPACK #-}!Word64 , mblockSize :: {-# UNPACK #-}!Word64 , blockSize :: {-# UNPACK #-}!Word64 } -- adjusting the number of capabilities on the fly | CapCreate { cap :: {-# UNPACK #-}!Int } | CapDelete { cap :: {-# UNPACK #-}!Int } | CapDisable { cap :: {-# UNPACK #-}!Int } | CapEnable { cap :: {-# UNPACK #-}!Int } -- capability sets | CapsetCreate { capset :: {-# UNPACK #-}!Capset , capsetType :: CapsetType } | CapsetDelete { capset :: {-# UNPACK #-}!Capset } | CapsetAssignCap { capset :: {-# UNPACK #-}!Capset , cap :: {-# UNPACK #-}!Int } | CapsetRemoveCap { capset :: {-# UNPACK #-}!Capset , cap :: {-# UNPACK #-}!Int } -- program/process info | RtsIdentifier { capset :: {-# UNPACK #-}!Capset , rtsident :: String } | ProgramArgs { capset :: {-# UNPACK #-}!Capset , args :: [String] } | ProgramEnv { capset :: {-# UNPACK #-}!Capset , env :: [String] } | OsProcessPid { capset :: {-# UNPACK #-}!Capset , pid :: {-# UNPACK #-}!PID } | OsProcessParentPid { capset :: {-# UNPACK #-}!Capset , ppid :: {-# UNPACK #-}!PID } | WallClockTime { capset :: {-# UNPACK #-}!Capset , sec :: {-# UNPACK #-}!Word64 , nsec :: {-# UNPACK #-}!Word32 } -- messages | Message { msg :: String } | UserMessage { msg :: String } | UserMarker { markername :: String } -- Events emitted by a parallel RTS -- Program /process info (tools might prefer newer variants above) | Version { version :: String } | ProgramInvocation { commandline :: String } -- startup and shutdown (incl. real start time, not first log entry) | CreateMachine { machine :: {-# UNPACK #-} !MachineId, realtime :: {-# UNPACK #-} !Timestamp} | KillMachine { machine :: {-# UNPACK #-} !MachineId } -- Haskell processes mgmt (thread groups that share heap and communicate) | CreateProcess { process :: {-# UNPACK #-} !ProcessId } | KillProcess { process :: {-# UNPACK #-} !ProcessId } | AssignThreadToProcess { thread :: {-# UNPACK #-} !ThreadId, process :: {-# UNPACK #-} !ProcessId } -- communication between processes | EdenStartReceive { } | EdenEndReceive { } | SendMessage { mesTag :: !MessageTag, senderProcess :: {-# UNPACK #-} !ProcessId, senderThread :: {-# UNPACK #-} !ThreadId, receiverMachine :: {-# UNPACK #-} !MachineId, receiverProcess :: {-# UNPACK #-} !ProcessId, receiverInport :: {-# UNPACK #-} !PortId } | ReceiveMessage { mesTag :: !MessageTag, receiverProcess :: {-# UNPACK #-} !ProcessId, receiverInport :: {-# UNPACK #-} !PortId, senderMachine :: {-# UNPACK #-} !MachineId, senderProcess :: {-# UNPACK #-} !ProcessId, senderThread :: {-# UNPACK #-} !ThreadId, messageSize :: {-# UNPACK #-} !MessageSize } | SendReceiveLocalMessage { mesTag :: !MessageTag, senderProcess :: {-# UNPACK #-} !ProcessId, senderThread :: {-# UNPACK #-} !ThreadId, receiverProcess :: {-# UNPACK #-} !ProcessId, receiverInport :: {-# UNPACK #-} !PortId } -- These events have been added for Mercury's benifit but are generally -- useful. | InternString { str :: String, sId :: {-# UNPACK #-}!StringId } -- Mercury specific events. | MerStartParConjunction { dyn_id :: {-# UNPACK #-}!ParConjDynId, static_id :: {-# UNPACK #-}!ParConjStaticId } | MerEndParConjunction { dyn_id :: {-# UNPACK #-}!ParConjDynId } | MerEndParConjunct { dyn_id :: {-# UNPACK #-}!ParConjDynId } | MerCreateSpark { dyn_id :: {-# UNPACK #-}!ParConjDynId, spark_id :: {-# UNPACK #-}!SparkId } | MerFutureCreate { future_id :: {-# UNPACK #-}!FutureId, name_id :: {-# UNPACK #-}!StringId } | MerFutureWaitNosuspend { future_id :: {-# UNPACK #-}!FutureId } | MerFutureWaitSuspended { future_id :: {-# UNPACK #-}!FutureId } | MerFutureSignal { future_id :: {-# UNPACK #-}!FutureId } | MerLookingForGlobalThread | MerWorkStealing | MerLookingForLocalSpark | MerReleaseThread { thread_id :: {-# UNPACK #-}!ThreadId } | MerCapSleeping | MerCallingMain -- perf events | PerfName { perfNum :: {-# UNPACK #-}!PerfEventTypeNum , name :: String } | PerfCounter { perfNum :: {-# UNPACK #-}!PerfEventTypeNum , tid :: {-# UNPACK #-}!KernelThreadId , period :: {-# UNPACK #-}!Word64 } | PerfTracepoint { perfNum :: {-# UNPACK #-}!PerfEventTypeNum , tid :: {-# UNPACK #-}!KernelThreadId } deriving Show {- [Note: Stop status in GHC-7.8.2] In GHC-7.7, a new thread block reason "BlockedOnMVarRead" was introduced, and placed adjacent to BlockedOnMVar (7). Therefore, event logs produced by GHC pre-7.8.2 encode BlockedOnBlackHole and following as 8..18, whereas GHC-7.8.2 event logs encode them as 9..19. Later, the prior event numbering was restored for GHC-7.8.3. See GHC bug #9003 for a discussion. The parsers in Events.hs have to be adapted accordingly, providing special ghc-7.8.2 parsers for the thread-stop event if GHC-7.8.2 produced the eventlog. The EVENT_USER_MARKER was not present in GHC-7.6.3, and a new event EVENT_HACK_BUG_T9003 was added in GHC-7.8.3, so we take presence of USER_MARKER and absence of HACK_BUG_T9003 as an indication that ghc-7.8.2 parsers should be used. -} --sync with ghc/includes/Constants.h data ThreadStopStatus = NoStatus | HeapOverflow | StackOverflow | ThreadYielding | ThreadBlocked | ThreadFinished | ForeignCall | BlockedOnMVar | BlockedOnMVarRead -- since GHC-7.8, see [Stop status since GHC-7.7] | BlockedOnBlackHole | BlockedOnRead | BlockedOnWrite | BlockedOnDelay | BlockedOnSTM | BlockedOnDoProc | BlockedOnCCall | BlockedOnCCall_NoUnblockExc | BlockedOnMsgThrowTo | ThreadMigrating | BlockedOnMsgGlobalise | BlockedOnBlackHoleOwnedBy {-# UNPACK #-}!ThreadId deriving (Show) -- normal GHC encoding, see [Stop status in GHC-7.8.2] mkStopStatus :: RawThreadStopStatus -> ThreadStopStatus mkStopStatus n = case n of 0 -> NoStatus 1 -> HeapOverflow 2 -> StackOverflow 3 -> ThreadYielding 4 -> ThreadBlocked 5 -> ThreadFinished 6 -> ForeignCall 7 -> BlockedOnMVar 8 -> BlockedOnBlackHole 9 -> BlockedOnRead 10 -> BlockedOnWrite 11 -> BlockedOnDelay 12 -> BlockedOnSTM 13 -> BlockedOnDoProc 14 -> BlockedOnCCall 15 -> BlockedOnCCall_NoUnblockExc 16 -> BlockedOnMsgThrowTo 17 -> ThreadMigrating 18 -> BlockedOnMsgGlobalise 19 -> NoStatus -- yeuch... this one does not actually exist in GHC eventlogs 20 -> BlockedOnMVarRead -- since GHC-7.8.3 _ -> error "mkStat" -- GHC 7.8.2 encoding, see [Stop status in GHC-7.8.2] mkStopStatus782 :: RawThreadStopStatus -> ThreadStopStatus mkStopStatus782 n = case n of 0 -> NoStatus 1 -> HeapOverflow 2 -> StackOverflow 3 -> ThreadYielding 4 -> ThreadBlocked 5 -> ThreadFinished 6 -> ForeignCall 7 -> BlockedOnMVar 8 -> BlockedOnMVarRead -- in GHC-7.8.2 9 -> BlockedOnBlackHole 10 -> BlockedOnRead 11 -> BlockedOnWrite 12 -> BlockedOnDelay 13 -> BlockedOnSTM 14 -> BlockedOnDoProc 15 -> BlockedOnCCall 16 -> BlockedOnCCall_NoUnblockExc 17 -> BlockedOnMsgThrowTo 18 -> ThreadMigrating 19 -> BlockedOnMsgGlobalise _ -> error "mkStat" maxThreadStopStatusPre77, maxThreadStopStatus782, maxThreadStopStatus :: RawThreadStopStatus maxThreadStopStatusPre77 = 18 -- see [Stop status in GHC-7.8.2] maxThreadStopStatus782 = 19 -- need to distinguish three cases maxThreadStopStatus = 20 data CapsetType = CapsetCustom | CapsetOsProcess | CapsetClockDomain | CapsetUnknown deriving Show mkCapsetType :: Word16 -> CapsetType mkCapsetType n = case n of 1 -> CapsetCustom 2 -> CapsetOsProcess 3 -> CapsetClockDomain _ -> CapsetUnknown -- | An event annotated with the Capability that generated it, if any data CapEvent = CapEvent { ce_cap :: Maybe Int, ce_event :: Event -- we could UNPACK ce_event, but the Event constructor -- might be shared, in which case we could end up -- increasing the space usage. } deriving Show --sync with ghc/parallel/PEOpCodes.h data MessageTag = Ready | NewPE | PETIDS | Finish | FailPE | RFork | Connect | DataMes | Head | Constr | Part | Terminate | Packet -- with GUM and its variants, add: -- ...| Fetch | Resume | Ack -- ...| Fish | Schedule | Free | Reval | Shark deriving (Enum, Show) offset :: RawMsgTag offset = 0x50 -- decoder and encoder toMsgTag :: RawMsgTag -> MessageTag toMsgTag = toEnum . fromIntegral . (\n -> n - offset) fromMsgTag :: MessageTag -> RawMsgTag fromMsgTag = (+ offset) . fromIntegral . fromEnum ghc-events-0.4.4.0/GHC/RTS/EventLogFormat.h0000644000000000000000000003245412520426612016234 0ustar0000000000000000/* ----------------------------------------------------------------------------- * * (c) The GHC Team, 2008-2012 * * Event log format * * The log format is designed to be extensible: old tools should be * able to parse (but not necessarily understand all of) new versions * of the format, and new tools will be able to understand old log * files. * * Each event has a specific format. If you add new events, give them * new numbers: we never re-use old event numbers. * * - The format is endian-independent: all values are represented in * bigendian order. * * - The format is extensible: * * - The header describes each event type and its length. Tools * that don't recognise a particular event type can skip those events. * * - There is room for extra information in the event type * specification, which can be ignored by older tools. * * - Events can have extra information added, but existing fields * cannot be changed. Tools should ignore extra fields at the * end of the event record. * * - Old event type ids are never re-used; just take a new identifier. * * * The format * ---------- * * log : EVENT_HEADER_BEGIN * EventType* * EVENT_HEADER_END * EVENT_DATA_BEGIN * Event* * EVENT_DATA_END * * EventType : * EVENT_ET_BEGIN * Word16 -- unique identifier for this event * Int16 -- >=0 size of the event in bytes (minus the header) * -- -1 variable size * Word32 -- length of the next field in bytes * Word8* -- string describing the event * Word32 -- length of the next field in bytes * Word8* -- extra info (for future extensions) * EVENT_ET_END * * Event : * Word16 -- event_type * Word64 -- time (nanosecs) * [Word16] -- length of the rest (for variable-sized events only) * ... extra event-specific info ... * * * To add a new event * ------------------ * * - In this file: * - give it a new number, add a new #define EVENT_XXX below * - In EventLog.c * - add it to the EventDesc array * - emit the event type in initEventLogging() * - emit the new event in postEvent_() * - generate the event itself by calling postEvent() somewhere * - In the Haskell code to parse the event log file: * - add types and code to read the new event * * -------------------------------------------------------------------------- */ #ifndef RTS_EVENTLOGFORMAT_H #define RTS_EVENTLOGFORMAT_H /* * Markers for begin/end of the Header. */ #define EVENT_HEADER_BEGIN 0x68647262 /* 'h' 'd' 'r' 'b' */ #define EVENT_HEADER_END 0x68647265 /* 'h' 'd' 'r' 'e' */ #define EVENT_DATA_BEGIN 0x64617462 /* 'd' 'a' 't' 'b' */ #define EVENT_DATA_END 0xffff /* * Markers for begin/end of the list of Event Types in the Header. * Header, Event Type, Begin = hetb * Header, Event Type, End = hete */ #define EVENT_HET_BEGIN 0x68657462 /* 'h' 'e' 't' 'b' */ #define EVENT_HET_END 0x68657465 /* 'h' 'e' 't' 'e' */ #define EVENT_ET_BEGIN 0x65746200 /* 'e' 't' 'b' 0 */ #define EVENT_ET_END 0x65746500 /* 'e' 't' 'e' 0 */ /* * Types of event */ #define EVENT_CREATE_THREAD 0 /* (thread) */ #define EVENT_RUN_THREAD 1 /* (thread) */ #define EVENT_STOP_THREAD 2 /* (thread, status, blockinfo) */ #define EVENT_THREAD_RUNNABLE 3 /* (thread) */ #define EVENT_MIGRATE_THREAD 4 /* (thread, new_cap) */ /* 5, 6, 7 deprecated */ #define EVENT_THREAD_WAKEUP 8 /* (thread, other_cap) */ #define EVENT_GC_START 9 /* () */ #define EVENT_GC_END 10 /* () */ #define EVENT_REQUEST_SEQ_GC 11 /* () */ #define EVENT_REQUEST_PAR_GC 12 /* () */ /* 13, 14 deprecated */ #define EVENT_CREATE_SPARK_THREAD 15 /* (spark_thread) */ #define EVENT_LOG_MSG 16 /* (message ...) */ /* EVENT_STARTUP should be deprecated at some point */ #define EVENT_STARTUP 17 /* (num_capabilities) */ #define EVENT_BLOCK_MARKER 18 /* (size, end_time, capability) */ #define EVENT_USER_MSG 19 /* (message ...) */ #define EVENT_GC_IDLE 20 /* () */ #define EVENT_GC_WORK 21 /* () */ #define EVENT_GC_DONE 22 /* () */ /* 23, 24 used by eden */ #define EVENT_CAPSET_CREATE 25 /* (capset, capset_type) */ #define EVENT_CAPSET_DELETE 26 /* (capset) */ #define EVENT_CAPSET_ASSIGN_CAP 27 /* (capset, cap) */ #define EVENT_CAPSET_REMOVE_CAP 28 /* (capset, cap) */ /* the RTS identifier is in the form of "GHC-version rts_way" */ #define EVENT_RTS_IDENTIFIER 29 /* (capset, name_version_string) */ /* the vectors in these events are null separated strings */ #define EVENT_PROGRAM_ARGS 30 /* (capset, commandline_vector) */ #define EVENT_PROGRAM_ENV 31 /* (capset, environment_vector) */ #define EVENT_OSPROCESS_PID 32 /* (capset, pid) */ #define EVENT_OSPROCESS_PPID 33 /* (capset, parent_pid) */ #define EVENT_SPARK_COUNTERS 34 /* (crt,dud,ovf,cnv,gcd,fiz,rem) */ #define EVENT_SPARK_CREATE 35 /* () */ #define EVENT_SPARK_DUD 36 /* () */ #define EVENT_SPARK_OVERFLOW 37 /* () */ #define EVENT_SPARK_RUN 38 /* () */ #define EVENT_SPARK_STEAL 39 /* (victim_cap) */ #define EVENT_SPARK_FIZZLE 40 /* () */ #define EVENT_SPARK_GC 41 /* () */ #define EVENT_INTERN_STRING 42 /* (string, id) {not used by ghc} */ #define EVENT_WALL_CLOCK_TIME 43 /* (capset, unix_epoch_seconds, nanoseconds) */ #define EVENT_THREAD_LABEL 44 /* (thread, name_string) */ #define EVENT_CAP_CREATE 45 /* (cap) */ #define EVENT_CAP_DELETE 46 /* (cap) */ #define EVENT_CAP_DISABLE 47 /* (cap) */ #define EVENT_CAP_ENABLE 48 /* (cap) */ #define EVENT_HEAP_ALLOCATED 49 /* (heap_capset, alloc_bytes) */ #define EVENT_HEAP_SIZE 50 /* (heap_capset, size_bytes) */ #define EVENT_HEAP_LIVE 51 /* (heap_capset, live_bytes) */ #define EVENT_HEAP_INFO_GHC 52 /* (heap_capset, n_generations, max_heap_size, alloc_area_size, mblock_size, block_size) */ #define EVENT_GC_STATS_GHC 53 /* (heap_capset, generation, copied_bytes, slop_bytes, frag_bytes, par_n_threads, par_max_copied, par_tot_copied) */ #define EVENT_GC_GLOBAL_SYNC 54 /* () */ #define EVENT_TASK_CREATE 55 /* (taskID, cap, tid) */ #define EVENT_TASK_MIGRATE 56 /* (taskID, cap, new_cap) */ #define EVENT_TASK_DELETE 57 /* (taskID) */ #define EVENT_USER_MARKER 58 /* (marker_name) */ #define EVENT_HACK_BUG_T9003 59 /* Hack: see trac #9003 */ /* Range 59 - 59 is available for new GHC and common events. */ /* Range 60 - 80 is used by eden for parallel tracing * see http://www.mathematik.uni-marburg.de/~eden/ */ /* these are used by eden but are replaced by new alternatives for ghc */ #define EVENT_VERSION 23 /* (version_string) */ #define EVENT_PROGRAM_INVOCATION 24 /* (commandline_string) */ /* start of parallel trace events */ #define EVENT_EDEN_START_RECEIVE 60 /* () */ #define EVENT_EDEN_END_RECEIVE 61 /* () */ #define EVENT_CREATE_PROCESS 62 /* (process) */ #define EVENT_KILL_PROCESS 63 /* (process) */ #define EVENT_ASSIGN_THREAD_TO_PROCESS 64 /* (thread, process) */ #define EVENT_CREATE_MACHINE 65 /* (machine, startupTime(in 10^-8 seconds after 19xx)) */ #define EVENT_KILL_MACHINE 66 /* (machine) */ #define EVENT_SEND_MESSAGE 67 /* (tag, sender_process, sender_thread, receiver_machine, receiver_process, receiver_inport) */ #define EVENT_RECEIVE_MESSAGE 68 /* (tag, receiver_process, receiver_inport, sender_machine, sender_process, sender_outport, message_size) */ #define EVENT_SEND_RECEIVE_LOCAL_MESSAGE 69 /* (tag, sender_process, sender_thread, receiver_process, receiver_inport) */ /* Range 100 - 139 is reserved for Mercury, see below. */ /* Range 140 - 159 is reserved for Perf events, see below. */ /* * The highest event code +1 that ghc itself emits. Note that some event * ranges higher than this are reserved but not currently emitted by ghc. * This must match the size of the EventDesc[] array in EventLog.c */ #define NUM_GHC_EVENT_TAGS 70 /* DEPRECATED EVENTS: */ /* These two are deprecated because we don't need to record the thread, it's implicit. We have to keep these #defines because for tiresome reasons we still need to parse them, see GHC.RTS.Events.ghc6Parsers for details. */ #define EVENT_RUN_SPARK 5 /* (thread) */ #define EVENT_STEAL_SPARK 6 /* (thread, victim_cap) */ /* shutdown replaced by EVENT_CAP_DELETE */ #define EVENT_SHUTDOWN 7 /* () */ #if 0 /* ghc changed how it handles sparks so these are no longer applicable */ #define EVENT_CREATE_SPARK 13 /* (cap, thread) */ #define EVENT_SPARK_TO_THREAD 14 /* (cap, thread, spark_thread) */ #endif /* * These event types are Mercury specific, Mercury may use up to event number * 139 */ #define EVENT_FIRST_MER_EVENT 100 #define NUM_MER_EVENTS 14 #define EVENT_MER_START_PAR_CONJUNCTION 100 /* (dyn id, static id) */ #define EVENT_MER_STOP_PAR_CONJUNCTION 101 /* (dyn id) */ #define EVENT_MER_STOP_PAR_CONJUNCT 102 /* (dyn id) */ #define EVENT_MER_CREATE_SPARK 103 /* (dyn id, spark id) */ #define EVENT_MER_FUT_CREATE 104 /* (fut id, memo'd name id) */ #define EVENT_MER_FUT_WAIT_NOSUSPEND 105 /* (fut id) */ #define EVENT_MER_FUT_WAIT_SUSPENDED 106 /* (fut id) */ #define EVENT_MER_FUT_SIGNAL 107 /* (fut id) */ #define EVENT_MER_LOOKING_FOR_GLOBAL_CONTEXT \ 108 /* () */ #define EVENT_MER_WORK_STEALING 109 /* () */ #define EVENT_MER_LOOKING_FOR_LOCAL_SPARK \ 112 /* () */ #define EVENT_MER_RELEASE_CONTEXT 110 /* (context id) */ #define EVENT_MER_ENGINE_SLEEPING 111 /* () */ #define EVENT_MER_CALLING_MAIN 113 /* () */ /* * These event types are parsed from hardware performance counters logs, * such as the Linux Performance Counters data available through * the perf subsystem. */ #define EVENT_PERF_NAME 140 /* (perf_num, name) */ #define EVENT_PERF_COUNTER 141 /* (perf_num, tid, period) */ #define EVENT_PERF_TRACEPOINT 142 /* (perf_num, tid) */ /* * Status values for EVENT_STOP_THREAD * * 1-5 are the StgRun return values (from includes/rts/Constants.h): * * #define HeapOverflow 1 * #define StackOverflow 2 * #define ThreadYielding 3 * #define ThreadBlocked 4 * #define ThreadFinished 5 * #define ForeignCall 6 * #define BlockedOnMVar 7 * #define BlockedOnMVarRead 20 * NOTE: in GHC-7.8.2, this was 8, and following states shifted one up * #define BlockedOnBlackHole 8 * #define BlockedOnRead 9 * #define BlockedOnWrite 10 * #define BlockedOnDelay 11 * #define BlockedOnSTM 12 * #define BlockedOnDoProc 13 * NOTE: unused GUM states 8, 9 (here: 14,15) in rts/Constants.h * #define BlockedOnCCall -- not used (see ForeignCall) * #define BlockedOnCCall_NoUnblockExc -- not used (see ForeignCall) * #define BlockedOnMsgThrowTo 16 * NOTE: 16 because unused GUM states ignored in ghc-events lib * Otherwise it would be 18, following would be 19, 20 * TODO: verify the above is what GHC does (16/17 could be 18/19) * #define ThreadMigrating 17 * #define BlockedOnMsgGlobalise 18 * NOTE: not present in GHC. Mercury-Event? */ #define THREAD_SUSPENDED_FOREIGN_CALL 6 /* * Capset type values for EVENT_CAPSET_CREATE */ #define CAPSET_TYPE_CUSTOM 1 /* reserved for end-user applications */ #define CAPSET_TYPE_OSPROCESS 2 /* caps belong to the same OS process */ #define CAPSET_TYPE_CLOCKDOMAIN 3 /* caps share a local clock/time */ #ifndef EVENTLOG_CONSTANTS_ONLY typedef StgWord16 EventTypeNum; typedef StgWord64 EventTimestamp; /* in nanoseconds */ typedef StgWord32 EventThreadID; typedef StgWord16 EventCapNo; typedef StgWord16 EventPayloadSize; /* variable-size events */ typedef StgWord16 EventThreadStatus; /* status for EVENT_STOP_THREAD */ typedef StgWord32 EventCapsetID; typedef StgWord16 EventCapsetType; /* types for EVENT_CAPSET_CREATE */ typedef StgWord64 EventTaskId; /* for EVENT_TASK_* */ typedef StgWord64 EventKernelThreadId; /* for EVENT_TASK_CREATE */ typedef StgWord32 EventProcessID; typedef StgWord16 EventMachineID; typedef EventThreadID EventPortID; #endif #endif /* RTS_EVENTLOGFORMAT_H */ ghc-events-0.4.4.0/GHC/RTS/Events.hs0000644000000000000000000015643712520426612014777 0ustar0000000000000000{-# LANGUAGE CPP,BangPatterns,PatternGuards #-} {-# OPTIONS_GHC -funbox-strict-fields -fwarn-incomplete-patterns #-} {- - Parser functions for GHC RTS EventLog framework. -} module GHC.RTS.Events ( -- * The event log types EventLog(..), EventType(..), Event(..), EventInfo(..), ThreadStopStatus(..), Header(..), Data(..), CapsetType(..), Timestamp, ThreadId, TaskId, KernelThreadId(..), -- some types for the parallel RTS ProcessId, MachineId, PortId, MessageSize, MessageTag(..), -- * Reading and writing event logs readEventLogFromFile, getEventLog, writeEventLogToFile, -- * Utilities CapEvent(..), sortEvents, groupEvents, sortGroups, buildEventTypeMap, -- * Printing showEventInfo, showThreadStopStatus, ppEventLog, ppEventType, ppEvent, -- * Perf events nEVENT_PERF_NAME, nEVENT_PERF_COUNTER, nEVENT_PERF_TRACEPOINT, sz_perf_num, sz_kernel_tid ) where {- Libraries. -} import Data.Binary import Data.Binary.Get hiding (skip) import qualified Data.Binary.Get as G import Data.Binary.Put import Control.Monad import Data.IntMap (IntMap) import qualified Data.IntMap as M import Control.Monad.Reader import Control.Monad.Except import qualified Data.ByteString.Lazy as L import Data.Function import Data.List import Data.Either import Data.Maybe import Text.Printf import Data.Array import GHC.RTS.EventTypes import GHC.RTS.EventParserUtils #define EVENTLOG_CONSTANTS_ONLY #include "EventLogFormat.h" ------------------------------------------------------------------------------ -- Binary instances getEventType :: GetHeader EventType getEventType = do etNum <- getH size <- getH :: GetHeader EventTypeSize let etSize = if size == 0xffff then Nothing else Just size -- 0xffff indicates variable-sized event etDescLen <- getH :: GetHeader EventTypeDescLen etDesc <- getEtDesc (fromIntegral etDescLen) etExtraLen <- getH :: GetHeader Word32 lift $ G.skip (fromIntegral etExtraLen) ete <- getH :: GetHeader Marker when (ete /= EVENT_ET_END) $ throwError ("Event Type end marker not found.") return (EventType etNum etDesc etSize) where getEtDesc :: Int -> GetHeader [Char] getEtDesc s = replicateM s (getH :: GetHeader Char) getHeader :: GetHeader Header getHeader = do hdrb <- getH :: GetHeader Marker when (hdrb /= EVENT_HEADER_BEGIN) $ throwError "Header begin marker not found" hetm <- getH :: GetHeader Marker when (hetm /= EVENT_HET_BEGIN) $ throwError "Header Event Type begin marker not found" ets <- getEventTypes emark <- getH :: GetHeader Marker when (emark /= EVENT_HEADER_END) $ throwError "Header end marker not found" return (Header ets) where getEventTypes :: GetHeader [EventType] getEventTypes = do m <- getH :: GetHeader Marker case () of _ | m == EVENT_ET_BEGIN -> do et <- getEventType nextET <- getEventTypes return (et : nextET) | m == EVENT_HET_END -> return [] | otherwise -> throwError "Malformed list of Event Types in header" getEvent :: EventParsers -> GetEvents (Maybe Event) getEvent (EventParsers parsers) = do etRef <- getE :: GetEvents EventTypeNum if (etRef == EVENT_DATA_END) then return Nothing else do !ts <- getE -- trace ("event: " ++ show etRef) $ do spec <- parsers ! fromIntegral etRef return (Just (Event ts spec)) -- -- standardEventParsers. -- standardParsers :: [EventParser EventInfo] standardParsers = [ (FixedSizeParser EVENT_STARTUP sz_cap (do -- (n_caps) c <- getE :: GetEvents CapNo return Startup{ n_caps = fromIntegral c } )), (FixedSizeParser EVENT_BLOCK_MARKER (sz_block_size + sz_time + sz_cap) (do -- (size, end_time, cap) block_size <- getE :: GetEvents BlockSize end_time <- getE :: GetEvents Timestamp c <- getE :: GetEvents CapNo lbs <- lift . lift $ getLazyByteString ((fromIntegral block_size) - (fromIntegral sz_block_event)) eparsers <- ask let e_events = runGet (runExceptT $ runReaderT (getEventBlock eparsers) eparsers) lbs return EventBlock{ end_time=end_time, cap= fromIntegral c, block_events=case e_events of Left s -> error s Right es -> es } )), -- EVENT_SHUTDOWN is replaced by EVENT_CAP_DELETE and GHC 7.6+ -- no longer generate the event; should be removed at some point (simpleEvent EVENT_SHUTDOWN Shutdown), (simpleEvent EVENT_REQUEST_SEQ_GC RequestSeqGC), (simpleEvent EVENT_REQUEST_PAR_GC RequestParGC), (simpleEvent EVENT_GC_START StartGC), (simpleEvent EVENT_GC_WORK GCWork), (simpleEvent EVENT_GC_IDLE GCIdle), (simpleEvent EVENT_GC_DONE GCDone), (simpleEvent EVENT_GC_END EndGC), (simpleEvent EVENT_GC_GLOBAL_SYNC GlobalSyncGC), (FixedSizeParser EVENT_GC_STATS_GHC (sz_capset + 2 + 5*8 + 4) (do -- (heap_capset, generation, copied_bytes, slop_bytes, frag_bytes, par_n_threads, par_max_copied, par_tot_copied) heapCapset <- getE gen <- getE :: GetEvents Word16 copied <- getE :: GetEvents Word64 slop <- getE :: GetEvents Word64 frag <- getE :: GetEvents Word64 parNThreads <- getE :: GetEvents Word32 parMaxCopied <- getE :: GetEvents Word64 parTotCopied <- getE :: GetEvents Word64 return GCStatsGHC{ gen = fromIntegral gen , parNThreads = fromIntegral parNThreads , ..} )), (FixedSizeParser EVENT_HEAP_ALLOCATED (sz_capset + 8) (do -- (heap_capset, alloc_bytes) heapCapset <- getE allocBytes <- getE return HeapAllocated{..} )), (FixedSizeParser EVENT_HEAP_SIZE (sz_capset + 8) (do -- (heap_capset, size_bytes) heapCapset <- getE sizeBytes <- getE return HeapSize{..} )), (FixedSizeParser EVENT_HEAP_LIVE (sz_capset + 8) (do -- (heap_capset, live_bytes) heapCapset <- getE liveBytes <- getE return HeapLive{..} )), (FixedSizeParser EVENT_HEAP_INFO_GHC (sz_capset + 2 + 4*8) (do -- (heap_capset, n_generations, max_heap_size, alloc_area_size, mblock_size, block_size) heapCapset <- getE gens <- getE :: GetEvents Word16 maxHeapSize <- getE :: GetEvents Word64 allocAreaSize <- getE :: GetEvents Word64 mblockSize <- getE :: GetEvents Word64 blockSize <- getE :: GetEvents Word64 return HeapInfoGHC{gens = fromIntegral gens, ..} )), (FixedSizeParser EVENT_CAP_CREATE (sz_cap) (do -- (cap) cap <- getE :: GetEvents CapNo return CapCreate{cap = fromIntegral cap} )), (FixedSizeParser EVENT_CAP_DELETE (sz_cap) (do -- (cap) cap <- getE :: GetEvents CapNo return CapDelete{cap = fromIntegral cap} )), (FixedSizeParser EVENT_CAP_DISABLE (sz_cap) (do -- (cap) cap <- getE :: GetEvents CapNo return CapDisable{cap = fromIntegral cap} )), (FixedSizeParser EVENT_CAP_ENABLE (sz_cap) (do -- (cap) cap <- getE :: GetEvents CapNo return CapEnable{cap = fromIntegral cap} )), (FixedSizeParser EVENT_CAPSET_CREATE (sz_capset + sz_capset_type) (do -- (capset, capset_type) cs <- getE ct <- fmap mkCapsetType getE return CapsetCreate{capset=cs,capsetType=ct} )), (FixedSizeParser EVENT_CAPSET_DELETE sz_capset (do -- (capset) cs <- getE return CapsetDelete{capset=cs} )), (FixedSizeParser EVENT_CAPSET_ASSIGN_CAP (sz_capset + sz_cap) (do -- (capset, cap) cs <- getE cp <- getE :: GetEvents CapNo return CapsetAssignCap{capset=cs,cap=fromIntegral cp} )), (FixedSizeParser EVENT_CAPSET_REMOVE_CAP (sz_capset + sz_cap) (do -- (capset, cap) cs <- getE cp <- getE :: GetEvents CapNo return CapsetRemoveCap{capset=cs,cap=fromIntegral cp} )), (FixedSizeParser EVENT_OSPROCESS_PID (sz_capset + sz_pid) (do -- (capset, pid) cs <- getE pd <- getE return OsProcessPid{capset=cs,pid=pd} )), (FixedSizeParser EVENT_OSPROCESS_PPID (sz_capset + sz_pid) (do -- (capset, ppid) cs <- getE pd <- getE return OsProcessParentPid{capset=cs,ppid=pd} )), (FixedSizeParser EVENT_WALL_CLOCK_TIME (sz_capset + 8 + 4) (do -- (capset, unix_epoch_seconds, nanoseconds) cs <- getE s <- getE ns <- getE return WallClockTime{capset=cs,sec=s,nsec=ns} )), (VariableSizeParser EVENT_LOG_MSG (do -- (msg) num <- getE :: GetEvents Word16 string <- getString num return Message{ msg = string } )), (VariableSizeParser EVENT_USER_MSG (do -- (msg) num <- getE :: GetEvents Word16 string <- getString num return UserMessage{ msg = string } )), (VariableSizeParser EVENT_USER_MARKER (do -- (markername) num <- getE :: GetEvents Word16 string <- getString num return UserMarker{ markername = string } )), (VariableSizeParser EVENT_PROGRAM_ARGS (do -- (capset, [arg]) num <- getE :: GetEvents Word16 cs <- getE string <- getString (num - sz_capset) return ProgramArgs{ capset = cs , args = splitNull string } )), (VariableSizeParser EVENT_PROGRAM_ENV (do -- (capset, [arg]) num <- getE :: GetEvents Word16 cs <- getE string <- getString (num - sz_capset) return ProgramEnv{ capset = cs , env = splitNull string } )), (VariableSizeParser EVENT_RTS_IDENTIFIER (do -- (capset, str) num <- getE :: GetEvents Word16 cs <- getE string <- getString (num - sz_capset) return RtsIdentifier{ capset = cs , rtsident = string } )), (VariableSizeParser EVENT_INTERN_STRING (do -- (str, id) num <- getE :: GetEvents Word16 string <- getString (num - sz_string_id) sId <- getE :: GetEvents StringId return (InternString string sId) )), (VariableSizeParser EVENT_THREAD_LABEL (do -- (thread, str) num <- getE :: GetEvents Word16 tid <- getE str <- getString (num - sz_tid) return ThreadLabel{ thread = tid , threadlabel = str } )) ] -- Parsers valid for GHC7 but not GHC6. ghc7Parsers :: [EventParser EventInfo] ghc7Parsers = [ (FixedSizeParser EVENT_CREATE_THREAD sz_tid (do -- (thread) t <- getE return CreateThread{thread=t} )), (FixedSizeParser EVENT_RUN_THREAD sz_tid (do -- (thread) t <- getE return RunThread{thread=t} )), (FixedSizeParser EVENT_THREAD_RUNNABLE sz_tid (do -- (thread) t <- getE return ThreadRunnable{thread=t} )), (FixedSizeParser EVENT_MIGRATE_THREAD (sz_tid + sz_cap) (do -- (thread, newCap) t <- getE nc <- getE :: GetEvents CapNo return MigrateThread{thread=t,newCap=fromIntegral nc} )), -- Yes, EVENT_RUN/STEAL_SPARK are deprecated, but see the explanation in the -- 'ghc6Parsers' section below. Since we're parsing them anyway, we might -- as well convert them to the new SparkRun/SparkSteal events. (FixedSizeParser EVENT_RUN_SPARK sz_tid (do -- (thread) _ <- getE :: GetEvents ThreadId return SparkRun )), (FixedSizeParser EVENT_STEAL_SPARK (sz_tid + sz_cap) (do -- (thread, victimCap) _ <- getE :: GetEvents ThreadId vc <- getE :: GetEvents CapNo return SparkSteal{victimCap=fromIntegral vc} )), (FixedSizeParser EVENT_CREATE_SPARK_THREAD sz_tid (do -- (sparkThread) st <- getE :: GetEvents ThreadId return CreateSparkThread{sparkThread=st} )), (FixedSizeParser EVENT_SPARK_COUNTERS (7*8) (do -- (crt,dud,ovf,cnv,gcd,fiz,rem) crt <- getE :: GetEvents Word64 dud <- getE :: GetEvents Word64 ovf <- getE :: GetEvents Word64 cnv <- getE :: GetEvents Word64 gcd <- getE :: GetEvents Word64 fiz <- getE :: GetEvents Word64 rem <- getE :: GetEvents Word64 return SparkCounters{sparksCreated = crt, sparksDud = dud, sparksOverflowed = ovf, sparksConverted = cnv, -- Warning: order of fiz and gcd reversed! sparksFizzled = fiz, sparksGCd = gcd, sparksRemaining = rem} )), (simpleEvent EVENT_SPARK_CREATE SparkCreate), (simpleEvent EVENT_SPARK_DUD SparkDud), (simpleEvent EVENT_SPARK_OVERFLOW SparkOverflow), (simpleEvent EVENT_SPARK_RUN SparkRun), (FixedSizeParser EVENT_SPARK_STEAL sz_cap (do -- (victimCap) vc <- getE :: GetEvents CapNo return SparkSteal{victimCap=fromIntegral vc} )), (simpleEvent EVENT_SPARK_FIZZLE SparkFizzle), (simpleEvent EVENT_SPARK_GC SparkGC), (FixedSizeParser EVENT_TASK_CREATE (sz_taskid + sz_cap + sz_kernel_tid) (do -- (taskID, cap, tid) taskId <- getE :: GetEvents TaskId cap <- getE :: GetEvents CapNo tid <- getE :: GetEvents KernelThreadId return TaskCreate{ taskId, cap = fromIntegral cap, tid } )), (FixedSizeParser EVENT_TASK_MIGRATE (sz_taskid + sz_cap*2) (do -- (taskID, cap, new_cap) taskId <- getE :: GetEvents TaskId cap <- getE :: GetEvents CapNo new_cap <- getE :: GetEvents CapNo return TaskMigrate{ taskId, cap = fromIntegral cap , new_cap = fromIntegral new_cap } )), (FixedSizeParser EVENT_TASK_DELETE (sz_taskid) (do -- (taskID) taskId <- getE :: GetEvents TaskId return TaskDelete{ taskId } )), (FixedSizeParser EVENT_THREAD_WAKEUP (sz_tid + sz_cap) (do -- (thread, other_cap) t <- getE oc <- getE :: GetEvents CapNo return WakeupThread{thread=t,otherCap=fromIntegral oc} )) ] -- special thread stop event parsers for GHC version 7.8.2 -- see [Stop status in GHC-7.8.2] in EventTypes.hs ghc782StopParser :: EventParser EventInfo ghc782StopParser = (FixedSizeParser EVENT_STOP_THREAD (sz_tid + sz_th_stop_status + sz_tid) (do -- (thread, status, info) t <- getE s <- getE :: GetEvents RawThreadStopStatus i <- getE :: GetEvents ThreadId return StopThread{thread = t, status = case () of _ | s > maxThreadStopStatus782 -> NoStatus | s == 9 {- XXX yeuch -} -- GHC-7.8.2: 9 == BlockedOnBlackHole -> BlockedOnBlackHoleOwnedBy i | otherwise -> mkStopStatus782 s} )) -- parsers for GHC < 7.8.2. Older versions do not use block info -- (different length). See [Stop status in GHC-7.8.2] in -- EventTypes.hs pre77StopParsers :: [EventParser EventInfo] pre77StopParsers = [ (FixedSizeParser EVENT_STOP_THREAD (sz_tid + sz_th_stop_status) (do -- (thread, status) t <- getE s <- getE :: GetEvents RawThreadStopStatus return StopThread{thread=t, status = if s > maxThreadStopStatusPre77 then NoStatus else mkStopStatus s} -- older version of the event, no block info )), (FixedSizeParser EVENT_STOP_THREAD (sz_tid + sz_th_stop_status + sz_tid) (do -- (thread, status, info) t <- getE s <- getE :: GetEvents RawThreadStopStatus i <- getE :: GetEvents ThreadId return StopThread{thread = t, status = case () of _ | s > maxThreadStopStatusPre77 -> NoStatus | s == 8 {- XXX yeuch -} -- pre-7.7: 8==BlockedOnBlackhole -> BlockedOnBlackHoleOwnedBy i | otherwise -> mkStopStatus s} )) ] -- parsers for GHC >= 7.8.3, always using block info field parser. -- See [Stop status in GHC-7.8.2] in EventTypes.hs post782StopParser :: EventParser EventInfo post782StopParser = (FixedSizeParser EVENT_STOP_THREAD (sz_tid + sz_th_stop_status + sz_tid) (do -- (thread, status, info) t <- getE s <- getE :: GetEvents RawThreadStopStatus i <- getE :: GetEvents ThreadId return StopThread{thread = t, status = case () of _ | s > maxThreadStopStatus -> NoStatus | s == 8 {- XXX yeuch -} -- post-7.8.2: 8==BlockedOnBlackhole -> BlockedOnBlackHoleOwnedBy i | otherwise -> mkStopStatus s} )) ----------------------- -- GHC 6.12 compat: GHC 6.12 reported the wrong sizes for some events, -- so we have to recognise those wrong sizes here for backwards -- compatibility. ghc6Parsers :: [EventParser EventInfo] ghc6Parsers = [ (FixedSizeParser EVENT_STARTUP 0 (do -- BUG in GHC 6.12: the startup event was incorrectly -- declared as size 0, so we accept it here. c <- getE :: GetEvents CapNo return Startup{ n_caps = fromIntegral c } )), (FixedSizeParser EVENT_CREATE_THREAD sz_old_tid (do -- (thread) t <- getE return CreateThread{thread=t} )), (FixedSizeParser EVENT_RUN_THREAD sz_old_tid (do -- (thread) t <- getE return RunThread{thread=t} )), (FixedSizeParser EVENT_STOP_THREAD (sz_old_tid + 2) (do -- (thread, status) t <- getE s <- getE :: GetEvents RawThreadStopStatus return StopThread{thread=t, status = if s > maxThreadStopStatusPre77 then NoStatus else mkStopStatus s} -- older version of the event uses pre-77 encoding -- (actually, it only uses encodings 0 to 5) -- see [Stop status in GHC-7.8.2] in EventTypes.hs )), (FixedSizeParser EVENT_THREAD_RUNNABLE sz_old_tid (do -- (thread) t <- getE return ThreadRunnable{thread=t} )), (FixedSizeParser EVENT_MIGRATE_THREAD (sz_old_tid + sz_cap) (do -- (thread, newCap) t <- getE nc <- getE :: GetEvents CapNo return MigrateThread{thread=t,newCap=fromIntegral nc} )), -- Note: it is vital that these two (EVENT_RUN/STEAL_SPARK) remain here (at -- least in the ghc6Parsers section) even though both events are deprecated. -- The reason is that .eventlog files created by the buggy GHC-6.12 -- mis-declare the size of these two events. So we have to handle them -- specially here otherwise we'll get the wrong size, leading to us getting -- out of sync and eventual parse failure. Since we're parsing them anyway, -- we might as well convert them to the new SparkRun/SparkSteal events. (FixedSizeParser EVENT_RUN_SPARK sz_old_tid (do -- (thread) _ <- getE :: GetEvents ThreadId return SparkRun )), (FixedSizeParser EVENT_STEAL_SPARK (sz_old_tid + sz_cap) (do -- (thread, victimCap) _ <- getE :: GetEvents ThreadId vc <- getE :: GetEvents CapNo return SparkSteal{victimCap=fromIntegral vc} )), (FixedSizeParser EVENT_CREATE_SPARK_THREAD sz_old_tid (do -- (sparkThread) st <- getE :: GetEvents ThreadId return CreateSparkThread{sparkThread=st} )), (FixedSizeParser EVENT_THREAD_WAKEUP (sz_old_tid + sz_cap) (do -- (thread, other_cap) t <- getE oc <- getE :: GetEvents CapNo return WakeupThread{thread=t,otherCap=fromIntegral oc} )) ] -- Parsers for parallel events. Parameter is the thread_id size, to create -- ghc6-parsers (using the wrong size) where necessary. parRTSParsers :: EventTypeSize -> [EventParser EventInfo] parRTSParsers sz_tid = [ (VariableSizeParser EVENT_VERSION (do -- (version) num <- getE :: GetEvents Word16 string <- getString num return Version{ version = string } )), (VariableSizeParser EVENT_PROGRAM_INVOCATION (do -- (cmd. line) num <- getE :: GetEvents Word16 string <- getString num return ProgramInvocation{ commandline = string } )), (simpleEvent EVENT_EDEN_START_RECEIVE EdenStartReceive), (simpleEvent EVENT_EDEN_END_RECEIVE EdenEndReceive), (FixedSizeParser EVENT_CREATE_PROCESS sz_procid (do p <- getE return CreateProcess{ process = p }) ), (FixedSizeParser EVENT_KILL_PROCESS sz_procid (do p <- getE return KillProcess{ process = p }) ), (FixedSizeParser EVENT_ASSIGN_THREAD_TO_PROCESS (sz_tid + sz_procid) (do t <- getE p <- getE return AssignThreadToProcess { thread = t, process = p }) ), (FixedSizeParser EVENT_CREATE_MACHINE (sz_mid + sz_realtime) (do m <- getE t <- getE return CreateMachine { machine = m, realtime = t }) ), (FixedSizeParser EVENT_KILL_MACHINE sz_mid (do m <- getE :: GetEvents MachineId return KillMachine { machine = m }) ), (FixedSizeParser EVENT_SEND_MESSAGE (sz_msgtag + 2*sz_procid + 2*sz_tid + sz_mid) (do tag <- getE :: GetEvents RawMsgTag sP <- getE :: GetEvents ProcessId sT <- getE :: GetEvents ThreadId rM <- getE :: GetEvents MachineId rP <- getE :: GetEvents ProcessId rIP <- getE :: GetEvents PortId return SendMessage { mesTag = toMsgTag tag, senderProcess = sP, senderThread = sT, receiverMachine = rM, receiverProcess = rP, receiverInport = rIP }) ), (FixedSizeParser EVENT_RECEIVE_MESSAGE (sz_msgtag + 2*sz_procid + 2*sz_tid + sz_mid + sz_mes) (do tag <- getE :: GetEvents Word8 rP <- getE :: GetEvents ProcessId rIP <- getE :: GetEvents PortId sM <- getE :: GetEvents MachineId sP <- getE :: GetEvents ProcessId sT <- getE :: GetEvents ThreadId mS <- getE :: GetEvents MessageSize return ReceiveMessage { mesTag = toMsgTag tag, receiverProcess = rP, receiverInport = rIP, senderMachine = sM, senderProcess = sP, senderThread= sT, messageSize = mS }) ), (FixedSizeParser EVENT_SEND_RECEIVE_LOCAL_MESSAGE (sz_msgtag + 2*sz_procid + 2*sz_tid) (do tag <- getE :: GetEvents Word8 sP <- getE :: GetEvents ProcessId sT <- getE :: GetEvents ThreadId rP <- getE :: GetEvents ProcessId rIP <- getE :: GetEvents PortId return SendReceiveLocalMessage { mesTag = toMsgTag tag, senderProcess = sP, senderThread = sT, receiverProcess = rP, receiverInport = rIP }) )] mercuryParsers = [ (FixedSizeParser EVENT_MER_START_PAR_CONJUNCTION (sz_par_conj_dyn_id + sz_par_conj_static_id) (do dyn_id <- getE static_id <- getE return (MerStartParConjunction dyn_id static_id)) ), (FixedSizeParser EVENT_MER_STOP_PAR_CONJUNCTION sz_par_conj_dyn_id (do dyn_id <- getE return (MerEndParConjunction dyn_id)) ), (FixedSizeParser EVENT_MER_STOP_PAR_CONJUNCT sz_par_conj_dyn_id (do dyn_id <- getE return (MerEndParConjunct dyn_id)) ), (FixedSizeParser EVENT_MER_CREATE_SPARK (sz_par_conj_dyn_id + sz_spark_id) (do dyn_id <- getE spark_id <- getE return (MerCreateSpark dyn_id spark_id)) ), (FixedSizeParser EVENT_MER_FUT_CREATE (sz_future_id + sz_string_id) (do future_id <- getE name_id <- getE return (MerFutureCreate future_id name_id)) ), (FixedSizeParser EVENT_MER_FUT_WAIT_NOSUSPEND (sz_future_id) (do future_id <- getE return (MerFutureWaitNosuspend future_id)) ), (FixedSizeParser EVENT_MER_FUT_WAIT_SUSPENDED (sz_future_id) (do future_id <- getE return (MerFutureWaitSuspended future_id)) ), (FixedSizeParser EVENT_MER_FUT_SIGNAL (sz_future_id) (do future_id <- getE return (MerFutureSignal future_id)) ), (simpleEvent EVENT_MER_LOOKING_FOR_GLOBAL_CONTEXT MerLookingForGlobalThread), (simpleEvent EVENT_MER_WORK_STEALING MerWorkStealing), (simpleEvent EVENT_MER_LOOKING_FOR_LOCAL_SPARK MerLookingForLocalSpark), (FixedSizeParser EVENT_MER_RELEASE_CONTEXT sz_tid (do thread_id <- getE return (MerReleaseThread thread_id)) ), (simpleEvent EVENT_MER_ENGINE_SLEEPING MerCapSleeping), (simpleEvent EVENT_MER_CALLING_MAIN MerCallingMain) ] perfParsers = [ (VariableSizeParser EVENT_PERF_NAME (do -- (perf_num, name) num <- getE :: GetEvents Word16 perfNum <- getE name <- getString (num - sz_perf_num) return PerfName{perfNum, name} )), (FixedSizeParser EVENT_PERF_COUNTER (sz_perf_num + sz_kernel_tid + 8) (do -- (perf_num, tid, period) perfNum <- getE tid <- getE period <- getE return PerfCounter{perfNum, tid, period} )), (FixedSizeParser EVENT_PERF_TRACEPOINT (sz_perf_num + sz_kernel_tid) (do -- (perf_num, tid) perfNum <- getE tid <- getE return PerfTracepoint{perfNum, tid} )) ] getData :: GetEvents Data getData = do db <- getE :: GetEvents Marker when (db /= EVENT_DATA_BEGIN) $ throwError "Data begin marker not found" eparsers <- ask let getEvents :: [Event] -> GetEvents Data getEvents events = do mb_e <- getEvent eparsers case mb_e of Nothing -> return (Data (reverse events)) Just e -> getEvents (e:events) -- in getEvents [] getEventBlock :: EventParsers -> GetEvents [Event] getEventBlock parsers = do b <- lift . lift $ isEmpty if b then return [] else do mb_e <- getEvent parsers case mb_e of Nothing -> return [] Just e -> do es <- getEventBlock parsers return (e:es) getEventLog :: ExceptT String Get EventLog getEventLog = do header <- getHeader let imap = M.fromList [ (fromIntegral (num t),t) | t <- eventTypes header] -- This test is complete, no-one has extended this event yet and all future -- extensions will use newly allocated event IDs. is_ghc_6 = Just sz_old_tid == do create_et <- M.lookup EVENT_CREATE_THREAD imap size create_et {- -- GHC6 writes an invalid header, we handle it here by using a -- different set of event parsers. Note that the ghc7 event parsers -- are standard events, and can be used by other runtime systems that -- make use of threadscope. -} -- GHC-7.8.2 uses a different thread block status encoding, -- and therefore requires a different parser for the stop -- event. Later, in GHC-7.8.3, the old encoding was restored. -- GHC-7.8.2 can be recognised by presence and absence of -- events in the header: -- * User markers were added in GHC-7.8 -- * an empty event HACK_BUG_T9003 was added in GHC-7.8.3 -- This fix breaks software which uses ghc-events and combines -- user markers with the older stop status encoding. We don't -- know of any such software, though. is_pre77 = M.notMember EVENT_USER_MARKER imap is_ghc782 = M.member EVENT_USER_MARKER imap && M.notMember EVENT_HACK_BUG_T9003 imap stopParsers = if is_pre77 then pre77StopParsers else if is_ghc782 then [ghc782StopParser] else [post782StopParser] event_parsers = if is_ghc_6 then standardParsers ++ ghc6Parsers ++ parRTSParsers sz_old_tid else standardParsers ++ ghc7Parsers ++ stopParsers ++ parRTSParsers sz_tid ++ mercuryParsers ++ perfParsers parsers = mkEventTypeParsers imap event_parsers dat <- runReaderT getData (EventParsers parsers) return (EventLog header dat) readEventLogFromFile :: FilePath -> IO (Either String EventLog) readEventLogFromFile f = do s <- L.readFile f return $ runGet (do v <- runExceptT getEventLog m <- isEmpty m `seq` return v) s -- ----------------------------------------------------------------------------- -- Utilities sortEvents :: [Event] -> [CapEvent] sortEvents = sortGroups . groupEvents -- | Sort the raw event stream by time, annotating each event with the -- capability that generated it. sortGroups :: [(Maybe Int, [Event])] -> [CapEvent] sortGroups groups = mergesort' (compare `on` (time . ce_event)) $ [ [ CapEvent cap e | e <- es ] | (cap, es) <- groups ] -- sorting is made much faster by the way that the event stream is -- divided into blocks of events. -- - All events in a block belong to a particular capability -- - The events in a block are ordered by time -- - blocks for the same capability appear in time order in the event -- stream and do not overlap. -- -- So to sort the events we make one list of events for each -- capability (basically just concat . filter), and then -- merge the resulting lists. groupEvents :: [Event] -> [(Maybe Int, [Event])] groupEvents es = (Nothing, n_events) : [ (Just (cap (head blocks)), concatMap block_events blocks) | blocks <- groups ] where (blocks, anon_events) = partitionEithers (map separate es) where separate e | b@EventBlock{} <- spec e = Left b | otherwise = Right e (cap_blocks, gbl_blocks) = partition (is_cap . cap) blocks where is_cap c = fromIntegral c /= ((-1) :: Word16) groups = groupBy ((==) `on` cap) $ sortBy (compare `on` cap) cap_blocks -- There are two sources of events without a capability: events -- in the raw stream not inside an EventBlock, and EventBlocks -- with cap == -1. We have to merge those two streams. -- In light of merged logs, global blocks may have overlapping -- time spans, thus the blocks are mergesorted n_events = mergesort' (compare `on` time) (anon_events : map block_events gbl_blocks) mergesort' :: (a -> a -> Ordering) -> [[a]] -> [a] mergesort' _ [] = [] mergesort' _ [xs] = xs mergesort' cmp xss = mergesort' cmp (merge_pairs cmp xss) merge_pairs :: (a -> a -> Ordering) -> [[a]] -> [[a]] merge_pairs _ [] = [] merge_pairs _ [xs] = [xs] merge_pairs cmp (xs:ys:xss) = merge cmp xs ys : merge_pairs cmp xss merge :: (a -> a -> Ordering) -> [a] -> [a] -> [a] merge _ [] ys = ys merge _ xs [] = xs merge cmp (x:xs) (y:ys) = case x `cmp` y of GT -> y : merge cmp (x:xs) ys _ -> x : merge cmp xs (y:ys) buildEventTypeMap :: [EventType] -> IntMap EventType buildEventTypeMap etypes = M.fromList [ (fromIntegral (num t),t) | t <- etypes ] ----------------------------------------------------------------------------- -- Some pretty-printing support showEventInfo :: EventInfo -> String showEventInfo spec = case spec of EventBlock end_time cap _block_events -> printf "event block: cap %d, end time: %d\n" cap end_time Startup n_caps -> printf "startup: %d capabilities" n_caps CreateThread thread -> printf "creating thread %d" thread RunThread thread -> printf "running thread %d" thread StopThread thread status -> printf "stopping thread %d (%s)" thread (showThreadStopStatus status) ThreadRunnable thread -> printf "thread %d is runnable" thread MigrateThread thread newCap -> printf "migrating thread %d to cap %d" thread newCap CreateSparkThread sparkThread -> printf "creating spark thread %d" sparkThread SparkCounters crt dud ovf cnv fiz gcd rem -> printf "spark stats: %d created, %d converted, %d remaining (%d overflowed, %d dud, %d GC'd, %d fizzled)" crt cnv rem ovf dud gcd fiz SparkCreate -> printf "spark created" SparkDud -> printf "dud spark discarded" SparkOverflow -> printf "overflowed spark discarded" SparkRun -> printf "running a local spark" SparkSteal victimCap -> printf "stealing a spark from cap %d" victimCap SparkFizzle -> printf "spark fizzled" SparkGC -> printf "spark GCed" TaskCreate taskId cap tid -> printf "task 0x%x created on cap %d with OS kernel thread %d" taskId cap (kernelThreadId tid) TaskMigrate taskId cap new_cap -> printf "task 0x%x migrated from cap %d to cap %d" taskId cap new_cap TaskDelete taskId -> printf "task 0x%x deleted" taskId Shutdown -> printf "shutting down" WakeupThread thread otherCap -> printf "waking up thread %d on cap %d" thread otherCap ThreadLabel thread label -> printf "thread %d has label \"%s\"" thread label RequestSeqGC -> printf "requesting sequential GC" RequestParGC -> printf "requesting parallel GC" StartGC -> printf "starting GC" EndGC -> printf "finished GC" GCWork -> printf "GC working" GCIdle -> printf "GC idle" GCDone -> printf "GC done" GlobalSyncGC -> printf "all caps stopped for GC" GCStatsGHC{..} -> printf "GC stats for heap capset %d: generation %d, %d bytes copied, %d bytes slop, %d bytes fragmentation, %d par threads, %d bytes max par copied, %d bytes total par copied" heapCapset gen copied slop frag parNThreads parMaxCopied parTotCopied HeapAllocated{..} -> printf "allocated on heap capset %d: %d total bytes till now" heapCapset allocBytes HeapSize{..} -> printf "size of heap capset %d: %d bytes" heapCapset sizeBytes HeapLive{..} -> printf "live data in heap capset %d: %d bytes" heapCapset liveBytes HeapInfoGHC{..} -> printf "heap stats for heap capset %d: generations %d, %d bytes max heap size, %d bytes alloc area size, %d bytes mblock size, %d bytes block size" heapCapset gens maxHeapSize allocAreaSize mblockSize blockSize CapCreate{cap} -> printf "created cap %d" cap CapDelete{cap} -> printf "deleted cap %d" cap CapDisable{cap} -> printf "disabled cap %d" cap CapEnable{cap} -> printf "enabled cap %d" cap Message msg -> msg UserMessage msg -> msg UserMarker markername -> printf "marker: %s" markername CapsetCreate cs ct -> printf "created capset %d of type %s" cs (show ct) CapsetDelete cs -> printf "deleted capset %d" cs CapsetAssignCap cs cp -> printf "assigned cap %d to capset %d" cp cs CapsetRemoveCap cs cp -> printf "removed cap %d from capset %d" cp cs OsProcessPid cs pid -> printf "capset %d: pid %d" cs pid OsProcessParentPid cs ppid -> printf "capset %d: parent pid %d" cs ppid WallClockTime cs sec nsec -> printf "capset %d: wall clock time %ds %dns (unix epoch)" cs sec nsec RtsIdentifier cs i -> printf "capset %d: RTS version \"%s\"" cs i ProgramArgs cs args -> printf "capset %d: args: %s" cs (show args) ProgramEnv cs env -> printf "capset %d: env: %s" cs (show env) UnknownEvent n -> printf "Unknown event type %d" n InternString str sId -> printf "Interned string: \"%s\" with id %d" str sId -- events for the parallel RTS Version version -> printf "compiler version is %s" version ProgramInvocation commandline -> printf "program invocation: %s" commandline EdenStartReceive -> printf "starting to receive" EdenEndReceive -> printf "stop receiving" CreateProcess process -> printf "creating process %d" process KillProcess process -> printf "killing process %d" process AssignThreadToProcess thread process -> printf "assigning thread %d to process %d" thread process CreateMachine machine realtime -> printf "creating machine %d at %d" machine realtime KillMachine machine -> printf "killing machine %d" machine SendMessage mesTag senderProcess senderThread receiverMachine receiverProcess receiverInport -> printf "sending message with tag %s from process %d, thread %d to machine %d, process %d on inport %d" (show mesTag) senderProcess senderThread receiverMachine receiverProcess receiverInport ReceiveMessage mesTag receiverProcess receiverInport senderMachine senderProcess senderThread messageSize -> printf "receiving message with tag %s at process %d, inport %d from machine %d, process %d, thread %d with size %d" (show mesTag) receiverProcess receiverInport senderMachine senderProcess senderThread messageSize SendReceiveLocalMessage mesTag senderProcess senderThread receiverProcess receiverInport -> printf "sending/receiving message with tag %s from process %d, thread %d to process %d on inport %d" (show mesTag) senderProcess senderThread receiverProcess receiverInport MerStartParConjunction dyn_id static_id -> printf "Start a parallel conjunction 0x%x, static_id: %d" dyn_id static_id MerEndParConjunction dyn_id -> printf "End par conjunction: 0x%x" dyn_id MerEndParConjunct dyn_id -> printf "End par conjunct: 0x%x" dyn_id MerCreateSpark dyn_id spark_id -> printf "Create spark for conjunction: 0x%x spark: 0x%x" dyn_id spark_id MerFutureCreate future_id name_id -> printf "Create future 0x%x named %d" future_id name_id MerFutureWaitNosuspend future_id -> printf "Wait didn't suspend for future: 0x%x" future_id MerFutureWaitSuspended future_id -> printf "Wait suspended on future: 0x%x" future_id MerFutureSignal future_id -> printf "Signaled future 0x%x" future_id MerLookingForGlobalThread -> "Looking for global thread to resume" MerWorkStealing -> "Trying to steal a spark" MerLookingForLocalSpark -> "Looking for a local spark to execute" MerReleaseThread thread_id -> printf "Releasing thread %d to the free pool" thread_id MerCapSleeping -> "Capability going to sleep" MerCallingMain -> "About to call the program entry point" PerfName{perfNum, name} -> printf "perf event %d named \"%s\"" perfNum name PerfCounter{perfNum, tid, period} -> printf "perf event counter %d incremented by %d in OS thread %d" perfNum (period + 1) (kernelThreadId tid) PerfTracepoint{perfNum, tid} -> printf "perf event tracepoint %d reached in OS thread %d" perfNum (kernelThreadId tid) showThreadStopStatus :: ThreadStopStatus -> String showThreadStopStatus HeapOverflow = "heap overflow" showThreadStopStatus StackOverflow = "stack overflow" showThreadStopStatus ThreadYielding = "thread yielding" showThreadStopStatus ThreadBlocked = "thread blocked" showThreadStopStatus ThreadFinished = "thread finished" showThreadStopStatus ForeignCall = "making a foreign call" showThreadStopStatus BlockedOnMVar = "blocked on an MVar" showThreadStopStatus BlockedOnMVarRead = "blocked reading an MVar" showThreadStopStatus BlockedOnBlackHole = "blocked on a black hole" showThreadStopStatus BlockedOnRead = "blocked on I/O read" showThreadStopStatus BlockedOnWrite = "blocked on I/O write" showThreadStopStatus BlockedOnDelay = "blocked on threadDelay" showThreadStopStatus BlockedOnSTM = "blocked in STM retry" showThreadStopStatus BlockedOnDoProc = "blocked on asyncDoProc" showThreadStopStatus BlockedOnCCall = "blocked in a foreign call" showThreadStopStatus BlockedOnCCall_NoUnblockExc = "blocked in a foreign call" showThreadStopStatus BlockedOnMsgThrowTo = "blocked in throwTo" showThreadStopStatus ThreadMigrating = "thread migrating" showThreadStopStatus BlockedOnMsgGlobalise = "waiting for data to be globalised" showThreadStopStatus (BlockedOnBlackHoleOwnedBy target) = "blocked on black hole owned by thread " ++ show target showThreadStopStatus NoStatus = "No stop thread status" ppEventLog :: EventLog -> String ppEventLog (EventLog (Header ets) (Data es)) = unlines $ concat ( [ ["Event Types:"] , map ppEventType ets , [""] -- newline , ["Events:"] , map (ppEvent imap) sorted , [""] ]) -- extra trailing newline where imap = buildEventTypeMap ets sorted = sortEvents es ppEventType :: EventType -> String ppEventType (EventType num dsc msz) = printf "%4d: %s (size %s)" num dsc (case msz of Nothing -> "variable"; Just x -> show x) ppEvent :: IntMap EventType -> CapEvent -> String ppEvent imap (CapEvent cap (Event time spec)) = printf "%9d: " time ++ (case cap of Nothing -> "" Just c -> printf "cap %d: " c) ++ case spec of UnknownEvent{ ref=ref } -> printf (desc (fromJust (M.lookup (fromIntegral ref) imap))) other -> showEventInfo spec type PutEvents a = PutM a putE :: Binary a => a -> PutEvents () putE = put runPutEBS :: PutEvents () -> L.ByteString runPutEBS = runPut writeEventLogToFile f el = L.writeFile f $ runPutEBS $ putEventLog el putType :: EventTypeNum -> PutEvents () putType = putE putCap :: Int -> PutEvents () putCap c = putE (fromIntegral c :: CapNo) putMarker :: Word32 -> PutEvents () putMarker = putE putEStr :: String -> PutEvents () putEStr = mapM_ putE putEventLog :: EventLog -> PutEvents () putEventLog (EventLog hdr es) = do putHeader hdr putData es putHeader :: Header -> PutEvents () putHeader (Header ets) = do putMarker EVENT_HEADER_BEGIN putMarker EVENT_HET_BEGIN mapM_ putEventType ets putMarker EVENT_HET_END putMarker EVENT_HEADER_END where putEventType (EventType n d msz) = do putMarker EVENT_ET_BEGIN putType n putE $ fromMaybe 0xffff msz putE (fromIntegral $ length d :: EventTypeDescLen) mapM_ put d -- the event type header allows for extra data, which we don't use: putE (0 :: Word32) putMarker EVENT_ET_END putData :: Data -> PutEvents () putData (Data es) = do putMarker EVENT_DATA_BEGIN -- Word32 mapM_ putEvent es putType EVENT_DATA_END -- Word16 eventTypeNum :: EventInfo -> EventTypeNum eventTypeNum e = case e of CreateThread {} -> EVENT_CREATE_THREAD RunThread {} -> EVENT_RUN_THREAD StopThread {} -> EVENT_STOP_THREAD ThreadRunnable {} -> EVENT_THREAD_RUNNABLE MigrateThread {} -> EVENT_MIGRATE_THREAD Shutdown {} -> EVENT_SHUTDOWN WakeupThread {} -> EVENT_THREAD_WAKEUP ThreadLabel {} -> EVENT_THREAD_LABEL StartGC {} -> EVENT_GC_START EndGC {} -> EVENT_GC_END GlobalSyncGC {} -> EVENT_GC_GLOBAL_SYNC RequestSeqGC {} -> EVENT_REQUEST_SEQ_GC RequestParGC {} -> EVENT_REQUEST_PAR_GC CreateSparkThread {} -> EVENT_CREATE_SPARK_THREAD SparkCounters {} -> EVENT_SPARK_COUNTERS SparkCreate {} -> EVENT_SPARK_CREATE SparkDud {} -> EVENT_SPARK_DUD SparkOverflow {} -> EVENT_SPARK_OVERFLOW SparkRun {} -> EVENT_SPARK_RUN SparkSteal {} -> EVENT_SPARK_STEAL SparkFizzle {} -> EVENT_SPARK_FIZZLE SparkGC {} -> EVENT_SPARK_GC TaskCreate {} -> EVENT_TASK_CREATE TaskMigrate {} -> EVENT_TASK_MIGRATE TaskDelete {} -> EVENT_TASK_DELETE Message {} -> EVENT_LOG_MSG Startup {} -> EVENT_STARTUP EventBlock {} -> EVENT_BLOCK_MARKER UserMessage {} -> EVENT_USER_MSG UserMarker {} -> EVENT_USER_MARKER GCIdle {} -> EVENT_GC_IDLE GCWork {} -> EVENT_GC_WORK GCDone {} -> EVENT_GC_DONE GCStatsGHC{} -> EVENT_GC_STATS_GHC HeapAllocated{} -> EVENT_HEAP_ALLOCATED HeapSize{} -> EVENT_HEAP_SIZE HeapLive{} -> EVENT_HEAP_LIVE HeapInfoGHC{} -> EVENT_HEAP_INFO_GHC CapCreate{} -> EVENT_CAP_CREATE CapDelete{} -> EVENT_CAP_DELETE CapDisable{} -> EVENT_CAP_DISABLE CapEnable{} -> EVENT_CAP_ENABLE CapsetCreate {} -> EVENT_CAPSET_CREATE CapsetDelete {} -> EVENT_CAPSET_DELETE CapsetAssignCap {} -> EVENT_CAPSET_ASSIGN_CAP CapsetRemoveCap {} -> EVENT_CAPSET_REMOVE_CAP RtsIdentifier {} -> EVENT_RTS_IDENTIFIER ProgramArgs {} -> EVENT_PROGRAM_ARGS ProgramEnv {} -> EVENT_PROGRAM_ENV OsProcessPid {} -> EVENT_OSPROCESS_PID OsProcessParentPid{} -> EVENT_OSPROCESS_PPID WallClockTime{} -> EVENT_WALL_CLOCK_TIME UnknownEvent {} -> error "eventTypeNum UnknownEvent" InternString {} -> EVENT_INTERN_STRING Version {} -> EVENT_VERSION ProgramInvocation {} -> EVENT_PROGRAM_INVOCATION EdenStartReceive {} -> EVENT_EDEN_START_RECEIVE EdenEndReceive {} -> EVENT_EDEN_END_RECEIVE CreateProcess {} -> EVENT_CREATE_PROCESS KillProcess {} -> EVENT_KILL_PROCESS AssignThreadToProcess {} -> EVENT_ASSIGN_THREAD_TO_PROCESS CreateMachine {} -> EVENT_CREATE_MACHINE KillMachine {} -> EVENT_KILL_MACHINE SendMessage {} -> EVENT_SEND_MESSAGE ReceiveMessage {} -> EVENT_RECEIVE_MESSAGE SendReceiveLocalMessage {} -> EVENT_SEND_RECEIVE_LOCAL_MESSAGE MerStartParConjunction {} -> EVENT_MER_START_PAR_CONJUNCTION MerEndParConjunction _ -> EVENT_MER_STOP_PAR_CONJUNCTION MerEndParConjunct _ -> EVENT_MER_STOP_PAR_CONJUNCT MerCreateSpark {} -> EVENT_MER_CREATE_SPARK MerFutureCreate {} -> EVENT_MER_FUT_CREATE MerFutureWaitNosuspend _ -> EVENT_MER_FUT_WAIT_NOSUSPEND MerFutureWaitSuspended _ -> EVENT_MER_FUT_WAIT_SUSPENDED MerFutureSignal _ -> EVENT_MER_FUT_SIGNAL MerLookingForGlobalThread -> EVENT_MER_LOOKING_FOR_GLOBAL_CONTEXT MerWorkStealing -> EVENT_MER_WORK_STEALING MerLookingForLocalSpark -> EVENT_MER_LOOKING_FOR_LOCAL_SPARK MerReleaseThread _ -> EVENT_MER_RELEASE_CONTEXT MerCapSleeping -> EVENT_MER_ENGINE_SLEEPING MerCallingMain -> EVENT_MER_CALLING_MAIN PerfName {} -> nEVENT_PERF_NAME PerfCounter {} -> nEVENT_PERF_COUNTER PerfTracepoint {} -> nEVENT_PERF_TRACEPOINT nEVENT_PERF_NAME, nEVENT_PERF_COUNTER, nEVENT_PERF_TRACEPOINT :: EventTypeNum nEVENT_PERF_NAME = EVENT_PERF_NAME nEVENT_PERF_COUNTER = EVENT_PERF_COUNTER nEVENT_PERF_TRACEPOINT = EVENT_PERF_TRACEPOINT putEvent :: Event -> PutEvents () putEvent (Event t spec) = do putType (eventTypeNum spec) put t putEventSpec spec putEventSpec (Startup caps) = do putCap (fromIntegral caps) putEventSpec (EventBlock end cap es) = do let block = runPutEBS (mapM_ putEvent es) put (fromIntegral (L.length block) + 24 :: Word32) putE end putE (fromIntegral cap :: CapNo) putLazyByteString block putEventSpec (CreateThread t) = do putE t putEventSpec (RunThread t) = do putE t -- here we assume that ThreadStopStatus fromEnum matches the definitions in -- EventLogFormat.h -- The standard encoding is used here, which is wrong for eventlogs -- produced by GHC-7.8.2 ([Stop status in GHC-7.8.2] in EventTypes.hs putEventSpec (StopThread t s) = do putE t putE $ case s of NoStatus -> 0 :: Word16 HeapOverflow -> 1 StackOverflow -> 2 ThreadYielding -> 3 ThreadBlocked -> 4 ThreadFinished -> 5 ForeignCall -> 6 BlockedOnMVar -> 7 BlockedOnMVarRead -> 20 -- since GHC-7.8.3 BlockedOnBlackHole -> 8 BlockedOnBlackHoleOwnedBy _ -> 8 BlockedOnRead -> 9 BlockedOnWrite -> 10 BlockedOnDelay -> 11 BlockedOnSTM -> 12 BlockedOnDoProc -> 13 BlockedOnCCall -> 14 BlockedOnCCall_NoUnblockExc -> 15 BlockedOnMsgThrowTo -> 16 ThreadMigrating -> 17 BlockedOnMsgGlobalise -> 18 putE $ case s of BlockedOnBlackHoleOwnedBy i -> i _ -> 0 putEventSpec (ThreadRunnable t) = do putE t putEventSpec (MigrateThread t c) = do putE t putCap c putEventSpec (CreateSparkThread t) = do putE t putEventSpec (SparkCounters crt dud ovf cnv fiz gcd rem) = do putE crt putE dud putE ovf putE cnv -- Warning: order of fiz and gcd reversed! putE gcd putE fiz putE rem putEventSpec SparkCreate = do return () putEventSpec SparkDud = do return () putEventSpec SparkOverflow = do return () putEventSpec SparkRun = do return () putEventSpec (SparkSteal c) = do putCap c putEventSpec SparkFizzle = do return () putEventSpec SparkGC = do return () putEventSpec (WakeupThread t c) = do putE t putCap c putEventSpec (ThreadLabel t l) = do putE (fromIntegral (length l) + sz_tid :: Word16) putE t putEStr l putEventSpec Shutdown = do return () putEventSpec RequestSeqGC = do return () putEventSpec RequestParGC = do return () putEventSpec StartGC = do return () putEventSpec GCWork = do return () putEventSpec GCIdle = do return () putEventSpec GCDone = do return () putEventSpec EndGC = do return () putEventSpec GlobalSyncGC = do return () putEventSpec (TaskCreate taskId cap tid) = do putE taskId putCap cap putE tid putEventSpec (TaskMigrate taskId cap new_cap) = do putE taskId putCap cap putCap new_cap putEventSpec (TaskDelete taskId) = do putE taskId putEventSpec GCStatsGHC{..} = do putE heapCapset putE (fromIntegral gen :: Word16) putE copied putE slop putE frag putE (fromIntegral parNThreads :: Word32) putE parMaxCopied putE parTotCopied putEventSpec HeapAllocated{..} = do putE heapCapset putE allocBytes putEventSpec HeapSize{..} = do putE heapCapset putE sizeBytes putEventSpec HeapLive{..} = do putE heapCapset putE liveBytes putEventSpec HeapInfoGHC{..} = do putE heapCapset putE (fromIntegral gens :: Word16) putE maxHeapSize putE allocAreaSize putE mblockSize putE blockSize putEventSpec CapCreate{cap} = do putCap cap putEventSpec CapDelete{cap} = do putCap cap putEventSpec CapDisable{cap} = do putCap cap putEventSpec CapEnable{cap} = do putCap cap putEventSpec (CapsetCreate cs ct) = do putE cs putE $ case ct of CapsetCustom -> 1 :: Word16 CapsetOsProcess -> 2 CapsetClockDomain -> 3 CapsetUnknown -> 0 putEventSpec (CapsetDelete cs) = do putE cs putEventSpec (CapsetAssignCap cs cp) = do putE cs putCap cp putEventSpec (CapsetRemoveCap cs cp) = do putE cs putCap cp putEventSpec (RtsIdentifier cs rts) = do putE (fromIntegral (length rts) + sz_capset :: Word16) putE cs putEStr rts putEventSpec (ProgramArgs cs as) = do let as' = unsep as putE (fromIntegral (length as') + sz_capset :: Word16) putE cs mapM_ putE as' putEventSpec (ProgramEnv cs es) = do let es' = unsep es putE (fromIntegral (length es') + sz_capset :: Word16) putE cs mapM_ putE es' putEventSpec (OsProcessPid cs pid) = do putE cs putE pid putEventSpec (OsProcessParentPid cs ppid) = do putE cs putE ppid putEventSpec (WallClockTime cs sec nsec) = do putE cs putE sec putE nsec putEventSpec (Message s) = do putE (fromIntegral (length s) :: Word16) mapM_ putE s putEventSpec (UserMessage s) = do putE (fromIntegral (length s) :: Word16) mapM_ putE s putEventSpec (UserMarker s) = do putE (fromIntegral (length s) :: Word16) mapM_ putE s putEventSpec (UnknownEvent {}) = error "putEventSpec UnknownEvent" putEventSpec (InternString str id) = do putE len mapM_ putE str putE id where len = (fromIntegral (length str) :: Word16) + sz_string_id putEventSpec (Version s) = do putE (fromIntegral (length s) :: Word16) mapM_ putE s putEventSpec (ProgramInvocation s) = do putE (fromIntegral (length s) :: Word16) mapM_ putE s putEventSpec ( EdenStartReceive ) = return () putEventSpec ( EdenEndReceive ) = return () putEventSpec ( CreateProcess process ) = do putE process putEventSpec ( KillProcess process ) = do putE process putEventSpec ( AssignThreadToProcess thread process ) = do putE thread putE process putEventSpec ( CreateMachine machine realtime ) = do putE machine putE realtime putEventSpec ( KillMachine machine ) = do putE machine putEventSpec ( SendMessage mesTag senderProcess senderThread receiverMachine receiverProcess receiverInport ) = do putE (fromMsgTag mesTag) putE senderProcess putE senderThread putE receiverMachine putE receiverProcess putE receiverInport putEventSpec ( ReceiveMessage mesTag receiverProcess receiverInport senderMachine senderProcess senderThread messageSize ) = do putE (fromMsgTag mesTag) putE receiverProcess putE receiverInport putE senderMachine putE senderProcess putE senderThread putE messageSize putEventSpec ( SendReceiveLocalMessage mesTag senderProcess senderThread receiverProcess receiverInport ) = do putE (fromMsgTag mesTag) putE senderProcess putE senderThread putE receiverProcess putE receiverInport putEventSpec (MerStartParConjunction dyn_id static_id) = do putE dyn_id putE static_id putEventSpec (MerEndParConjunction dyn_id) = do putE dyn_id putEventSpec (MerEndParConjunct dyn_id) = do putE dyn_id putEventSpec (MerCreateSpark dyn_id spark_id) = do putE dyn_id putE spark_id putEventSpec (MerFutureCreate future_id name_id) = do putE future_id putE name_id putEventSpec (MerFutureWaitNosuspend future_id) = do putE future_id putEventSpec (MerFutureWaitSuspended future_id) = do putE future_id putEventSpec (MerFutureSignal future_id) = do putE future_id putEventSpec MerLookingForGlobalThread = return () putEventSpec MerWorkStealing = return () putEventSpec MerLookingForLocalSpark = return () putEventSpec (MerReleaseThread thread_id) = do putE thread_id putEventSpec MerCapSleeping = return () putEventSpec MerCallingMain = return () putEventSpec PerfName{..} = do putE (fromIntegral (length name) + sz_perf_num :: Word16) putE perfNum mapM_ putE name putEventSpec PerfCounter{..} = do putE perfNum putE tid putE period putEventSpec PerfTracepoint{..} = do putE perfNum putE tid -- [] == [] -- [x] == x\0 -- [x, y, z] == x\0y\0 unsep :: [String] -> String unsep = concatMap (++"\0") -- not the most efficient, but should be ok splitNull :: String -> [String] splitNull [] = [] splitNull xs = case span (/= '\0') xs of (x, xs') -> x : splitNull (drop 1 xs') ghc-events-0.4.4.0/GHC/RTS/Events/0000755000000000000000000000000012520426612014423 5ustar0000000000000000ghc-events-0.4.4.0/GHC/RTS/Events/Analysis.hs0000644000000000000000000002427712520426612016556 0ustar0000000000000000module GHC.RTS.Events.Analysis ( Machine (..) , validate , validates , simulate , Profile (..) , profile , profileIndexed , profileRouted , extractIndexed , refineM , profileM , indexM , toList , toMaybe , Process (..) , routeM ) where import GHC.RTS.Events import Data.Map (Map) import qualified Data.Map as M import Data.Maybe (fromMaybe, catMaybes) import Data.Either (rights) -------------------------------------------------------------------------------- -- | This is based on a simple finite state machine hence the names `delta` -- for the state transition function. -- Since states might be more than simple pattern matched constructors, we -- use `finals :: state -> Bool`, rather than `Set state`, to indicate that -- the machine is in some final state. Similarly for `alpha`, which -- indicates the alphabet of inputs to a machine. -- The function `delta` returns `Maybe` values, where `Nothing` -- indicates that no valid transition is possible: ie, there has been an -- error. data Machine s i = Machine { initial :: s -- ^ Initial state , final :: s -> Bool -- ^ Valid final states , alpha :: i -> Bool -- ^ Valid input alphabet , delta :: s -> i -> Maybe s -- ^ State transition function } -- | This machine always accepts, never terminates, and always has unit state. unitMachine :: Machine () i unitMachine = Machine { initial = () , final = const False , alpha = const True , delta = (\s i -> Just ()) } -- | The `step` function runs a machine in a state against a single input. -- The state remains fixed once a final state is encountered. The -- result is `Left state input` if some `state` failed for an `ìnput`, and -- `Right state` for a successful state. step :: Machine s i -> s -> i -> Either (s, i) s step m s i | final m s = Right s | alpha m i = case delta m s i of Just s' -> Right s' Nothing -> Left (s, i) | otherwise = Right s -- | The `validate` function takes a machine and a list of inputs. The machine -- is started from its initial state and run against the inputs in turn. -- It returns the state and input on failure, and just the state on success. validate :: Machine s i -> [i] -> Either (s, i) s validate m = foldl (>>=) (Right (initial m)) . map (flip (step m)) -- | This function is similar to `validate`, but outputs each intermediary -- state as well. For an incremental version, use `simulate`. validates :: Machine s i -> [i] -> [Either (s, i) s] validates m = scanl (>>=) (Right (initial m)) . map (flip (step m)) -------------------------------------------------------------------------------- -- A Process is a list of successful values, followed by an error if one -- occured. This captures the idea that a computation may produce a list of -- elements before possibly failing. This gives us an incremental interface -- to data processed from machine transitions. data Process e a = Done | Fail e | Prod a (Process e a) deriving Show toList :: Process e a -> [a] toList (Fail _) = [] toList Done = [] toList (Prod a as) = a : toList as toMaybe :: Process e a -> Maybe e toMaybe (Fail e) = Just e toMaybe Done = Nothing toMaybe (Prod _ as) = toMaybe as -- | A machine can be analysed while it is accepting input in order to extract -- some information. This function takes a machine and a function that extracts -- data and produces output. On failure, the machine state and input are -- produced. Note that when an input is not in the machine's alphabet, -- then there is no transition, and so no output is produced in response -- to that input. analyse :: Machine s i -- ^ The machine used -> (s -> i -> Maybe o) -- ^ An extraction function that may produce output -> [i] -- ^ A list of input -> Process (s, i) o -- ^ A process that produces output analyse machine extract is = go (initial machine) is where -- go :: s -> [i] -> Process (s, i) o go _ [] = Done go s (i:is) | final machine s = Done | alpha machine i = case delta machine s i of Nothing -> Fail (s, i) Just s' -> case extract s i of Nothing -> go s' is Just o -> Prod o (go s' is) | otherwise = go s is -- | Machines sometimes need to operate on coarser input than they are defined -- for. This function takes a function that refines input and a machine that -- works on refined input, and produces a machine that can work on coarse input. refineM :: (i -> j) -> Machine s j -> Machine s i refineM refine machine = Machine { initial = initial machine , final = final machine , alpha = alpha machine . refine , delta = \s -> delta machine s . refine } -------------------------------------------------------------------------------- -- | This function produces a process that outputs all the states that a -- machine goes through. simulate :: Machine s i -> [i] -> Process (s, i) (s, i) simulate machine = analyse machine (\s i -> delta machine s i >>= \s' -> return (s', i)) -------------------------------------------------------------------------------- -- | A state augmented by Timestamp information is held in `profileState`. -- When the state changes, `profileMap` stores a map between each state -- and its cumulative time. data Profile s = Profile { profileState :: s -- ^ The current state , profileTime :: Timestamp -- ^ The entry time of the state } deriving (Show) -- | This function takes a machine and profiles its state. profileM :: Ord s => (i -> Timestamp) -> Machine s i -> Machine (Profile s) i profileM timer machine = Machine { initial = Profile (initial machine) 0 , final = final machine . profileState , alpha = alpha machine , delta = profileMDelta } where profileMDelta (Profile s _) i = do s' <- delta machine s i return $ Profile s' (timer i) -- | extractProfile returns the state, the time this state was made, -- and the time spent in this state. extractProfile :: (i -> Timestamp) -- ^ Extracts current timestamp -> Profile s -- ^ A profiled state -> i -- ^ Some input -> Maybe (s, Timestamp, Timestamp) -- ^ (state, currentTime, elapsedTime) extractProfile timer p i = Just (profileState p, profileTime p, timer i - profileTime p) profile :: (Ord s, Eq s) => Machine s i -- ^ A machine to profile -> (i -> Timestamp) -- ^ Converts input to timestamps -> [i] -- ^ The list of input -> Process (Profile s, i) (s, Timestamp, Timestamp) profile machine timer = analyse (profileM timer machine) (extractProfile timer) profileIndexed :: (Ord k, Ord s, Eq s) => Machine s i -> (i -> Maybe k) -> (i -> Timestamp) -> [i] -> Process (Map k (Profile s), i) (k, (s, Timestamp, Timestamp)) profileIndexed machine index timer = analyse (indexM index (profileM timer machine)) (extractIndexed (extractProfile timer) index) extractIndexed :: Ord k => (s -> i -> Maybe o) -> (i -> Maybe k) -> (Map k s -> i -> Maybe (k, o)) extractIndexed extract index m i = do k <- index i s <- M.lookup k m o <- extract s i return (k, o) -- | An indexed machine takes a function that multiplexes the input to a key -- and then takes a machine description to an indexed machine. indexM :: Ord k => (i -> Maybe k) -- ^ An indexing function -> Machine s i -- ^ A machine to index with -> Machine (Map k s) i -- ^ The indexed machine indexM index machine = Machine { initial = M.empty , final = indexMFinal , alpha = indexMAlpha , delta = indexMDelta } where -- An indexer never reaches a final state: it is always possible that -- an event comes along that is accepted by a machine that is not -- yet in in the index. -- -- An alternative view is that the indexer is in a final state if all its -- elements are, but this would not allow the creation of new indexes: -- indexMFinal m = not (M.null m) && (all (final machine) . M.elems $ m) indexMFinal = const False -- The alphabet of the indexer is that of its elements. indexMAlpha = alpha machine -- If the index is not yet in the mapping, we start a new machine in its -- initial state. The indexer fails if indexed state fails. indexMDelta m i = do k <- index i let state = fromMaybe (initial machine) (M.lookup k m) state' <- delta machine state i return $ M.insert k state' m profileRouted :: (Ord k, Ord s, Eq s, Eq r) => Machine s i -> Machine r i -> (r -> i -> Maybe k) -> (i -> Timestamp) -> [i] -> Process ((Map k (Profile s), r), i) (k, (s, Timestamp, Timestamp)) profileRouted machine router index timer = analyse (routeM router index (profileM timer machine)) (extractRouted (extractProfile timer) index) extractRouted :: Ord k => (s -> i -> Maybe o) -> (r -> i -> Maybe k) -> ((Map k s, r) -> i -> Maybe (k, o)) extractRouted extract index (m, r) i = do k <- index r i s <- M.lookup k m o <- extract s i return (k, o) -- | A machine can be indexed not only by the inputs, but also by the state -- of an intermediary routing machine. This is a generalisation of indexM. routeM :: (Ord k) => Machine r i -> (r -> i -> Maybe k) -> Machine s i -> Machine (Map k s, r) i routeM router index machine = Machine { initial = (M.empty, initial router) , final = routeMFinal , alpha = routeMAlpha , delta = routeMDelta } where -- As with indexers, there is no final state. routeMFinal = const False -- The alphabet is that of the router combined with the machine routeMAlpha i = alpha router i || alpha machine i routeMDelta (m, r) i = do r' <- if alpha router i then delta router r i else return r m' <- if alpha machine i then case index r' i of Just k -> do s' <- delta machine (fromMaybe (initial machine) (M.lookup k m)) i return $ M.insert k s' m Nothing -> return m else return m return (m', r') ghc-events-0.4.4.0/GHC/RTS/Events/Merge.hs0000644000000000000000000001234012520426612016016 0ustar0000000000000000{-# OPTIONS_GHC -funbox-strict-fields #-} module GHC.RTS.Events.Merge (mergeEventLogs) where import GHC.RTS.Events import Data.Monoid import Data.List (foldl') import qualified Data.Map as M import Data.Word (Word32, Word16) -- TODO: add a merge mode where the events are synchronized using -- the wall clock time event at the start of both eventlogs (for newer GHCs). -- Such merge is not associative so we either need to take many arguments -- or cope with eventlogs with many wall clock time events (assume they -- are products of previous merges). To decide. {- GHC numbers caps and capsets in sequential order, starting at 0. Threads are similarly numbered, but start at 1. In order to merge logs 'x' and 'y', we find the # of occupied numbers for each variable type in 'x', then increment each variable in 'y' by that amount. We assume that if a number is occupied, so are all lower numbers. This guarantees that variables in each log don't clash, and that the meaning of each reference to a thread/cap/capset is preserved. -} mergeEventLogs :: EventLog -> EventLog -> EventLog mergeEventLogs (EventLog h1 (Data xs)) (EventLog h2 (Data ys)) = let headerMap = M.fromList . map (\ et@EventType {num} -> (num, et)) m1 = headerMap $ eventTypes h1 m2 = headerMap $ eventTypes h2 combine et1 et2 | et1 == et2 = et1 combine _ _ = error "can't merge eventlogs with inconsistent headers" m = M.unionWith combine m1 m2 h = Header $ M.elems m in h == h `seq` -- Detect inconsistency ASAP. EventLog h . Data . mergeOn time xs $ shift (maxVars xs) ys mergeOn :: Ord b => (a -> b) -> [a] -> [a] -> [a] mergeOn f [] ys = ys mergeOn f xs [] = xs mergeOn f (x:xs) (y:ys) | f x <= f y = x : mergeOn f xs (y:ys) | otherwise = y : mergeOn f (x:xs) ys -- TODO: rename, since these are not maximal values, but numbers of used values data MaxVars = MaxVars { mcapset :: !Word32 , mcap :: !Int , mthread :: !ThreadId } -- TODO introduce parallel RTS process and machine var.s instance Monoid MaxVars where mempty = MaxVars 0 0 0 mappend (MaxVars a b c) (MaxVars x y z) = MaxVars (max a x) (b + y) (max c z) -- avoid space leaks: mconcat = foldl' mappend mempty -- Capabilities are represented as Word16. An event block marked with the -- capability of 0xffff belongs to no capability isCap :: Int -> Bool isCap x = fromIntegral x /= ((-1) :: Word16) -- For caps we find the maximum value by summing the @Startup@ declarations. -- TODO: it's not trivial to add CapCreate since we don't know -- if created caps are guaranteed to be numbered consecutively or not -- (are they? is it asserted in GHC code somewhere?). We might instead -- just scan all events mentioning a cap and take the maximum, -- but it's a slower and much longer code, requiring constant maintenance. maxVars :: [Event] -> MaxVars maxVars = mconcat . map (maxSpec . spec) where -- only checking binding sites right now, sufficient? maxSpec (Startup n) = mempty { mcap = n } -- Threads start at 1. maxSpec (CreateThread t) = mempty { mthread = t } maxSpec (CreateSparkThread t) = mempty { mthread = t } -- Capsets start at 0. maxSpec (CapsetCreate cs _) = mempty {mcapset = cs + 1 } maxSpec (EventBlock _ _ es) = maxVars es maxSpec _ = mempty sh :: Num a => a -> a -> a sh x y = x + y shift :: MaxVars -> [Event] -> [Event] shift mv@(MaxVars mcs mc mt) = map (\(Event t s) -> Event t $ shift' s) where -- -1 marks a block that isn't attached to a particular capability shift' (EventBlock et c bs) = EventBlock et (msh c) $ shift mv bs where msh x = if isCap x then sh mc x else x shift' (CreateThread t) = CreateThread $ sh mt t shift' (RunThread t) = RunThread $ sh mt t shift' (StopThread t s) = StopThread (sh mt t) s shift' (ThreadRunnable t) = ThreadRunnable $ sh mt t shift' (MigrateThread t c) = MigrateThread (sh mt t) (sh mc c) shift' (WakeupThread t c) = WakeupThread (sh mt t) (sh mc c) shift' (ThreadLabel t l) = ThreadLabel (sh mt t) l shift' (CreateSparkThread t) = CreateSparkThread (sh mt t) shift' (SparkSteal c) = SparkSteal (sh mc c) shift' (TaskCreate tk c tid) = TaskCreate tk (sh mc c) tid shift' (TaskMigrate tk c1 c2) = TaskMigrate tk (sh mc c1) (sh mc c2) shift' (CapCreate c) = CapCreate (sh mc c) -- TODO: correct? shift' (CapDelete c) = CapDelete (sh mc c) -- TODO: correct? shift' (CapDisable c) = CapDisable (sh mc c) shift' (CapEnable c) = CapEnable (sh mc c) shift' (CapsetCreate cs cst) = CapsetCreate (sh mcs cs) cst shift' (CapsetDelete cs) = CapsetDelete (sh mcs cs) shift' (CapsetAssignCap cs c) = CapsetAssignCap (sh mcs cs) (sh mc c) shift' (CapsetRemoveCap cs c) = CapsetRemoveCap (sh mcs cs) (sh mc c) shift' (RtsIdentifier cs rts) = RtsIdentifier (sh mcs cs) rts shift' (ProgramArgs cs as) = ProgramArgs (sh mcs cs) as shift' (ProgramEnv cs es) = ProgramEnv (sh mcs cs) es shift' (OsProcessPid cs pid) = OsProcessPid (sh mcs cs) pid shift' (OsProcessParentPid cs ppid) = OsProcessParentPid (sh mcs cs) ppid shift' (WallClockTime cs sec nsec) = WallClockTime (sh mcs cs) sec nsec shift' x = x -- TODO extend by new shift for Eden events ghc-events-0.4.4.0/GHC/RTS/Events/Analysis/0000755000000000000000000000000012520426612016206 5ustar0000000000000000ghc-events-0.4.4.0/GHC/RTS/Events/Analysis/Thread.hs0000644000000000000000000000337312520426612017757 0ustar0000000000000000module GHC.RTS.Events.Analysis.Thread ( ThreadState (..) , threadMachine ) where import GHC.RTS.Events import GHC.RTS.Events.Analysis -------------------------------------------------------------------------------- -- | This datatype defines the state machine for a single thread. data ThreadState = ThreadInitial | ThreadQueued | ThreadRunning | ThreadStopped | ThreadFinal deriving (Show, Eq, Ord) -- | This state machine tracks the events processed by a thread. threadMachine :: Machine ThreadState EventInfo threadMachine = Machine { initial = ThreadInitial , final = threadFinal , alpha = threadAlpha , delta = threadDelta } where threadFinal ThreadFinal = True threadFinal _ = False threadAlpha (CreateThread _) = True threadAlpha (RunThread _) = True threadAlpha (StopThread _ _) = True threadAlpha (WakeupThread _ _) = True threadAlpha _ = False -- ThreadInitial threadDelta ThreadInitial (CreateThread _) = Just ThreadQueued -- ThreadQueued threadDelta ThreadQueued (RunThread _) = Just ThreadRunning threadDelta ThreadQueued (WakeupThread _ _) = Just ThreadQueued -- ThreadRunning threadDelta ThreadRunning (StopThread _ StackOverflow) = Just ThreadQueued threadDelta ThreadRunning (StopThread _ HeapOverflow) = Just ThreadQueued threadDelta ThreadRunning (StopThread _ ForeignCall) = Just ThreadQueued threadDelta ThreadRunning (StopThread _ ThreadFinished) = Just ThreadFinal threadDelta ThreadRunning (StopThread _ _) = Just ThreadStopped -- ThreadStopped threadDelta ThreadStopped (RunThread _) = Just ThreadRunning threadDelta ThreadStopped (WakeupThread _ _) = Just ThreadQueued -- Unknown threadDelta _ _ = Nothingghc-events-0.4.4.0/GHC/RTS/Events/Analysis/Capability.hs0000644000000000000000000002150012520426612020621 0ustar0000000000000000module GHC.RTS.Events.Analysis.Capability ( capabilityThreadPoolMachine , capabilityThreadRunMachine , capabilityThreadIndexer , capabilityTaskPoolMachine , capabilityTaskOSMachine ) where import GHC.RTS.Events import GHC.RTS.Events.Analysis import Data.Map (Map) import qualified Data.Map as M -- | This state machine tracks threads residing on capabilities. -- Each thread can only reside on one capability, but can be migrated between -- them. capabilityThreadPoolMachine :: Machine (Map ThreadId Int) CapEvent capabilityThreadPoolMachine = Machine { initial = M.empty , final = const False , alpha = capabilityThreadPoolMachineAlpha , delta = capabilityThreadPoolMachineDelta } where capabilityThreadPoolMachineAlpha capEvent = case spec . ce_event $ capEvent of (CreateThread _) -> True (StopThread _ _) -> True (MigrateThread _ _) -> True _ -> False capabilityThreadPoolMachineDelta mapping capEvent = do capId <- ce_cap capEvent case spec . ce_event $ capEvent of (CreateThread threadId) -> insertThread threadId capId mapping (StopThread threadId ThreadFinished) -> deleteThread threadId mapping (StopThread _ _) -> Just mapping (MigrateThread threadId capId') -> deleteThread threadId mapping >>= insertThread threadId capId' _ -> Nothing where insertThread :: ThreadId -> Int -> Map ThreadId Int -> Maybe (Map ThreadId Int) insertThread threadId capId m | threadId `M.member` m = Nothing -- The thread already exists | otherwise = Just $ M.insert threadId capId m deleteThread :: ThreadId -> Map ThreadId Int -> Maybe (Map ThreadId Int) deleteThread threadId m | threadId `M.notMember` m = Nothing -- The thread doesn't exist | otherwise = Just $ M.delete threadId m -- | This state machine tracks threads running on capabilities, only one thread -- may run on a capability at a time. capabilityThreadRunMachine :: Machine (Map Int ThreadId) CapEvent capabilityThreadRunMachine = Machine { initial = M.empty , final = const False , alpha = threadRunAlpha , delta = threadRunDelta } where threadRunAlpha capEvent = case spec . ce_event $ capEvent of -- TODO: can threads be migrated while they are running? -- TODO: take into account paused threads (RunThread _) -> True (StopThread _ _ ) -> True _ -> False -- The indexer fails if a thread is inserted where one already exists, -- or if a thread is deleted that doesn't exist. threadRunDelta mapping e = do capId <- ce_cap e case spec . ce_event $ e of (RunThread threadId) -> runThread capId threadId mapping (StopThread threadId _ ) -> stopThread threadId mapping _ -> Just mapping where runThread :: Int -> ThreadId -> Map Int ThreadId -> Maybe (Map Int ThreadId) runThread capId threadId m | capId `M.member` m = Nothing -- A thread is already on this cap | threadId `elem` M.elems m = Nothing -- This thread is already on a cap | otherwise = Just $ M.insert capId threadId m stopThread :: ThreadId -> Map Int ThreadId -> Maybe (Map Int ThreadId) stopThread threadId m | notElem threadId . M.elems $ m = Nothing -- The thread doesn't exist | otherwise = Just $ M.filter (/= threadId) m capabilityThreadIndexer :: Map Int ThreadId -> CapEvent -> Maybe ThreadId capabilityThreadIndexer m capEvent = case spec . ce_event $ capEvent of (CreateSparkThread threadId) -> Just threadId (CreateThread threadId) -> Just threadId (RunThread threadId) -> Just threadId (StopThread threadId _) -> Just threadId (ThreadRunnable threadId) -> Just threadId (MigrateThread threadId _) -> Just threadId (WakeupThread threadId capId) -> if Just capId == ce_cap capEvent then Just threadId else Nothing _ -> mThreadId where mThreadId = ce_cap capEvent >>= (\capId -> M.lookup capId m) -- | This state machine tracks Haskell tasks, represented by TaskId, -- residing on capabilities. -- Each Haskell task can only reside on one capability, but can be migrated -- between them. capabilityTaskPoolMachine :: Machine (Map TaskId Int) CapEvent capabilityTaskPoolMachine = Machine { initial = M.empty , final = const False , alpha = capabilityTaskPoolMachineAlpha , delta = capabilityTaskPoolMachineDelta } where capabilityTaskPoolMachineAlpha capEvent = case spec . ce_event $ capEvent of TaskCreate{} -> True TaskDelete{} -> True TaskMigrate{} -> True _ -> False capabilityTaskPoolMachineDelta mapping capEvent = do case spec . ce_event $ capEvent of TaskCreate {taskId, cap} -> insertTask taskId cap mapping TaskDelete {taskId} -> deleteTask taskId Nothing mapping TaskMigrate {taskId, cap, new_cap} -> deleteTask taskId (Just cap) mapping >>= insertTask taskId new_cap _ -> Nothing where insertTask :: TaskId -> Int -> Map TaskId Int -> Maybe (Map TaskId Int) insertTask taskId cap m | taskId `M.member` m = Nothing -- The task already exists. | otherwise = Just $ M.insert taskId cap m deleteTask :: TaskId -> Maybe Int -> Map TaskId Int -> Maybe (Map TaskId Int) deleteTask taskId expectedcap m | Just oldcap <- M.lookup taskId m , maybe True (==oldcap) expectedcap = Just $ M.delete taskId m | otherwise = Nothing -- The task doesn't exist, or does but with an unexpected cap. -- | This state machine tracks Haskell tasks (represented by the KernelThreadId -- of their OS thread) residing on capabilities and additionally -- tracks the (immutable) assignment of OS thread ids (KernelThreadId) -- to tasks ids (TaskId). -- Each Haskell task can only reside on one capability, but can be migrated -- between them. -- -- Invariant for the @(Map KernelThreadId Int, Map TaskId KernelThreadId)@ -- type: the second map is an injection (verified by the machine -- in 'insertTaskOS') and the following sets are equal: -- keys of the fist map and values of the second -- (follows from the construction of the maps by the machine). -- -- The machine verifies as much as 'capabilityTaskPoolMachine' and additionally -- the data invariant, and offers a richer verification profile. capabilityTaskOSMachine :: Machine (Map KernelThreadId Int, Map TaskId KernelThreadId) CapEvent capabilityTaskOSMachine = Machine { initial = (M.empty, M.empty) , final = const False , alpha = capabilityTaskOSMachineAlpha , delta = capabilityTaskOSMachineDelta } where capabilityTaskOSMachineAlpha capEvent = case spec . ce_event $ capEvent of TaskCreate{} -> True TaskDelete{} -> True TaskMigrate{} -> True _ -> False capabilityTaskOSMachineDelta mapping capEvent = do case spec . ce_event $ capEvent of TaskCreate {taskId, cap, tid} -> insertTaskOS taskId cap tid mapping TaskDelete {taskId} -> deleteTaskOS taskId mapping TaskMigrate {taskId, new_cap} -> migrateTaskOS taskId new_cap mapping _ -> Nothing where insertTaskOS :: TaskId -> Int -> KernelThreadId -> (Map KernelThreadId Int, Map TaskId KernelThreadId) -> Maybe (Map KernelThreadId Int, Map TaskId KernelThreadId) insertTaskOS taskId cap tid (m, ma) | taskId `M.member` ma = Nothing -- The task already exists. | tid `M.member` m = Nothing -- The OS thread already exists. | otherwise = Just (M.insert tid cap m, M.insert taskId tid ma) deleteTaskOS :: TaskId -> (Map KernelThreadId Int, Map TaskId KernelThreadId) -> Maybe (Map KernelThreadId Int, Map TaskId KernelThreadId) deleteTaskOS taskId (m, ma) = case M.lookup taskId ma of Nothing -> Nothing -- The task doesn't exist. Just tid -> Just (M.delete tid m, M.delete taskId ma) migrateTaskOS :: TaskId -> Int -> (Map KernelThreadId Int, Map TaskId KernelThreadId) -> Maybe (Map KernelThreadId Int, Map TaskId KernelThreadId) migrateTaskOS taskId new_cap (m, ma) = case M.lookup taskId ma of Nothing -> Nothing -- The task doesn't exist. Just tid -> Just (M.insert tid new_cap m, ma) -- The assignment is immutable. ghc-events-0.4.4.0/GHC/RTS/Events/Analysis/SparkThread.hs0000644000000000000000000001127212520426612020755 0ustar0000000000000000module GHC.RTS.Events.Analysis.SparkThread ( SparkThreadState (..) , sparkThreadMachine , capabilitySparkThreadMachine , capabilitySparkThreadIndexer ) where import GHC.RTS.Events import GHC.RTS.Events.Analysis import Data.Map (Map) import qualified Data.Map as M import Data.Set (Set) import qualified Data.Set as S import Debug.Trace data SparkThreadState = SparkThreadInitial | SparkThreadCreated | SparkThreadRunning Int | SparkThreadPaused Int | SparkThreadFinal deriving (Eq, Ord, Show) sparkThreadMachine :: Machine SparkThreadState EventInfo sparkThreadMachine = Machine { initial = SparkThreadInitial , final = sparkThreadFinal , alpha = sparkThreadAlpha , delta = sparkThreadDelta } where sparkThreadFinal SparkThreadFinal = True sparkThreadFinal _ = False -- sparkThreadAlpha (CreateSparkThread _) = True sparkThreadAlpha (RunThread _) = True sparkThreadAlpha (StopThread _ _) = True sparkThreadAlpha SparkRun = True sparkThreadAlpha (SparkSteal _) = True sparkThreadAlpha _ = False -- SparkThreadInitial -- sparkThreadDelta SparkThreadInitial (CreateSparkThread _) = Just SparkThreadInitial sparkThreadDelta SparkThreadInitial (RunThread _) = Just SparkThreadCreated -- SparkThreadCreated sparkThreadDelta SparkThreadCreated SparkRun = Just (SparkThreadRunning 0) sparkThreadDelta SparkThreadCreated (SparkSteal _) = Just (SparkThreadRunning 0) sparkThreadDelta SparkThreadCreated (StopThread _ ThreadFinished) = Just SparkThreadFinal -- SparkThreadRunning sparkThreadDelta (SparkThreadRunning n) (StopThread _ ThreadFinished) = Just SparkThreadFinal sparkThreadDelta (SparkThreadRunning n) (StopThread _ _) = Just (SparkThreadPaused n) sparkThreadDelta (SparkThreadRunning n) SparkRun = Just (SparkThreadRunning (n+1)) sparkThreadDelta (SparkThreadRunning n) (SparkSteal _) = Just (SparkThreadRunning (n+1)) -- SparkThreadPaused sparkThreadDelta (SparkThreadPaused n) (RunThread _) = Just (SparkThreadRunning n) -- Other sparkThreadDelta _ _ = Nothing capabilitySparkThreadMachine :: Machine (Map Int ThreadId, Set ThreadId) CapEvent capabilitySparkThreadMachine = Machine { initial = (M.empty, S.empty) , final = const False , alpha = capabilitySparkThreadAlpha , delta = capabilitySparkThreadDelta } where capabilitySparkThreadAlpha capEvent = case spec . ce_event $ capEvent of (CreateSparkThread _) -> True (RunThread _) -> True (StopThread _ _) -> True _ -> False capabilitySparkThreadDelta (m, s) e = do capId <- ce_cap e case spec . ce_event $ e of (CreateSparkThread threadId) -> createThread threadId -- (StopThread threadId ThreadFinished) -> stopThread threadId (StopThread threadId _) -> pauseThread threadId (RunThread threadId) -> runThread capId threadId _ -> Just (m, s) where createThread :: ThreadId -> Maybe (Map Int ThreadId, Set ThreadId) createThread threadId | S.member threadId s = Nothing -- A spark thread with this Id already created | otherwise = Just (m, S.insert threadId s) runThread :: Int -> ThreadId -> Maybe (Map Int ThreadId, Set ThreadId) runThread capId threadId | M.member capId m = Nothing -- A thread is already on this cap | threadId `elem` M.elems m = Nothing -- This thread is already on a cap | S.notMember threadId s = Just (m, s) -- Not a spark thread | otherwise = Just (M.insert capId threadId m, S.insert threadId s) stopThread :: ThreadId -> Maybe (Map Int ThreadId, Set ThreadId) stopThread threadId = Just (M.filter (/= threadId) m, S.delete threadId s) pauseThread :: ThreadId -> Maybe (Map Int ThreadId, Set ThreadId) pauseThread threadId = Just (M.filter (/= threadId) m, s) capabilitySparkThreadIndexer :: (Map Int ThreadId, Set ThreadId) -> CapEvent -> Maybe ThreadId capabilitySparkThreadIndexer (m, s) capEvent = case spec . ce_event $ capEvent of (CreateThread threadId) -> inSparkThreadPool threadId (RunThread threadId) -> inSparkThreadPool threadId (StopThread threadId _) -> inSparkThreadPool threadId -- (WakeupThread threadId _) -> inSparkThreadPool threadId _ -> ce_cap capEvent >>= (\capId -> M.lookup capId m) where inSparkThreadPool :: ThreadId -> Maybe ThreadId inSparkThreadPool threadId | S.member threadId s = Just threadId | otherwise = Nothing