How to diagnose a loop in a large Haskell program?

Hi, I am struggling to debug a loop (some nontermination behaviour) of a huge program. Normally, I use `stack build` to generate it. I have tried to use `trace` at lots of places in the code, recompile and see what happens. However, it isn't always clear in what order the trace statements are fired, because of the lazy evaluation of Haskell. So I tried another approach. I have a function fatal :: HasCallStack => Text -> a fatal msg = exitWith . Fatal . T.lines $ ( msg <> "\n" <> (utf8BuilderToText . displayCallStackFull $ callStack) ) displayCallStackFull :: CallStack -> Utf8Builder displayCallStackFull cs = case reverse $ getCallStack cs of [] -> "<no call stack found>" xs -> mconcat $ fmap showCall xs where showCall :: (String, SrcLoc) -> Utf8Builder showCall (desc, loc) = let file = srcLocFile loc in "\n" <> fromString file <> ":" <> displayShow (srcLocStartLine loc) <> ":" <> displayShow (srcLocStartCol loc) <> " " <> fromString desc (The function to show the stack was inspired from https://hackage.haskell.org/package/rio-0.1.22.0/docs/RIO.html#v:displayCall... ). I would expect that at any place where I force a call to `fatal`, I would get the full stacktrace. Unfortunately, I only get the place where the call to fatal is in the code. I have been looking at the documentation of both stack and ghc, but I don't understand how to compile my code in a way that the full stacktrace is shown. Until now the best guess I have is stack install --profile --no-strip && ampersand -- check testing/Sentinel/Tests/ShouldSucceed/OnlyValidation/Issue280.adl The ultimate goal is to get rid of this ugly bug regarding the loop. Any help/suggestions is really appreciated! Thanks for reading. Han Joosten

