hpc-strobe (empty) → 0.1
raw patch · 8 files changed
+750/−0 lines, 8 filesdep +basedep +filepathdep +hpcsetup-changed
Dependencies added: base, filepath, hpc
Files
- LICENSE +29/−0
- README +257/−0
- Setup.hs +2/−0
- demonstration/StrobeClock.hs +203/−0
- demonstration/showClock1.sh +39/−0
- demonstration/strobeHpcDiff1.sh +100/−0
- hpc-strobe.cabal +41/−0
- src/Trace/Hpc/Strobe.hs +79/−0
+ LICENSE view
@@ -0,0 +1,29 @@+Copyright (c) 2009, Thorkil Naur+All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are+met:++1. Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++2. Redistributions in binary form must reproduce the above copyright+ notice, this list of conditions and the following disclaimer in the+ documentation and/or other materials provided with the distribution.++3. Neither the name of the author nor the names of his contributors may+ be used to endorse or promote products derived from this software+ without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS+IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED+TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README view
@@ -0,0 +1,257 @@+=======================================================================+README: hpc-strobe: Hpc-generated strobes for a running Haskell program+=======================================================================++hpc-strobe is a rudimentary library that demonstrates the possibility of+using Hpc (Haskell Program Coverage) to inspect the state of a running+Haskell program. Please refer to++ Andy Gill and Colin Runciman: "Haskell Program Coverage", in+ Haskell Workshop, ACM Press, 2007++for a description of Hpc. At the time of writing this (2009-May-08),+the paper is available at++ http://www.ittc.ku.edu/~andygill/papers/Hpc07.pdf++In ordinary use of Hpc, a single so-called tix file is produced at the+end of a run. The tix file records how many times each expression has+been used during the run. This can be used to mark up the source code,+identifying expressions that have not been used.++hpc-strobe uses the basic machinery provided by Hpc to produce multiple+tix files, also called strobes, representing the coverage at different+times while the program is running. By subtracting such two tix files,+again using Hpc machinery, a tix file representing the expressions used+between the times of recording the subtracted tix files is produced.+This may be used, for example, to get a better idea of what a+long-running program is doing. It could also be used as a profiling+tool, getting information about how many times individual expressions+are used.++A program is included whose strobe differences produce a crude rendering+of an analog clock when they are used to mark up the source code using+Hpc.++Use of the library involves a simple change of the main function and+also requires the program to be enabled for hpc. At the time of writing,+this means using a fairly recent version of GHC and compiling the+Haskell code with the -fhpc option.++In the rest of this README, please find (1) download information; (2)+build and install information; (3) information on how to run the+demonstration program and render the analog clock; (4) a bit of+background information; and (5) some final remarks. Information on how+to use the library can be found in the haddock documentation which is+based on comments in src/Trace/Hpc/Strobe.hs in the package.++1. Downloading hpc-strobe+-------------------------++hpc-strobe is on hackage, so for example:++ $ wget http://hackage.haskell.org/packages/archive/hpc-strobe/0.1/hpc-strobe-0.1.tar.gz++2. Building and installing hpc-strobe+-------------------------------------++First unpack the package:++ $ tar xvz hpc-strobe-0.1.tar.gz++Then build and install the Cabal way:++ $ cd hpc-strobe-0.1+ $ runhaskell Setup.hs configure # Additional options may be used+ $ runhaskell Setup.hs build+ $ runhaskell Setup.hs haddock # Optional+ $ runhaskell Setup.hs install # Privileges (sudo) may be needed++For example:++ $ tar xvfz ../../test/hpc/hpc-strobeDarcsRepository/hpc-strobe/dist/hpc-strobe-0.1.tar.gz + hpc-strobe-0.1/+ hpc-strobe-0.1/demonstration/+ hpc-strobe-0.1/demonstration/showClock1.sh+ hpc-strobe-0.1/demonstration/StrobeClock.hs+ hpc-strobe-0.1/demonstration/strobeHpcDiff1.sh+ hpc-strobe-0.1/hpc-strobe.cabal+ hpc-strobe-0.1/LICENSE+ hpc-strobe-0.1/README+ hpc-strobe-0.1/Setup.hs+ hpc-strobe-0.1/src/+ hpc-strobe-0.1/src/Trace/+ hpc-strobe-0.1/src/Trace/Hpc/+ hpc-strobe-0.1/src/Trace/Hpc/Strobe.hs+ $ cd hpc-strobe-0.1/+ $ runhaskell Setup.hs configure --user --prefix=/Users/thorkilnaur/tn/install/hpc-strobe-0.1+ Configuring hpc-strobe-0.1...+ $ runhaskell Setup.hs build+ Preprocessing library hpc-strobe-0.1...+ Building hpc-strobe-0.1...+ [1 of 1] Compiling Trace.Hpc.Strobe ( src/Trace/Hpc/Strobe.hs, dist/build/Trace/Hpc/Strobe.o )+ ar: creating archive dist/build/libHShpc-strobe-0.1.a+ $ runhaskell Setup.hs haddock+ Preprocessing library hpc-strobe-0.1...+ Running Haddock for hpc-strobe-0.1...+ Documentation created: dist/doc/html/hpc-strobe/index.html+ $ runhaskell Setup.hs install+ Installing: /Users/thorkilnaur/tn/install/hpc-strobe-0.1/lib/hpc-strobe-0.1/ghc-6.8.2+ Registering hpc-strobe-0.1...+ Reading package info from "dist/installed-pkg-config" ... done.+ Saving old package config file... done.+ Writing new package config file... done.+ $ ++3. Running the demonstration program+------------------------------------++I show how to run he demonstration program in-place in the unpacked+package directory:++ $ cd demonstration+ $ ghc --version+ The Glorious Glasgow Haskell Compilation System, version 6.8.2+ $ ghc --make StrobeClock.hs -fhpc+ [1 of 1] Compiling Main ( StrobeClock.hs, StrobeClock.o )+ Linking StrobeClock ...+ $ mkdir tixfiles+ $ ./StrobeClock tixfiles + StrobeClock(2009-May-08 10.41): Canvas pixel height 39, pixel width 39+ StrobeClock(2009-May-08 10.41): 634+ StrobeClock(2009-May-08 10.41): 1266+ ...++StrobeClock never stops, so at this point, enter a separate shell and++ $ cd hpc-strobe-0.1/demonstration + $ ls -tr tixfiles | tail -n 3+ StrobeClock_254.tix+ StrobeClock_255.tix+ StrobeClock_256.tix+ $ ++to watch the growing list of strobes.++Note: StrobeClock will not complain if you forget to create the tixfiles+directory: In that case, no tixfiles will be written. Whether this+should be considered an error or a feature, I haven't decided.++To produce a single strobe difference, a shell script strobeHpcDiff1.sh+is provided. For example:++ $ sh strobeHpcDiff1.sh . tixfiles StrobeClock 0 5+ Writing: Main.hs.html+ Writing: hpc_index.html+ Writing: hpc_index_fun.html+ Writing: hpc_index_alt.html+ Writing: hpc_index_exp.html+ strobeHpc_StrobeClock_5_SUB_0_20090508_140251/+ strobeHpc_StrobeClock_5_SUB_0_20090508_140251/Main.hs.html+ $ ++This deposits marked-up source code in a time-stamped directory. It+also produces a .tar.gz file for that directory. Please look at the+strobeHpcDiff1.sh code itself for usage information.++Now point your browser to the Main.hs.html file in the time-stamped+directory. On my Mac OS X, I can do++ $ /Applications/Firefox.app/Contents/MacOS/firefox strobeHpc_StrobeClock_5_SUB_0_20090508_140251/Main.hs.html &+ [1] 23707+ $ ++but something different may be needed. Now scroll down a few lines in+this marked-up version of the StrobeClock.hs code to display the canvas+function. You should be able to make out a crude rendering of an analog+clock, showing the local time of day. And since we have taken the+difference over 5 strobes, with 1 second between each, the seconds hand+on the clock is smeared, covering those 5 seconds.++For a more dynamic experience, with StrobeClock still running:++ $ sh showClock1.sh + showClock1.sh: Skip over tixfiles/StrobeClock_0.tix to tixfiles/StrobeClock_1.tix+ showClock1.sh: Skip over tixfiles/StrobeClock_1.tix to tixfiles/StrobeClock_2.tix+ ...+ showClock1.sh: Skip over tixfiles/StrobeClock_30.tix to tixfiles/StrobeClock_31.tix+ showClock1.sh: Mark up tixfiles/StrobeClock_31.tix to tixfiles/StrobeClock_32.tix+ Writing: Main.hs.html+ Writing: hpc_index.html+ Writing: hpc_index_fun.html+ Writing: hpc_index_alt.html+ Writing: hpc_index_exp.html+ ...++This creates a directory, ClockDisplay, and maintains in this directory+a marked-up Main.hs.html that corresponds to the difference between the+third- and second-latest strobes in the tixfiles directory.+(showClock1.sh assumes that the tixfiles directory is named "tixfiles"+and also that the tixfile filename prefix is "StrobeClock".)++Then point your browser to this file, for example (again after entering+a new shell: showClock1.sh runs forever; also, I need to close the+other firefox before starting a new one):++ $ cd hpc-strobe-0.1/demonstration + $ /Applications/Firefox.app/Contents/MacOS/firefox ClockDisplay/Main.hs.html &+ [1] 24813+ $ ++This will show the most recently marked-up strobe difference, hence the+current local time will be rendered in the canvas function. Smearing+may occur, but refreshing the display usually helps.++In addition to PPC Mac OS X 10.4 with GHC 6.8.2, the demonstration has+been tried successfully on Windows with GHC 6.8.2 with both MSYS and+Cygwin; and on Ubuntu x86 Linux with GHC 6.10.2.++4. Background+-------------++The path to using the reflect interface in Hpc started with my desire to+investigate a long-winding darcs pull (some GHC HEAD into GHC STABLE).+See http://bugs.darcs.net/issue1075. Earlier, to investigate the+HughesPJ pretty-printing library, I had written a simple tracer that did+a source-to-source transformation of Haskell code, inserting calls to+Debug.Trace.trace for all top-level definitions in a Haskell module. See+http://hackage.haskell.org/trac/ghc/ticket/1337. This was at a point in+time where Hpc was not working. So my initial idea was to do something+similar to darcs, transforming selected darcs modules to figure out what+they were doing.++The work started around 2008-Sep-02. After struggling for a while, I+had settled on a modified version of the Hpc.c that comes with the GHC+runtime system that wrote out tix files regularly. Immediately+afterwards, however, I stumbled over the Trace.Hpc.Reflect and+Trace.Hpc.Tix modules that supported exactly what I needed. Thanks to+the foresight of Andy Gill and Colin Runciman, everything turned out to+be surprisingly simple. In fact, a major motivation for publishing the+present library is simply to make this technique better known. The+hpc-strobe library itself is really not adding anything significant to+Hpc itself.++At the Hac5/darcs sprint 2, I gave a brief presentation of the+technique:++ http://blog.darcs.net/2009/04/darcs-hacking-sprint-2-report.html++Thanks to Don Steward for helping here.++5. Final words+--------------++As mentioned, the contents of the hpc-strobe library itself is really+not particularly significant and it is easy to imagine a number of+generalizations and variations of the technique that opens up what I+believe is a fairly rich field of valuable applications.++I should mention the hpc-tracer library by Andy Gill and Colin Runciman:++ http://hackage.haskell.org/cgi-bin/hackage-scripts/package/hpc-tracer++I must admit that I have not studied this library in detail, but it+clearly seems to be headed in much the same direction as hpc-strobe,+but with a more elaborate user interface.++Thorkil Naur
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ demonstration/StrobeClock.hs view
@@ -0,0 +1,203 @@+-- StrobeClock.hs: Demonstrate hpc-strobe by rendering a crude analog+-- clock in the marked-up code+-- Copyright (c) 2009, Thorkil Naur+--+-- Usage: ./StrobeClock tixfile-directory+--+-- Note: The indicated tixfile-directory must exist.+--++module Main where++ import System+ import IO+ import Time+ import Control.Concurrent+ import List++ import Trace.Hpc.Strobe++ progName = "StrobeClock"+ progStamp = "2009-May-08 17.26"++ -- The clock will be rendered in the following part of the code. The+ -- number of lines and their width may be adjusted; the width of the+ -- shortest line will determine the width of the clock.++ canvas x+ = [+ [x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x]+ , [x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x]+ , [x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x]+ , [x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x]+ , [x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x]+ , [x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x]+ , [x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x]+ , [x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x]+ , [x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x]+ , [x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x]+ , [x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x]+ , [x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x]+ , [x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x]+ , [x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x]+ , [x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x]+ , [x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x]+ , [x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x]+ , [x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x]+ , [x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x]+ , [x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x]+ , [x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x]+ , [x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x]+ , [x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x]+ , [x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x]+ , [x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x]+ , [x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x]+ , [x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x]+ , [x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x]+ , [x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x]+ , [x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x]+ , [x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x]+ , [x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x]+ , [x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x]+ , [x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x]+ , [x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x]+ , [x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x]+ , [x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x]+ , [x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x]+ , [x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x]+ , [x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x]+ ]++ -- Canvas dimensions:++ pixelHeight = (length $ canvas 0) - 1+ pixelWidth = minimum $ map ((subtract 1) . length) $ canvas 0++ -- Defines the shape of pixels: To calibrate, measure the height and+ -- width of a square part of the canvas as rendered and enter the+ -- ratio here:++ pixelHeightDividedByWidth = 16.2/17.4++ -- World coordinate system is such that a 2x2 square with (0,0) in its+ -- center fits exactly inside the canvas rectangle:++ worldDimensions+ = let+ rawDimensions = [1.0,pixelHeightDividedByWidth]+ in+ map ((*2.0) . (/(minimum rawDimensions))) rawDimensions++ worldLowerLeftCorner = map (negate . (/2.0)) worldDimensions++ -- Converting between coordinate systems:++ canvasToWorld [row,col]+ = zipWith (+) worldLowerLeftCorner $ zipWith (*) worldDimensions+ [fromIntegral col / fromIntegral pixelWidth,+ 1.0 - fromIntegral row / fromIntegral pixelHeight]++ worldToCanvas wcs+ = let+ [c0,r0]+ = zipWith (/) (zipWith (-) wcs worldLowerLeftCorner)+ worldDimensions+ in+ [round $ (1.0 - r0) * fromIntegral pixelHeight,+ round $ c0 * fromIntegral pixelWidth]++ -- Shade outside unit circle:++ circleShade+ = filter ((>1.0) . sum . map (^2) . canvasToWorld)+ [ [row,col] | row <- [0..pixelHeight], col <- [0..pixelWidth] ]++ -- Line:++ canvasLine [r1,c1] [r2,c2]+ = if abs (r2 - r1) > abs (c2 - c1) then+ map reverse $ canvasLine [c1,r1] [c2,r2]+ else+ if abs (c2 - c1) > 0 then+ let+ [(c1',r1'),(c2',r2')] = sort [(c1,r1),(c2,r2)]+ in+ [ [r,c] | c <- [c1'..c2'],+ let r = r1' + (round $ fromIntegral (r2' - r1')+ * fromIntegral (c - c1')+ / fromIntegral (c2' - c1')) ]+ else+ [[r1,c1]]++ worldLine [x1,y1] [x2,y2]+ = canvasLine (worldToCanvas [x1,y1]) (worldToCanvas [x2,y2])++ -- Piece of radial line, angle measured in degrees from vertical,+ -- clockwise:++ worldRadial angle from to+ = let+ radians = (90.0 - angle) / 180.0 * pi+ [p1,p2]+ = map (\t -> map (*t) [cos radians,sin radians]) [from,to]+ in+ worldLine p1 p2++ -- Clock:++ worldClockFixed+ = concat [ worldRadial (fromIntegral a) 0.9 1.0+ | a <- [30,60..360] ]+ ++ concat [ worldRadial (fromIntegral a) 0.8 1.0+ | a <- [90,180..360] ]+ ++ circleShade++ worldClockVariable h m s+ = concat [ worldRadial ah 0.0 0.55 ]+ ++ concat [ worldRadial (ah+4.0) 0.0 0.45 ]+ ++ concat [ worldRadial (ah-4.0) 0.0 0.45 ]+ ++ concat [ worldRadial am 0.0 0.9 ]+ ++ concat [ worldRadial (am-2.5) 0.0 0.8 ]+ ++ concat [ worldRadial (am+2.5) 0.0 0.8 ]+ ++ concat [ worldRadial as (-0.15) 1.0 ]+ where+ as = fromIntegral s * (360.0/60.0)+ m' = fromIntegral m + fromIntegral s / 60.0+ am = m'*(360/60.0)+ ah = (fromIntegral h + m'/60.0)*(360.0/12.0)++ main'+ = do+ putStrLn $+ progName ++ "(" ++ progStamp ++ "): Canvas pixel height "+ ++ show pixelHeight ++ ", pixel width " ++ show pixelWidth+ mapM_+ (\n ->+ do+ clTime <- getClockTime+ localTime@(CalendarTime{ctHour = hr,+ ctMin = mn, ctSec = sc}) <- toCalendarTime clTime+ let+ timeStamp = calendarTimeToString localTime+ in+ do+ putStrLn $ progName ++ "(" ++ progStamp ++ "): "+ ++ (show $+ sum [ ((canvas n)!!i)!!j+ | [i,j] <- worldClockFixed+ ++ worldClockVariable hr mn sc ])+ threadDelay 950000+ ) [1..]++ mainArgsInterpret [tixfileDirectory]+ = withStrobesWrittenRegularly tixfileDirectory progName 1000000+ main'++ mainArgsInterpret args+ = error $ "Usage: \"./" ++ progName ++ " tixfile-directory\""++ main+ = do+ hSetBuffering stdout NoBuffering+ args <- getArgs+ mainArgsInterpret args
+ demonstration/showClock1.sh view
@@ -0,0 +1,39 @@+#!/bin/sh+# showClock1.sh: Show latest difference between clock tix+# sh showClock1.sh+# 2009-Apr-27 21.00 / TN++PREFIX=tixfiles/StrobeClock_++CURRENT=0++mkdir -p ClockDisplay++while true; do++ NEXT=`expr $CURRENT + 1`+ AFTER=`expr $NEXT + 1`++ while [ ! -f ${PREFIX}${AFTER}.tix ]; do echo $0: Waiting for ${PREFIX}${AFTER}.tix; sleep 1; done++ TWOAFTER=`expr $AFTER + 1`++ if [ -f ${PREFIX}${TWOAFTER}.tix ]; then++ echo $0: Skip over ${PREFIX}${CURRENT}.tix to ${PREFIX}${NEXT}.tix++ else++ echo $0: Mark up ${PREFIX}${CURRENT}.tix to ${PREFIX}${NEXT}.tix++ hpc combine --function=SUB --output=showClock1.tix ${PREFIX}${NEXT}.tix ${PREFIX}${CURRENT}.tix++ hpc markup --highlight-covered showClock1.tix++ mv Main.hs.html ClockDisplay/++ fi++ CURRENT=$NEXT++done
+ demonstration/strobeHpcDiff1.sh view
@@ -0,0 +1,100 @@+#!/bin/sh+# strobeHpcDiff1.sh: Difference between tix strobe files 1+# sh strobeHpcDiff1.sh source-directory strobe-tix-directory strobe-tix-file-suffix strobe-from strobe-to+# 2008-Sep-14 11.57 / TN+# 2009-May-08 17.43 / TN: Replace "==" by "=" in tests++COUNT=0+for F in *.html; do+ if [ -e "$F" ]; then+ COUNT=`expr $COUNT + 1`+ echo 1>&2 $0: Found .html file \"$F\"+ fi+done++if [ "$COUNT" != 0 ]; then+ echo 1>&2 $0: Please clean out .html files+ exit 1+fi++if [ "$#" = "0" ]; then+ echo 1>&2 $0: Please specify source-directory parameter+ exit 1+fi+SOURCE_DIRECTORY="$1"+shift++if [ "$#" = "0" ]; then+ echo 1>&2 $0: Please specify strobe-tix-directory parameter+ exit 1+fi+STROBE_TIX_DIRECTORY="$1"+shift++if [ "$#" = "0" ]; then+ echo 1>&2 $0: Please specify strobe-tix-file-suffix parameter+ exit 1+fi+STROBE_TIX_FILE_SUFFIX="$1"+shift++if [ "$#" = "0" ]; then+ echo 1>&2 $0: Please specify strobe-from parameter+ exit 1+fi+STROBE_FROM="$1"+shift++if [ "$#" = "0" ]; then+ echo 1>&2 $0: Please specify strobe-to parameter+ exit 1+fi+STROBE_TO="$1"+shift++if [ "$#" != 0 ]; then+ echo 1>&2 $0: There are $# superfluous parameters: "$@"+ exit 1+fi++STROBE_TIX_SUFFIX=${STROBE_TIX_DIRECTORY}/${STROBE_TIX_FILE_SUFFIX}_+STROBE_TIX_OUTPUT=${STROBE_TIX_FILE_SUFFIX}_${STROBE_TO}_SUB_${STROBE_FROM}+STROBE_TIX_OUTPUT_FILE=${STROBE_TIX_OUTPUT}.tix++hpc combine --function=SUB --output=${STROBE_TIX_OUTPUT_FILE} ${STROBE_TIX_SUFFIX}${STROBE_TO}.tix ${STROBE_TIX_SUFFIX}${STROBE_FROM}.tix+RC="$?"+if [ "$RC" != 0 ]; then+ echo 1>&2 $0: hpc combine: Unexpected return code $RC+ exit 1+fi++hpc markup --highlight-covered --srcdir=${SOURCE_DIRECTORY} ${STROBE_TIX_OUTPUT_FILE}+RC="$?"+if [ "$RC" != 0 ]; then+ echo 1>&2 $0: hpc combine: Unexpected return code $RC+ exit 1+fi++WORKING_DIR=strobeHpc_${STROBE_TIX_OUTPUT}_`date +%Y%m%d_%H%M%S`++mkdir ${WORKING_DIR}+RC="$?"+if [ "$RC" != 0 ]; then+ echo 1>&2 $0: mkdir ${WORKING_DIR}: Unexpected return code $RC+ exit 1+fi++mv `grep -l '"istickedoff"' *.html` ${WORKING_DIR}+RC="$?"+if [ "$RC" != 0 ]; then+ echo 1>&2 $0: mv `grep -l '"istickedoff"' ${WORKING_DIR}/*.html` .: Unexpected return code $RC+ exit 1+fi++tar cvzf ${WORKING_DIR}.tar.gz ${WORKING_DIR}++rm *.html++# Exit OK:++exit 0
+ hpc-strobe.cabal view
@@ -0,0 +1,41 @@+Name: hpc-strobe+Version: 0.1+Synopsis: Hpc-generated strobes for a running Haskell program+License: BSD3+License-file: LICENSE+Author: Thorkil Naur+Maintainer: naur@post11.tele.dk+Build-Type: Simple+Cabal-Version: >=1.2+Description: A rudimentary library that demonstrates the+ possibility of using Hpc (Haskell Program Coverage)+ to inspect the state of a running Haskell program.+ Use of the library involves a simple change of the+ main function and also requires the program to be+ enabled for hpc. At the time of writing, this means+ using a fairly recent version of GHC and compiling+ the Haskell code with the @-fhpc@ option.+Category: Trace, Debug+extra-source-files: README+ demonstration/StrobeClock.hs+ demonstration/strobeHpcDiff1.sh+ demonstration/showClock1.sh++Library+ Build-Depends: base, hpc, filepath+ Exposed-modules: Trace.Hpc.Strobe+ hs-source-dirs: src+ ghc-options: -Wall++--+-- Note: Checking the package on+-- http://hackage.haskell.org/packages/upload.html reports:+--+-- Exposed modules use unallocated top-level names: Trace+--+-- I feel somewhat justified in keeping this name, since the hpc+-- package itself uses Trace.Hpc.Tix and Trace.Hpc.Reflect. But I am+-- certainly open to suggested alternative names.+--+-- Regards Thorkil+--
+ src/Trace/Hpc/Strobe.hs view
@@ -0,0 +1,79 @@+------------------------------------------------------------------------+-- |+-- Module : Trace.Hpc.Strobe+-- Copyright : (C) 2009, Thorkil Naur+-- License : BSD3-style (see LICENSE)+--+-- Maintainer : Thorkil Naur+-- Stability : unstable+-- Portability : Requires GHC with Hpc support.+--+-- A rudimentary library that demonstrates the possibility of+-- using Hpc (Haskell Program Coverage) to inspect the state of+-- a running Haskell program. Use of the library involves a+-- simple change of the main function and also requires the+-- program to be enabled for hpc. At the time of writing, this+-- means using a fairly recent version of GHC and compiling the+-- Haskell code with the @-fhpc@ option.+--+------------------------------------------------------------------------++module Trace.Hpc.Strobe (++ -- * Write strobes (tix files) regularly while program is running+ withStrobesWrittenRegularly++ ) where++import System.FilePath+import Control.Concurrent+import Trace.Hpc.Tix+import Trace.Hpc.Reflect++strobe :: FilePath -> String -> Int -> IO ()+strobe directory filePrefix interval+ = do mapM_ go [0..]+ where+ go :: Integer -> IO ()+ go d = do strobeTix d+ threadDelay interval+ fileName n = (filePrefix ++ "_" ++ show n) <.> "tix"+ strobeTix n = do tix <- examineTix+ writeTix (directory </> fileName n) tix++-- | Replace+--+-- @+-- main = \<your main function>+-- @+--+-- by+--+-- @+-- myMain = \<your main function>+-- main = withStrobesWrittenRegularly+-- \"\<tixfile directory>\"+-- \"myMain\"+-- 1000000+-- myMain+-- @+--+-- and strobes (separate Hpc tix files) will be written regularly,+-- with 1 second (1000000 microseconds) between each writing of a+-- strobe. The tix files will be deposited in the indicated tixfile+-- directory and be named \"myMain_\<index>.tix\" where the+-- index is taken from [0..].++withStrobesWrittenRegularly+ :: FilePath -- ^ Name of directory where .tix files are deposited.+ -- If this directory does not exist, no tix files are+ -- written.+ -> String -- ^ Prefix of file name for .tix files.+ -> Int -- ^ Microseconds between writing a .tix file.+ -> IO () -- ^ The main function to be strobe'd.+ -> IO () -- ^ The modified main function.++withStrobesWrittenRegularly directory filePrefix interval mainFunction+ = do+ forkIO $ strobe directory filePrefix interval+ mainFunction