mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 22:02:23 +01:00
By implementing these improvements, users will have the ability to choose specific parts of the trace output. Currently, when executing a file using the explorer with the --trace_file=- or --trace_file=filename.txt flag, the resulting output is an extensive and verbose log containing all the information. In this PR, I have introduced the `ProgramPhase` enum class, which have distinct phases encountered during the compilation of a program in the explorer. Each member of this enum class corresponds to a specific phase, signifying the relevant information to be included in the trace output. The phases covered by the `ProgramPhase` enum class are as follows: 1. Printing the source program 2. Name resolution 3. Control flow resolution 4. Type checking 5. Unformed variable resolution 6. Printing declarations 7. Printing the timings 8. Printing whole output. These phases can be selected by passing the following compiler flags along with `--trace_file=-`. `-trace_source_program`, `-trace_name_resolution`, `-trace_control_flow_resolution`, `-trace_type_checking`, `-trace_unformed_variables_resolution`, `-trace_declarations`, `-trace_execution`, `-trace_timing` and `-trace_all`. If none of these flags is passed only execution trace will be added to the output. Co-authored-by: Richard Smith <richard@metafoo.co.uk>
116 lines
4.3 KiB
C++
116 lines
4.3 KiB
C++
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
|
|
// Exceptions. See /LICENSE for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
#include "explorer/parse_and_execute/parse_and_execute.h"
|
|
|
|
#include <locale>
|
|
|
|
#include "common/check.h"
|
|
#include "common/error.h"
|
|
#include "explorer/interpreter/exec_program.h"
|
|
#include "explorer/interpreter/stack_space.h"
|
|
#include "explorer/syntax/parse.h"
|
|
#include "explorer/syntax/prelude.h"
|
|
#include "llvm/ADT/ScopeExit.h"
|
|
|
|
namespace Carbon {
|
|
|
|
// Returns a scope exit function for printing the timing of a step on scope
|
|
// exit. Note the use prints step timings in reverse order.
|
|
static auto PrintTimingOnExit(TraceStream* trace_stream, const char* label,
|
|
std::chrono::steady_clock::time_point* cursor) {
|
|
auto end = std::chrono::steady_clock::now();
|
|
auto duration = end - *cursor;
|
|
*cursor = end;
|
|
auto exit_scope_function = llvm::make_scope_exit([=]() {
|
|
trace_stream->set_current_phase(ProgramPhase::Timing);
|
|
if (trace_stream->is_enabled()) {
|
|
*trace_stream << "Time elapsed in " << label << ": "
|
|
<< std::chrono::duration_cast<std::chrono::milliseconds>(
|
|
duration)
|
|
.count()
|
|
<< "ms\n";
|
|
trace_stream->set_current_phase(ProgramPhase::Unknown);
|
|
}
|
|
});
|
|
return exit_scope_function;
|
|
}
|
|
|
|
static auto ParseAndExecuteHelper(std::function<ErrorOr<AST>(Arena*)> parse,
|
|
const std::string& prelude_path,
|
|
Nonnull<TraceStream*> trace_stream,
|
|
Nonnull<llvm::raw_ostream*> print_stream)
|
|
-> ErrorOr<int> {
|
|
return RunWithExtraStack([&]() -> ErrorOr<int> {
|
|
Arena arena;
|
|
auto cursor = std::chrono::steady_clock::now();
|
|
|
|
ErrorOr<AST> parse_result = parse(&arena);
|
|
auto print_parse_time = PrintTimingOnExit(trace_stream, "Parse", &cursor);
|
|
if (!parse_result.ok()) {
|
|
return ErrorBuilder() << "SYNTAX ERROR: " << parse_result.error();
|
|
}
|
|
|
|
AddPrelude(prelude_path, &arena, &parse_result->declarations,
|
|
&parse_result->num_prelude_declarations);
|
|
auto print_prelude_time =
|
|
PrintTimingOnExit(trace_stream, "AddPrelude", &cursor);
|
|
|
|
// Semantically analyze the parsed program.
|
|
ErrorOr<AST> analyze_result =
|
|
AnalyzeProgram(&arena, *parse_result, trace_stream, print_stream);
|
|
auto print_analyze_time =
|
|
PrintTimingOnExit(trace_stream, "AnalyzeProgram", &cursor);
|
|
if (!analyze_result.ok()) {
|
|
return ErrorBuilder() << "COMPILATION ERROR: " << analyze_result.error();
|
|
}
|
|
|
|
// Run the program.
|
|
trace_stream->set_current_phase(ProgramPhase::Execution);
|
|
ErrorOr<int> exec_result =
|
|
ExecProgram(&arena, *analyze_result, trace_stream, print_stream);
|
|
auto print_exec_time =
|
|
PrintTimingOnExit(trace_stream, "ExecProgram", &cursor);
|
|
|
|
if (!exec_result.ok()) {
|
|
return ErrorBuilder() << "RUNTIME ERROR: " << exec_result.error();
|
|
}
|
|
trace_stream->set_current_phase(ProgramPhase::Unknown);
|
|
|
|
auto print_trace_timing_heading = llvm::make_scope_exit([=]() {
|
|
trace_stream->set_current_phase(ProgramPhase::Timing);
|
|
if (trace_stream->is_enabled()) {
|
|
*trace_stream << "********** printing timing **********\n";
|
|
}
|
|
trace_stream->set_current_phase(ProgramPhase::Unknown);
|
|
});
|
|
|
|
return exec_result;
|
|
});
|
|
}
|
|
|
|
auto ParseAndExecuteFile(const std::string& prelude_path,
|
|
const std::string& input_file_name, bool parser_debug,
|
|
Nonnull<TraceStream*> trace_stream,
|
|
Nonnull<llvm::raw_ostream*> print_stream)
|
|
-> ErrorOr<int> {
|
|
auto parse = [&](Arena* arena) {
|
|
return Parse(arena, input_file_name, parser_debug);
|
|
};
|
|
return ParseAndExecuteHelper(parse, prelude_path, trace_stream, print_stream);
|
|
}
|
|
|
|
auto ParseAndExecute(const std::string& prelude_path, const std::string& source)
|
|
-> ErrorOr<int> {
|
|
auto parse = [&](Arena* arena) {
|
|
return ParseFromString(arena, "test.carbon", source,
|
|
/*parser_debug=*/false);
|
|
};
|
|
TraceStream trace_stream;
|
|
return ParseAndExecuteHelper(parse, prelude_path, &trace_stream,
|
|
&llvm::nulls());
|
|
}
|
|
|
|
} // namespace Carbon
|