Han Joosten
Hi,
I am struggling to debug a loop (some nontermination behaviour) of a huge program. Normally, I use `stack build` to generate it. I have tried to use `trace` at lots of places in the code, recompile and see what happens. However, it isn't always clear in what order the trace statements are fired, because of the lazy evaluation of Haskell.
So I tried another approach. I have a function
fatal :: HasCallStack => Text -> a fatal msg = exitWith . Fatal . T.lines $ ( msg <> "\n" <> (utf8BuilderToText . displayCallStackFull $ callStack) )
displayCallStackFull :: CallStack -> Utf8Builder displayCallStackFull cs = case reverse $ getCallStack cs of [] -> "<no call stack found>" xs -> mconcat $ fmap showCall xs where showCall :: (String, SrcLoc) -> Utf8Builder showCall (desc, loc) = let file = srcLocFile loc in "\n" <> fromString file <> ":" <> displayShow (srcLocStartLine loc) <> ":" <> displayShow (srcLocStartCol loc) <> " " <> fromString desc
(The function to show the stack was inspired from https://hackage.haskell.org/package/rio-0.1.22.0/docs/RIO.html#v:displayCall...).
I would expect that at any place where I force a call to `fatal`, I would get the full stacktrace. Unfortunately, I only get the place where the call to fatal is in the code.
Hi. Do the calling functions have call stack constraints? Quoting from the GHC manual: https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/callstack.html "The call stack will only extend as far as the types allow it." I think compilation with `--profile` (stack) or `--enable-profiling` (cabal-install) activates "simulated call-stacks" which seem to differ from the call stacks obtained by `HasCallStack`. Is this correct? On a side note: I usually get a complete call stacks when compiling with `cabal build --enable-profiling`. Dominik
I have been looking at the documentation of both stack and ghc, but I don't understand how to compile my code in a way that the full stacktrace is shown.
Until now the best guess I have is
stack install --profile --no-strip && ampersand -- check testing/Sentinel/Tests/ShouldSucceed/OnlyValidation/Issue280.adl
The ultimate goal is to get rid of this ugly bug regarding the loop. Any help/suggestions is really appreciated!
Thanks for reading. Han Joosten
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.

I just noticed, maybe you are interested in the `-xc` runtime system
option? This option can be activated when compiling with profiling
support. See here:
https://downloads.haskell.org/ghc/latest/docs/users_guide/profiling.html#rts...
Dominik
Dominik Schrempf
Han Joosten
writes: Hi,
I am struggling to debug a loop (some nontermination behaviour) of a huge program. Normally, I use `stack build` to generate it. I have tried to use `trace` at lots of places in the code, recompile and see what happens. However, it isn't always clear in what order the trace statements are fired, because of the lazy evaluation of Haskell.
So I tried another approach. I have a function
fatal :: HasCallStack => Text -> a fatal msg = exitWith . Fatal . T.lines $ ( msg <> "\n" <> (utf8BuilderToText . displayCallStackFull $ callStack) )
displayCallStackFull :: CallStack -> Utf8Builder displayCallStackFull cs = case reverse $ getCallStack cs of [] -> "<no call stack found>" xs -> mconcat $ fmap showCall xs where showCall :: (String, SrcLoc) -> Utf8Builder showCall (desc, loc) = let file = srcLocFile loc in "\n" <> fromString file <> ":" <> displayShow (srcLocStartLine loc) <> ":" <> displayShow (srcLocStartCol loc) <> " " <> fromString desc
(The function to show the stack was inspired from https://hackage.haskell.org/package/rio-0.1.22.0/docs/RIO.html#v:displayCall...).
I would expect that at any place where I force a call to `fatal`, I would get the full stacktrace. Unfortunately, I only get the place where the call to fatal is in the code.
Hi.
Do the calling functions have call stack constraints?
Quoting from the GHC manual: https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/callstack.html
"The call stack will only extend as far as the types allow it."
I think compilation with `--profile` (stack) or `--enable-profiling` (cabal-install) activates "simulated call-stacks" which seem to differ from the call stacks obtained by `HasCallStack`. Is this correct?
On a side note: I usually get a complete call stacks when compiling with `cabal build --enable-profiling`.
Dominik
I have been looking at the documentation of both stack and ghc, but I don't understand how to compile my code in a way that the full stacktrace is shown.
Until now the best guess I have is
stack install --profile --no-strip && ampersand -- check testing/Sentinel/Tests/ShouldSucceed/OnlyValidation/Issue280.adl
The ultimate goal is to get rid of this ugly bug regarding the loop. Any help/suggestions is really appreciated!
Thanks for reading. Han Joosten
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.

Thanks for the pointers. I never realized that "simulated call-stack" could be something different than the HasCallStack stuff. When I used the following command, I get the callstack info I was looking for: stack install --profile --no-strip --ghc-options -fprof-auto-calls && ampersand -- check testing/Sentinel/Tests/ShouldSucceed/OnlyValidation/Issue280.adl I hope this will help me to find the loop. Op do 22 sep. 2022 om 11:52 schreef Dominik Schrempf < dominik.schrempf@gmail.com>:
I just noticed, maybe you are interested in the `-xc` runtime system option? This option can be activated when compiling with profiling support. See here:
https://downloads.haskell.org/ghc/latest/docs/users_guide/profiling.html#rts...
Dominik
Dominik Schrempf
writes: Han Joosten
writes: Hi,
I am struggling to debug a loop (some nontermination behaviour) of a huge program. Normally, I use `stack build` to generate it. I have tried to use `trace` at lots of places in the code, recompile and see what happens. However, it isn't always clear in what order the trace statements are fired, because of the lazy evaluation of Haskell.
So I tried another approach. I have a function
fatal :: HasCallStack => Text -> a fatal msg = exitWith . Fatal . T.lines $ ( msg <> "\n" <> (utf8BuilderToText . displayCallStackFull $ callStack) )
displayCallStackFull :: CallStack -> Utf8Builder displayCallStackFull cs = case reverse $ getCallStack cs of [] -> "<no call stack found>" xs -> mconcat $ fmap showCall xs where showCall :: (String, SrcLoc) -> Utf8Builder showCall (desc, loc) = let file = srcLocFile loc in "\n" <> fromString file <> ":" <> displayShow (srcLocStartLine loc) <> ":" <> displayShow (srcLocStartCol loc) <> " " <> fromString desc
(The function to show the stack was inspired from https://hackage.haskell.org/package/rio-0.1.22.0/docs/RIO.html#v:displayCall... ).
I would expect that at any place where I force a call to `fatal`, I would get the full stacktrace. Unfortunately, I only get the place where the call to fatal is in the code.
Hi.
Do the calling functions have call stack constraints?
Quoting from the GHC manual: https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/callstack.html
"The call stack will only extend as far as the types allow it."
I think compilation with `--profile` (stack) or `--enable-profiling` (cabal-install) activates "simulated call-stacks" which seem to differ from the call stacks obtained by `HasCallStack`. Is this correct?
On a side note: I usually get a complete call stacks when compiling with `cabal build --enable-profiling`.
Dominik
I have been looking at the documentation of both stack and ghc, but I
don't understand how to compile my code in a way that the full stacktrace is
shown.
Until now the best guess I have is
stack install --profile --no-strip && ampersand -- check testing/Sentinel/Tests/ShouldSucceed/OnlyValidation/Issue280.adl
The ultimate goal is to get rid of this ugly bug regarding the loop. Any help/suggestions is really appreciated!
Thanks for reading. Han Joosten
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.
participants (2)
-
Dominik Schrempf
-
Han Joosten