Skip to content

Commit 9d9f7ae

Browse files
committed
io-sim: use Deque for runqueue
Author: @bolt12
1 parent 2e8e4e2 commit 9d9f7ae

File tree

2 files changed

+16
-10
lines changed

2 files changed

+16
-10
lines changed

io-sim/io-sim.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ library
5252
io-classes >=0.2 && <0.3,
5353
exceptions >=0.10,
5454
containers,
55+
deque,
5556
parallel,
5657
pretty-simple,
5758
psqueues >=0.2 && <0.3,

io-sim/src/Control/Monad/IOSim/Internal.hs

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,9 @@ module Control.Monad.IOSim.Internal
5353

5454
import Prelude hiding (read)
5555

56-
import Data.Foldable (traverse_)
56+
import Deque.Strict (Deque)
57+
import qualified Deque.Strict as Deque
58+
import Data.Foldable (traverse_, toList)
5759
import qualified Data.List as List
5860
import qualified Data.List.Trace as Trace
5961
import Data.Maybe (mapMaybe)
@@ -66,6 +68,8 @@ import qualified Data.Set as Set
6668
import Data.Time (UTCTime (..), fromGregorian)
6769
import Data.Dynamic
6870

71+
import GHC.Exts (fromList)
72+
6973
import Control.Exception (NonTermination (..),
7074
assert, throw)
7175
import Control.Monad (join)
@@ -123,7 +127,7 @@ data TimerVars s = TimerVars !(TVar s TimeoutState) !(TVar s Bool)
123127
-- | Internal state.
124128
--
125129
data SimState s a = SimState {
126-
runqueue :: ![ThreadId],
130+
runqueue :: !(Deque ThreadId),
127131
-- | All threads other than the currently running thread: both running
128132
-- and blocked threads.
129133
threads :: !(Map ThreadId (Thread s a)),
@@ -140,7 +144,7 @@ data SimState s a = SimState {
140144
initialState :: SimState s a
141145
initialState =
142146
SimState {
143-
runqueue = [],
147+
runqueue = mempty,
144148
threads = Map.empty,
145149
curTime = Time 0,
146150
timers = PSQ.empty,
@@ -156,15 +160,15 @@ invariant :: Maybe (Thread s a) -> SimState s a -> Bool
156160
invariant (Just running) simstate@SimState{runqueue,threads,clocks} =
157161
not (threadBlocked running)
158162
&& threadId running `Map.notMember` threads
159-
&& threadId running `List.notElem` runqueue
163+
&& threadId running `List.notElem` toList runqueue
160164
&& threadClockId running `Map.member` clocks
161165
&& invariant Nothing simstate
162166

163167
invariant Nothing SimState{runqueue,threads,clocks} =
164168
all (`Map.member` threads) runqueue
165169
&& and [ threadBlocked t == (threadId t `notElem` runqueue)
166170
| t <- Map.elems threads ]
167-
&& runqueue == List.nub runqueue
171+
&& toList runqueue == List.nub (toList runqueue)
168172
&& and [ threadClockId t `Map.member` clocks
169173
| t <- Map.elems threads ]
170174

@@ -400,7 +404,7 @@ schedule thread@Thread{
400404
, threadNextTId = 1
401405
}
402406
threads' = Map.insert tid' thread'' threads
403-
trace <- schedule thread' simstate { runqueue = runqueue ++ [tid']
407+
trace <- schedule thread' simstate { runqueue = Deque.snoc tid' runqueue
404408
, threads = threads' }
405409
return (SimTrace time tid tlbl (EventThreadForked tid') trace)
406410

@@ -563,7 +567,7 @@ deschedule Yield thread simstate@SimState{runqueue, threads} =
563567
-- algorithms are not sensitive to the exact policy, so long as it is a
564568
-- fair policy (all runnable threads eventually run).
565569

566-
let runqueue' = runqueue ++ [threadId thread]
570+
let runqueue' = Deque.snoc (threadId thread) runqueue
567571
threads' = Map.insert (threadId thread) thread threads in
568572
reschedule simstate { runqueue = runqueue', threads = threads' }
569573

@@ -629,7 +633,8 @@ deschedule Sleep _thread _simstate =
629633
-- When there is no current running thread but the runqueue is non-empty then
630634
-- schedule the next one to run.
631635
reschedule :: SimState s a -> ST s (SimTrace a)
632-
reschedule simstate@SimState{ runqueue = tid:runqueue', threads } =
636+
reschedule simstate@SimState{ runqueue, threads }
637+
| Just (tid, runqueue') <- Deque.uncons runqueue =
633638
assert (invariant Nothing simstate) $
634639

635640
let thread = threads Map.! tid in
@@ -638,7 +643,7 @@ reschedule simstate@SimState{ runqueue = tid:runqueue', threads } =
638643

639644
-- But when there are no runnable threads, we advance the time to the next
640645
-- timer event, or stop.
641-
reschedule simstate@SimState{ runqueue = [], threads, timers, curTime = time } =
646+
reschedule simstate@SimState{ threads, timers, curTime = time } =
642647
assert (invariant Nothing simstate) $
643648

644649
-- important to get all events that expire at this time
@@ -679,7 +684,7 @@ unblockThreads wakeup simstate@SimState {runqueue, threads} =
679684
-- To preserve our invariants (that threadBlocked is correct)
680685
-- we update the runqueue and threads together here
681686
(unblocked, simstate {
682-
runqueue = runqueue ++ unblocked,
687+
runqueue = runqueue <> fromList unblocked,
683688
threads = threads'
684689
})
685690
where

0 commit comments

Comments
 (0)