@simonpj describe an tantalizing idea in our call: One of the issues with the profiler is that it forces the user to investigate in a top-down manner: you start at the top of your program, adding cost-centers to its major components, look at the profile, find the largest cost center, and drill down to the next level. This can be remarkably painful, especially when you have a particular function that you want to find uses of (e.g. "why am I calling
Data.Map.lookup so much?").
@simonpj's suggested a mechanism which would mirror the "bottom-up" behavior of
HasCallStack: introduce a way to mark a function such that all call-sites of the function are given cost-centers after simplification (@simonpj rather suggested that this be done by integrating
HasCallStack and Ticky-Ticky, but I suspect it would be significantly easier to implement this with the cost-center profiler).
Concretely, I think the implementation would look like the following:
- introduce a pragma to mark a function as introducing call-site cost-centers; this would be recorded in the function's
- introduce a pass at the end of the Core-to-Core pipeline (or perhaps some logic in CorePrep), only enabled when profiling is enabled, which would walk the AST and wrap applications of so-marked functions with cost-centers. The cost-center name could be derived from either the enclosing let-binder names or source notes (as done in #16765).
This could even be implemented entirely as a plugin, using Core annotations to mark bindings and a Core-to-Core plugin to introduce cost centers.