leaky 0.1.7.0 → 0.2.0.0
raw patch · 15 files changed
+382/−203 lines, 15 filesdep +cpphsdep ~deepseq-boundeddep ~seqaiddep ~template-haskell
Dependencies added: cpphs
Dependency ranges changed: deepseq-bounded, seqaid, template-haskell
Files
- HTML/index.html +1/−1
- HTML/leaky.html +29/−21
- HTML/output.html +39/−31
- HTML/style.css +42/−1
- LICENSE +2/−2
- README +2/−2
- Types_explicit_SOP.hs +13/−22
- Types_no_SOP.hs +24/−22
- changelog.txt +6/−0
- deepseq-bounded-seqaid-leaky.css +34/−0
- deepseq-bounded-seqaid-leaky.html +89/−0
- leaky-full-incl-types.hs +15/−10
- leaky-full.hs +16/−10
- leaky.cabal +52/−69
- leaky.hs +18/−12
HTML/index.html view
@@ -1,4 +1,4 @@-<!DOCTYPE html>+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html> <head> <title>Leaky: Minimal robust Haskell space leak</title>
HTML/leaky.html view
@@ -1,4 +1,4 @@-<!DOCTYPE html>+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html> <head> <title>Leaky: Minimal robust Haskell space leak</title>@@ -26,11 +26,11 @@ <p> <em style="display: block; margin-left: 15px; margin-right: 100px;">-"[Writers of] compilers for lazy functional languages have been dealing with space leaks for more than 30 years and have developed a number of strategies to help.+“[Writers of] compilers for lazy functional languages have been dealing with space leaks for more than 30 years and have developed a number of strategies to help. ...-Despite all the improvements, space leaks remain a thorn in the side of lazy evaluation, producing a significant disadvantage to weigh against the benefits."+Despite all the improvements, space leaks remain a thorn in the side of lazy evaluation, producing a significant disadvantage to weigh against the benefits.” <p>-"Pinpointing space leaks is a skill that takes practice and perseverance. Better tools could significantly simplify the process."+“Pinpointing space leaks is a skill that takes practice and perseverance. Better tools could significantly simplify the process.” </em> <p>@@ -42,7 +42,14 @@ Such dire leaks can arise several times per week. <p>+<a id="r4"></a>+The problem stems from the lazy evaluation model of <span>Haskell <a href="#4">[4]</a></span>+which has been discussed at length elsewhere (see <a href="#Related">Related</a>). +<p>+<a id="dig01s" class="dig-toggle-show" href='javascript:toggle("dig01");'>Show</a>+<div id="dig01" class="digression">+<a id="dig01h" class="dig-toggle-hide" href='javascript:toggle("dig01");'>Hide</a><p style="margin-bottom: 0px;"> <a id="r3"></a> All space leak degrades performance, and production-quality programs should eradicate as much leak behaviour as <span>possible. <a href="#3">[3]</a></span> Difficulty ranges from distracting (minutes) to formidable (days, or worse).@@ -50,15 +57,9 @@ Understanding what's going on requires thinking about memory at a low level, and the abstractions involved are more complex than traditional block allocation. For space leak debugging, the current best practises constitute a black art. Leak behaviour is also extremely sensitive to build configuration (compiler version, and flags such as optimisation level).+</div> -<p> -<a id="r4"></a>-The problem stems from the lazy evaluation model of <span>Haskell <a href="#4">[4]</a></span>-which has been discussed at length elsewhere (see <a href="#Related">Related</a>).--<p>- <h3>What can we do?</h3> This situation seems pretty hopeless. Can anything be done?@@ -92,7 +93,7 @@ <h3>Show me a simple example of a program that leaks</h3> -The <a href="http://hackage.haskell.org/package/leaky">leaky</a> package contains a small Haskell 98 program known to leak even with -O2 optimisation under GHC 7.8.3.+The <a href="http://hackage.haskell.org/package/leaky">leaky</a> package contains a small Haskell 98 program known to leak even with -O2 optimisation under GHC 7.8.4 (and 7.10.1-rc1). It also contains build flavours which test some new tools (<a href="http://hackage.haskell.org/package/deepseq-bounded"><span class="nowrap">deepseq-bounded</span></a> and <a href="http://hackage.haskell.org/package/seqaid">seqaid</a>). Installing <tt>seqaid</tt> and running <tt>seqaid demo</tt> is a good way to get started experimenting with <tt>leaky</tt>. <!--Installing <a href="http://hackage.haskell.org/package/seqaid">seqaid</a> and running <tt>seqaid demo</tt> is a good way to get started experimenting with <a href="http://hackage.haskell.org/package/leaky">leaky</a>.-->@@ -101,7 +102,7 @@ <p> <div style="margin-top: -24px;"><a id="dig02s" class="dig-toggle-show" style="margin-left: 20px; border-top: 0px; margin-top: 6px; margin-bottom: 6px;" href='javascript:toggle("dig02");'>Show</a></div> <div id="dig02" class="digression" style="margin-left: 20px; border-top: 0px; margin-top: 6px; margin-bottom: 12px;">-<a id="dig02h" class="dig-toggle-hide" href='javascript:toggle("dig02");'>Hide</a><p>+<a id="dig02h" class="dig-toggle-hide" href='javascript:toggle("dig02");'>Hide</a><p style="margin-bottom: 0px;"> !--div style="font-size: 12pt; margin: 45px 20% 35px 20px;"-- The purpose of this wiki page is to help ensure that a space leak example which actually leaks is always available. The maintainer of the <a href="http://hackage.haskell.org/package/leaky">leaky</a> package is committed to its good upkeep, so a working example leak should always be there, based on the most current information collected here.@@ -125,7 +126,8 @@ <!--a href="code.html" style="margin-left: 30px;">leaky-min-cppd.hs</a--> <pre style="width: 800px;"> - -- This leaks with GHC 7.8.3 -O2, strict field notwithstanding.+ -- This leaks with GHC 7.8.4 -O2, strict field notwithstanding.+ -- (Indeed it leaks with GHC 7.10.1-rc1 -O2.) duration = 5000000 -- XXX tune for your hardware period = duration `div` 10@@ -152,15 +154,17 @@ And here is the same program with some extras to tinker with. <p>-<a id="dig01s" class="dig-toggle-show" href='javascript:toggle("dig01");'>Show</a>-<div id="dig01" class="digression">-<a id="dig01h" class="dig-toggle-hide" href='javascript:toggle("dig01");'>Hide</a><p>+<a id="dig02s" class="dig-toggle-show" href='javascript:toggle("dig02");'>Show</a>+<div id="dig02" class="digression">+<a id="dig02h" class="dig-toggle-hide" href='javascript:toggle("dig02");'>Hide</a><p style="margin-bottom: 0px;"> <!--div style="margin-top: 20px;"--> <!--a href="code.html" style="margin-left: 30px;">leaky-min.hs</a--> <pre style="width: 800px;"> ------------------------------------------------------------------------------- +-- You will want to compile this <b>-with-rtsopts=-T</b> for STATS to work.+ -- So, with the following configuration, -O2 is smart enough -- to produce the correct Bool output, without seeming to -- do any work. (But not with -O0 or even with -O.)@@ -227,7 +231,7 @@ duration = 5000000 -- XXX tune for your hardware report_period = duration `div` 10---report_period = 500000 -- GHC 7.8.3 -O2 is two smart (when STATS=0)+--report_period = 500000 -- GHC 7.8.* -O2 is two smart (when STATS=0) ------------------------------------------------------------------------------- @@ -291,7 +295,7 @@ let new_total_bytes_allocated = last_total_bytes_allocated #if ! NO_PERIODIC_BRANCH if 0 == i `mod` report_period--- if 0 == i `mod` 2 -- GHC 7.8.3 -O2 is two smart+-- if 0 == i `mod` 2 -- GHC 7.8.* -O2 is two smart then do -- putStrLn "." -- unnecessary return ()@@ -314,11 +318,11 @@ </div> <p>-These and other variants are available in the <tt>leaky</tt> source package.+These and other variants are available in the <a href="http://hackage.haskell.org/package/leaky">leaky</a> source package. <h3>Explanation of Output</h3> -If you actually build the <tt>leaky</tt> package with Cabal, the version built is further elaborated, and demonstrates <tt>seqaid</tt>.+When the <tt>leaky</tt> package is built with Cabal, the version built is further elaborated, and demonstrates <tt>seqaid</tt>. The output is <a href="output.html">discussed here</a>. <!--@@ -473,6 +477,10 @@ <li><a href="https://www.haskell.org/haskellwiki/Performance/Data_types"> Data types</a> </ul>++<div class="comments" onclick="javascript:document.location.href = 'http://www.reddit.com/r/haskell/comments/2pscxh/ann_deepseqbounded_seqaid_leaky/';">+<a href="http://www.reddit.com/r/haskell/comments/2pscxh/ann_deepseqbounded_seqaid_leaky/"><b>Discussion</b></a><br /><span style="font-size: 60%;"><a style="display: inline-block; color: black; position: relative; top: -8px; href="http://www.reddit.com/r/haskell/comments/2pscxh/ann_deepseqbounded_seqaid_leaky/">(reddit) </a></span>+</div> <div class="footer"> Andrew Seniuk 2014
HTML/output.html view
@@ -1,4 +1,4 @@-<!DOCTYPE html>+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html> <head> <title>Leaky : Output Under Seqaid</title>@@ -6,6 +6,9 @@ <meta http-equiv="Pragma" content="no-cache" /> <meta http-equiv="Expires" content="0" /> <link rel="stylesheet" href="style.css" />+<style>+tt { background: transparent; }+</style> </head> <body> <!--body style="width: 800px;"-->@@ -16,43 +19,48 @@ Output of <tt>leaky</tt> as instrumented with <tt>seqaid</tt> </h3> -The following shows the output of <a href="http://hackage.haskell.org/package/seqaid"><tt>seqaid</tt></a> with <a href="http://hackage.haskell.org/package/leaky"><tt>leaky</tt></a>.-You would see something close to this if you ran <tt>leaky</tt> with default configuration.-It is a wee bit contrived, as I sweep <a href="http://hackage.haskell.org/package/deepseq-bounded/docs/Control-DeepSeq-Bounded-NFDataN.html"><tt>NFDataN</tt></a> <tt><em>N</em></tt> value to a fixed depth, and then the fixed (hand-optimised) <a href="http://hackage.haskell.org/package/deepseq-bounded/docs/Control-DeepSeq-Bounded-Pattern.html"><tt>Pattern</tt></a> is developed by replaying iterated <a href="https://hackage.haskell.org/package/deepseq-bounded/docs/Control-DeepSeq-Bounded-PatAlg.html#v:shrinkPat"><tt>shrinkPat</tt></a> in reverse.-But it does illustrate the sorts of effects possible, once <tt>seqaid</tt> has an optimiser.+The following shows the output of <a href="http://hackage.haskell.org/package/seqaid"><tt class="virgin">seqaid</tt></a> with <a href="http://hackage.haskell.org/package/leaky"><tt class="virgin">leaky</tt></a>.+You would see something close to this if you ran <tt class="virgin">leaky</tt> with default configuration.+It is a wee bit contrived, as I sweep <a href="http://hackage.haskell.org/package/deepseq-bounded/docs/Control-DeepSeq-Bounded-NFDataN.html"><tt class="virgin">NFDataN</tt></a> <tt class="virgin"><em>N</em></tt> value to a fixed depth, and then the fixed (hand-optimised) <a href="http://hackage.haskell.org/package/deepseq-bounded/docs/Control-DeepSeq-Bounded-Pattern.html"><tt class="virgin">Pattern</tt></a> is developed by replaying iterated <a href="https://hackage.haskell.org/package/deepseq-bounded/docs/Control-DeepSeq-Bounded-PatUtil.html#v:shrinkPat"><tt class="virgin">shrinkPat</tt></a> in reverse.+But it does illustrate the sorts of effects possible, once <tt class="virgin">seqaid</tt> has an optimiser. -<p>-Using <tt>NFDataN.forcen <em>N</em></tt>:+<p style="margin-top: 35px;">+Using <tt class="virgin">NFDataN.forcen <em>N</em></tt> <pre>- live alloc type- N 0 357828 3350236 TA- N 1 686376 3316512 TA- N 2 909104 4942636 TA- N 3 1121052 4979364 TA- N 4 1301872 5560432 TA- N 5 1609760 53440684 TA- N 6 151460 54431296 TA- N 7 139240 53374284 TA- N 8 129440 53405380 TA+ live alloc type+ N 0 357828 3350236 TA+ N 1 686376 3316512 TA+ N 2 909104 4942636 TA+ N 3 1121052 4979364 TA+ N 4 1301872 5560432 TA+ N 5 1609760 53440684 TA+ N 6 151460 54431296 TA+ N 7 139240 53374284 TA+ N 8 129440 53405380 TA </pre> <p>-Using <tt>NFDataP.forcep <em>P</em></tt>:-<pre>- live alloc type- P . 457296 3341600 TA- P .{...} 698872 5220200 TA- P .{.{...}..} 954252 6063164 TA- P .{.{...{.}}..} 1243156 6572740 TA- P .{.{...{.{.#..}}}..{..}} 1452016 8829248 TA- P .{.{..{.}.{.{.{.}#..{.}}}}..{..{.}}} 319744 10577588 TA- P .{.{..{.}.{.{.{.}#..{.}}}}..{..{.}}} 159284 8870360 TA- P .{.{..{.}.{.{.{.}#..{.}}}}..{..{.}}} 150004 8826904 TA- P .{.{..{.}.{.{.{.}#..{.}}}}..{..{.}}} 190012 8748076 TA- P .{.{..{.}.{.{.{.}#..{.}}}}..{..{.}}} 128232 8867404 TA+Using <tt class="virgin">NFDataP.forcep <em>P</em></tt>:+<pre style="margin-bottom: 0px;">+ live alloc type+ P . 227756 1769792 TA+ P <span style="color: #BBB;">(</span>. .. <span style="color: #BBB;">)</span> 296620 3060904 TA+ P <span style="color: #BBB;">(</span>(.. . ).. <span style="color: #BBB;">)</span> 360508 4908612 TA+ P <span style="color: #BBB;">(</span>(.. (. )).. <span style="color: #BBB;">)</span> 421472 5852124 TA+ P <span style="color: #BBB;">(</span>(.. ((. ... ))).(.. )<span style="color: #BBB;">)</span> 521860 9556760 TA+ P <span style="color: #BBB;">(</span>(.(.)(((.)..(.)))).(.(.))<span style="color: #BBB;">)</span> 607100 11270660 TA+ P <span style="color: #BBB;">(</span>(!(!)(((!).!(!))))!(!(!))<span style="color: #BBB;">)</span> 1925776 2392040 TA+ P <span style="color: #BBB;">(</span>(!(!)(((!).!(!))))!(!(!))<span style="color: #BBB;">)</span> 1529652 10297768 TA+ P <span style="color: #BBB;">(</span>(!(!)(((!).!(!))))!(!(!))<span style="color: #BBB;">)</span> 1249900 2393836 TA+ P <span style="color: #BBB;">(</span>(!(!)(((!).!(!))))!(!(!))<span style="color: #BBB;">)</span> 690336 13244056 TA+ P <span style="color: #BBB;">(</span>(!(!)(((!).!(!))))!(!(!))<span style="color: #BBB;">)</span> 212580 13974556 TA+ P <span style="color: #BBB;">(</span>(!(!)(((!).!(!))))!(!(!))<span style="color: #BBB;">)</span> 216936 11284560 TA </pre> <p>-A few comments are in order:+A sort of <a href="http://www.fremissant.net/seqaid/extra2.html">commentary</a> on the change history is on a separate page.++<h3 style="margin-top: 40px;">Remarks</h3>+ <ul> <li>You can see the space leak as a steady, substantial growth in the heap size, from <tt><em>N</em></tt> equal 0 through 5, and again in the first five pattern lines. <li>You can see the first large, strict blobs get hit at a depth of 5 (with <tt>forcen</tt>).
HTML/style.css view
@@ -1,6 +1,10 @@-pre { font-size: 12pt; margin-left: 20px; padding-left: 10px; padding-right: 10px; padding-top: 10px; padding-bottom: 10px; background-color: #DDD; }++pre { font-size: 12pt; margin-left: 20px; padding-left: 10px; padding-right: 10px; padding-top: 10px; padding-bottom: 10px; background-color: rgba(230,230,230,1.0); }+pre.virgin { padding-left: 0px; padding-right: 0px; font-size: 85%; background-color: transparent; margin-top: 0px; margin-bottom: 0px; } tt { padding-left: 2px; padding-right: 2px; font-size: 85%; background-color: rgba(220,220,220,0.5); } tt.virgin { padding-left: 0px; padding-right: 0px; font-size: 85%; background-color: transparent; }+div.digression > tt { padding-left: 0px; padding-right: 0px; font-size: 85%; background-color: transparent; }+div.digression > p > tt { padding-left: 0px; padding-right: 0px; font-size: 85%; background-color: transparent; } /* Works, but not nicely: red { color: #f00; } */@@ -15,6 +19,11 @@ h2 { margin-top: 30px; color: #777; } h3 { margin-top: 30px; color: #444; } h4 { margin-top: 40px; color: #222; }+a:visited { color: #7700BB; } /* visited link */+a:hover { color: #BB00BB; } /* mouse over link */+a:active { color: #7700BB; } /* selected link */+a.comments:link { color: #0000BB; } /* unvisited link */+div.comments { cursor: hand; text-align: center; display: inline-block; padding-left: 12px; padding-right: 12px; padding-top: 8px; padding-bottom: 0px; background-color: #CDE; cursor: pointer; font-family: sans; font-size: 90%; margin-top: 30px; margin-left: 10px; } div.footer { font-family: sans; font-size: 70%; margin-top: 40px; } div.footer > tt { font-size: 90%; } /*@@ -27,3 +36,35 @@ td { text-align: top; vertical-align: top; padding-left: 8px; padding-top: 16px; } li { margin-top: 4px; } .nowrap { white-space: nowrap; }+.cmnt { color: #888; }+.dcmnt { color: #555; }+hr.hrule {+/* Thanks to http://css-tricks.com/examples/hrs/ */+ border: 0;+ height: 1px;+ background: #333;+ background-image: -webkit-linear-gradient(left, #ccc, #333, #ccc); + background-image: -moz-linear-gradient(left, #ccc, #333, #ccc); + background-image: -ms-linear-gradient(left, #ccc, #333, #ccc); + background-image: -o-linear-gradient(left, #ccc, #333, #ccc); + margin: 50px 0 5px 0;+}+/* Thanks to SO answer of daGUY in http://stackoverflow.com/questions/2539207/ho+w-to-change-the-strike-out-line-through-thickness-in-css */+.strikeout {+ position: relative;+ padding-left: 3pt;+ padding-right: 3pt;+}+.strikeout::after {+ border-bottom: 2px solid #C33;+ content: "";+ left: 0;+ position: absolute;+ right: 0;+ top: 50%;+}+.grey { color: #BBB; letter-spacing: -4px; }++tt { background: transparent; }+
LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) 2014, Andrew Seniuk+Copyright (c) 2014-2015, Andrew G. Seniuk All rights reserved. @@ -13,7 +13,7 @@ disclaimer in the documentation and/or other materials provided with the distribution. - * Neither the name of Andrew Seniuk nor the names of other+ * Neither the name of Andrew G. Seniuk nor the names of other contributors may be used to endorse or promote products derived from this software without specific prior written permission.
README view
@@ -26,7 +26,7 @@ Run by supplying a seed for the random number generator: - > ./dist/build/leaky/leaky 123+ > ./dist/build/leaky/leaky 234 Or you may prefer to build in a sandbox:@@ -39,7 +39,7 @@ And to run: - > ./.cabal-sandbox/bin/leaky 123+ > ./.cabal-sandbox/bin/leaky 234 NOTE: If you don't build with Cabal, you will need to
Types_explicit_SOP.hs view
@@ -63,8 +63,6 @@ import System.Random - import Data.List ( foldl' )- import Debug.Trace ( trace ) #if 0@@ -81,15 +79,18 @@ type State = TA - doWork :: Num a => Blob a -> a- doWork (Blob lst) = foldl' (+) 0 lst-- data Blob a = Blob [a]- deriving (Show,Generic,Typeable,Data)-+ -- This is behaviourally a "strict blob", within the diagnostic+ -- purposes of leaky. It incurs a large, constant cost when+ -- the head is evaluated. This is also a reasonable model+ -- for function application (except then the cost is usually+ -- a function of argument values). [?]+ data Blob a = Blob [a] deriving (Show,Generic,Typeable,Data) instance (NFData a,Num a) => NFData (Blob a) where rnf x = force (doWork x) `seq` () instance (NFData a,Num a) => NFDataN (Blob a) where rnfn n x = force (doWork x) `seq` () instance (NFData a,Num a,Typeable a) => NFDataP (Blob a) where rnfp p x = force (doWork x) `seq` ()+ doWork :: Num a => Blob a -> a+ doWork (Blob lst) = sum lst+--doWork (Blob lst) = sum lst :: Num a => a -- XXX Why exactly is this needed, when it wasn't needed when -- everything was in one module??...@@ -105,6 +106,7 @@ #endif #if 1+ -- (No strict fields.) data TA = A1 Int | A2 TB Int TC data TB = B1 | B2 TC | B3 Int TA TB@@ -115,7 +117,9 @@ #else data TC = C1 Int TC | C2 Int | C3 TC ![Int] TC #endif+ #else+ -- All Int fields strict (!): data TA = A1 !Int | A2 TB !Int TC data TB = B1 | B2 TC | B3 !Int TA TB@@ -126,6 +130,7 @@ #else data TC = C1 !Int TC | C2 !Int | C3 TC ![Int] TC #endif+ #endif deriving instance Show TA@@ -150,20 +155,6 @@ instance NFDataP TC where rnfp = grnfp instance NFDataN TC where rnfn = grnfn instance NFData TC where rnf = genericRnf--#if FORCING_STRATEGY >= 5- -- LATER: XXX Exactly the opposite is true now; I have- -- switched off the use of -fplugin-opt= flags, and am- -- opting for the seqaidTH splice meta-call to signal- -- to the plugin (via presence of SeqaidAnnIncludeList- -- annotation) that the module is to be processed.- -- If you leave this splice active, you get an error,- -- at the present time (that's the reason for USE_SECOND_MODULE).- ------- -- No need to comment this out when not in use; the TH code knows- -- if the plugin is slated to run on a module or not.---seqaidTH-#endif deriveGeneric ''TA deriveGeneric ''TB
Types_no_SOP.hs view
@@ -12,6 +12,11 @@ ------------------------------------------------------------------------------- +-- For certain kinds of debugging, esp. of deepseq-bounded...+#define REQUIRE_DATA_INSTANCE 0++-------------------------------------------------------------------------------+ module Types_no_SOP where import Control.DeepSeq.Bounded@@ -24,9 +29,6 @@ import System.Random - import Data.List ( foldl' )-- #if 0 #if FORCING_STRATEGY == 4 import Seqaid.Runtime ( seqaid )@@ -41,15 +43,22 @@ type State = TA - doWork :: Num a => Blob a -> a- doWork (Blob lst) = foldl' (+) 0 lst-- data Blob a = Blob [a]- deriving (Show,Generic,Typeable,Data)-+ -- This is behaviourally a "strict blob", within the diagnostic+ -- purposes of leaky. It incurs a large, constant cost when+ -- the head is evaluated. This is also a reasonable model+ -- for function application (except then the cost is usually+ -- a function of argument values). [?]+ data Blob a = Blob [a] deriving (Show,Generic,Typeable,Data) instance (NFData a,Num a) => NFData (Blob a) where rnf x = force (doWork x) `seq` () instance (NFData a,Num a) => NFDataN (Blob a) where rnfn n x = force (doWork x) `seq` ()+#if REQUIRE_DATA_INSTANCE+ instance (NFData a,Num a,Typeable a,Data a) => NFDataP (Blob a) where rnfp p x = force (doWork x) `seq` ()+#else instance (NFData a,Num a,Typeable a) => NFDataP (Blob a) where rnfp p x = force (doWork x) `seq` ()+#endif+ doWork :: Num a => Blob a -> a+ doWork (Blob lst) = sum lst+--doWork (Blob lst) = sum lst :: Num a => a -- XXX Why exactly is this needed, when it wasn't needed when -- everything was in one module??...@@ -59,12 +68,16 @@ hackblah = getStdGen #else deriving instance Typeable StdGen+#if REQUIRE_DATA_INSTANCE+ instance Data StdGen -- only for certain deepseq-bounded debugging+#endif instance NFData StdGen where rnf x = () instance NFDataN StdGen where rnfn n x = () instance NFDataP StdGen where rnfp p x = () #endif #if 1+ -- (No strict fields.) data TA = A1 Int | A2 TB Int TC data TB = B1 | B2 TC | B3 Int TA TB@@ -75,7 +88,9 @@ #else data TC = C1 Int TC | C2 Int | C3 TC ![Int] TC #endif+ #else+ -- All Int fields strict (!): data TA = A1 !Int | A2 TB !Int TC data TB = B1 | B2 TC | B3 !Int TA TB@@ -86,20 +101,7 @@ #else data TC = C1 !Int TC | C2 !Int | C3 TC ![Int] TC #endif-#endif -#if FORCING_STRATEGY >= 5- -- LATER: XXX Exactly the opposite is true now; I have- -- switched off the use of -fplugin-opt= flags, and am- -- opting for the seqaidTH splice meta-call to signal- -- to the plugin (via presence of SeqaidAnnIncludeList- -- annotation) that the module is to be processed.- -- If you leave this splice active, you get an error,- -- at the present time (that's the reason for USE_SECOND_MODULE).- ------- -- No need to comment this out when not in use; the TH code knows- -- if the plugin is slated to run on a module or not.---seqaidTH #endif -------------------------------------------------------------------------------
+ changelog.txt view
@@ -0,0 +1,6 @@++0.1.7.0 -> 0.2.0.0+ - deepseq-bounded had a major version bump+ - fixed cpphs missing dependency for seqaid (also affects this package)+ - more...+
+ deepseq-bounded-seqaid-leaky.css view
@@ -0,0 +1,34 @@++pre { font-size: 14pt; margin-left: 20px; padding-left: 10px; padding-right: 10px; padding-top: 10px; padding-bottom: 10px; background-color: rgba(230,230,230,1.0); }+tt { padding-left: 2px; padding-right: 2px; font-size: 100%; background-color: rgba(220,220,220,0.5); }+tt.virgin { padding-left: 0px; padding-right: 0px; font-size: 100%; background-color: transparent; }+/* Works, but not nicely:+red { color: #f00; }+*/+.red { color: #f00; }+div.outdated { display: inline-block; padding-left: 2px; padding-right: 2px; padding-top: 2px; font-size: 80%; background-color: #EEC; }+div.digression { display: none; padding: 8px 8px 8px 8px; font-size: 80%; background-color: #EDD; }+div.digression-closed { display: inline-block; padding: 8px 8px 8px 8px; font-size: 80%; background-color: #EDD; }+.dig-toggle-show { outline: 0; text-decoration: none; color: #33E; display: inline-block; padding: 8px 8px 8px 8px; font-size: 11pt; background-color: #EDD; }+.dig-toggle-hide { outline: 0; text-decoration: none; color: #33E; display: inline-block; padding: 0px 0px 4px 0px; font-size: 11pt; background-color: #EDD; }+a { text-decoration: none; }+div.main { font-size: 16pt; margin-left: 10px; margin-right: 100px; margin-bottom: 40px; }+h2 { margin-top: 30px; color: #777; }+h3 { margin-top: 30px; color: #444; }+h4 { margin-top: 40px; color: #222; }+div.comments { font-family: sans; font-size: 80%; margin-top: 40px; }+div.footer { font-family: sans; font-size: 80%; margin-top: 40px; }+div.footer > tt { font-size: 90%; }+/*+table.table { text-align: top; vertical-align: top; }+table.table > tr { text-align: top; vertical-align: top; }+table.table > tr > td { text-align: top; vertical-align: top; }+*/+/* table { border-collapse: collapse; } */+tr { text-align: top; vertical-align: top; }+td { text-align: top; vertical-align: top; padding-left: 8px; padding-top: 16px; }+li { margin-top: 4px; }+.nowrap { white-space: nowrap; }++tt { background: transparent; }+
+ deepseq-bounded-seqaid-leaky.html view
@@ -0,0 +1,89 @@+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">+<html>+<head>+<title>Seqaid : Space leak diagnostic and remedial tool</title>+<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />+<meta http-equiv="Pragma" content="no-cache" />+<meta http-equiv="Expires" content="0" />+<link rel="stylesheet" href="deepseq-bounded-seqaid-leaky.css" />+</head>+<body>+<!--body style="width: 800px;"-->++<div class="main">++<h2 style="margin-top: 50px; color: #555;">deepseq-bounded, seqaid, leaky</h2>++This trio of related packages explores strictness control in a variety of ways.++<p>+<a href="http://www.fremissant.net/deepseq-bounded">deepseq-bounded</a> provides classes and generic functions to artificially force evaluation, to extents controlled by static or dynamic configuration.++<p>+<a href="http://www.fremissant.net/seqaid">seqaid</a> puts that into practise, providing a GHC plugin to auto-instrument your package with a strictness harness, which is dynamically optimisable during runtime.+This is supported directly in the GHC compilation pipeline, without requiring (or performing!) any edits to your sources.++<p>+<a href="http://www.fremissant.net/leaky">leaky</a> is a minimal, prototypic executable that leaks space under current <span class="nowrap">state-of-the-art</span> compilation (even with <span class="nowrap">-O2 GHC <a href="https://downloads.haskell.org/~ghc/7.10.1-rc1/">7.10.1-rc1</a></span>; but certainly <span class="nowrap">with -O2 GHC 7.8.*</span>).++<p>+On hackage.haskell.org:+<ul>+<li> <a href="https://hackage.haskell.org/package/deepseq-bounded">deepseq-bounded</a>+<li> <a href="https://hackage.haskell.org/package/seqaid">seqaid</a>+<li> <a href="https://hackage.haskell.org/package/leaky">leaky</a>+</ul>++<p>+I've started a <a href="http://www.reddit.com/r/haskell/comments/2pscxh/ann_deepseqbounded_seqaid_leaky/">reddit discussion</a> page for the three together.++<p>+Easiest way to try them all, is to install seqaid and run the demo:++<pre>+ cabal install seqaid+ seqaid demo+</pre>++<p>+This tests seqaid on a local copy of the leaky source package.++<p>+It turned out to be routine to extend deepseq-bounded and seqaid to dynamically configurable parallelisation (paraid?).+Many other wrappers could be explored, too!+Maybe seqaid should be renamed to koolaid or something...++<p>+It's a pretty complicated system, and just first release, so there's bound to be lots of problems.+For now, any issues or comments can be directed to the reddit page (or private email).+There's also the list announcement threads on <tt>haskell-cafe</tt> and <tt>glasgow-haskell-users</tt> for general discussion, and on <tt>ghc-devs</tt> for technical.+I'll maintain a <a href="http://www.fremissant.net/seqaid/trac">casual list</a> of bugs and feature requests, and will set up a proper tracker if there's interest.++<div class="footer" style="margin-top: 40px;">+Andrew Seniuk 2014+<br>+<tt>rasfar@gmail.com</tt>+</div>++</div>++<script language="javascript">+function toggle(id1){+ var ele_s = document.getElementById(id1+"s");+ var ele_h = document.getElementById(id1+"h");+ var ele = document.getElementById(id1);+ if( ele.style.display == "inline-block" ){+ ele.style.display = "none";+ ele_s.style.display = "inline-block";+ ele_h.style.display = "none";+ }else{+ ele.style.display = "inline-block";+ ele_s.style.display = "none";+ ele_h.style.display = "block";+ }+}+</script>++</body>+</html>+
leaky-full-incl-types.hs view
@@ -377,21 +377,26 @@ -- (Only referenced when FORCING_STRATEGY=3.) #if FORCING_STRATEGY == 3 #if USE_STRICT_BLOB- let pat = compilePat ".{.{..{.}.{.{.{.}#..{.}}}}..{..{.}}}"--- let pat = compilePat ".{.{..{.}.{.{.{.}...{.}}}}..{..{.}}}"+#if 1+ let pat | deepseq_bounded_flag__new_improved_pattern_grammar+ = compilePat "((!(!)(((!).!(!))))!(!(!)))"+ | otherwise+ = compilePat "!(!(!!(!)!(!(!(!).!!(!))))!!(!!(!)))"+--- = compilePat "!(!(!!(!)!(!(!(!)!!!(!))))!!(!!(!)))" #else-#if 0-#elif 1- let pat = mkPat state -- identical to the explicit pattern below-#elif 0- let pat = compilePat ".{.{..{.}.{.{.{.}..{.}}}}..{..{.}}}"-#elif 0- let pat = compilePat "*" -- should be (is) equivalent to rnf+#if NEW_IMPROVED_PATTERN_GRAMMAR+ let pat = compilePat "((!(!)(((!).!(!))))!(!(!)))"+#else+ let pat = compilePat "!(!(!!(!)!(!(!(!).!!(!))))!!(!!(!)))"+-- let pat = compilePat "!(!(!!(!)!(!(!(!)!!!(!))))!!(!!(!)))" #endif #endif+#else+ let pat = mkPat state -- identical to the explicit pattern below+#endif putStrLn $ showPat pat #else- let pat = compilePat "#"+ let pat = emptyPat #endif #if USE_GROWING_LIST
leaky-full.hs view
@@ -328,21 +328,27 @@ -- (Only referenced when FORCING_STRATEGY=3.) #if FORCING_STRATEGY == 3 #if USE_STRICT_BLOB- let pat = compilePat ".{.{..{.}.{.{.{.}#..{.}}}}..{..{.}}}"--- let pat = compilePat ".{.{..{.}.{.{.{.}...{.}}}}..{..{.}}}"+#if 1+ let pat | deepseq_bounded_flag__new_improved_pattern_grammar+ = compilePat "((!(!)(((!).!(!))))!(!(!)))"+ | otherwise+ = compilePat "!(!(!!(!)!(!(!(!).!!(!))))!!(!!(!)))"+--- = compilePat "!(!(!!(!)!(!(!(!)!!!(!))))!!(!!(!)))" #else-#if 0-#elif 1- let pat = mkPat state -- identical to the explicit pattern below-#elif 0- let pat = compilePat ".{.{..{.}.{.{.{.}..{.}}}}..{..{.}}}"-#elif 0- let pat = compilePat "*" -- should be (is) equivalent to rnf+#if NEW_IMPROVED_PATTERN_GRAMMAR+ let pat = compilePat "((!(!)(((!).!(!))))!(!(!)))"+#else+ let pat = compilePat "!(!(!!(!)!(!(!(!).!!(!))))!!(!!(!)))"+-- let pat = compilePat "!(!(!!(!)!(!(!(!)!!!(!))))!!(!!(!)))" #endif #endif+#else+-- XXX untested for a long time+ let pat = mkPat state+#endif putStrLn $ showPat pat #else- let pat = compilePat "#"+ let pat = emptyPat #endif #if STATS
leaky.cabal view
@@ -1,30 +1,46 @@ name: leaky-version: 0.1.7.0+version: 0.2.0.0 synopsis: Robust space leak, and its strictification-description: Robust space leak, and its strictification, for testing <http://hackage.haskell.org/package/deepseq-bounded deepseq-bounded> and <http://hackage.haskell.org/package/seqaid seqaid>.- .- See also the project <http://www.fremissant.net/leaky homepage> for more information.- .- Please share your comments on this <http://www.reddit.com/r/haskell/comments/2pscxh/ann_deepseqbounded_seqaid_leaky/ reddit> discussion.-homepage: http://www.fremissant.net/leaky license: BSD3 license-file: LICENSE author: Andrew G. Seniuk maintainer: Andrew Seniuk <rasfar@gmail.com>+homepage: http://fremissant.net/leaky bug-reports: http://fremissant.net/leaky/trac ---bug-reports: Andrew Seniuk <rasfar@gmail.com> category: Testing build-type: Simple+stability: experimental cabal-version: >=1.10-tested-with: GHC==7.8.1, GHC==7.8.3---tested-with: GHC==7.6.3, GHC==7.8.1, GHC==7.8.3 +-- However, seqaid requires GHC>=7.8.+--+-- As for 7.10.1-rc1, latest cabal-install seemingly+-- cannot interoperate with it; but you can compile+-- leaky-min.hs at least, which still leaks -O2.+tested-with:+-- , GHC==7.6.3+ GHC==7.6.3+ , GHC==7.8.1+ , GHC==7.8.3+ , GHC==7.8.4+ , GHC==7.10.1-rc1++description: Robust space leak, and its strictification, for testing <http://hackage.haskell.org/package/deepseq-bounded deepseq-bounded> and <http://hackage.haskell.org/package/seqaid seqaid>.+ .+ See also the project <http://www.fremissant.net/leaky homepage> for more information.+ .+ Please share your comments on this <http://www.reddit.com/r/haskell/comments/2pscxh/ann_deepseqbounded_seqaid_leaky/ reddit> discussion.+ extra-source-files: README+ , changelog.txt , HTML/*.html , HTML/*.css+ , deepseq-bounded-seqaid-leaky.html+ , deepseq-bounded-seqaid-leaky.css , rough-fs-twiddling-guide.txt , leaky-full.hs@@ -54,6 +70,10 @@ -- XXX Would be nice if could avoid the TH when FORCING_STRATEGY < 4. +Flag HELLO_HACKAGE_VISITOR+ Description: [Note to those reading on Hackage:] Please ignore these flags, which would be better presented in a collapsed state. The flags are mostly for development purposes.+ Default: False+ Flag TURN_ON_SEQAID_PLUGIN Description: Only when True, provide the options to enable the seqaid preprocessor and GHC plugin. Default: True@@ -75,7 +95,7 @@ --Default: False Flag USING_SANDBOX- Description: I use them, but it's not default because it makes for much longer initial build, as all the dependencies (except base libs) need first to be installed (into the sandbox).+ Description: I use them, but it's not default because it makes for much longer initial build, as all the dependencies (except base libs) need first to be installed into the sandbox. --Default: True Default: False @@ -86,8 +106,8 @@ Flag PROFILE Description: Enable profiling- Default: True---Default: False+--Default: True+ Default: False Flag USE_GROWING_LIST Description: The problem with using a growing list is, it itself is a leak (as it were), so it's hard to see you've plugged anything. However, the slowdown of "force" relative to "forcep" will be noticed! Alternative to GROWING is FIXED (is at length 10000 at the moment). Fixed list is infinite if INFINITE set below. (INFINITE has no effect when GROWING set.)@@ -119,24 +139,19 @@ executable leaky + build-tools: cpphs+ main-is: leaky.hs --main-is: leaky-min.hs --main-is: leaky-min-cppd.hs---leaky-pris.hs contains just the maladies.---leaky.hs contains these, and remedies as well.---leaky-no-let-without-in.hs is due to a bug in GHC HsExpr Outputable----main-is: leaky-pris.hs----main-is: leaky-no-let-without-in.hs --- -- XXX Get rid of this Temp one soon (just a wee experiment)!...--- other-modules: Temp- other-modules: Types_no_SOP , Types_explicit_SOP build-depends: base == 4.*+ , cpphs > 1.14 , random == 1.1 ---------- BEGIN SEQAID-SPECIFIC -- PART 1 of 2 ----------@@ -148,18 +163,19 @@ build-depends: - deepseq-bounded == 0.5.*+ deepseq-bounded == 0.6.* , deepseq-generics == 0.1.*- , generics-sop == 0.1.*- , template-haskell == 2.9.*+ , template-haskell+-- , template-haskell == 2.9.* -- XXX this is no good !! (co-evolving packages) -- I guess the best is to leave it unconstrained...--- , seqaid == 0.1.7.*+ , seqaid == 0.2.0.0+-- , seqaid == 0.2.* -- Hopefully this will simply install the latest one, -- which ought to be fine:- , seqaid+-- , seqaid if flag(OMNITYPIC) build-depends:@@ -177,6 +193,8 @@ if flag(PROFILE) ghc-options: -fprof-auto -auto-all -caf-all + ghc-options: -pgmPcpphs -optP--cpp+ ---------- BEGIN SEQAID-SPECIFIC -- PART 2 of 2 ---------- if flag(TURN_ON_SEQAID_PLUGIN)@@ -191,20 +209,15 @@ if flag(OMNITYPIC) ghc-options: -optF omnitypic - -- Cabal (1.20) says that we should use "extensions: TemplateHaskell",- -- which it then complains is deprecated -- but we'd really rather just- -- give -XTemplateHaskell to GHC along with the other plugin-related- -- options, in a compact group: -- ghc-options: -XTemplateHaskell default-extensions: TemplateHaskell -- other-extensions: TemplateHaskell -- extensions: TemplateHaskell --- We need -rtsopts above for other reasons (when get into -h* profile--- integration); although -rtsopts is probably not needed for that--- in recent GHC? But in any case, the below I think you WOULDN'T--- need -rtsopts, since you're explicitly setting (augmenting, hopefully)--- the default RTS options with the -T option.+-- Since what version of GHC does -with-rtsopts imply -rtsopts?+-- The first allowing -with-rtsopts? Is there a source to learn about+-- the history of appearances of options (a "Since" column would+-- be useful in the GHC Users Guide - Flags Reference)... ghc-options: -with-rtsopts=-T -- ghc-options: -rtsopts -with-rtsopts=-T @@ -222,41 +235,6 @@ ---------- END SEQAID-SPECIFIC -- PART 2 of 2 ---------- ----------------------------------------------------------- Trying to silence the "Loading package" lines of TH!--- (This did not work out, but there's always sed...).--- Refer to https://ghc.haskell.org/trac/ghc/ticket/5647 and its--- usurper https://ghc.haskell.org/trac/ghc/ticket/7863.---- http://www.macs.hw.ac.uk/~dsg/gph/docs/4.06/users_guide/options-output.html--- this was suggested, but 7.8.3 doesn't recognise an -odump option.---ghc-options: -odump seqaid-ghc-odump.log---- With -v0 you get no "Compiling" lines for each module compiled :(--- On the other hand, ... we /could/ detect the presence of this option--- via seqaidpp, and synthesize compilation progress output lines.--- In either case, we do see the plugin-specific output lines, which--- is almost enough...--- ...And I tried that, but I'm getting duplicate output and don't--- quite understand it; so living with the "standard" TH dumping--- of "Loading package" lines!--- Will provide the "z" bash script that pipes through sed,--- for user's convenience in case they care.---ghc-options: -v0---- This doesn't suppress any output for me, anyway.---------- Seems to work.---ghc-options: -j=2--- Seems to work.---ghc-options: "-j 2"--- This will cause an error when seqaidpp runs, for some--- undetermined reason.---ghc-options: -j 2--------------------------------------------------------- -- Needed for all FORCING_STRATEGY's now: ghc-options: -with-rtsopts=-T --ghc-options: -rtsopts -with-rtsopts=-T@@ -293,6 +271,11 @@ cpp-options: -DUSE_STRICT_BLOB=1 else cpp-options: -DUSE_STRICT_BLOB=0++------------------------------------------------------++--ghc-options: -O0+--ghc-options: -O2 ------------------------------------------------------
leaky.hs view
@@ -291,8 +291,8 @@ #else -- XXX I haven't gotten to the bottom of why there's this discrepancy... #if FORCING_STRATEGY == 6- duration = 10000---duration = 100000+--duration = 10000+ duration = 100000 #else #if FORCING_STRATEGY == 5 duration = 10000@@ -328,21 +328,27 @@ -- (Only referenced when FORCING_STRATEGY=3.) #if FORCING_STRATEGY == 3 #if USE_STRICT_BLOB- let pat = compilePat ".{.{..{.}.{.{.{.}#..{.}}}}..{..{.}}}"--- let pat = compilePat ".{.{..{.}.{.{.{.}...{.}}}}..{..{.}}}"+#if 1+ let pat | deepseq_bounded_flag__new_improved_pattern_grammar+ = compilePat "((!(!)(((!).!(!))))!(!(!)))"+ | otherwise+ = compilePat "!(!(!!(!)!(!(!(!).!!(!))))!!(!!(!)))"+--- = compilePat "!(!(!!(!)!(!(!(!)!!!(!))))!!(!!(!)))" #else-#if 0-#elif 1- let pat = mkPat state -- identical to the explicit pattern below-#elif 0- let pat = compilePat ".{.{..{.}.{.{.{.}..{.}}}}..{..{.}}}"-#elif 0- let pat = compilePat "*" -- should be (is) equivalent to rnf+#if NEW_IMPROVED_PATTERN_GRAMMAR+ let pat = compilePat "((!(!)(((!).!(!))))!(!(!)))"+#else+ let pat = compilePat "!(!(!!(!)!(!(!(!).!!(!))))!!(!!(!)))"+-- let pat = compilePat "!(!(!!(!)!(!(!(!)!!!(!))))!!(!!(!)))" #endif #endif+#else+-- XXX untested for a long time+ let pat = mkPat state+#endif putStrLn $ showPat pat #else- let pat = compilePat "#"+ let pat = emptyPat #endif #if STATS