edentv-4.1.0.0: RTSEventsParserOld.lhs
EdenTV Project.
The Haskell-based viewer. Port to new GHC events.
\begin{code}
{-# OPTIONS -XNamedFieldPuns #-}
module RTSEventsParserOLD where
import Text.Printf
import qualified EdenTvType as E
import GHC.RTS.Events
import TinyZipper
import Data.Binary.Get
import Control.Monad
import Control.Monad.Error
import Data.ByteString.Lazy (ByteString)
import System.IO.Unsafe (unsafePerformIO)
import Control.Monad
import Control.Monad.State
import Data.Maybe
--import Data.IntMap (IntMap)
--import qualified Data.IntMap as M
import Data.Either
import Data.Tree
import List
import qualified Data.HashMap as Hash
import qualified Control.Exception as C
import Debug.Trace
data Err a = Ok !a | Failed String
\end{code}
----------------------------------
--
-- Reader function
--
----------------------------------
We mimic the behaviour of the original reader function @toEvents@.
-- TraceParser.hs
data Err a = Ok !a | Failed String
toEvents :: [Char] -> Err Events
toEvents [] = Failed "File empty"
toEvents ts = Ok ...
-- EdenTvTypes.hs
type Events = (([Machine],[Process],[Thread]),[(MachineID,Double)],MessageList,(Seconds,Seconds,Double,Double),(Int,Int,Int))
-- loM loP loT machine starttimes msgs/heads min_t max_t maxMsgSize MaxLD #M #P #T
oh my...
------------------------------------
We need to read events from a bytestring!
-- GHC.RTS.Events says:
readEventLogFromFile :: FilePath -> IO (Either String EventLog)
readEventLogFromFile f = do
s <- L.readFile f
return $ runGet (do v <- runErrorT $ getEventLog
m <- isEmpty
m `seq` return v) s
\begin{code}
readGhcEventsSingle :: ByteString -> IO (Either String EventLog)
readGhcEventsSingle s = return $ runGet (do v <- runErrorT $ getEventLog
m <- isEmpty
m `seq` return v) $ s
\end{code}
Now we can read events from a bytestring!
\begin{code}
type RTSEvents = (E.MachineID, [Event])
readOne :: EventLog -> Either String RTSEvents
readOne evtlog = let ghcevents = map ce_event $ sortEvents (events $ dat evtlog)
mID = getMachineID ghcevents
in either (\err -> Left err) (\id -> Right (id, ghcevents)) mID
where getMachineID :: [Event] -> Either String E.MachineID
getMachineID ((Event{time, spec=CreateMachine{machine}}):_) =
Right $ fromIntegral machine
getMachineID (_:xs) = getMachineID xs
getMachineID [] = Left "readSingle: No Create Machine Event found"
\end{code}
As we can read events from a single stream, we can also read multiple event
files from a zip archive
\begin{code}
readAll :: FilePath -> IO (Either String [RTSEvents])
readAll zippath = do
files' <- readZip zippath
either (\err -> return $ Left err)
(\files -> do
eventlogs <- sequence $ map readGhcEventsSingle files
let (errparse, logs) = partitionEithers eventlogs
case null errparse of
True -> do
let (errevts, events) = partitionEithers $ map readOne logs
case null errevts of
False -> return $ Left "readAll: Events error"
True -> return $ Right events
False -> return $ Left "readAll: Parse error")
files'
{-
We need to catch Exceptions here, because getEventLog (GHC.RTS.Events) uses Lazy Bytestrings and
non-strict Get!
-}
parseRawFile :: FilePath -> IO (Either String [RTSEvents])
parseRawFile zipfile = C.catch (readAll zipfile) catchBadFile
where catchBadFile :: C.SomeException -> IO (Either String [RTSEvents])
catchBadFile e = return (Left "Parse: Bad File")
\end{code}
we want to know how long a message was processed
- when an EdenStartReceive Event is found we store the startTime and go on searching
for received Messages in this block, until the matching EdenEndReceive Event is found.
- for each process found in this block we store the process id and receive time, so that we can
seperate the blocks in Process view
\begin{code}
getReceiveLengths :: [(E.MachineID, Double)] -> [(E.MachineID, [Event])] -> [E.ReceiveLength]
getReceiveLengths syncTimes ((mID, events):otherMachines) = (process mID events) ++ (getReceiveLengths syncTimes otherMachines)
where process :: E.MachineID -> [Event] -> [((E.MachineID,[(Int,E.Seconds)]), E.Seconds, E.Seconds)]
process mID (event:events) = case (spec event) of
EdenStartReceive -> case endT of
(-1) -> process mID events -- skip faulty (no EdenEndReceive Event found)
_ -> ((mID, pID), startT, endT) : (process mID events) -- block ok, store and do next
where pID = getProcessID events -- scan for receiving processes and their receive times
startT = convertTimestampWithSync (toSyncTime syncTimes mID) (time event)
endT = getEndTime events
getEndTime :: [Event] -> E.Seconds
getEndTime (event:events) = case (spec event) of
EdenEndReceive -> convertTimestampWithSync (toSyncTime syncTimes mID) (time event)
_ -> getEndTime events
getEndTime [] = (-1)
eventTime e = convertTimestampWithSync (toSyncTime syncTimes mID) (time e)
getProcessID :: [Event] -> [(Int,E.Seconds)]
getProcessID (event:events) = case (spec event) of
ReceiveMessage RFork _ _ _ _ _ _ -> getProcessID events
CreateProcess p -> (fromIntegral p, eventTime event) : (getProcessID events)
ReceiveMessage _ _ _ _ _ _ _ -> (fromIntegral $ receiverProcess (spec event), eventTime event) : (getProcessID events)
EdenEndReceive -> []
_ -> getProcessID events
getProcessID [] = []
_ -> process mID events
process _ [] = []
getReceiveLengths _ [] = []
\end{code}
time in the tracefile is stored in ticks, which are not comparable between machines.
to match times between traces we calculate a realtime offset for each machine,
stored in a (ID,Seconds) List
This helper function retrieves the realtime offset for a given machine id.
\begin{code}
toSyncTime :: [(E.MachineID, Double)] -> E.MachineID -> Double
toSyncTime ((mId, t):machines) i
| mId == i = t
| otherwise = toSyncTime machines i
toSyncTime [] _ = 0
\end{code}
Now we need to create the Eden Events structure.
For this we insert the events one by one into the Structure,
until all Events are processed.
\begin{code}
traceRTSFile :: FilePath -> IO (Err E.Events)
traceRTSFile file = do
ghcevents' <- parseRawFile file
case ghcevents' of
Left err -> return (Failed err)
Right ghcevents -> do
return (Ok injectedEvents)
where
-- insert events in final structure and close open messages
processedEvents = closeOpenLists $ process ghcevents emptyoe
-- inject additional information
injectedEvents = injectLOMessages leftMessages $ injectProcMessages $ injectMaxStartupDifference (maxStartupDifference maxEnd) $ injectStartupDifferences diffStartups $ injectReceiveTimes rcvTimes processedEvents
------------------------------
-- 'additional information' --
------------------------------
leftMessages = snd (processLeftOvers ghcevents ([],[]))
-- startup differences -- used for 'better aligning' machines
diffStartups = startupDifferences ghcevents (maxStartupTimeOfTrace ghcevents)
-- receive length -- used to draw small rectangles to show how long it took to receive a message
rcvTimes = getReceiveLengths syncTimes ghcevents
-- used for rescaling of x-axis when we align to startup times
endTimes = endTimesOfTrace ghcevents
maxEnd = getMaxEndTime processedEvents
-- tracefile only contains timestamp with 'TICKS' of local machine
-- we use this table to convert TICKS to global time
syncTimes = getSyncTimes (mainTimeOfTrace ghcevents) ghcevents
-- we need to store to which process a thread belongs
luptable = createThreadLookupTable ghcevents
-- from old haskell EdenTV
-- initial events structure
emptyoe = (([],[],[]),[(0,firstTime)], fml firstTime, (firstTime, firstTime, 0, -1))
where firstTime = minCreateMachineTimeOfTrace ghcevents
getMaxEndTime ((lom,lop,lot),mst, maxSt, rcv,(min_t, m_t,_,mmsg,mld),nums) = m_t
-- mainTime is the realtime of the first machine
mainTimeOfTrace :: [(E.MachineID, [Event])] -> Double
mainTimeOfTrace ((1,machine):machines) = realtimeOfMachine machine
mainTimeOfTrace (_:machines) = mainTimeOfTrace machines
mainTimeOfTrace [] = 0
-- syncTimes are the offset of machine-realtimes to the 'mainTime'
getSyncTimes :: Double -> [(E.MachineID, [Event])] -> [(E.MachineID, Double)]
getSyncTimes mainTime ((mID,evts):machines) = ((mID,t): (getSyncTimes mainTime machines))
where t = (realtimeOfMachine evts) - mainTime
getSyncTimes _ [] = []
-- injects the max startup difference time into the final Events structure
-- needed because insertEvent doesn't cover startup difference times
injectMaxStartupDifference :: E.Seconds -> E.Events -> E.Events
injectMaxStartupDifference time ((lom,lop,lot),mst, maxSt, rcv,(min_t, m_t,_,mmsg,mld),nums) = ((lom,lop,lot),mst,maxSt,rcv,(min_t,m_t,time,mmsg,mld),nums)
-- the maximal difference of startup times
-- used to re-calculate the latest time of all events
maxStartupDifference :: E.Seconds -> E.Seconds
maxStartupDifference maxE = let difftimes = zipWith (\(_, diffs) (_,end) -> if diffs + end > maxE then (diffs+end)-maxE else 0) (snd diffStartups) endTimes
in seq difftimes $ maximum difftimes
-- times of last event of all machines
endTimesOfTrace :: [(E.MachineID, [Event])] -> [(E.MachineID, E.Seconds)]
endTimesOfTrace evts = map endTime evts
where endTime (mID, evt) = (mID, convertTimestampWithSync (toSyncTime syncTimes mID) $ time $ last evt)
-- injects the receive times into the final Events structure
-- needed because insertEvent doesn't cover receive times
injectReceiveTimes :: [E.ReceiveLength] -> E.Events -> E.Events
injectReceiveTimes inj ((lom,lop,lot),mst, maxSt, (ml,aml,hml,pt, _ ),stats,nums) = ((lom,lop,lot),mst,maxSt,(ml,aml,hml,pt, inj ),stats,nums)
-- injects the left out Head Messages
-- needed because insertEvent throws them away
injectLOMessages :: [E.Message] -> E.Events -> E.Events
injectLOMessages inj ((lom,lop,lot),mst, maxSt, (ml,_,hml,pt, rcvl ),stats,nums) = ((lom,lop,lot),mst,maxSt,(ml,inj,hml,pt, rcvl ),stats,nums)
-- injects the startup differences into the final Events structure
-- needed because insertEvent doesn't cover startup differences
injectStartupDifferences :: (E.Seconds,[(Int,E.Seconds)]) -> E.Events -> E.Events
injectStartupDifferences inj ((lom,lop,lot),mst, _ ,(ml,aml,hml,pt, rcvl ),stats,nums) = ((lom,lop,lot),mst, inj,(ml,aml,hml,pt, rcvl ),stats,nums)
-- builds startup differences table of a trace
-- trace -> maxStartupTime of Trace -> (maxStartupTime, diffTable)
startupDifferences :: [(E.MachineID, [Event])] -> E.Seconds -> (E.Seconds, [(Int,E.Seconds)])
startupDifferences ((mId,evts):machines) maxS = let s = convertTimestampWithSync (toSyncTime syncTimes mId) (startupTimestampOfMachine evts)
in seq s (maxS,((mId,(maxS-s)): (startupDifferences' machines maxS)))
where startupDifferences' ((mId,evts):machines) maxS = let s = convertTimestampWithSync (toSyncTime syncTimes mId) (startupTimestampOfMachine evts)
in seq s ((mId,(maxS-s)): (startupDifferences' machines maxS))
startupDifferences' [] _ = []
startupDifferences [] _ = (0,[])
-- from old haskell EdenTV
-- creates initial MessageList
fml :: E.Seconds -> E.OpenMessageList
fml t = ([],[],([(1,[((1,1),E.OSM t (0,0) (-1) (-1) 85)],[((0,0),E.ORM t (1,1) (-1) (-1) 85 4)],[])],[((0,0),[])],Node (0,0) []),([],0,[]))
-- determines the earliest CreateMachine time from all Machines -- which is equivalent with the earliest event time
minCreateMachineTimeOfTrace :: [(E.MachineID, [Event])] -> E.Seconds
minCreateMachineTimeOfTrace = minimum . map (\(mID, machine) -> convertTimestampWithSync (fromMaybe 0 $ lookup mID syncTimes) (createmachineTimestampOfMachine machine))
-- determines the latest Startup time from all Machies
maxStartupTimeOfTrace :: [(E.MachineID, [Event])] -> E.Seconds
maxStartupTimeOfTrace = maximum . map (\(mID, machine) -> convertTimestampWithSync (fromMaybe 0 $ lookup mID syncTimes) (startupTimestampOfMachine machine))
-- extracts the CreateMachine Timestamp of a list of all Machine Events
createmachineTimestampOfMachine :: [Event] -> Timestamp
createmachineTimestampOfMachine ((Event {time, spec=CreateMachine{}}):xs) = time
createmachineTimestampOfMachine (_:xs) = createmachineTimestampOfMachine xs
createmachineTimestampOfMachine _ = error "No Machine created"
-- extracts the realtime of a list of all Machine Events
realtimeOfMachine :: [Event] -> Double
realtimeOfMachine ((Event {time, spec=CreateMachine{realtime}}):xs) = ((fromIntegral realtime)/10e7)-((fromIntegral time) / 10e8)
realtimeOfMachine (_:xs) = realtimeOfMachine xs
realtimeOfMachine _ = error "No realtime found"
-- extracts the Startup Timestamp of a list of all Machine Events
startupTimestampOfMachine :: [Event] -> Timestamp
startupTimestampOfMachine ((Event { time, spec=Startup { n_caps } }) :xs) = time
startupTimestampOfMachine (_:xs) = startupTimestampOfMachine xs
startupTimestampOfMachine _ = error "No Machine started"
-- walks over the list of machines (which contains all events for this machine) and inserts all events
-- in an accumulated OpenEvents structure
-- when no events are left, we are finished and just need to close open lists in the generated structure
process :: [(E.MachineID, [Event])] -> E.OpenEvents -> E.OpenEvents
process ((mID, (evt:evts)):machines) oe = let convertTimestamp = convertTimestampWithSync (toSyncTime syncTimes mID)
newOE = insertEvent convertTimestamp luptable (mID,evt) oe
in seq newOE $ process ((mID,evts):machines) newOE
process ((_,[]):machines) oe = process machines oe
process [] oe = oe
-- insertLeftOutMessages :: E.ProcessID -> E.OpenMessageEvent -> ([OpenMessage],[Message]) -> ([OpenMessage],[Message])
processLeftOvers :: [(E.MachineID, [Event])] -> ([E.OpenMessage],[E.Message]) -> ([E.OpenMessage],[E.Message])
processLeftOvers ((mID, (evt:evts)):machines) oe = let convertTimestamp = convertTimestampWithSync (toSyncTime syncTimes mID)
in case spec evt of
SendMessage{
mesTag,
senderProcess,
senderThread,
receiverMachine,
receiverProcess,
receiverInport} -> let newOE = insertLeftOutMessages (mID, (fromIntegral senderProcess))
(E.OSM (convertTimestamp (time evt)) (fromIntegral receiverMachine, fromIntegral receiverProcess) (fromIntegral senderThread) (fromIntegral receiverInport) (readTag mesTag))
oe
in processLeftOvers ((mID,evts):machines) newOE
ReceiveMessage{
mesTag,
receiverProcess,
receiverInport,
senderMachine,
senderProcess,
senderThread,
messageSize} -> let newOE = insertLeftOutMessages ((fromIntegral senderMachine), (fromIntegral senderProcess))
(E.ORM (convertTimestamp (time evt)) (mID, fromIntegral receiverProcess) (fromIntegral senderThread) (fromIntegral receiverInport) (readTag mesTag) (fromIntegral messageSize))
oe
in processLeftOvers ((mID,evts):machines) newOE
_ -> processLeftOvers ((mID,evts):machines) oe
processLeftOvers ((_,[]):machines) oe = processLeftOvers machines oe
processLeftOvers [] oe = oe
-- Manually build Process Table
-- and ProcMessages (needed because wrong results
-- when those messages are processed in a 'wrong' order, and
-- finding the right order is just as complex as this)
sendRForks = map (\(mID, evts) -> (mID, filter (isSendRFork) evts)) ghcevents
isSendRFork :: Event -> Bool
isSendRFork evt = case spec evt of
SendMessage{mesTag=RFork} -> True
_ -> False
rcv_crtRForks = map (\(mID, evts) -> (mID, filter (\evt -> case spec evt of ReceiveMessage{mesTag=RFork} -> True; CreateProcess{} -> True; _ -> False) evts)) ghcevents
injectProcMessages :: E.Events -> E.Events
injectProcMessages ((lom,lop,lot),mst, inj ,(ml,aml,hml,pt, rcvl ),stats,nums) = ((lom,lop,lot),mst, inj,(ml++procMessages,aml,hml,processTree, rcvl ),stats,nums)
childTable :: [(E.ProcessID, [E.ProcessID])]
procMessages :: [E.Message]
(childTable,procMessages) = createChildTable sendRForks rcv_crtRForks [] []
processTree :: E.ProcessTree
processTree = unfoldTree buildTree ((1,1), fromJust (lookup (1,1) childTable))
buildTree :: (E.ProcessID, [E.ProcessID]) -> (E.ProcessID, [(E.ProcessID, [E.ProcessID])])
buildTree (pid, pids) = (pid, map (\p -> let mps = lookup p childTable
in case mps of
Nothing -> (p, [])
Just ps -> (p, ps)) pids)
createChildTable :: [(E.MachineID, [Event])] -> [(E.MachineID, [Event])] -> [(E.ProcessID, [E.ProcessID])] -> [E.Message] -> ([(E.ProcessID, [E.ProcessID])], [E.Message])
createChildTable ((mID, evt:evts):machines) rcvers table procMsgs=
let SendMessage{senderProcess,receiverMachine} = spec evt
senderProc = (mID, fromIntegral sProc)
receiverMach = fromIntegral receiverMachine
sMach = fromIntegral mID
sProc = senderProcess
sTime = convertTimestampWithSync (toSyncTime syncTimes mID) (time evt)
Just rcvEvents = lookup receiverMach rcvers
(childId, remainingEvents, child) = nextChildId rcvEvents
childProcess = (receiverMach, childId)
newRcvers = updateReceivers receiverMach rcvers remainingEvents
newTable = addChild table senderProc childProcess
newProcMsgs = child:procMsgs
addChild :: [(E.ProcessID, [E.ProcessID])] -> E.ProcessID -> E.ProcessID -> [(E.ProcessID, [E.ProcessID])]
addChild (cur@(pid, childs):pids) father child
| pid == father = ((pid, (child:childs)):pids)
| otherwise = cur : (addChild pids father child)
addChild [] father child = [(father, [child])]
updateReceivers :: E.MachineID -> [(E.MachineID, [Event])] -> [Event] -> [(E.MachineID, [Event])]
updateReceivers i (mach@(mID, evts):machines) update
| mID == i = ((mID, update):machines)
| otherwise = mach : (updateReceivers i machines update)
updateReceivers _ [] _ = error "not updated"
nextChildId (e:es) = case spec e of
ReceiveMessage{senderMachine,senderProcess,
messageSize} -> if senderMachine == sMach && senderProcess == sProc
then let (Event{spec=CreateProcess{process}}, rest) = getNextAndRemove (\evt -> case spec evt of CreateProcess{} -> True; _ -> False) es
childId = fromIntegral process
channelID = (senderProc, 0, (receiverMach, childId),0)
rTime = convertTimestampWithSync (toSyncTime syncTimes receiverMach) (time e)
child = E.MSG channelID sTime rTime 85 (fromIntegral messageSize)
in (childId, rest, child)
else let (id, rest, child) = nextChildId es
in (id, e:rest, child)
_ -> let (id, rest, child) = nextChildId es
in (id, e:rest, child)
nextChildId [] = error "next child not found"
getNextAndRemove :: (a -> Bool) -> [a] -> (a, [a])
getNextAndRemove p (x:xs)
| p x = (x,xs)
| otherwise = let (y,ys) = getNextAndRemove p xs
in (y,x:ys)
getNextAndRemove _ [] = (error "next not found", [])
in createChildTable ((mID, evts):machines) newRcvers newTable newProcMsgs
createChildTable ((mID, []):machines) rcvers table procMsgs = createChildTable machines rcvers table procMsgs
createChildTable [] ecv table procMsgs = (table,procMsgs)
-- converts a timestamp in TICKS to Seconds with respect to a realtime offset 'sync'
convertTimestampWithSync :: E.Seconds -> Timestamp -> E.Seconds
convertTimestampWithSync sync x = sync + (fromIntegral x / 10e8)
readTag :: MessageTag -> Int
readTag tag = case tag of
-- Log.Ready -> 80
-- Log.NewPE -> 81
-- Log.PETIDS -> 82
-- Log.Finish -> 83
-- Log.Fail -> 84
RFork -> 85
Connect -> 86
DataMes -> 87
Head -> 88
Constr -> 89
Part -> 90
-- Log.Packet -> 92
Terminate -> 91
_ -> -1
type ThreadLookupMap = Hash.HashMap E.MachineID (Hash.HashMap Int Int)
createThreadLookupMap :: [(E.MachineID, [Event])] -> ThreadLookupMap
createThreadLookupMap list = let table = createThreadLookupTable list
hashv1 = map (\(mID, x) -> (mID, Hash.fromList x)) table
in Hash.fromList hashv1
createThreadLookupTable :: [(E.MachineID, [Event])] -> [(E.MachineID, [(Int, Int)])]
createThreadLookupTable ((mId, es):xs) = (mId, createTable es) : createThreadLookupTable xs
where createTable :: [Event] -> [(Int, Int)]
createTable ((Event{time,spec=AssignThreadToProcess{thread,process}}):es) = ((fromIntegral thread, fromIntegral process): createTable es)
createTable (_:es) = createTable es
createTable [] = []
createThreadLookupTable [] = []
type Lookuptable = [(E.MachineID, [(Int, Int)])]
lookupProcess :: Lookuptable -> E.MachineID -> Int -> Int
lookupProcess ((machine, es):ts) sMachine sThread = if machine == sMachine then lookupProcess' es sThread else lookupProcess ts sMachine sThread
where lookupProcess' lst@((x,y):xs) z = if x == z then y else lookupProcess' xs z
lookupProcess' [] z = error ("Thread not found" ++ (show sMachine) ++ " " ++ (show z))
lookupProcess [] sMachine sThread = error ("--Thread not found" ++ (show sMachine) ++ " " ++ (show sThread))
insertLeftOutMessages :: E.ProcessID -> E.OpenMessageEvent -> ([E.OpenMessage],[E.Message]) -> ([E.OpenMessage],[E.Message])
insertLeftOutMessages sp newMessage ocMsgs@(openMsgList, closedMessages)
| or [(tag == 88),(tag == 87)] = let ((_,sp'),(_,rp')) = (sp, rp)
in if (min sp' rp') >= 0
then seq oml (seq cml (oml,cml))
else ocMsgs
| otherwise = ocMsgs
where (time, rp@(rm,_),out,inp,tag,size) = case newMessage of
E.ORM t p o i r s -> (t,p,o,i,r,s)
E.OSM t p o i r -> (t,p,o,i,r,0)
(oml,cml) = searchID openMsgList
searchID :: [E.OpenMessage] -> ([E.OpenMessage], [E.Message])
searchID oml@(om@(iB,msgs):oms)
| sp > iB = seq cms' (seq oms' (om:oms',cms')) -- go on
| sp == iB = if null newOms -- OMList found => look for matching message
then (oms,newCms)
else ((iB, newOms):oms,newCms)
| otherwise = ((sp,[newMessage]):oml,closedMessages) -- no OMList for threadId found
where (oms',cms') = searchID oms -- recurse
(newOms,newCms) = insertOrReplace msgs -- try to find matching OpenMessage
insertOrReplace :: [E.OpenMessageEvent] -> ([E.OpenMessageEvent], [E.Message])
insertOrReplace (o:os) = case closeMessage o newMessage of
Nothing -> seq os' (o:os', cls')
Just c -> (os, c:closedMessages)
where (os',cls') = insertOrReplace os
insertOrReplace [] = ([newMessage],closedMessages)
closeMessage :: E.OpenMessageEvent -> E.OpenMessageEvent -> Maybe E.Message
closeMessage (E.OSM t1 p1 o1 i1 r1) (E.ORM t2 p2 o2 i2 r2 s2)
| and [p1==p2, o1==o2, i1==i2, r1==r2] = Just (E.MSG (sp,o1,p1,i1) t1 t2 r1 s2)
| otherwise = Nothing
closeMessage (E.ORM t2 p2 o2 i2 r2 s2) (E.OSM t1 p1 o1 i1 r1)
| and [p1==p2, o1==o2, i1==i2, r1==r2] = Just (E.MSG (sp,o1,p1,i1) t1 t2 r1 s2)
| otherwise = Nothing
closeMessage _ _ = Nothing
searchID [] = ([(sp, [newMessage])], closedMessages)
-- legacy code of old haskell EdenTV
-- modified to work with new Tracefile Format
insertEvent :: (Timestamp -> E.Seconds) -> Lookuptable -> (E.MachineID, Event) -> E.OpenEvents -> E.OpenEvents
insertEvent convertTimestamp lutable (mId, Event{time, spec}) oldEvents@(oEvts@(ms,ps,ts),mts,ocMsgs,(minTime,maxTime,nP,maxLD))
| isMsgEvent = seq newMsgEvents ((newMs, newPs,ts),mts,newMsgEvents,(minTime,newMax,nP,maxLD)) -- process the event
| isTrdEvent = let (newTData, mPE) = newTrdEvents
(newPData, mME) = case mPE of
[] -> (ps, []) -- no virtual process event
pe -> insPEventList pe ps -- insert generated process event
newMData = case mME of
[] -> ms -- no virtual machine event
me -> insMEventList mId me ms -- insert generated machine event
in seq newMData ((newMData, newPData, newTData),mts,ocMsgs,(minTime,newMax,nP,maxLD))
| isPrcEvent = let (newPData,mME) = newPrcEvents
newMData = case mME of
Nothing -> ms -- no virtual machine event
Just me -> insMEvent mId me ms -- virtual machine event generated
in seq newMData ((newMData,newPData,ts),mts,newOcMsgs,(minTime,newMax,newNP,maxLD))
| isMchEvent = let newData = case gcEvents of
Nothing -> (newMchEvents, ps, ts)
Just (p,t) -> let newPE = insPeByMID mId p ps
newTE = insTeByMID mId t ts
in (newMchEvents, newPE, newTE)
in seq newData (newData,newMchTimes,ocMsgs,(min',max',nP,maxLD'))
| otherwise = oldEvents -- ignore unknown events
where
(isMsgEvent, newMsgEvents, newMs, newPs) = case spec of
SendMessage{mesTag=Connect} -> (False, undefined, undefined, undefined) -- ignore
SendMessage{
mesTag,
senderProcess,
senderThread,
receiverMachine,
receiverProcess,
receiverInport} -> (True, createNewMsgEvents (mId, fromIntegral senderProcess)
(E.OSM (convertTimestamp time) (fromIntegral receiverMachine, fromIntegral receiverProcess)
(fromIntegral senderThread) (fromIntegral receiverInport) (readTag mesTag)), nms, nps)
ReceiveMessage{
mesTag,
receiverProcess,
receiverInport,
senderMachine,
senderProcess,
senderThread,
messageSize} -> (True, createNewMsgEvents (fromIntegral senderMachine, fromIntegral senderProcess)
(E.ORM (convertTimestamp time) (mId, fromIntegral receiverProcess)
(fromIntegral senderThread) (fromIntegral receiverInport) (readTag mesTag) (fromIntegral messageSize)), nms, nps)
_ -> (False, undefined, undefined, undefined)
where createNewMsgEvents i event = insertMessage i event ocMsgs
proc = case spec of SendMessage _ p _ _ _ _ -> fromIntegral p; ReceiveMessage _ p _ _ _ _ _ -> fromIntegral p
(nms, nps) = increaseMsgCount (mId, proc) ms ps spec
(isTrdEvent,newTrdEvents) = case spec of
RunThread {
thread } -> (True, newEvents (E.RunThread (convertTimestamp time)))
AssignThreadToProcess {
thread,
process} -> (True, newEvents (E.NewThread (convertTimestamp time) (0))) -- #####hack outport? always zero in toSDDF
StopThread {
thread,
status} -> case status of
ThreadFinished -> (True, newEvents (E.KillThread (convertTimestamp time)))
ThreadBlocked -> (True, newEvents (E.BlockThread (convertTimestamp time) (0) (1))) -- ####hack inport? reason?
_ -> (True, newEvents (E.SuspendThread (convertTimestamp time)))
WakeupThread {
thread,
otherCap} -> (True, newEvents (E.DeblockThread (convertTimestamp time)))
_ -> (False, undefined)
where proc = lookupProcess lutable mId thre -- hack
thre = fromIntegral (thread spec) -- hack
newEvents evt = insertThreadEvent ((mId, proc), thre) evt ts
(isPrcEvent,newPrcEvents,newOcMsgs,newNP) = case spec of
CreateProcess {
process} -> (True, newEvents (E.NewProcess (convertTimestamp time)), ocMsgs, nP + 1)
KillProcess {
process} -> (True, newEvents (E.KillProcess (convertTimestamp time) (0,0,0)), delFromProcList (mId,fromIntegral process) ocMsgs, nP)
_ -> (False, undefined, undefined, undefined)
where newEvents evt = insPEvent (mId, fromIntegral (process spec)) evt ps
(isMchEvent,newMchEvents,newMchTimes,maxLD',gcEvents) = case spec of
CreateMachine{} -> (True, newEvents (E.StartMachine (convertTimestamp time)), (mId, convertTimestamp time):mts, maxLD, Nothing)
Startup{n_caps} -> (True, ms, mts, maxLD, Nothing)
KillMachine _ -> (True, newEvents (E.EndMachine (convertTimestamp time)), mts, maxLD, Nothing)
-- JB, WAS: 849 ->
--233 -> (True, newEvents (GCMachine getGCTime v2 v3 v4 v5), mts, max maxLD v5, -- hack todo GC
-- Just (GCProcess getGCTime v2 v3 v4 v5, GCThread getGCTime v2 v3 v4 v5))
_ -> (False, undefined, undefined, undefined, undefined)
where newEvents evt = insMEvent mId evt ms
-- compute new min/max times:
newMax = max (convertTimestamp time) maxTime
(min', max') = if (convertTimestamp time) > maxTime
then (minTime, (convertTimestamp time))
else (newMin, maxTime)
newMin :: E.Seconds
newMin = min (convertTimestamp time) minTime
insMEventList :: E.MachineID -> [E.MachineEvent] -> [E.Machine] -> [E.Machine]
insMEventList i (m:ms) lst = insMEvent i m (insMEventList i ms lst)
insMEventList _ _ lst = lst
insMEvent :: E.MachineID -> E.MachineEvent -> [E.Machine] -> [E.Machine]
insMEvent i1 evt lst@(e@(i2,allP,blkP,stat@(p,s,r),evts):es) -- insert in existing list of machines
| i2 > i1 = let es' = (insMEvent i1 evt es) in seq es' (e : es') -- go on
| i2 == i1 = let e' = insertHere in seq e' (e' : es) -- existing machine
| otherwise = (i1,0,0,(0,0,0),[evt]) : lst -- new machine => no processes
where insertHere = case evt of
E.MSuspendProcess sec -> let newEvts = case head evts of
E.SuspendedMachine _ -> evts
_ -> (E.SuspendedMachine sec):evts
in (i2,allP,blkP,stat,newEvts)
E.MRunProcess sec -> (i2,allP,blkP,stat,(E.RunningMachine sec):evts)
E.MBlockProcess sec -> let newBlkP = blkP + 1
newEvts = if newBlkP < allP
then (E.SuspendedMachine sec):evts
else (E.BlockedMachine sec):evts
in (i2,allP,newBlkP,stat,newEvts)
E.GCMachine _ _ _ _ _ -> (i2,allP,blkP,stat,evt:evts)
E.MNewProcess sec -> let newAllP = allP + 1
newEvts = if blkP == allP -- test if evt may be skipped:
then (E.SuspendedMachine sec):evts
else evts
in (i2,allP + 1,blkP,(p+1,s,r),newEvts)
E.MKillRProcess sec -> let newAllP = allP - 1
newEvts = if newAllP > 0
then (E.SuspendedMachine sec):evts
else (E.IdleMachine sec):evts
in (i2,newAllP,blkP,stat,newEvts)
E.MKillSProcess sec -> let newAllP = allP - 1
newEvts = if newAllP > 0
then evts
else (E.IdleMachine sec):evts
in (i2,newAllP,blkP,stat,newEvts)
E.MKillBProcess sec -> let newAllP = allP - 1
newBlkP = blkP - 1
newEvts = if newAllP > 0
then evts
else (E.IdleMachine sec):evts
in (i2,newAllP,newBlkP,stat,newEvts)
E.MIdleProcess sec -> let newEvts = case head evts of
E.SuspendedMachine _ -> evts
_ -> (E.SuspendedMachine sec):evts
in (i2,allP,blkP,stat,newEvts)
E.EndMachine _ -> (i2,0,0,stat,evt:evts)
_ -> error ("insMEvent: unknown event: " ++ show evt)
insMEvent i1 evt [] = [(i1,0,0,(0,0,0),[evt])] -- brand new machine => no processes
insPEventList :: [(E.ProcessID,E.ProcessEvent)] -> [E.Process] -> ([E.Process],[E.MachineEvent])
insPEventList ((i,p):ps) lst = let (ps',mes) = insPEventList ps lst
(lst',me) = insPEvent i p ps'
in case me of
Nothing -> (lst',mes)
Just me -> (lst',me:mes)
insPEventList _ lst = (lst,[])
insPeByMID :: E.MachineID -> E.ProcessEvent -> [E.Process] -> [E.Process]
insPeByMID i evt lst@(e@((m,_),_,_,_,_):es)
| i == m = insertHere lst -- first process on machine i found, insert event
| otherwise = let es' = insPeByMID i evt es in seq es' (e:es') -- search on
where insertHere lst@(e@(i'@(m,_),a,b,s,evts):es)
| i == m = let es' = insertHere es in case take 1 evts of
[E.KillProcess _ _] -> seq es' ( e : es') -- process not alive
[E.BlockedProcess _] -> seq es' ((i',a,b,s,(E.BlockedProcess (convertTimestamp time):evt:evts)):es')
[E.SuspendedProcess _] -> seq es' ((i',a,b,s,(E.SuspendedProcess (convertTimestamp time):evt:evts)):es')
_ -> seq es' ((i',a,b,s,evt:evts) : es') -- not possible?
| otherwise = lst -- all processes on machine i worked up
insertHere [] = []
insPEvent :: E.ProcessID -> E.ProcessEvent -> [E.Process] -> ([E.Process],Maybe E.MachineEvent)
insPEvent i1 evt lst@(e@(i2,allT,blkT,stat@(t,s,r),evts):es)
| i1 < i2 = let (es',mEvt) = insPEvent i1 evt es in seq es' (seq mEvt (e : es', mEvt))
| i1 == i2 = (insertHere : es, vMachineEvent) {- case evt of -- a new entry for every new process
NewProcess sec -> ((i1,0,0,(0,0,0),[evt]):lst, Just (MNewProcess time))
_ -> (insertHere : es, vMachineEvent) -}
| otherwise = ((i1,0,0,(0,0,0),[evt]):lst,Just (E.MNewProcess (convertTimestamp time))) -- new Process => evt == NewProcess
where (insertHere,vMachineEvent) = case evt of
E.PNewThread sec -> let newAllT = allT + 1
in if blkT == allT -- was Process blocked?
then ((i1,newAllT,blkT,(t+1,s,r),(E.SuspendedProcess sec):evts), Just (E.MSuspendProcess sec))
else ((i1,newAllT,blkT,(t+1,s,r),evts),Nothing)
E.PKillRThread sec -> let newAllT = allT - 1
(newEvts,newMEvt) = if newAllT > 0
then if blkT < newAllT
then ((E.SuspendedProcess sec):evts, Just (E.MSuspendProcess sec))
else ((E.BlockedProcess sec):evts, Just (E.MBlockProcess sec))
else case evts of
(E.KillProcess _ _:_) -> (evts, Nothing)
_ -> ((E.IdleProcess sec):evts, Just (E.MIdleProcess sec))
in ((i1,newAllT,blkT,stat,newEvts),newMEvt)
E.PKillSThread sec -> let newAllT = allT - 1
(newEvts,newMEvt) = if newAllT > 0
then if blkT < newAllT
then (evts, Nothing)
else ((E.BlockedProcess sec):evts, Just (E.MBlockProcess sec))
else case evts of
(E.KillProcess _ _:_) -> (evts, Nothing)
_ -> ((E.IdleProcess sec):evts, Just (E.MIdleProcess sec))
in ((i1,newAllT,blkT,stat,newEvts), newMEvt)
E.PKillBThread sec -> let newAllT = allT - 1
newBlkT = blkT - 1
(newEvts,newMEvt) = if newAllT > 0
then (evts, Nothing)
else case evts of
(E.KillProcess _ _:_) -> (evts, Nothing)
_ -> ((E.IdleProcess sec):evts, Just (E.MIdleProcess sec))
in ((i1,newAllT,newBlkT,stat,newEvts), newMEvt)
E.PRunThread sec -> ((i1,allT,blkT,stat,(E.RunningProcess sec):evts),Just (E.MRunProcess sec))
E.PSuspendThread sec -> ((i1,allT,blkT,stat,(E.SuspendedProcess sec):evts), Just (E.MSuspendProcess sec))
E.PBlockThread sec -> let newBlkT = blkT + 1
(newEvts,newMEvt) = if newBlkT < allT
then ((E.SuspendedProcess sec):evts,Just (E.MSuspendProcess sec))
else ((E.BlockedProcess sec):evts,Just (E.MBlockProcess sec))
in ((i1,allT,newBlkT,stat,newEvts),newMEvt)
E.PDeblockThread sec -> let newBlkT = blkT - 1
(newEvts,newMEvt) = if newBlkT < allT -- was process blocked?
then ((E.SuspendedProcess sec):evts,Just (E.MSuspendProcess sec))
else (evts,Nothing)
in ((i1,allT,newBlkT,stat,newEvts),newMEvt)
E.NewProcess sec -> ((i1,0,0,(t,s,r),(evt:evts)),Just (E.MNewProcess sec))
E.LabelProcess sec _ -> ((i1,allT,blkT,stat,evt:evts),Nothing)
-- KillProcess holds the statistic information for the ending process
E.KillProcess sec _ -> let evt' = E.KillProcess sec (t,s,r)
in case evts of
(E.RunningProcess _:_) -> ((i1,0,0,(0,0,0),(evt':evts)),Just (E.MKillRProcess sec))
(E.BlockedProcess _:_) -> ((i1,0,0,(0,0,0),(evt':evts)),Just (E.MKillBProcess sec))
_ -> ((i1,0,0,(0,0,0),(evt':evts)),Just (E.MKillSProcess sec))
_ -> error ("unknown event: " ++ show evt)
insPEvent i1 evt [] = ([(i1,0,0,(0,0,0),[evt])],Just (E.MNewProcess (convertTimestamp time))) -- new Process => evt == NewProcess
insTeByMID :: E.MachineID -> E.ThreadEvent -> [E.OpenThread] -> [E.OpenThread]
insTeByMID i evt lst@(e@(m,(lti,lte),ts):es)
| i == m = (m,(((m,-1),-1),evt),insertHere ts):es -- machine i found, insert event into threads; the ((m,-1),-1)
-- inserts 'evt' the next time insTEvent is run.
| otherwise = let es' = insTeByMID i evt es in seq es' (e:es') -- search on
where insertHere (l@(i,evts):ls) = let ls' = insertHere ls
in case take 1 evts of
-- skip already killed threads:
[E.KillThread _] -> seq ls' (l:ls') -- Thread already dead
-- The following entry describes the last suspended thread. The SuspendThread-event hasn't yet
-- been inserted, it resides in 'lte':
[E.RunThread _] -> seq ls' ((i,E.setEventTime lte (convertTimestamp time):evt:lte:evts):ls')
-- other threads are blocked or suspended:
[lastEvent] -> seq ls' ((i,E.setEventTime lastEvent (convertTimestamp time):evt:evts):ls')
insertHere [] = []
insertThreadEvent :: E.ThreadID -> E.ThreadEvent -> [E.OpenThread] -> ([E.OpenThread], [(E.ProcessID,E.ProcessEvent)])
insertThreadEvent i@((m,_),_) evt tl@(t@(im,(lti,lte),ts):tls)
| m < im = let (tls', pEvt') = insertThreadEvent i evt tls -- look for corresponding machine
in seq tls' (seq pEvt' (t:tls',pEvt')) -- recurse
| m == im = case lte of
E.SuspendThread _ -> case evt of
E.RunThread _ -> if i == lti
then ((im,(i,E.DummyThread),ts):tls,[]) -- suppress flattering
else bothEvents
_ -> bothEvents
E.DummyThread -> case evt of
E.SuspendThread _ -> ((im,(i,evt),ts):tls, []) -- deter SuspendThread-Event
_ -> let (ts',pEvt') = insTEvent' i evt ts in ((im,(i,E.DummyThread),ts'):tls,[(t2pID i,pEvt')])
otherwise -> insertThreadEvent i evt tls
| otherwise = ((m,(i,E.DummyThread),[(i,[evt])]):tl,[(t2pID i,vProcessEvent evt [])]) -- new machine
where bothEvents = let (ts2,pEvt2) = insTEvent' lti lte ts
(ts3,pEvt3) = insTEvent' i evt ts2
in ((im,(i,E.DummyThread),ts3):tls,[(t2pID i,pEvt3),(t2pID lti,pEvt2)])
insertThreadEvent i@((m,_),_) evt [] = ([(m,(i,E.DummyThread),[(i,[evt])])],[(t2pID i,vProcessEvent evt [])])
insTEvent' :: E.ThreadID -> E.ThreadEvent -> [E.Thread] -> ([E.Thread],E.ProcessEvent)
insTEvent' i@((m,_),t) ne lst@(e@(ib@((im,_),it),evts):es)
| i' < ib' = let (es', mEvt') = (insTEvent' i ne es) in seq es' (seq mEvt' (e:es',mEvt'))
| i' == ib' = ((i,(ne:evts)):es, vProcessEvent ne evts)
| otherwise = ((i,[ne]):lst,vProcessEvent ne evts)
where
i' = (m,t)
ib' = (im,it)
insTEvent' i evt _ = ([(i,[evt])],vProcessEvent evt [])
vProcessEvent :: E.ThreadEvent -> [E.ThreadEvent] -> E.ProcessEvent
vProcessEvent evt evts = case evt of
E.KillThread sec -> case evts of
(E.BlockThread _ _ _:_) -> E.PKillBThread sec
(E.RunThread _ :_) -> E.PKillRThread sec
_ -> E.PKillSThread sec
E.RunThread sec -> E.PRunThread sec
E.SuspendThread sec -> E.PSuspendThread sec
E.BlockThread sec _ _ -> E.PBlockThread sec
E.DeblockThread sec -> E.PDeblockThread sec
E.NewThread _ _ -> E.PNewThread (convertTimestamp time)
increaseMsgCount :: E.ProcessID -> [E.Machine] -> [E.Process] ->
EventTypeSpecificInfo -> ([E.Machine], [E.Process])
increaseMsgCount pID@(mID,_) ml pl spec = (incM ml, incP pl)
where incM :: [E.Machine] -> [E.Machine]
incM (m@(i, aP, bP, (p,s,r), es):ms)
| i > mID = m : incM ms -- go on
| i == mID = case spec of
SendMessage _ _ _ _ _ _ -> ((i, aP, bP, (p, s+1, r), es):ms)
ReceiveMessage _ _ _ _ _ _ _ -> ((i, aP, bP, (p, s, r+1), es):ms)
otherwise -> m:ms -- should not occur
| otherwise = m:ms -- not found? nevermind...
incM _ = []
incP :: [E.Process] -> [E.Process]
incP (p@(i,aT,bT,(t,s,r),es):ps)
| i > pID = p : incP ps
| i == pID = case spec of
SendMessage _ _ _ _ _ _ -> ((i, aT, bT, (t, s+1, r), es):ps)
ReceiveMessage _ _ _ _ _ _ _ -> ((i, aT, bT, (t, s, r+1), es):ps)
otherwise -> p:ps -- should not occur
| otherwise = p:ps -- not found? nevermind...
incP _ = []
newProc :: E.ProcessID -> E.ProcessID -> E.ProcessList -> E.ProcessTree -> (E.ProcessList, E.ProcessTree)
newProc dad son pls pt = (addProcPath son (dadPath) pls, addChildPrc son dadPath pt)
where dadPath = []--TODO getPath dad pls ++ [dad]
getPath :: E.ProcessID -> E.ProcessList -> [E.ProcessID]
getPath pId (p@(i,path):ps)
| i < pId = getPath pId ps
| i == pId = path
| otherwise = error ("not impl: getPath, otherwise " ++ (show son) ++ " " ++ show (pId,pls))
getPath _ _ = []
addProcPath :: E.ProcessID -> [E.ProcessID] -> E.ProcessList -> E.ProcessList
addProcPath pId path pls@(p@(i,lst):ps)
| i < pId = let ps' = addProcPath pId path ps in seq ps' (p:ps')
| i == pId = (pId,path) : ps
| otherwise = (pId,path) : pls
addProcPath pId path _ = [(pId, path)]
addChildPrc :: E.ProcessID -> [E.ProcessID] -> E.ProcessTree -> E.ProcessTree
addChildPrc pId [p] (Node i pts) = Node i ((Node pId []):pts)
addChildPrc pId path@(p:ps) pt@(Node i pts)
| p == i = let pts' = stepDown ps pts in seq pts' (Node i pts')
| otherwise = error ("addChildPrc: wrong ProcessTree found (" ++ show p ++ "!=" ++ show i ++ ")")
where stepDown :: [E.ProcessID] -> [E.ProcessTree] -> [E.ProcessTree]
stepDown path@(p:ps) pts@(t@(Node i _):ts)
| i == p = let t' = addChildPrc pId path t in seq t' (t':ts)
| otherwise = let ts' = stepDown path ts in seq ts' (t:ts')
stepDown path [] = seq (putStrLn ("stepDown: path " ++ show path ++ " not found in Process Tree:" ++ show pt)) []
addChildPrc pId [] pt = pt
delFromProcList :: E.ProcessID -> E.OpenMessageList -> E.OpenMessageList
delFromProcList pId oml = oml
insertMessage :: E.ProcessID -> E.OpenMessageEvent -> E.OpenMessageList -> E.OpenMessageList
insertMessage sp newMessage ocMsgs@(openMsgList,closedMessages,partMsgs@(openPrcMsgs,prcTbl,prcTree),(headMessages,hSize,closedHeads))
| tag == 88 = let ohl' = addHeadMsg (sp, out, rp, inp) headMessages
in seq ohl' (openMsgList, closedMessages, partMsgs,(ohl', hSize, closedHeads))
| tag == 87 = let (ohl,chl,hs') = searchHeadMsg (sp,out,rp,inp) headMessages
in seq cml (seq chl (oml,cml,partMsgs,(ohl,max hs' hSize,chl)))
| tag == 85 = ocMsgs
| otherwise = let ((_,sp'),(_,rp')) = (sp,rp)
in if (min sp' rp') >= 0
then seq oml (seq cml (oml,cml,partMsgs,(headMessages,hSize,closedHeads)))
else ocMsgs
where (time, rp@(rm,_),out,inp,tag,size) = case newMessage of
E.ORM t p o i r s -> (t,p,o,i,r,s)
E.OSM t p o i r -> (t,p,o,i,r,0)
(oml,cml) = searchID openMsgList
addHeadMsg :: E.ChannelID -> [E.OpenHeadMessage] -> [E.OpenHeadMessage]
addHeadMsg cId hml@(h@(idB,s,i,hsm,hrm):hs)
| cId > idB = let hs' = addHeadMsg cId hs in seq hs' (h:hs') -- not found yet: search on
| cId == idB = case newMessage of
E.ORM _ _ _ _ _ _ -> case hrm of -- entry found, increase quantity and size
[firstMsg] -> (idB,(s+size),(i+1),hsm,time:hrm):hs -- second received Message
(lastMsg:fm) -> (idB,(s+size),(i+1),hsm, time:fm):hs -- replace last received Message
[] -> (idB,(s+size),(i+1),hsm, [time] ):hs -- first received Message
E.OSM _ _ _ _ _ -> case hsm of -- entry found, don't touch values
[firstMsg] -> (idB,s,i,time:hsm,hrm):hs
(lastMsg:fm) -> (idB,s,i,time:fm ,hrm):hs
[] -> (idB,s,i, [time] ,hrm):hs
| otherwise = case newMessage of
E.ORM _ _ _ _ _ _ -> (cId,size,1,[],[time]):hml -- insert new entry before h
E.OSM _ _ _ _ _ -> (cId,size,0,[time],[]):hml
addHeadMsg cId [] = case newMessage of
E.ORM _ _ _ _ _ _ -> [(cId,size,1,[],[time])]
E.OSM _ _ _ _ _ -> [(cId,size,0,[time],[])]
searchHeadMsg :: E.ChannelID -> [E.OpenHeadMessage] -> ([E.OpenHeadMessage],[E.HeadMessage],Double)
searchHeadMsg cId hml@(h@(idB,s,i,hsm,hrm):hs)
| cId > idB = let (hs',ch',ms') = searchHeadMsg cId hs
in seq hs' (seq ch' (h:hs',ch',ms'))
| cId == idB = let sInt = s + size
sDouble = fromIntegral sInt
in case newMessage of
E.ORM _ _ _ _ _ _ ->
if length hsm == 3
then (hs, (cId,(ts1,tr1,ts2,time),sDouble,(i+1)):closedHeads, sDouble)
else ((idB,sInt,(i+1),hsm,time:hrm):hs,closedHeads,sDouble)
E.OSM _ _ _ _ _ ->
if length hrm == 3
then (hs, (cId,(ts1,tr1,time,tr2),sDouble,i):closedHeads,sDouble)
else ((idB,s,i,time:hsm,hrm):hs,closedHeads,sDouble)
| otherwise = (hml,closedHeads,0)
where ts2 = head hsm
ts1 = last hsm
tr2 = head hrm
tr1 = last hrm
searchHeadMsg cId [] = ([], closedHeads,0)
searchID :: [E.OpenMessage] -> ([E.OpenMessage], [E.Message])
searchID oml@(om@(iB,msgs):oms)
| sp > iB = seq cms' (seq oms' (om:oms',cms')) -- go on
| sp == iB = if null newOms -- OMList found => look for matching message
then (oms,newCms)
else ((iB, newOms):oms,newCms)
| otherwise = ((sp,[newMessage]):oml,closedMessages) -- no OMList for threadId found
where (oms',cms') = searchID oms -- recurse
(newOms,newCms) = insertOrReplace msgs -- try to find matching OpenMessage
insertOrReplace :: [E.OpenMessageEvent] -> ([E.OpenMessageEvent], [E.Message])
insertOrReplace (o:os) = case closeMessage o newMessage of
Nothing -> seq os' (o:os', cls')
Just c -> (os, c:closedMessages)
where (os',cls') = insertOrReplace os
insertOrReplace [] = ([newMessage],closedMessages)
closeMessage :: E.OpenMessageEvent -> E.OpenMessageEvent -> Maybe E.Message
closeMessage (E.OSM t1 p1 o1 i1 r1) (E.ORM t2 p2 o2 i2 r2 s2)
| and [p1==p2, o1==o2, i1==i2, r1==r2] = Just (E.MSG (sp,o1,p1,i1) t1 t2 r1 s2)
| otherwise = Nothing
closeMessage (E.ORM t2 p2 o2 i2 r2 s2) (E.OSM t1 p1 o1 i1 r1)
| and [p1==p2, o1==o2, i1==i2, r1==r2] = Just (E.MSG (sp,o1,p1,i1) t1 t2 r1 s2)
| otherwise = Nothing
closeMessage _ _ = Nothing
searchID [] = ([(sp, [newMessage])], closedMessages)
closeOpenLists :: E.OpenEvents -> E.Events
closeOpenLists (events@(mEvents,pEvents,tEvents),mTimes,(_,closedMessages,(_,_,Node _ pTrees),(openHeadMessages,hSize,headMessages)),(minTime,maxTime,numP,maxLD)) =
seq mEvents (seq minTime (seq allHeadMessages
((mEvents,pEvents,newThreadEvents),mTimes,undefined,(closedMessages,[],allHeadMessages,reversedProcTree, []),
(minTime,maxTime,0,hSize,(fromIntegral maxLD)),(length mEvents,numP,length newThreadEvents))))
where allHeadMessages = handleOpenHeadMsgs openHeadMessages headMessages
newThreadEvents = concat (map (\(_,_,ts) -> ts) tEvents)
reversedProcTree :: E.ProcessTree
reversedProcTree = if null pTrees
then Node (0,0) []
else reverseSubForests (head pTrees)
reverseSubForests :: E.ProcessTree -> E.ProcessTree
reverseSubForests (Node i f) = Node i (map reverseSubForests (reverse f))
handleOpenHeadMsgs :: [E.OpenHeadMessage] -> [E.HeadMessage] -> [E.HeadMessage]
handleOpenHeadMsgs [] hm = hm
handleOpenHeadMsgs ((ch,s,i,sml,rml):os) hm = case zip sml rml of
((lst',lrt'):(fst',frt'):_) -> handleOpenHeadMsgs os ((newHeadMsg fst' frt' lst' lrt'):hm)
_ -> handleOpenHeadMsgs os hm
where newHeadMsg :: E.Seconds -> E.Seconds -> E.Seconds -> E.Seconds -> E.HeadMessage
newHeadMsg tS1 tR1 tS2 tR2 = (ch,(tS1,tR1,tS2,tR2),fromIntegral s,i)
t2pID :: E.ThreadID -> E.ProcessID
t2pID tid = fst tid
instance Eq ThreadStopStatus where
NoStatus == NoStatus = True
NoStatus == _ = False
HeapOverflow == HeapOverflow = True
HeapOverflow == _ = False
StackOverflow == StackOverflow = True
StackOverflow == _ = False
ThreadYielding == ThreadYielding = True
ThreadYielding == _ = False
ThreadBlocked == ThreadBlocked = True
ThreadBlocked == _ = False
ThreadFinished == ThreadFinished = True
ThreadFinished == _ = False
ForeignCall == ForeignCall = True
ForeignCall == _ = False
\end{code}