IORefCAS 0.0.1 → 0.0.1.1
raw patch · 3 files changed
+134/−3 lines, 3 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
Files
- Data/CAS.hs +1/−1
- IORefCAS.cabal +6/−2
- README.md +127/−0
Data/CAS.hs view
@@ -1,7 +1,7 @@ {-# LANGUAGE MagicHash, UnboxedTuples, BangPatterns, MagicHash, TypeSynonymInstances, FlexibleInstances, MultiParamTypeClasses #-} --- | Atomic compare and swap for IORefs and CASRefs.+-- | Atomic compare and swap for IORefs and STRefs. module Data.CAS ( casSTRef, casIORef, atomicModifyIORefCAS, atomicModifyIORefCAS_,
IORefCAS.cabal view
@@ -1,5 +1,5 @@ Name: IORefCAS-Version: 0.0.1+Version: 0.0.1.1 License: BSD3 License-file: LICENSE Author: Adam C. Foltzer, Ryan Newton@@ -8,6 +8,10 @@ Build-type: Simple Cabal-version: >=1.8 +-- Version History:+-- 0.0.1 -- initial release+-- 0.0.1.1 -- minor bump to include README+ Synopsis: Atomic compare and swap for IORefs and CASRefs. Description:@@ -27,7 +31,7 @@ the interface in `Data.CAS.Class` is used. Extra-Source-Files:- Makefile, Test.hs+ Makefile, Test.hs, README.md Library exposed-modules: Data.CAS,
+ README.md view
@@ -0,0 +1,127 @@+See haddock in Data.CAS+++A few notes on performance results+==================================+++[2011.11.12] Initial Measurements+---------------------------------++ An initial round of tests gives the following results when executing+ 100K CAS's from each of four threads on a 3.33GHz Nehalem desktop:++ RAW Haskell CAS: 0.143s 25% productivity 58MB alloc, 204,693 successes+ 'Fake' CAS: 0.9s - 1.42s 89% productivity, 132M alloc, 104,044 successes+ Foreign CAS: 1.6s 23% productivity, 82M alloc, 264,821 successes++ "Successes" counts the total number of CAS operations that actually+ succeeded.++ This microbenchmark is spending a lot of its time in Gen 0 garbage collection.++ Next, a million CAS's per thread:++ RAW Haskell CAS: 0.65 - 1.0 20% productivity 406MB alloc (can stack overflow)+ 'Fake' CAS: 14.3 - 17s 270% CPU 92% productivity 1.3GB alloc 1,008,468 successes+ Foreign CAS: Stack overflow after 28.5s ... 300-390% CPU, 15% productivity, ++ After bumping the stack size up it takes a long+ time to finish, even after it has printed the+ sample success bit vectors.+ + With -K100M:+ 78s 6% productivity, 898M alloc, 3,324,943 successes+ 67 seconds elapsed in Gen 0 GC!!++ Something odd is going on here. How could it spend so long in GC+ for so little allocation?? For only two threads the Foreign+ implementation drops to 22s, but still 17.97s elapsed in Gen 0 GC.+ + What about the Raw haskell CAS? It also wil stack overflow with the+ current version of the test. With a 1G stack it can do 5Mx4 CAS's+ (8,9M successful) in 6.7 seconds. 10M in 17s. And STILL not seeing+ the previous segfault with the Raw CAS version...+ +[2011.11.12] Simple Stack Overflow Fix+--------------------------------------++ After making sure that all the (+1)'s in the test are strict, the+ stack overflow goes away and the numbers change (Raw does 5M in 3.3s+ instead of 6.7s). BUT there's still quite a lot of time spent in+ GC. Here's 1Mx4 CAS's again:+ + RAW Haskell CAS: 0.7s (23% prod, 0.8s total Gen 0 GC)+ 'Fake' CAS: 11.8s (91% prod, 0.8s total Gen 0 GC)+ Foreign CAS: 52s (6% prod)+ + And then adding -A1M makes a neglible change in runtime for Raw, but+ reduces the # of gen0 collections from 484 to 235.++ Ok, how about testing on a 3.1GHz Westmere.+ Wow, just ran into this:++ cc1: internal compiler error: Segmentation fault+ Please submit a full bug report,+ with preprocessed source if appropriate.+ See <http://bugzilla.redhat.com/bugzilla> for instructions.+ make: *** [all] Error 1++ On a different machine it worked (default runtime flags 1Mx4 CAS):++ RAW Haskell CAS: 0.7s + 'Fake' CAS: 8.1s+ Foreign CAS: 46s++ The lack of hyperthreading may also be helping.++ <TODO>: + The primary source of allocation in this example is the accumulation+ of the [Bool] lists of success and failure. I should disable those+ and test again.+++[2011.11.13] Testing specialized CAS.Foreign instance+-----------------------------------------------------++All of the above results were for a cell containing an Int. That+would not have triggered the specialized (Storable-based) instance in+Foreign.hs. There SHOULD be special cases for all word-sized scalars,+but currently there's just one for Word32. Let's test that one.++ Word32 1Mx4 CAS's:+ RAW Haskell CAS: 0.57s (13.7% prod)+ Foreign CAS: 0.64s (15% prod)++Wow, the foreign one is doing as well as the Haskell one even though+there's some extra silliness in the Foreign.CASRef type (causing a+runtime case dispatch to unpack).+++[2011.11.13] Testing atomicModify based on CAS+----------------------------------------------++An atomicModify based on CAS offers a drop-in replacement that could+improve performance. I implemented one which will try CAS until it+fails a certain number of times ("30" for now, but needs to be tuned).++These seem to work well. They are cheaper than you would think given+how long it takes to get successful CAS attempts under contention:++ 1Mx4 CAS attempts or atomicModifies:+ 0.19s -- CAS attempts 1.07M successful.+ 0.02s -- 1M atomicModifyIORefCAS on 1 thread+ 0.13s -- 1Mx2 atomicModifyIORefCAS on 2 threads+ 0.37s -- 1Mx4 atomicModifyIORefCAS on 4 threads++And they are cheaper than the real atomicModifyIORef (which also seems+to have a stack space problem right now because of its laziness). But+with a huge stack (1G) it will succeed:++ 1.27s -- 1Mx4 atomicModifyIORef++But inserting extra strictness (an evaluate call) to avoid the+stack-leak actually makes it slower:++ 2.08s -- 1Mx4 atomicModifyIORef, stricter+