Ticket #7606: ghc-stride-scheduling-sorted-list-2.10.patch

File ghc-stride-scheduling-sorted-list-2.10.patch, 27.3 KB (added by ezyang, 4 months ago)

Sorted list implementation draft 2

  • compiler/llvmGen/LlvmCodeGen/CodeGen.hs

    diff --git a/compiler/llvmGen/LlvmCodeGen/CodeGen.hs b/compiler/llvmGen/LlvmCodeGen/CodeGen.hs
    index 763656a..f6cd118 100644
    a b  
    3131import Unique 
    3232import Util 
    3333 
    34 import Data.List ( partition ) 
    35  
     34import Data.List  ( partition ) 
     35import Data.Maybe ( fromMaybe ) 
    3636 
    3737type LlvmStatements = OrdList LlvmStatement 
    3838 
     
    706706genCondBranch env cond idT idF = do 
    707707    let labelT = blockIdToLlvm idT 
    708708    let labelF = blockIdToLlvm idF 
     709    -- See Note [Literals and branch conditions] 
    709710    (env', vc, stmts, top) <- exprToVarOpt env i1Option cond 
    710711    if getVarType vc == i1 
    711712        then do 
     
    714715        else 
    715716            panic $ "genCondBranch: Cond expr not bool! (" ++ show vc ++ ")" 
    716717 
     718{- Note [Literals and branch conditions] 
     719~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
     720 
     721It is important that whenever we generate branch conditions for 
     722literals like '1', they are properly narrowed to an LLVM expression of 
     723type 'i1' (for bools.) Otherwise, nobody is happy. So when we convert 
     724a CmmExpr to an LLVM expression for a branch conditional, exprToVarOpt 
     725must be certain to return a properly narrowed type. genLit is 
     726responsible for this, in the case of literal integers. 
     727 
     728Often, we won't see direct statements like: 
     729 
     730    if(1) { 
     731      ... 
     732    } else { 
     733      ... 
     734    } 
     735 
     736at this point in the pipeline, because the Glorious Code Generator 
     737will do trivial branch elimination in the sinking pass (among others,) 
     738which will eliminate the expression entirely. 
     739 
     740However, it's certainly possible and reasonable for this to occur in 
     741hand-written C-- code. Consider something like: 
     742 
     743    #ifndef SOME_CONDITIONAL 
     744    #define CHECK_THING(x) 1 
     745    #else 
     746    #define CHECK_THING(x) some_operation((x)) 
     747    #endif 
     748 
     749    f() { 
     750 
     751      if (CHECK_THING(xyz)) { 
     752        ... 
     753      } else { 
     754        ... 
     755      } 
     756 
     757    } 
     758 
     759In such an instance, CHECK_THING might result in an *expression* in 
     760one case, and a *literal* in the other, depending on what in 
     761particular was #define'd. So we must be sure to properly narrow the 
     762literal in this case to i1 as it won't be eliminated beforehand. 
     763 
     764For a real example of this, see ./rts/StgStdThunks.cmm 
     765 
     766-} 
     767 
     768 
    717769 
    718770-- | Switch branch 
    719771-- 
     
    770822exprToVarOpt env opt e = case e of 
    771823 
    772824    CmmLit lit 
    773         -> genLit env lit 
     825        -> genLit opt env lit -- See Note [Literals and branch conditions] 
    774826 
    775827    CmmLoad e' ty 
    776828        -> genLoad env e' ty 
     
    12061258 
    12071259 
    12081260-- | Generate code for a literal 
    1209 genLit :: LlvmEnv -> CmmLit -> UniqSM ExprData 
    1210 genLit env (CmmInt i w) 
    1211   = return (env, mkIntLit (LMInt $ widthInBits w) i, nilOL, []) 
     1261genLit :: EOption -> LlvmEnv -> CmmLit -> UniqSM ExprData 
     1262genLit (EOption opt) env (CmmInt i w) 
     1263  -- See Note [Literals and branch conditions] 
     1264  = let width = fromMaybe (LMInt $ widthInBits w) opt 
     1265    in return (env, mkIntLit width i, nilOL, []) 
    12121266 
    1213 genLit env (CmmFloat r w) 
     1267genLit _ env (CmmFloat r w) 
    12141268  = return (env, LMLitVar $ LMFloatLit (fromRational r) (widthToLlvmFloat w), 
    12151269              nilOL, []) 
    12161270 
    1217 genLit env cmm@(CmmLabel l) 
     1271genLit _ env cmm@(CmmLabel l) 
    12181272  = let dflags = getDflags env 
    12191273        label = strCLabel_llvm env l 
    12201274        ty = funLookup label env 
     
    12361290                (v1, s1) <- doExpr lmty $ Cast LM_Ptrtoint var (llvmWord dflags) 
    12371291                return (env, v1, unitOL s1, []) 
    12381292 
    1239 genLit env (CmmLabelOff label off) = do 
     1293genLit opt env (CmmLabelOff label off) = do 
    12401294    let dflags = getDflags env 
    1241     (env', vlbl, stmts, stat) <- genLit env (CmmLabel label) 
     1295    (env', vlbl, stmts, stat) <- genLit opt env (CmmLabel label) 
    12421296    let voff = toIWord dflags off 
    12431297    (v1, s1) <- doExpr (getVarType vlbl) $ LlvmOp LM_MO_Add vlbl voff 
    12441298    return (env', v1, stmts `snocOL` s1, stat) 
    12451299 
    1246 genLit env (CmmLabelDiffOff l1 l2 off) = do 
     1300genLit opt env (CmmLabelDiffOff l1 l2 off) = do 
    12471301    let dflags = getDflags env 
    1248     (env1, vl1, stmts1, stat1) <- genLit env (CmmLabel l1) 
    1249     (env2, vl2, stmts2, stat2) <- genLit env1 (CmmLabel l2) 
     1302    (env1, vl1, stmts1, stat1) <- genLit opt env (CmmLabel l1) 
     1303    (env2, vl2, stmts2, stat2) <- genLit opt env1 (CmmLabel l2) 
    12501304    let voff = toIWord dflags off 
    12511305    let ty1 = getVarType vl1 
    12521306    let ty2 = getVarType vl2 
     
    12621316        else 
    12631317            panic "genLit: CmmLabelDiffOff encountered with different label ty!" 
    12641318 
    1265 genLit env (CmmBlock b) 
    1266   = genLit env (CmmLabel $ infoTblLbl b) 
     1319genLit opt env (CmmBlock b) 
     1320  = genLit opt env (CmmLabel $ infoTblLbl b) 
    12671321 
    1268 genLit _ CmmHighStackMark 
     1322genLit _ _ CmmHighStackMark 
    12691323  = panic "genStaticLit - CmmHighStackMark unsupported!" 
    12701324 
    12711325 
  • compiler/prelude/primops.txt.pp

    diff --git a/compiler/prelude/primops.txt.pp b/compiler/prelude/primops.txt.pp
    index 6d551d9..0ff7e2c 100644
    a b  
    18391839   out_of_line = True 
    18401840   has_side_effects = True 
    18411841 
     1842primop  SetTicketsOp "setTickets#" GenPrimOp 
     1843  ThreadId# -> Int# -> State# RealWorld -> State# RealWorld 
     1844  with 
     1845  out_of_line = True 
     1846  has_side_effects = True 
     1847 
     1848primop  GetTicketsOp "getTickets#" GenPrimOp 
     1849  ThreadId# -> State# RealWorld -> (# State# RealWorld, Int# #) 
     1850  with 
     1851  out_of_line = True 
     1852  has_side_effects = True 
     1853 
     1854primop  ModifyTicketsOp "modifyTickets#" GenPrimOp 
     1855  ThreadId# -> Int# -> Int# -> Int# -> State# RealWorld -> (# State# RealWorld, Int# #) 
     1856  with 
     1857  out_of_line = True 
     1858  has_side_effects = True 
     1859 
    18421860------------------------------------------------------------------------ 
    18431861section "Weak pointers" 
    18441862------------------------------------------------------------------------ 
  • docs/users_guide/intro.xml

    diff --git a/docs/users_guide/intro.xml b/docs/users_guide/intro.xml
    index 5ec013f..b21b793 100644
    a b  
    130130      </varlistentry> 
    131131 
    132132      <varlistentry> 
    133         <term>glasgow-haskell-bugs:</term> 
     133        <term>ghc-devs:</term> 
    134134        <listitem> 
    135           <para>This list is for reporting and discussing GHC bugs. 
    136             However, please see <xref linkend="bug-reporting" /> before 
    137             posting here.</para> 
     135          <para>The hardcore GHC developers hang out here.</para> 
    138136 
    139137          <variablelist> 
    140138            <varlistentry> 
    141139              <term>list email address:</term> 
    142140              <listitem> 
    143                 <para><email>glasgow-haskell-bugs@haskell.org</email></para> 
     141                <para><email>ghc-devs@haskell.org</email></para> 
    144142              </listitem> 
    145143            </varlistentry> 
    146144 
     
    148146              <term>subscribe at:</term> 
    149147              <listitem> 
    150148                <para><ulink 
    151               url="http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs"><literal>http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs</literal></ulink>.</para> 
     149              url="http://www.haskell.org/mailman/listinfo/ghc-devs"><literal>http://www.haskell.org/mailman/listinfo/ghc-devs</literal></ulink>.</para> 
    152150              </listitem> 
    153151            </varlistentry> 
    154152 
    155153            <varlistentry> 
    156154              <term>admin email address:</term> 
    157155              <listitem> 
    158                 <para><email>glasgow-haskell-bugs-admin@haskell.org</email></para> 
     156                <para><email>ghc-devs-admin@haskell.org</email></para> 
    159157              </listitem> 
    160158            </varlistentry> 
    161159 
     
    163161              <term>list archives:</term> 
    164162              <listitem> 
    165163                <para><ulink 
    166                          url="http://www.haskell.org/pipermail/glasgow-haskell-bugs/"><literal>http://www.haskell.org/pipermail/glasgow-haskell-bugs/</literal></ulink></para> 
    167               </listitem> 
    168             </varlistentry> 
    169           </variablelist> 
    170         </listitem> 
    171       </varlistentry> 
    172  
    173       <varlistentry> 
    174         <term>cvs-ghc:</term> 
    175         <listitem> 
    176           <para>The hardcore GHC developers hang out here.  This list 
    177           also gets commit message from the GHC darcs repository.  There are 
    178           other lists for other darcs 
    179           repositories (most notably <literal>cvs-libraries</literal>). 
    180           </para> 
    181  
    182           <variablelist> 
    183             <varlistentry> 
    184               <term>list email address:</term> 
    185               <listitem> 
    186                 <para><email>cvs-ghc@haskell.org</email></para> 
    187               </listitem> 
    188             </varlistentry> 
    189  
    190             <varlistentry> 
    191               <term>subscribe at:</term> 
    192               <listitem> 
    193                 <para><ulink 
    194               url="http://www.haskell.org/mailman/listinfo/cvs-ghc"><literal>http://www.haskell.org/mailman/listinfo/cvs-ghc</literal></ulink>.</para> 
    195               </listitem> 
    196             </varlistentry> 
    197  
    198             <varlistentry> 
    199               <term>admin email address:</term> 
    200               <listitem> 
    201                 <para><email>cvs-ghc-admin@haskell.org</email></para> 
    202               </listitem> 
    203             </varlistentry> 
    204  
    205             <varlistentry> 
    206               <term>list archives:</term> 
    207               <listitem> 
    208                 <para><ulink 
    209           url="http://www.haskell.org/pipermail/cvs-ghc/"><literal>http://www.haskell.org/pipermail/cvs-ghc/</literal></ulink></para> 
     164          url="http://www.haskell.org/pipermail/ghc-devs/"><literal>http://www.haskell.org/pipermail/ghc-devs/</literal></ulink></para> 
    210165              </listitem> 
    211166            </varlistentry> 
    212167          </variablelist> 
  • docs/users_guide/ug-book.xml.in

    diff --git a/docs/users_guide/ug-book.xml.in b/docs/users_guide/ug-book.xml.in
    index 4d4489f..dc5d4f7 100644
    a b  
    33<title>@ProjectName@ User's Guide, Version @ProjectVersion@</title> 
    44<author><othername>The GHC Team</othername></author> 
    55<address> 
    6 <email>glasgow-haskell-&lcub;bugs,users&rcub;-request@haskell.org</email> 
     6<email>glasgow-haskell-users-request@haskell.org</email> 
    77</address> 
    88</bookinfo> 
    99 
  • includes/rts/Constants.h

    diff --git a/includes/rts/Constants.h b/includes/rts/Constants.h
    index 5ff4d4e..5ec5e11 100644
    a b  
    273273 */ 
    274274#define TSO_SQUEEZED 128 
    275275 
     276/** 
     277 * Used to indicate that the TSO got promoted in the run queue, and thus 
     278 * that its ss_pass is not indicative of the true state of the system. 
     279 */ 
     280#define TSO_PROMOTED 256 
     281 
    276282/* 
    277283 * The number of times we spin in a spin lock before yielding (see 
    278284 * #3758).  To tune this value, use the benchmark in #3758: run the 
  • includes/rts/storage/TSO.h

    diff --git a/includes/rts/storage/TSO.h b/includes/rts/storage/TSO.h
    index 82f5a75..583c7e1 100644
    a b  
    168168     */ 
    169169    StgWord32  tot_stack_size; 
    170170 
     171    // These are bounded above by STRIDE1, which is less than a max 
     172    // 32-bit word. 
     173    StgWord32 ss_tickets, ss_stride, ss_remain; 
     174    // 64-bit to prevent overflows; only ever accessed by the task which owns TSO. 
     175    StgWord64 ss_pass; 
     176 
    171177} *StgTSOPtr; 
    172178 
    173179typedef struct StgStack_ { 
  • includes/stg/MiscClosures.h

    diff --git a/includes/stg/MiscClosures.h b/includes/stg/MiscClosures.h
    index 61e6b09..e6d5fcd 100644
    a b  
    402402RTS_FUN_DECL(stg_unmaskAsyncExceptionszh); 
    403403RTS_FUN_DECL(stg_myThreadIdzh); 
    404404RTS_FUN_DECL(stg_labelThreadzh); 
     405RTS_FUN_DECL(stg_getTicketszh); 
     406RTS_FUN_DECL(stg_setTicketszh); 
     407RTS_FUN_DECL(stg_modifyTicketszh); 
    405408RTS_FUN_DECL(stg_isCurrentThreadBoundzh); 
    406409RTS_FUN_DECL(stg_threadStatuszh); 
    407410 
  • rts/Capability.c

    diff --git a/rts/Capability.c b/rts/Capability.c
    index 811df58..903f6ad 100644
    a b  
    276276    cap->pinned_object_block = NULL; 
    277277    cap->pinned_object_blocks = NULL; 
    278278 
     279    cap->ss_pass = 1; 
     280 
    279281#ifdef PROFILING 
    280282    cap->r.rCCCS = CCS_SYSTEM; 
    281283#else 
  • rts/Capability.h

    diff --git a/rts/Capability.h b/rts/Capability.h
    index 3348f88..81322c8 100644
    a b  
    5858    StgTSO *run_queue_hd; 
    5959    StgTSO *run_queue_tl; 
    6060 
     61    // [SSS] Stride scheduling extensions.  The Task with this 
     62    // Capability has exclusive access to this variable. 
     63    StgWord64 ss_pass; 
     64 
    6165    // Tasks currently making safe foreign calls.  Doubly-linked. 
    6266    // When returning, a task first acquires the Capability before 
    6367    // removing itself from this list, so that the GC can find all 
  • rts/Linker.c

    diff --git a/rts/Linker.c b/rts/Linker.c
    index fa1de89..c673bac 100644
    a b  
    11301130      SymI_HasProto(stg_mkApUpd0zh)                                     \ 
    11311131      SymI_HasProto(stg_myThreadIdzh)                                   \ 
    11321132      SymI_HasProto(stg_labelThreadzh)                                  \ 
     1133      SymI_HasProto(stg_getTicketszh)                                   \ 
     1134      SymI_HasProto(stg_setTicketszh)                                   \ 
     1135      SymI_HasProto(stg_modifyTicketszh)                                \ 
    11331136      SymI_HasProto(stg_newArrayzh)                                     \ 
    11341137      SymI_HasProto(stg_newArrayArrayzh)                                \ 
    11351138      SymI_HasProto(stg_newBCOzh)                                       \ 
  • rts/PrimOps.cmm

    diff --git a/rts/PrimOps.cmm b/rts/PrimOps.cmm
    index ebcee6a..a737508 100644
    a b  
    628628  return (); 
    629629} 
    630630 
     631stg_setTicketszh ( gcptr threadid, W_ n ) 
     632{ 
     633  ccall setTickets(threadid "ptr", n); 
     634  return (); 
     635} 
     636 
     637stg_getTicketszh ( gcptr threadid ) 
     638{ 
     639  W_ r; 
     640  (r) = ccall getTickets(threadid "ptr"); 
     641  return (r); 
     642} 
     643 
     644stg_modifyTicketszh ( gcptr threadid, W_ n, W_ d, W_ x ) 
     645{ 
     646  W_ r; 
     647  (r) = ccall modifyTickets(threadid "ptr", n, d, x); 
     648  return (r); 
     649} 
     650 
    631651stg_isCurrentThreadBoundzh (/* no args */) 
    632652{ 
    633653  W_ r; 
  • rts/Schedule.c

    diff --git a/rts/Schedule.c b/rts/Schedule.c
    index a21b312..96cfebc 100644
    a b  
    148148static rtsBool scheduleHandleHeapOverflow( Capability *cap, StgTSO *t ); 
    149149static rtsBool scheduleHandleYield( Capability *cap, StgTSO *t, 
    150150                                    nat prev_what_next ); 
    151 static void scheduleHandleThreadBlocked( StgTSO *t ); 
     151static void scheduleHandleThreadBlocked( Capability *cap, StgTSO *t ); 
    152152static rtsBool scheduleHandleThreadFinished( Capability *cap, Task *task, 
    153153                                             StgTSO *t ); 
    154154static rtsBool scheduleNeedHeapProfile(rtsBool ready_to_gc); 
     
    537537        break; 
    538538 
    539539    case ThreadBlocked: 
    540         scheduleHandleThreadBlocked(t); 
     540        scheduleHandleThreadBlocked(cap, t); 
    541541        break; 
    542542 
    543543    case ThreadFinished: 
     
    575575        setTSOPrev(cap, tso->_link, tso->block_info.prev); 
    576576    } 
    577577    tso->_link = tso->block_info.prev = END_TSO_QUEUE; 
     578    tso->flags &= ~TSO_PROMOTED; 
    578579 
    579580    IF_DEBUG(sanity, checkRunQueue(cap)); 
    580581} 
     
    781782                    setTSOPrev(cap, t, prev); 
    782783                    prev = t; 
    783784                } else { 
    784                     appendToRunQueue(free_caps[i],t); 
     785                    leaveRunQueue(cap,t); 
     786                    joinRunQueue(free_caps[i],t); 
    785787 
    786788                    traceEventMigrateThread (cap, t, free_caps[i]->no); 
    787789 
     
    12171219 * -------------------------------------------------------------------------- */ 
    12181220 
    12191221static void 
    1220 scheduleHandleThreadBlocked( StgTSO *t 
    1221 #if !defined(DEBUG) 
    1222     STG_UNUSED 
    1223 #endif 
    1224     ) 
     1222scheduleHandleThreadBlocked( Capability *cap, StgTSO *t ) 
    12251223{ 
    12261224 
    12271225      // We don't need to do anything.  The thread is blocked, and it 
     
    12341232    //      threadPaused() might have raised a blocked throwTo 
    12351233    //      exception, see maybePerformBlockedException(). 
    12361234 
     1235    leaveRunQueue(cap, t); 
     1236 
    12371237#ifdef DEBUG 
    12381238    traceThreadStatus(DEBUG_sched, t); 
    12391239#endif 
     
    12571257    // blocked mode (see #2910). 
    12581258    awakenBlockedExceptionQueue (cap, t); 
    12591259 
     1260    leaveRunQueue(cap, t); 
     1261 
    12601262      // 
    12611263      // Check whether the thread that just completed was a bound 
    12621264      // thread, and if so return with the result.   
     
    22962298{ 
    22972299    // The thread goes at the *end* of the run-queue, to avoid possible 
    22982300    // starvation of any threads already on the queue. 
    2299     appendToRunQueue(cap,tso); 
     2301    joinRunQueue(cap,tso); 
    23002302} 
    23012303 
    23022304void 
     
    23072309#if defined(THREADED_RTS) 
    23082310    cpu %= enabled_capabilities; 
    23092311    if (cpu == cap->no) { 
    2310         appendToRunQueue(cap,tso); 
     2312        joinRunQueue(cap,tso); 
    23112313    } else { 
    23122314        migrateThread(cap, tso, &capabilities[cpu]); 
    23132315    } 
    23142316#else 
    2315     appendToRunQueue(cap,tso); 
     2317    joinRunQueue(cap,tso); 
    23162318#endif 
    23172319} 
    23182320 
     
    23372339    task->incall->ret = ret; 
    23382340    task->incall->stat = NoStatus; 
    23392341 
    2340     appendToRunQueue(cap,tso); 
     2342    joinRunQueue(cap,tso); 
    23412343 
    23422344    DEBUG_ONLY( id = tso->id ); 
    23432345    debugTrace(DEBUG_sched, "new bound thread (%lu)", (unsigned long)id); 
  • rts/Schedule.h

    diff --git a/rts/Schedule.h b/rts/Schedule.h
    index 8b7caea..0677295 100644
    a b  
    116116 
    117117void resurrectThreads (StgTSO *); 
    118118 
     119// STRIDE1 defines the maximum resolution we can achieve in scheduling. 
     120#define STRIDE1 (1 << 20) 
     121// Defualt tickets is set to STRIDE1, so that the IO manager gets 
     122// maximum priority. 
     123#define DEFAULT_TICKETS (1 << 20) 
     124 
    119125/* ----------------------------------------------------------------------------- 
    120126 * Some convenient macros/inline functions... 
    121127 */ 
     
    135141appendToRunQueue (Capability *cap, StgTSO *tso) 
    136142{ 
    137143    ASSERT(tso->_link == END_TSO_QUEUE); 
     144    tso->ss_pass += tso->ss_stride; 
    138145    if (cap->run_queue_hd == END_TSO_QUEUE) { 
    139146        cap->run_queue_hd = tso; 
    140147        tso->block_info.prev = END_TSO_QUEUE; 
     148        cap->run_queue_tl = tso; 
    141149    } else { 
    142         setTSOLink(cap, cap->run_queue_tl, tso); 
    143         setTSOPrev(cap, tso, cap->run_queue_tl); 
     150        StgTSO *t, *next; 
     151        next = END_TSO_QUEUE; 
     152        for (t = cap->run_queue_tl; t != END_TSO_QUEUE; next = t, t = t->block_info.prev) { 
     153            if (tso->ss_pass >= t->ss_pass || t->flags & TSO_PROMOTED) { 
     154                if (next == END_TSO_QUEUE) { 
     155                    // it's the last one! 
     156                    // this should overwhelmingly be the case when priorities 
     157                    // are not being set 
     158                    setTSOLink(cap, cap->run_queue_tl, tso); 
     159                    setTSOPrev(cap, tso, cap->run_queue_tl); 
     160                    cap->run_queue_tl = tso; 
     161                } else { 
     162                    // XXX is there like a necessary order or something? 
     163                    setTSOLink(cap, tso, next); 
     164                    setTSOPrev(cap, tso, t); 
     165                    setTSOLink(cap, t, tso); 
     166                    setTSOPrev(cap, next, tso); 
     167                } 
     168                break; 
     169            } 
     170        } 
     171        if (t == END_TSO_QUEUE) { 
     172            setTSOLink(cap, tso, cap->run_queue_hd); 
     173            tso->block_info.prev = END_TSO_QUEUE; 
     174            cap->run_queue_hd = tso; 
     175        } 
    144176    } 
    145     cap->run_queue_tl = tso; 
     177} 
     178 
     179INLINE_HEADER void 
     180joinRunQueue(Capability *cap, StgTSO *tso) { 
     181    tso->ss_pass = cap->ss_pass + tso->ss_remain; 
     182    tso->flags &= ~TSO_PROMOTED; 
     183    appendToRunQueue(cap, tso); 
    146184} 
    147185 
    148186/* Push a thread on the beginning of the run queue. 
     
    151189EXTERN_INLINE void 
    152190pushOnRunQueue (Capability *cap, StgTSO *tso); 
    153191 
     192// This code is a little dangerous, since it temporarily bypasses 
     193// stride scheduling.  However, since we do increase ss_pass, 
     194// as long as the process doesn't continually get rescheduled with 
     195// pushOn, it will eventually be penalized for the time it took. 
     196// Since I think the old code was written to avoid this kid of 
     197// starvation, deferred punishment should be OK. (Also, failing 
     198// to put threads in front after they allocate causes massive 
     199// performance problems.) 
    154200EXTERN_INLINE void 
    155201pushOnRunQueue (Capability *cap, StgTSO *tso) 
    156202{ 
     203    tso->ss_pass += tso->ss_stride; 
     204    tso->flags |= TSO_PROMOTED; 
    157205    setTSOLink(cap, tso, cap->run_queue_hd); 
    158206    tso->block_info.prev = END_TSO_QUEUE; 
    159207    if (cap->run_queue_hd != END_TSO_QUEUE) { 
     
    161209    } 
    162210    cap->run_queue_hd = tso; 
    163211    if (cap->run_queue_tl == END_TSO_QUEUE) { 
    164         cap->run_queue_tl = tso; 
     212        cap->run_queue_tl = tso; 
    165213    } 
    166214} 
    167215 
     216INLINE_HEADER void 
     217fastJoinRunQueue(Capability *cap, StgTSO *tso) { 
     218    tso->ss_pass = cap->ss_pass + tso->ss_remain; 
     219    pushOnRunQueue(cap, tso); 
     220} 
     221 
    168222/* Pop the first thread off the runnable queue. 
    169223 */ 
    170224INLINE_HEADER StgTSO * 
     
    180234    if (cap->run_queue_hd == END_TSO_QUEUE) { 
    181235        cap->run_queue_tl = END_TSO_QUEUE; 
    182236    } 
     237    if (t->flags & TSO_PROMOTED) { 
     238        t->flags &= ~TSO_PROMOTED; 
     239        // its pass is nonsense, don't count it 
     240    } else { 
     241        if (cap->run_queue_hd != END_TSO_QUEUE) { 
     242            // relies on a PROMOTED invariant: promoted elements 
     243            // are ALWAYS in the front of the queue 
     244            ASSERT(cap->run_queue_hd->flags & TSO_PROMOTED == 0); 
     245            cap->ss_pass = cap->run_queue_hd->ss_pass; 
     246        } 
     247    } 
    183248    return t; 
    184249} 
    185250 
     
    189254    return cap->run_queue_hd; 
    190255} 
    191256 
     257INLINE_HEADER void 
     258leaveRunQueue (Capability *cap STG_UNUSED, StgTSO *tso STG_UNUSED) 
     259{ 
     260    int r = tso->ss_pass - cap->ss_pass; 
     261    if (r > 0) { 
     262        tso->ss_remain = (StgWord32)r; 
     263    } else { 
     264        tso->ss_remain = 0; 
     265    } 
     266} 
     267 
    192268void removeFromRunQueue (Capability *cap, StgTSO *tso); 
    193269extern void promoteInRunQueue (Capability *cap, StgTSO *tso); 
    194270 
  • rts/Sparks.c

    diff --git a/rts/Sparks.c b/rts/Sparks.c
    index 4241656..4e9b5a5 100644
    a b  
    4545 
    4646    traceEventCreateSparkThread(cap, tso->id); 
    4747 
    48     appendToRunQueue(cap,tso); 
     48    joinRunQueue(cap,tso); 
    4949} 
    5050 
    5151/* -------------------------------------------------------------------------- 
  • rts/Threads.c

    diff --git a/rts/Threads.c b/rts/Threads.c
    index b617616..a8f38fb 100644
    a b  
    112112 
    113113    tso->trec = NO_TREC; 
    114114 
     115    tso->ss_tickets = DEFAULT_TICKETS; 
     116    tso->ss_stride = STRIDE1 / tso->ss_tickets; 
     117    tso->ss_remain = tso->ss_stride; // avoid starvation when lots of new threads are being created 
     118 
    115119#ifdef PROFILING 
    116120    tso->prof.cccs = CCS_MAIN; 
    117121#endif 
     
    136140} 
    137141 
    138142/* --------------------------------------------------------------------------- 
     143 * Ticket allocations on threads 
     144 * ------------------------------------------------------------------------ */ 
     145 
     146#define TICKET_ERROR (STRIDE1 + 1) 
     147 
     148void 
     149setTickets(StgTSO *tso, W_ tickets) 
     150{ 
     151    if (tickets > STRIDE1) { 
     152        barf("setTickets: too many tickets"); 
     153    } else if (tickets <= 0) { 
     154        barf("setTickets: too few tickets"); 
     155    } 
     156    ACQUIRE_LOCK(&sched_mutex); 
     157    StgWord64 stride = STRIDE1 / tickets; 
     158    StgWord64 remain = (tso->ss_remain * stride) / tso->ss_stride; 
     159    tso->ss_tickets = tickets; 
     160    tso->ss_stride = stride; 
     161    tso->ss_remain = remain; 
     162    RELEASE_LOCK(&sched_mutex); 
     163} 
     164 
     165W_ 
     166modifyTickets(StgTSO *tso, W_ n, W_ d, W_ x) 
     167{ 
     168    ACQUIRE_LOCK(&sched_mutex); 
     169    W_ tickets = (tso->ss_tickets * n) / d + x; 
     170    W_ delta; 
     171    if (tickets > STRIDE1 || tickets <= 0) { 
     172        delta = TICKET_ERROR; 
     173        goto cleanup; 
     174    } 
     175    StgWord64 stride = STRIDE1 / tickets; 
     176    StgWord64 remain = (tso->ss_remain * stride) / tso->ss_stride; 
     177    delta = tso->ss_tickets - tickets; 
     178    tso->ss_tickets = tickets; 
     179    tso->ss_stride = stride; 
     180    tso->ss_remain = remain; 
     181cleanup: 
     182    RELEASE_LOCK(&sched_mutex); 
     183    return delta; 
     184} 
     185 
     186W_ 
     187getTickets(StgTSO *tso) 
     188{ 
     189    return tso->ss_tickets; 
     190} 
     191 
     192/* --------------------------------------------------------------------------- 
    139193 * Comparing Thread ids. 
    140194 * 
    141195 * This is used from STG land in the implementation of the 
     
    236290void 
    237291tryWakeupThread (Capability *cap, StgTSO *tso) 
    238292{ 
     293    rtsBool migrating = rtsFalse; 
    239294    traceEventThreadWakeup (cap, tso, tso->cap->no); 
    240295 
    241296#ifdef THREADED_RTS 
     
    282337        goto unblock; 
    283338    } 
    284339 
     340    case ThreadMigrating: 
     341        migrating = rtsTrue; 
    285342    case BlockedOnBlackHole: 
    286343    case BlockedOnSTM: 
    287     case ThreadMigrating: 
    288344        goto unblock; 
    289345 
    290346    default: 
     
    296352    // just run the thread now, if the BH is not really available, 
    297353    // we'll block again. 
    298354    tso->why_blocked = NotBlocked; 
    299     appendToRunQueue(cap,tso); 
     355    if (migrating) { 
     356        joinRunQueue(cap, tso); 
     357    } else { 
     358        appendToRunQueue(cap,tso); 
     359    } 
    300360 
    301361    // We used to set the context switch flag here, which would 
    302362    // trigger a context switch a short time in the future (at the end 
     
    322382    traceEventMigrateThread (from, tso, to->no); 
    323383    // ThreadMigrating tells the target cap that it needs to be added to 
    324384    // the run queue when it receives the MSG_TRY_WAKEUP. 
     385    leaveRunQueue(from, tso); 
    325386    tso->why_blocked = ThreadMigrating; 
    326387    tso->cap = to; 
    327388    tryWakeupThread(from, tso); 
  • rts/Threads.h

    diff --git a/rts/Threads.h b/rts/Threads.h
    index 6d26610..39794f3 100644
    a b  
    1313 
    1414#define END_BLOCKED_EXCEPTIONS_QUEUE ((MessageThrowTo*)END_TSO_QUEUE) 
    1515 
     16void setTickets(StgTSO *tso, W_ n); 
     17W_ modifyTickets(StgTSO *tso, W_ n, W_ d, W_ x); 
     18W_ getTickets(StgTSO *tso); 
     19 
    1620StgTSO * unblockOne (Capability *cap, StgTSO *tso); 
    1721StgTSO * unblockOne_ (Capability *cap, StgTSO *tso, rtsBool allow_migrate); 
    1822 
  • rts/posix/Select.c

    diff --git a/rts/posix/Select.c b/rts/posix/Select.c
    index 3d92a46..b39338b 100644
    a b  
    107107        tso->_link = END_TSO_QUEUE; 
    108108        IF_DEBUG(scheduler,debugBelch("Waking up sleeping thread %lu\n", (unsigned long)tso->id)); 
    109109        // MainCapability: this code is !THREADED_RTS 
    110         pushOnRunQueue(&MainCapability,tso); 
     110        fastJoinRunQueue(&MainCapability,tso); 
    111111        flag = rtsTrue; 
    112112    } 
    113113    return flag; 
     
    305305                IF_DEBUG(scheduler,debugBelch("Waking up blocked thread %lu\n", (unsigned long)tso->id)); 
    306306                  tso->why_blocked = NotBlocked; 
    307307                  tso->_link = END_TSO_QUEUE; 
    308                   pushOnRunQueue(&MainCapability,tso); 
     308                  fastJoinRunQueue(&MainCapability,tso); 
    309309              } else { 
    310310                  if (prev == NULL) 
    311311                      blocked_queue_hd = tso; 
  • rts/win32/AsyncIO.c

    diff --git a/rts/win32/AsyncIO.c b/rts/win32/AsyncIO.c
    index 979df0c..cfd2c0f 100644
    a b  
    303303                        // save the StgAsyncIOResult in the 
    304304                        // stg_block_async_info stack frame, because 
    305305                        // the block_info field will be overwritten by 
    306                         // pushOnRunQueue(). 
     306                        // fastJoinRunQueue(). 
    307307                        tso->stackobj->sp[1] = (W_)tso->block_info.async_result; 
    308                         pushOnRunQueue(&MainCapability, tso); 
     308                        fastJoinRunQueue(&MainCapability, tso); 
    309309                        break; 
    310310                    } 
    311311                    break;