trace_stream.h 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #ifndef CARBON_EXPLORER_BASE_TRACE_STREAM_H_
  5. #define CARBON_EXPLORER_BASE_TRACE_STREAM_H_
  6. #include <bitset>
  7. #include <optional>
  8. #include <string>
  9. #include <string_view>
  10. #include <vector>
  11. #include "common/check.h"
  12. #include "common/ostream.h"
  13. #include "explorer/base/nonnull.h"
  14. #include "explorer/base/source_location.h"
  15. #include "llvm/ADT/ArrayRef.h"
  16. namespace Carbon {
  17. class TraceStream;
  18. // Enumerates the phases of the program used for tracing and controlling which
  19. // program phases are included for tracing.
  20. enum class ProgramPhase {
  21. SourceProgram, // Phase for the source program.
  22. NameResolution, // Phase for name resolution.
  23. ControlFlowResolution, // Phase for control flow resolution.
  24. TypeChecking, // Phase for type checking.
  25. UnformedVariableResolution, // Phase for unformed variables resolution.
  26. Declarations, // Phase for printing declarations.
  27. Execution, // Phase for program execution.
  28. Timing, // Phase for timing logs.
  29. Unknown, // Represents an unknown program phase.
  30. All, // Represents all program phases.
  31. Last = All // Last program phase indicator.
  32. };
  33. // Encapsulates the trace stream so that we can cleanly disable tracing while
  34. // the prelude is being processed. The prelude is expected to take a
  35. // disproprotionate amount of time to log, so we try to avoid it.
  36. class TraceStream {
  37. public:
  38. explicit TraceStream() = default;
  39. // Returns true if tracing is currently enabled.
  40. auto is_enabled() const -> bool {
  41. return stream_.has_value() && !in_prelude_ &&
  42. allowed_phases_[static_cast<int>(current_phase_)] &&
  43. (!source_loc_ ||
  44. allowed_file_kinds_[static_cast<int>(source_loc_->file_kind())]);
  45. }
  46. // Sets whether the prelude is being skipped.
  47. auto set_in_prelude(bool in_prelude) -> void { in_prelude_ = in_prelude; }
  48. // Sets the trace stream. This should only be called from the main.
  49. auto set_stream(Nonnull<llvm::raw_ostream*> stream) -> void {
  50. stream_ = stream;
  51. }
  52. auto set_current_phase(ProgramPhase current_phase) -> void {
  53. current_phase_ = current_phase;
  54. }
  55. auto set_allowed_phases(llvm::ArrayRef<ProgramPhase> allowed_phases_list)
  56. -> void {
  57. if (allowed_phases_list.empty()) {
  58. allowed_phases_.set(static_cast<int>(ProgramPhase::Execution));
  59. } else {
  60. for (auto phase : allowed_phases_list) {
  61. if (phase == ProgramPhase::All) {
  62. allowed_phases_.set();
  63. } else {
  64. allowed_phases_.set(static_cast<int>(phase));
  65. }
  66. }
  67. }
  68. }
  69. auto set_allowed_file_kinds(llvm::ArrayRef<FileKind> kind_list) -> void {
  70. for (auto kind : kind_list) {
  71. allowed_file_kinds_.set(static_cast<int>(kind));
  72. }
  73. }
  74. auto set_source_loc(std::optional<SourceLocation> source_loc) -> void {
  75. source_loc_ = source_loc;
  76. }
  77. auto source_loc() const -> std::optional<SourceLocation> {
  78. return source_loc_;
  79. }
  80. // Returns the internal stream. Requires is_enabled.
  81. auto stream() const -> llvm::raw_ostream& {
  82. CARBON_CHECK(is_enabled() && stream_.has_value());
  83. return **stream_;
  84. }
  85. auto current_phase() const -> ProgramPhase { return current_phase_; }
  86. auto add_blank_lines(int num_blank_lines) const -> void {
  87. CARBON_CHECK(is_enabled() && stream_);
  88. if (!is_trace_empty_) {
  89. for (int i = 0; i < num_blank_lines; ++i) {
  90. **stream_ << "\n";
  91. }
  92. }
  93. }
  94. // Outputs a trace message. Requires is_enabled.
  95. template <typename T>
  96. auto operator<<(T&& message) const -> llvm::raw_ostream& {
  97. CARBON_CHECK(is_enabled() && stream_);
  98. if (is_trace_empty_) {
  99. is_trace_empty_ = false;
  100. }
  101. **stream_ << message;
  102. return **stream_;
  103. }
  104. // These functions can be used for adding line prefixes in the trace output.
  105. auto Indent() const -> llvm::raw_ostream& { return *this << " "; }
  106. auto Start() const -> llvm::raw_ostream& { return *this << "->> "; }
  107. auto End() const -> llvm::raw_ostream& { return *this << "<<- "; }
  108. auto Call() const -> llvm::raw_ostream& { return *this << "-() "; }
  109. auto Match() const -> llvm::raw_ostream& { return *this << "=== "; }
  110. auto Result() const -> llvm::raw_ostream& { return *this << "==> "; }
  111. auto Add() const -> llvm::raw_ostream& { return *this << " + "; }
  112. auto Remove() const -> llvm::raw_ostream& { return *this << " - "; }
  113. auto Read() const -> llvm::raw_ostream& { return *this << "<-- "; }
  114. auto Write() const -> llvm::raw_ostream& { return *this << "--> "; }
  115. auto Allocate() const -> llvm::raw_ostream& { return *this << "++# "; }
  116. auto Deallocate() const -> llvm::raw_ostream& { return *this << "--# "; }
  117. auto Substitute() const -> llvm::raw_ostream& { return *this << "->+ "; }
  118. auto Push() const -> llvm::raw_ostream& { return *this << ">[] "; }
  119. auto Pop() const -> llvm::raw_ostream& { return *this << "<[] "; }
  120. auto Not() const -> llvm::raw_ostream& { return *this << "-!- "; }
  121. auto Skip() const -> llvm::raw_ostream& { return *this << ">>> "; }
  122. auto Source() const -> llvm::raw_ostream& {
  123. // add a blank line before prefix.
  124. add_blank_lines(1);
  125. return *this << "*** ";
  126. }
  127. // Format utility methods
  128. void Heading(std::string_view heading) const {
  129. add_blank_lines(2);
  130. const std::string_view stars = "* * * * * * * * * *";
  131. const std::string dashed_line(stars.size() * 2 + heading.size() + 4, '-');
  132. *this << stars << " " << heading << " " << stars << "\n"
  133. << dashed_line << "\n";
  134. }
  135. void SubHeading(std::string_view sub_heading) const {
  136. add_blank_lines(1);
  137. const std::string_view dashes = "- - - - -";
  138. const std::string dashed_line(dashes.size() * 2 + sub_heading.size() + 4,
  139. '-');
  140. *this << dashes << " " << sub_heading << " " << dashes << "\n"
  141. << dashed_line << "\n";
  142. }
  143. private:
  144. bool in_prelude_ = false;
  145. mutable bool is_trace_empty_ = true;
  146. ProgramPhase current_phase_ = ProgramPhase::Unknown;
  147. std::optional<SourceLocation> source_loc_ = std::nullopt;
  148. std::optional<Nonnull<llvm::raw_ostream*>> stream_;
  149. std::bitset<static_cast<int>(ProgramPhase::Last) + 1> allowed_phases_;
  150. std::bitset<static_cast<int>(FileKind::Last) + 1> allowed_file_kinds_;
  151. };
  152. // This is a RAII class to set the current program phase, destructor invocation
  153. // restores the previous phase.
  154. class SetProgramPhase {
  155. public:
  156. explicit SetProgramPhase(TraceStream& trace_stream,
  157. ProgramPhase program_phase)
  158. : trace_stream_(trace_stream),
  159. initial_phase_(trace_stream.current_phase()) {
  160. trace_stream.set_current_phase(program_phase);
  161. }
  162. ~SetProgramPhase() { trace_stream_.set_current_phase(initial_phase_); }
  163. // This can be used for cases when current phase is set multiple times within
  164. // the same scope.
  165. auto update_phase(ProgramPhase program_phase) -> void {
  166. trace_stream_.set_current_phase(program_phase);
  167. }
  168. private:
  169. TraceStream& trace_stream_;
  170. ProgramPhase initial_phase_;
  171. };
  172. // This is a RAII class to set the source location in trace stream, destructor
  173. // invocation restores the initial source location.
  174. class SetFileContext {
  175. public:
  176. explicit SetFileContext(TraceStream& trace_stream,
  177. std::optional<SourceLocation> source_loc)
  178. : trace_stream_(trace_stream),
  179. initial_source_loc_(trace_stream.source_loc()) {
  180. trace_stream_.set_source_loc(source_loc);
  181. }
  182. ~SetFileContext() { trace_stream_.set_source_loc(initial_source_loc_); }
  183. // This can be used for cases when source location needs to be updated
  184. // multiple times within the same scope.
  185. auto update_source_loc(std::optional<SourceLocation> source_loc) {
  186. trace_stream_.set_source_loc(source_loc);
  187. }
  188. private:
  189. TraceStream& trace_stream_;
  190. std::optional<SourceLocation> initial_source_loc_;
  191. };
  192. } // namespace Carbon
  193. #endif // CARBON_EXPLORER_BASE_TRACE_STREAM_H_