1 #ifndef HALIDE_COMPILER_LOGGER_H_
2 #define HALIDE_COMPILER_LOGGER_H_
3 
4 /** \file
5  * Defines an interface used to gather and log compile-time information, stats, etc
6  * for use in evaluating internal Halide compilation rules and efficiency.
7  *
8  * The 'standard' implementation simply logs all gathered data to
9  * a local file (in JSON form), but the entire implementation can be
10  * replaced by custom definitions if you have unusual logging needs.
11  */
12 
13 #include <iostream>
14 #include <map>
15 #include <memory>
16 #include <set>
17 #include <string>
18 #include <utility>
19 
20 #include "Expr.h"
21 #include "Target.h"
22 
23 namespace Halide {
24 namespace Internal {
25 
26 class CompilerLogger {
27 public:
28     /** The "Phase" of compilation, used for some calls */
29     enum class Phase {
30         HalideLowering,
31         LLVM,
32     };
33 
34     CompilerLogger() = default;
35     virtual ~CompilerLogger() = default;
36 
37     /** Record when a particular simplifier rule matches.
38      */
39     virtual void record_matched_simplifier_rule(const std::string &rulename, Expr expr) = 0;
40 
41     /** Record when an expression is non-monotonic in a loop variable.
42      */
43     virtual void record_non_monotonic_loop_var(const std::string &loop_var, Expr expr) = 0;
44 
45     /** Record when can_prove() fails, but cannot find a counterexample.
46      */
47     virtual void record_failed_to_prove(Expr failed_to_prove, Expr original_expr) = 0;
48 
49     /** Record total size (in bytes) of final generated object code (e.g., file size of .o output).
50      */
51     virtual void record_object_code_size(uint64_t bytes) = 0;
52 
53     /** Record the compilation time (in seconds) for a given phase.
54      */
55     virtual void record_compilation_time(Phase phase, double duration) = 0;
56 
57     /**
58      * Emit all the gathered data to the given stream. This may be called multiple times.
59      */
60     virtual std::ostream &emit_to_stream(std::ostream &o) = 0;
61 };
62 
63 /** Set the active CompilerLogger object, replacing any existing one.
64  * It is legal to pass in a nullptr (which means "don't do any compiler logging").
65  * Returns the previous CompilerLogger (if any). */
66 std::unique_ptr<CompilerLogger> set_compiler_logger(std::unique_ptr<CompilerLogger> compiler_logger);
67 
68 /** Return the currently active CompilerLogger object. If set_compiler_logger()
69  * has never been called, a nullptr implementation will be returned.
70  * Do not save the pointer returned! It is intended to be used for immediate
71  * calls only. */
72 CompilerLogger *get_compiler_logger();
73 
74 /** JSONCompilerLogger is a basic implementation of the CompilerLogger interface
75  * that saves logged data, then logs it all in JSON format in emit_to_stream().
76  */
77 class JSONCompilerLogger : public CompilerLogger {
78 public:
79     JSONCompilerLogger() = default;
80 
81     JSONCompilerLogger(
82         const std::string &generator_name,
83         const std::string &function_name,
84         const std::string &autoscheduler_name,
85         const Target &target,
86         const std::string &generator_args,
87         bool obfuscate_exprs);
88 
89     void record_matched_simplifier_rule(const std::string &rulename, Expr expr) override;
90     void record_non_monotonic_loop_var(const std::string &loop_var, Expr expr) override;
91     void record_failed_to_prove(Expr failed_to_prove, Expr original_expr) override;
92     void record_object_code_size(uint64_t bytes) override;
93     void record_compilation_time(Phase phase, double duration) override;
94 
95     std::ostream &emit_to_stream(std::ostream &o) override;
96 
97 protected:
98     const std::string generator_name;
99     const std::string function_name;
100     const std::string autoscheduler_name;
101     const Target target;
102     const std::string generator_args;
103     const bool obfuscate_exprs{false};
104 
105     // Maps from string representing rewrite rule -> list of Exprs that matched that rule
106     std::map<std::string, std::vector<Expr>> matched_simplifier_rules;
107 
108     // Maps loop_var -> list of Exprs that were nonmonotonic for that loop_var
109     std::map<std::string, std::vector<Expr>> non_monotonic_loop_vars;
110 
111     // List of (unprovable simplified Expr, original version of that Expr passed to can_prove()).
112     std::vector<std::pair<Expr, Expr>> failed_to_prove_exprs;
113 
114     // Total code size generated, in bytes.
115     uint64_t object_code_size{0};
116 
117     // Map of the time take for each phase of compilation.
118     std::map<Phase, double> compilation_time;
119 
120     void obfuscate();
121     void emit();
122 };
123 
124 }  // namespace Internal
125 }  // namespace Halide
126 
127 #endif  // HALIDE_COMPILER_LOGGER_H_
128