(Will be streamed today, 2024-07-17, at 1830 UTC live on YouTube.)
Nice video! The new exception framework is terrific.
I hope this is on topic, but if not, I am happy to have this moved to a new thread.
To my mind, the info provenance backtrace is very promising as – according to the table – it avoids:
- Need to annotate each function with
HasCallStack
(HasCallStackBacktrace
). - Runtime performance hit (
CostCentreBacktrace
).
Of course there is no free lunch, and apparently the binary size is larger. But of these three limitations, I think there are many who would happily trade space to avoid the other two.
Consequently, I wonder if more can be said on IPEBacktrace
? I find the semantics confusing. The output seems highly sensitive to seemingly random details. For example, given the following functions:
readBadFile :: IO String
readBadFile = readFile "bang"
ioEx :: IO ()
ioEx = void readBadFile
ioExExtra :: IO ()
ioExExtra = do
putStrLn "In ioExExtra"
_ <- readBadFile
pure ()
we see different output:
-- ioEx
hs-backtraces: bang: openFile: does not exist (No such file or directory)
IPE backtrace:
Lib.readBadFile (src/Lib.hs:52:1-29)
Lib.readBadFileHcs (src/Lib.hs:68:27-32) -- what? this is wrong
-- ioExExtra
In ioExExtra
hs-backtraces: bang: openFile: does not exist (No such file or directory)
IPE backtrace:
Lib. (:)
Lib.readBadFile (src/Lib.hs:52:24-29)
To make matters more confusing, if I comment out the putStrLn
in ioExExtra
:
diff --git a/src/Lib.hs b/src/Lib.hs
index 510d67d..f37c88d 100644
--- a/src/Lib.hs
+++ b/src/Lib.hs
@@ -56,7 +56,7 @@ ioEx = void readBadFile
ioExExtra :: IO ()
ioExExtra = do
- putStrLn "In ioExExtra"
+ --putStrLn "In ioExExtra"
_ <- readBadFile
pure ()
Inexplicably, the unrelated ioEx
's output changes:
hs-backtraces: bang: openFile: does not exist (No such file or directory)
IPE backtrace:
Lib. (:)
Lib.readBadFile (src/Lib.hs:52:24-29)
I documented some of these interactions here: GitHub - tbidne/hs-backtraces.
I see from the user’s guide that this stuff is just approximate, so fair enough:
This flag enables the generation of a table which maps the address of an info table to an approximate source position.
And there are some open GHC issues.
Still, I wonder if anyone knows the state of things e.g.
- Is this right, or am I doing something horribly wrong?
- Is there an expectation that IPE could be more reliable in the future (maybe a particular gitlab issue)?
- If 2 is fixed, am I right to think that IPE could be the “best” stacktrace for general usage, for those who do not mind the space overhead?
Thanks!
Hey
There is a source note that explains how the source spans are selected: compiler/GHC/Driver/GenerateCgIPEStub.hs · c2525e9eaacc62e7f11db0bf0793554c01ca1544 · Glasgow Haskell Compiler / GHC · GitLab (Stacktraces from Info Table Provenance Entries (IPE based stack unwinding))
So, you may have to compare the Cmm (C–) code to see why stacktraces differ.
It may of course be that you found a bug. I will check your (excellent!) reproducer when I find some time. (I’m a bit in a hurry right now, but thought giving a quick, incomplete answer would be better than letting you wait any longer…)
Regarding your questions:
-
Hard to say after a quick glimpse. I will get back to that when I find some time.
-
If there are bugs, I hope we’ll iron them out. Reports like yours are really helpful!
Some “dynamic” will stay due to GHC optimizing/rewriting code. -
If all libraries are compiled with IPEs, you get long stacktraces with little runtime overhead (mostly memory) and no source code changes. If you are referring to the future, I’m tempted to say “Yes” (though, this is my personal opinion - AFAIK there’s no “official” answer to this question.)
Thanks for the answer! There is a lot of useful information in those links.
Comparing the examples against the Cmm sounds like a great idea. I am happy to try my hand at it at some point – time eludes us all… – though I’m a complete novice in this area, so it will probably not be quick .