cs242 multi cores are coming for 50 years hardware
play

!!"!#"$%& cs242 ! ! Multi-cores are coming! ! - For 50 - PDF document

!!"!#"$%& cs242 ! ! Multi-cores are coming! ! - For 50 years, hardware designers delivered 40-50% increases per year in sequential program speed. ! - Around 2004, this pattern failed because power and cooling issues made it impossible


  1. !!"!#"$%& cs242 ! ! Multi-cores are coming! ! - For 50 years, hardware designers delivered 40-50% increases per year in sequential program speed. ! - Around 2004, this pattern failed because power and cooling issues made it impossible to increase clock Kathleen Fisher ! frequencies. ! - Now hardware designers are using the extra transistors that Moore’ s law is still delivering to put more processors on a single chip. ! Reading: “Beautiful Concurrency”, ! If we want to improve program speed, “The Transactional Memory / Garbage Collection Analogy” ! concurrent programs are no longer optional. ! Thanks to Simon Peyton Jones for these slides. ! Libraries build ! Concurrent programming is essential to layered concurrency improve performance on a multi-core. ! abstractions ! Library ! ! Yet the state of the art in concurrent Library ! programming is 30 years old: Library ! locks and condition variables. " " Library ! (In Java: synchronized , wait , and notify .) ! Library ! Library ! Library ! ! Locks and condition variables are Concurrency primitives ! fundamentally flawed: it’ s like building a sky- scraper out of bananas. ! Hardware ! This lecture describes significant recent progress: bricks and mortar instead of bananas. ! At Atomic Blocks ! Locks and condition variables ! Atomic blocks ! (a) are hard to use and ! (a) are easier (b) do not compose. ! to use and ! Library ! Library ! (b) they do y ! compose. ! r a r Library ! b Library ! i L Library ! L i b r a Library ! r y ! Library ! Library ! Library ! Library ! Library ! Library ! e s ! a b l Atomic blocks ! a r i n v t i o n d i c o n d s a c k L o 3 primitives: atomically, retry, orElse ! Hardware ! Hardware ! !&

  2. ! !!"!#"$%& ! Consider a (correct) Java bank Account class: ! A 30-second review: ! class Account{ ! float balance; ! ! Ra Races: forgotten locks lead to inconsistent views ! ! Dea eadlock: locks acquired in “wrong” order ! synchronized void deposit(float amt) { ! balance += amt; ! ! Lost wakeu eups: : forgotten notify to condition variables ! } ! ! Di Diabol bolical e error r recovery: need to restore invariants synchronized void withdraw(float amt) { ! and release locks in exception handlers ! if (balance < amt) ! throw new OutOfMoneyError(); ! balance -= amt; ! } ! ! These are serious problems. But even worse... ! } ! ! Now suppose we want to add the ability to transfer funds from one account to another. ! ! Simply calling withdraw and deposit to ! Synchronizing transfer can cause deadlock: ! implement transfer causes a race condition: ! class Account{ ! float balance; ! class Account{ ! synchronized void deposit(float amt) { ! float balance; ! balance += amt; ! synchronized void deposit(float amt) { ! } ! balance += amt; ! synchronized void withdraw(float amt) { ! } ! if (balance < amt) ! synchronized void withdraw(float amt) { ! throw new OutOfMoneyError(); ! if (balance < amt) ! balance -= amt; ! throw new OutOfMoneyError(); ! } ! balance -= amt; ! synchronized ! } ! void transfer_wrong2(Acct other, float amt) { ! void transfer_wrong1(Acct other, float amt) { ! // can deadlock with parallel reverse-transfer ! other.withdraw(amt); ! this.deposit(amt); ! // race condition: wrong sum of balances ! other.withdraw(amt); ! this.deposit(amt);} ! } ! } ! } ! Scalable double-ended queue: one lock per cell ! Diffi fficulty of f qu queu eue e Codin Co ding g styl yle ! imp mplem emen entation ! Sequential code ! Undergraduate ! No interference if ends “far enough” apart ! But watch out when the queue is 0, 1, or 2 elements long! ! '&

  3. !!"!#"$%& Diffi fficulty of f qu queu eue e Diffi fficulty of f qu queu eue e Co Codin ding g styl yle ! Diffi fficulty of f concurren ent qu queu eue ! Codin Co ding g styl yle ! Codin Co ding g styl yle ! imp mplem emen entation ! imp mplem emen entation ! Sequential code ! Undergraduate ! Sequential code ! Undergraduate ! Sequential code ! Undergraduate ! Locks and condition Publishable result at Locks and condition Publishable result at Locks and condition Publishable result at variables ! international conference ! variables ! international conference 1 ! variables ! international conference 1 ! Atomic blocks ! Undergraduate ! 1 Simp mple, fast, and practical non-blocking and blocking concurren ent qu queu eue e algorithms ms. ! 1 Simp mple, fast, and practical non-blocking and blocking concurren ent qu queu eue e algorithms ms. ! Like database Optimistic ! transactions ! concurrency ! atomically {... <code> ...} ! atomically {...sequential code...} ! One possibility: ! ! To a first approximation, just write the sequential code, ! Execute <code> without taking any locks. ! and wrap atomically around it. ! read y; ! Log each read and write in <code> to a read z; ! All-or-nothing semantics: At Atomic commit. ! write 10 x; thread-local transaction log. ! write 42 z; … ! Atomic block executes in Is Isolation. ! ! Writes go to the log only, not to memory. ! ! Cannot deadlock (there are no locks!). ! A C I D ! ! At the end, the transaction validates the log. ! ! Atomicity makes error recovery easy ! If valid, atomically co commits changes to memory. ! - (e.g. throw exception inside sequ equen ential code). ! If not valid, re-runs from the beginning, discarding changes. ! - ! Logging memory effects is expensive. ! ! Haskell already partitions the world into ! Realizing STM ! - immutable values (zillions and zillions) ! Haskell programmers brutally trained from - mutable locations (some or none) ! birth to use memory in ! Only need to log the latter! ! effects sparingly. ! ! Type system controls where I/O effects happen. ! Haskell ! ! Monad infrastructure ideal for constructing transactions & implicitly passing transaction log. ! ! Already paid the bill. Simply reading or writing a mutable location is expensive (involving a procedure call) so transaction overhead is not as large as in an imperative language. ! (&

  4. !!"!#"$%& newIORef :: a -> IO (IORef a) " readIORef :: IORef a -> IO a " writeIORef :: IORef a -> a -> IO () ! ! Consider a simple Haskell program: ! Recall that Haskell IO Monad functions newIORef , readIORef , and writeIORef manage mutable state. ! main = do { putStrLn (reverse “yes”); " ! putStrLn “no” } ! main = do { r <- newIORef 0; ! ! ! Effects are explicit in the type system. ! incR r; ! s <- readIORef r; ! (reverse “yes”) :: String — No effects ! print s } " (putStr “no” ) :: IO () — Effects okay ! incR :: IORef Int -> IO () ! ! Main program is a computation with effects. ! incR r = do { v <- readIORef r; ! writeRef r (v+1) } ! main :: IO () ! Reads and writes are 100% explicit. The type system disallows (r + 6) because r :: IORef Int . ! ! The forkIO function spawns a thread. ! ! Idea: add a function atomically that executes its argument computation atomically. ! ! It takes an IO action as its argument. ! forkIO :: IO () -> IO ThreadId ! atomically :: IO a -> IO a — almost ! main = do { r <- newIORef 0; ! main = do { ! forkIO (incR r); ! r <- newIORef 0; ! A race ! incR r; ! forkIO (atomically (incR r)); ! atomically (incR r); ! ... } ! ... } ! incR :: IORef Int -> IO () ! incR r = do { v <- readIORef r; ! Worry: What prevents using incR outside atomically , which writeIORef r (v+1) } ! would allow data races between code inside atomic and outside? ! ! Introduce a type for imperative transaction variables atomically :: STM a -> IO a " ( TVar ) and a new Monad ( STM ) to track transactions. ! newTVar :: a -> STM (TVar a) " readTVar :: TVar a -> STM a " ! Ensure TVars can only be modified in transactions. ! writeTVar :: TVar a -> a -> STM () ! ! Can’ t fiddle with TVars outside atomic block. [good] ! atomically :: STM a -> IO a " newTVar :: a -> STM (TVar a) " ! Can’ t do IO or manipulate regular imperative readTVar :: TVar a -> STM a " writeTVar :: TVar a -> a -> STM () ! variables inside atomic block. [sad, but also good] ! incT :: TVar Int -> STM () ! atomically (if x<y then launchMissiles) ! incT r = do { v <- readTVar r; ! ! ...and, best of all... ! writeTVar r (v+1) } ! main = do { r <- atomically (newTVar 0); ! forkIO (atomically (incT r)); ! atomically (incT r); ! ... } ! )&

Download Presentation
Download Policy: The content available on the website is offered to you 'AS IS' for your personal information and use only. It cannot be commercialized, licensed, or distributed on other websites without prior consent from the author. To download a presentation, simply click this link. If you encounter any difficulties during the download process, it's possible that the publisher has removed the file from their server.

Recommend


More recommend