3

So I have the following code from Preventing caching of computation in Criterion benchmark and my aim is to be able to step from main directly into the function defaultMain in Criterion.Main :

{-# OPTIONS -fno-full-laziness #-}
{-# OPTIONS_GHC -fno-cse #-}
{-# LANGUAGE BangPatterns #-}
module Main where
import Criterion.Main
import Data.List

num :: Int
num = 100000000

lst :: a -> [Int]
lst _ = [1,2..num]

myadd :: Int -> Int -> Int
myadd !x !y = let !result = x + y in
  result

mysum = foldl' myadd 0

main :: IO ()
main = defaultMain [
  bgroup "summation" 
    [bench "mysum" $ whnf (mysum . lst) ()]
  ]

and the cabal file is :

name:                test
version:             0.1.0.0
build-type:          Simple
cabal-version:       >=1.10

executable test
  main-is:             Main.hs
  build-depends:       base >=4.8 && <4.9,
                       criterion==1.1.0.0
  default-language:    Haskell2010
  ghc-options:         "-O3"

(using ghc 7.10.1 and cabal 1.22.0.0).

If from within cabal repl I try to set a breakpoint in criterion I get the following error :

*Main> :break Criterion.Main.defaultMain
cannot set breakpoint on defaultMain: module Criterion.Main is not interpreted

Furthermore if I try to add the package I get the following error :

*Main> :add *Criterion

<no location info>: module ‘Criterion’ is a package module
Failed, modules loaded: Main.

If I do within the directory git clone https://github.com/bos/criterion and then add the following two lines to my cabal file :

other-modules:       Criterion
hs-source-dirs:      .
                 ./criterion

then upon doing cabal build I get the following errors :

criterion/Criterion/IO.hs:23:0:
     error: missing binary operator before token "("
     #if MIN_VERSION_binary(0, 6, 3)

so I suspect that I have to do a full on merge of the criterion cabal file with my cabal file above, which feels a bit excessive.

Is there an easier way for me to go about setting a breakpoint in Criterion, so that I can step (when debugging in cabal repl/ghci) directly from my source into criterion's source? Thanks

p.s. There is a related question at Debugging IO in a package module inside GHCi but unfortunately it did not help.

Community
  • 1
  • 1
artella
  • 5,068
  • 4
  • 27
  • 35
  • 1
    I don't know the answer to the `cabal` file part, but as far as I know, GHCi can *only* debug code in its internal bytecode format. In particular, you want to avoid natively compiling with `cabal build`, since the resulting `.o` files would be used by default instead of bytecode. – Ørjan Johansen Apr 06 '15 at 23:47
  • @ØrjanJohansen Thanks, I have managed to debug cassava before by "merging" the cabal files, which allowed me to seamlessly step from my application into cassava. However the same attempts with criterion results in a `criterion-1.1.0.0/cbits/time-posix.o: relocation R_X86_64_PC32 against undefined symbol clock_gettime@@GLIBC_2.2.5 can not be used when making a shared object; recompile with -fPIC`, which is what I am currently trying to solve! – artella Apr 07 '15 at 06:13
  • @ØrjanJohansen : Ah it seems that the way to resolve the `time-posix.o` error in comment above is to add the option `cc-options: -fPIC`. So for the moment I can achieve the desired behaviour by merging the cabal files and adding `cc-options: -fPIC` to the resulting cabal file. – artella Apr 07 '15 at 10:02
  • Great! This does sound like a generally useful tip. If you want you can post an answer to your own question describing how you solved it. – Ørjan Johansen Apr 07 '15 at 14:20
  • @ØrjanJohansen : I posted the method below. Thanks. – artella Apr 08 '15 at 20:19

1 Answers1

2

This is how I managed to achieve the desired goal of being able to step (within cabal repl) from my code into the criterion source :

  1. First do :

    mkdir /tmp/testCrit
    cd /tmp/testCrit
    
  2. Download criterion-1.1.0.0.tar.gz

  3. Unzip into /tmp/testCrit, so we should have /tmp/testCrit/criterion-1.1.0.0. In this directory we have Criterion.hs etc.

  4. Then jump into the folder containing the criterion source and do :

    cd /tmp/testCrit/criterion-1.1.0.0
    cabal sandbox init
    cabal install -j
    

    Note that this creates a directory : /tmp/testCrit/criterion-1.1.0.0/dist/dist-sandbox-782e42f0/build/autogen which we shall use later

  5. Back in /tmp/testCrit create a Main.hs file containing the benchmark code above and also the cabal file above, but merge it with the criterion cabal file contained in /tmp/testCrit/criterion-1.1.0.0 in the following way. Note the main new additions are the lines :

    cc-options: -fPIC
    

    which allows one to run it in cabal repl, and the following lines :

    hs-source-dirs: 
      ./
      ./criterion-1.1.0.0
      ./criterion-1.1.0.0/dist/dist-sandbox-782e42f0/build/autogen
    

    The full cabal file should then look like :

      name:                test
      version:             0.1.0.0
      build-type:          Simple
      cabal-version:       >=1.10
    
      executable test
        main-is:             Main.hs
        build-depends:       
          base >=4.8 && <4.9,
          aeson >= 0.8,
          ansi-wl-pprint >= 0.6.7.2,
          base >= 4.5 && < 5,
          binary >= 0.5.1.0,
          bytestring >= 0.9 && < 1.0,
          cassava >= 0.3.0.0,
          containers,
          deepseq >= 1.1.0.0,
          directory,
          filepath,
          Glob >= 0.7.2,
          hastache >= 0.6.0,
          mtl >= 2,
          mwc-random >= 0.8.0.3,
          optparse-applicative >= 0.11,
          parsec >= 3.1.0,
          statistics >= 0.13.2.1,
          text >= 0.11,
          time,
          transformers,
          transformers-compat >= 0.4,
          vector >= 0.7.1,
          vector-algorithms >= 0.4
        default-language:    Haskell2010
        ghc-options:         "-O3"
        c-sources: 
          ./criterion-1.1.0.0/cbits/cycles.c
          ./criterion-1.1.0.0/cbits/time-posix.c
        hs-source-dirs: 
          ./
          ./criterion-1.1.0.0
          ./criterion-1.1.0.0/dist/dist-sandbox-782e42f0/build/autogen
        cc-options: -fPIC
    
  6. Then in the main directory do :

    cd /tmp/testCrit/
    cabal sandbox init
    cabal install -j
    
  7. Then we can spin up a cabal repl and step directly into criterion from our Main.hs code :

    *Main> :break Criterion.Main.defaultMain
    Breakpoint 0 activated at criterion-1.1.0.0/Criterion/Main.hs:79:15-43
    *Main> main
    Stopped at criterion-1.1.0.0/Criterion/Main.hs:79:15-43
    _result :: [Benchmark] -> IO () = _
    [criterion-1.1.0.0/Criterion/Main.hs:79:15-43] *Main> :step
    Stopped at criterion-1.1.0.0/Criterion/Main.hs:(131,1)-(147,39)
    _result :: IO () = _
    [criterion-1.1.0.0/Criterion/Main.hs:(131,1)-(147,39)] *Main> :step
    Stopped at criterion-1.1.0.0/Criterion/Main.hs:(131,29)-(147,39)
    _result :: IO () = _
    bs :: [Benchmark] = [_]
    defCfg :: Criterion.Types.Config = _
    [criterion-1.1.0.0/Criterion/Main.hs:(131,29)-(147,39)] *Main> :step
    Stopped at criterion-1.1.0.0/Criterion/Main.hs:132:10-37
    _result :: IO Criterion.Main.Options.Mode = _
    defCfg :: Criterion.Types.Config = _
    
artella
  • 5,068
  • 4
  • 27
  • 35