Title: Would you like some syntactic sugar with your TBB?
1Would you like some syntactic sugar with your TBB?
2What is TBB?
- C library for writing concurrent programs
- Classes for
- Loop-based concurrency
- Task-based concurrency
- Pipelines
- Concurrent data structures
- Atomic types
3TBB good?
- Im excited
- Integrates well with C
- Large library, many paradigms
- Broader than MapReduce, OpenMP
4TBB syntax
- Low-level syntax
- templates, operator overloading, placement new
- High-level syntax
- Tons of boilerplate code
- main.C in parallel_while othello went from 206 to
424 lines (doing 3 loops), gt58 boilerplate - Separation of code
- Loop bodies lexically moved
5TBB syntax
- while( moves.size() )
- b board
- b.applyMove( moves.front() )
- moves.pop()
- / Recurse /
- quality
- Lookahead( b, other_color, newdepth )
- if( quality gt nBest )
- nBest quality
-
-
6- while( moves.size() )
- b board
- b.applyMove( moves.front() )
- moves.pop()
- / Recurse /
- quality
- Lookahead( b, other_color, newdepth )
- if( quality gt nBest )
- nBest quality
-
-
parallel_whileltLookaheadMoveEvaluatorgt
w QueueGenerator g(moves) LookaheadMoveEvaluator
e(nBest, board, other_color, newdepth) w.run(g,
e)
7class QueueGenerator queueltOthelloMovegt
_moves public QueueGenerator
(queueltOthelloMovegt moves) _moves(moves)
bool pop_if_present
(OthelloMove out_move)
if(_moves.empty()) return false else
out_move _moves.front()
_moves.pop() return true
- while( moves.size() )
- b board
- b.applyMove( moves.front() )
- moves.pop()
- / Recurse /
- quality
- Lookahead( b, other_color, newdepth )
- if( quality gt nBest )
- nBest quality
-
-
8class LookaheadMoveEvaluator atomicltintgt
_nBest OthelloBoard const _board char
_otherColor int _newDepth public
LookaheadMoveEvaluator
(atomicltintgt nBest,
OthelloBoard const board,
char otherColor, int
newDepth) _nBest(nBest) ,
_board(board) , _otherColor(otherColor)
, _newDepth(newDepth)
- while( moves.size() )
- b board
- b.applyMove( moves.front() )
- moves.pop()
- / Recurse /
- quality
- Lookahead( b, other_color, newdepth )
- if( quality gt nBest )
- nBest quality
-
-
9void operator() (OthelloMove move) const
OthelloBoard b _board b.applyMove(move)
int quality Lookahead( b,
_otherColor, _newDepth ) int curNBest
_nBest while(quality gt curNBest
_nBest.compare_and_swap
(quality, curNBest) ! curNBest)
curNBest _nBest typedef OthelloMove
argument_type
- while( moves.size() )
- b board
- b.applyMove( moves.front() )
- moves.pop()
- / Recurse /
- quality
- Lookahead( b, other_color, newdepth )
- if( quality gt nBest )
- nBest quality
-
-
10But these transformations are all mechanical!
11class QueueGenerator queueltOthelloMovegt
_moves public QueueGenerator
(queueltOthelloMovegt moves) _moves(moves)
bool pop_if_present
(OthelloMove out_move)
if(_moves.empty()) return false else
out_move _moves.front()
_moves.pop() return true
- while( moves.size() )
- b board
- b.applyMove( moves.front() )
- moves.pop()
- / Recurse /
- quality
- Lookahead( b, other_color, newdepth )
- if( quality gt nBest )
- nBest quality
-
-
12class LookaheadMoveEvaluator atomicltintgt
_nBest OthelloBoard const _board char
_otherColor int _newDepth public
LookaheadMoveEvaluator
(atomicltintgt nBest,
OthelloBoard const board,
char otherColor, int
newDepth) _nBest(nBest) ,
_board(board) , _otherColor(otherColor)
, _newDepth(newDepth)
- while( moves.size() )
- b board
- b.applyMove( moves.front() )
- moves.pop()
- / Recurse /
- quality
- Lookahead( b, other_color, newdepth )
- if( quality gt nBest )
- nBest quality
-
-
13class LookaheadMoveEvaluator atomicltintgt
_nBest OthelloBoard const _board char
_otherColor int _newDepth public
LookaheadMoveEvaluator
(atomicltintgt nBest,
OthelloBoard const board,
char otherColor, int
newDepth) _nBest(nBest) ,
_board(board) , _otherColor(otherColor)
, _newDepth(newDepth)
- while( moves.size() )
- b board
- b.applyMove( moves.front() )
- moves.pop()
- / Recurse /
- quality
- Lookahead( b, other_color, newdepth )
- if( quality gt nBest )
- nBest quality
-
-
14So do this automagically
- Extend the syntax of C
- Implement a source-to-source transformation
15So do this automagically
16New syntax
- tbb_shared new qualifier
- Concept variable is shared between threads
- Implementation a reference is used in the class
17New syntax
- concurrent_for(var , start , end , grainsize)
- var can name an existing variable or declare a
new one must be compatible with blocked_range - Iterates over start, end )
- If omitted grainsize, uses auto_partitioner()
- Cant specify different increments
- Current status parses (and typechecks), but
transformation incomplete
18New syntax
- cwhile_iterator type itervarconcurrent_while(con
d) cwhile_generator genstmts
bodystmts - Generates two classes
- Generator (stream) class checks cond if true,
runs genstmts - Body class runs bodystmts
- Communicate via a cwhile_iterator
- genstmts should write to itervar
- bodystmts should read from itervar
19New syntax
- cwhile_iterator type itervarconcurrent_while(con
d) cwhile_generator genstmts
bodystmts - Current status implemented
- Only minor restrictions no nested
concurrent_while, types of variables used
restricted
20C elision
- define
- concurrent_while -gt while
- cwhile_iterator -gt
- tbb_shared -gt
- concurrent_for(var, start, end, )
-gt for(varstart, var ! end, var) - But doesnt work if var declares a variable
21Othello revisited
concurrent_while( moves.size() gt 0 )
cwhile_generator move moves.front()
moves.pop() OthelloBoard b
board b.applyMove(move) int
quality Lookahead( b,
other_color, newdepth ) if( quality gt
nBest ) tbbspin_mutexscoped_lock
l ((tbbspin_mutex)lock)
if(quality gt nBest) nBest
quality
- while( moves.size() )
- b board
- b.applyMove( moves.front() )
- moves.pop()
- / Recurse /
- quality
- Lookahead( b, other_color, newdepth )
- if( quality gt nBest )
- nBest quality
-
-
22What changed?
- while( moves.size() )
- b board
- b.applyMove( moves.front() )
- moves.pop()
- quality Lookahead( b, other_color, newdepth
) - if( quality gt nBest )
- nBest quality
-
-
23What changed?
- while( moves.size() )
- b board
- b.applyMove( moves.front() )
- moves.pop()
- quality Lookahead( b, other_color, newdepth
) - if( quality gt nBest )
- nBest quality
-
-
24What changed?
- while( moves.size() )
- b board
- OthelloMove move moves.front()
- b.applyMove(move)
- moves.pop()
- quality Lookahead( b, other_color, newdepth
) - if( quality gt nBest )
- nBest quality
-
-
25What changed?
- while( moves.size() )
- b board
- OthelloMove move moves.front()
- b.applyMove(move)
- moves.pop()
- quality Lookahead( b, other_color, newdepth
) - if( quality gt nBest )
- nBest quality
-
-
26What changed?
- while( moves.size() )
- OthelloMove move moves.front()
- moves.pop()
- b board
- b.applyMove(move)
-
- quality Lookahead( b, other_color, newdepth
) - if( quality gt nBest )
- nBest quality
-
-
27What changed?
- while( moves.size() )
- OthelloMove move moves.front()
- moves.pop()
-
- OthelloBoard b board
- b.applyMove(move)
-
- int quality Lookahead( b, other_color,
newdepth ) - if(quality gt nBest)
- nBest quality
-
-
28What changed?
- concurrent_while( moves.size() )
- cwhile_generator
- OthelloMove move moves.front()
- moves.pop()
-
- OthelloBoard b board
- b.applyMove(move)
-
- int quality Lookahead( b, other_color,
newdepth ) - if( quality gt nBest )
- tbbspin_mutexscoped_lock
l((tbbspin_mutex)lock) - if(quality gt nBest)
- nBest quality
-
-
-
29Done!
- concurrent_while( moves.size() )
- cwhile_generator
- OthelloMove move moves.front()
- moves.pop()
-
- OthelloBoard b board
- b.applyMove(move)
-
- int quality Lookahead( b, other_color,
newdepth ) - if( quality gt nBest )
- tbbspin_mutexscoped_lock
l((tbbspin_mutex)lock) - if(quality gt nBest)
- nBest quality
-
-
-
30Anything else?
- includes for TBB headers
- Removed declaration for OthelloBoard b and int
quality - Added cwhile_iterator to definition of move
- Added tbb_shared to definition of nBest
- Added a declaration for the lock
- Added another declaration of OthelloBoard b in
another branch - Created a task_scheduler_init object in main
31Anything else?
- Changed CCg and LDg to use tbbetter driver
- Added a I and L flag to the TBB directories
- Added ltbb to the linker flags
32Interesting point constness
- Loop-carried dependencies wrong
- This translates to not modifying thread-local
variables - Any not marked tbb_shared!
- Which iteration did the value come from?
- Also applies to reading the value of a variable
changed in the loop - TBB enforces operator() is const
33Performance (othello, lookahead 7)
34Wrapping up
- Got some done more to do
- Goals if this were a longer-term project (or if I
hadnt procrastinated like mad) - Finish concurrent_for
- Find a translation for parallel_reduce
- Make cilk code compile
- Goals for a serious project
- Engineering on the parser
- Bug squashing (still 7 or so outstanding 5
patched by sed) - Integrate with other compilers
- Improve edge cases
- If you can do 80 of the job with 50 of the
work, that is the right way
35Questions?
36Alternate syntax
- Alternate names
- cwhile_generator?!
- Really easy to change
- Updating test cases probably longer process
- tbb_shared implies volatile?
- Seems useful, but already broke
37Alternate syntax
- concurrent_while(iterator, cond)
- Explicit as to what iterator is being used
- Currently you must use exactly one variable
declared with cwhile_iterator inside the body of
each concurrent_while - concurrent_while() cwhile_generator
cwhile_body
38What really happens
othello.cc
cc1plus -E
modified elsa
sed
othello.o
cc1plus -E
cc1plus
as