Skip to content

Commit adff3e1

Browse files
macurtis-amdTarun Prabhu
authored andcommitted
Automerge: [flang][Driver] Preliminary support for -ftime-report (#122894)
The behavior is not entirely consistent with that of clang for the moment since detailed timing information on the LLVM IR optimization and code generation passes is not provided. The -ftime-report= option is also not enabled since that is only relevant for information about the LLVM IR passes. However, some code to handle that option has been included, to make it easier to support the option when the issues blocking it are resolved. A FortranSupport library has been created that is intended to mirror the LLVM and MLIR support libraries. Based on @tarunprabhu's PR llvm/llvm-project#107270 with minor changes addressing latest review feedback. He's busy and we'd like to get this support in ASAP. Co-authored-by: Tarun Prabhu <tarun.prabhu@gmail.com>
2 parents 4c2dbf0 + 310c281 commit adff3e1

File tree

14 files changed

+352
-12
lines changed

14 files changed

+352
-12
lines changed

clang/include/clang/Driver/Options.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4108,7 +4108,7 @@ defm ms_tls_guards : BoolFOption<"ms-tls-guards",
41084108
"Do not emit code to perform on-demand initialization of thread-local variables">,
41094109
PosFlag<SetTrue>>;
41104110
def ftime_report : Flag<["-"], "ftime-report">, Group<f_Group>,
4111-
Visibility<[ClangOption, CC1Option]>,
4111+
Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>,
41124112
MarshallingInfoFlag<CodeGenOpts<"TimePasses">>;
41134113
def ftime_report_EQ: Joined<["-"], "ftime-report=">, Group<f_Group>,
41144114
Visibility<[ClangOption, CC1Option]>, Values<"per-pass,per-pass-run">,

clang/lib/Driver/ToolChains/Flang.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -150,10 +150,12 @@ void Flang::addCodegenOptions(const ArgList &Args,
150150
if (shouldLoopVersion(Args))
151151
CmdArgs.push_back("-fversion-loops-for-stride");
152152

153-
Args.addAllArgs(CmdArgs, {options::OPT_flang_experimental_hlfir,
154-
options::OPT_flang_deprecated_no_hlfir,
155-
options::OPT_fno_ppc_native_vec_elem_order,
156-
options::OPT_fppc_native_vec_elem_order});
153+
Args.addAllArgs(CmdArgs,
154+
{options::OPT_flang_experimental_hlfir,
155+
options::OPT_flang_deprecated_no_hlfir,
156+
options::OPT_fno_ppc_native_vec_elem_order,
157+
options::OPT_fppc_native_vec_elem_order,
158+
options::OPT_ftime_report, options::OPT_ftime_report_EQ});
157159
}
158160

159161
void Flang::addPicOptions(const ArgList &Args, ArgStringList &CmdArgs) const {

flang/include/flang/Frontend/CompilerInstance.h

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "flang/Parser/provenance.h"
2121
#include "flang/Semantics/runtime-type-info.h"
2222
#include "flang/Semantics/semantics.h"
23+
#include "flang/Support/StringOstream.h"
2324
#include "llvm/Support/raw_ostream.h"
2425
#include "llvm/Target/TargetMachine.h"
2526

@@ -85,6 +86,27 @@ class CompilerInstance {
8586
/// facilitate this. It is optional and will normally be just a nullptr.
8687
std::unique_ptr<llvm::raw_pwrite_stream> outputStream;
8788

89+
/// @name Timing
90+
/// Objects needed when timing is enabled.
91+
/// @{
92+
/// The timing manager.
93+
mlir::DefaultTimingManager timingMgr;
94+
95+
/// The root of the timingScope. This will be reset in @ref executeAction if
96+
/// timers have been enabled.
97+
mlir::TimingScope timingScopeRoot;
98+
99+
/// @name Timing stream
100+
/// The output streams to capture the timing. Three different streams are
101+
/// needed because the timing classes all work slightly differently. We create
102+
/// these streams so we have control over when and how the timing is
103+
/// displayed. Otherwise, the timing is only displayed when the corresponding
104+
/// managers/timers go out of scope.
105+
std::unique_ptr<Fortran::support::string_ostream> timingStreamMLIR;
106+
std::unique_ptr<Fortran::support::string_ostream> timingStreamLLVM;
107+
std::unique_ptr<Fortran::support::string_ostream> timingStreamCodeGen;
108+
/// @}
109+
88110
public:
89111
explicit CompilerInstance();
90112

@@ -254,6 +276,42 @@ class CompilerInstance {
254276
/// Produces the string which represents target feature
255277
std::string getTargetFeatures();
256278

279+
/// {
280+
/// @name Timing
281+
/// @{
282+
bool isTimingEnabled() const { return timingMgr.isEnabled(); }
283+
284+
mlir::DefaultTimingManager &getTimingManager() { return timingMgr; }
285+
const mlir::DefaultTimingManager &getTimingManager() const {
286+
return timingMgr;
287+
}
288+
289+
mlir::TimingScope &getTimingScopeRoot() { return timingScopeRoot; }
290+
const mlir::TimingScope &getTimingScopeRoot() const {
291+
return timingScopeRoot;
292+
}
293+
294+
/// Get the timing stream for the MLIR pass manager.
295+
llvm::raw_ostream &getTimingStreamMLIR() {
296+
assert(timingStreamMLIR && "Timing stream for MLIR was not set");
297+
return *timingStreamMLIR;
298+
}
299+
300+
/// Get the timing stream for the new LLVM pass manager.
301+
llvm::raw_ostream &getTimingStreamLLVM() {
302+
assert(timingStreamLLVM && "Timing stream for LLVM was not set");
303+
return *timingStreamLLVM;
304+
}
305+
306+
/// Get the timing stream fro the legacy LLVM pass manager.
307+
/// NOTE: If the codegen is updated to use the new pass manager, this should
308+
/// no longer be needed.
309+
llvm::raw_ostream &getTimingStreamCodeGen() {
310+
assert(timingStreamCodeGen && "Timing stream for codegen was not set");
311+
return *timingStreamCodeGen;
312+
}
313+
/// @}
314+
257315
private:
258316
/// Create a new output file
259317
///

flang/include/flang/Frontend/CompilerInvocation.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "flang/Lower/LoweringOptions.h"
2222
#include "flang/Parser/parsing.h"
2323
#include "flang/Semantics/semantics.h"
24+
#include "mlir/Support/Timing.h"
2425
#include "clang/Basic/Diagnostic.h"
2526
#include "clang/Basic/DiagnosticOptions.h"
2627
#include "llvm/Option/ArgList.h"
@@ -143,6 +144,10 @@ class CompilerInvocation : public CompilerInvocationBase {
143144
},
144145
};
145146

147+
/// Whether to time the invocation. Set when -ftime-report or -ftime-report=
148+
/// is enabled.
149+
bool enableTimers;
150+
146151
public:
147152
CompilerInvocation() = default;
148153

@@ -222,6 +227,8 @@ class CompilerInvocation : public CompilerInvocationBase {
222227
return defaultKinds;
223228
}
224229

230+
bool getEnableTimers() const { return enableTimers; }
231+
225232
/// Create a compiler invocation from a list of input options.
226233
/// \returns true on success.
227234
/// \returns false if an error was encountered while parsing the arguments
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
//===-- CompilerInstance.h - Flang Compiler Instance ------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef FORTRAN_SUPPORT_STRINGOSTREAM_H
14+
#define FORTRAN_SUPPORT_STRINGOSTREAM_H
15+
16+
#include <llvm/Support/raw_ostream.h>
17+
18+
namespace Fortran::support {
19+
20+
/// Helper class to maintain both the an llvm::raw_string_ostream object and
21+
/// its associated buffer.
22+
class string_ostream : public llvm::raw_string_ostream {
23+
private:
24+
std::string buf;
25+
26+
public:
27+
string_ostream() : llvm::raw_string_ostream(buf) {}
28+
};
29+
30+
} // namespace Fortran::support
31+
32+
#endif // FORTRAN_SUPPORT_STRINGOSTREAM_H

flang/include/flang/Support/Timing.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//===- Timing.h - Execution time measurement facilities ---------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// Facilities to measure and provide statistics on execution time.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef FORTRAN_SUPPORT_TIMING_H
14+
#define FORTRAN_SUPPORT_TIMING_H
15+
16+
#include "mlir/Support/Timing.h"
17+
18+
namespace Fortran::support {
19+
20+
/// Create a strategy to render the captured times in plain text. This is
21+
/// intended to be passed to a TimingManager.
22+
std::unique_ptr<mlir::OutputStrategy> createTimingFormatterText(
23+
llvm::raw_ostream &os);
24+
25+
} // namespace Fortran::support
26+
27+
#endif // FORTRAN_SUPPORT_TIMING_H

flang/lib/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ add_subdirectory(Decimal)
44
add_subdirectory(Lower)
55
add_subdirectory(Parser)
66
add_subdirectory(Semantics)
7+
add_subdirectory(Support)
78
add_subdirectory(Frontend)
89
add_subdirectory(FrontendTool)
910

flang/lib/Frontend/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ add_flang_library(flangFrontend
2929
FortranEvaluate
3030
FortranCommon
3131
FortranLower
32+
FortranSupport
3233
FIRDialect
3334
FIRDialectSupport
3435
FIRSupport

flang/lib/Frontend/CompilerInstance.cpp

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,12 @@
1717
#include "flang/Parser/parsing.h"
1818
#include "flang/Parser/provenance.h"
1919
#include "flang/Semantics/semantics.h"
20+
#include "flang/Support/Timing.h"
21+
#include "mlir/Support/RawOstreamExtras.h"
2022
#include "clang/Basic/DiagnosticFrontend.h"
2123
#include "llvm/ADT/StringExtras.h"
2224
#include "llvm/MC/TargetRegistry.h"
25+
#include "llvm/Pass.h"
2326
#include "llvm/Support/Errc.h"
2427
#include "llvm/Support/Error.h"
2528
#include "llvm/Support/FileSystem.h"
@@ -147,7 +150,7 @@ void CompilerInstance::clearOutputFiles(bool eraseFiles) {
147150
}
148151

149152
bool CompilerInstance::executeAction(FrontendAction &act) {
150-
auto &invoc = this->getInvocation();
153+
CompilerInvocation &invoc = this->getInvocation();
151154

152155
llvm::Triple targetTriple{llvm::Triple(invoc.getTargetOpts().triple)};
153156
if (targetTriple.getArch() == llvm::Triple::ArchType::x86_64) {
@@ -167,6 +170,25 @@ bool CompilerInstance::executeAction(FrontendAction &act) {
167170
// Set options controlling lowering to FIR.
168171
invoc.setLoweringOptions();
169172

173+
if (invoc.getEnableTimers()) {
174+
llvm::TimePassesIsEnabled = true;
175+
176+
timingStreamMLIR = std::make_unique<Fortran::support::string_ostream>();
177+
timingStreamLLVM = std::make_unique<Fortran::support::string_ostream>();
178+
timingStreamCodeGen = std::make_unique<Fortran::support::string_ostream>();
179+
180+
timingMgr.setEnabled(true);
181+
timingMgr.setDisplayMode(mlir::DefaultTimingManager::DisplayMode::Tree);
182+
timingMgr.setOutput(
183+
Fortran::support::createTimingFormatterText(*timingStreamMLIR));
184+
185+
// Creating a new TimingScope will automatically start the timer. Since this
186+
// is the top-level timer, this is ok because it will end up capturing the
187+
// time for all the bookkeeping and other tasks that take place between
188+
// parsing, lowering etc. for which finer-grained timers will be created.
189+
timingScopeRoot = timingMgr.getRootScope();
190+
}
191+
170192
// Run the frontend action `act` for every input file.
171193
for (const FrontendInputFile &fif : getFrontendOpts().inputs) {
172194
if (act.beginSourceFile(*this, fif)) {
@@ -176,6 +198,34 @@ bool CompilerInstance::executeAction(FrontendAction &act) {
176198
act.endSourceFile();
177199
}
178200
}
201+
202+
if (timingMgr.isEnabled()) {
203+
timingScopeRoot.stop();
204+
205+
// Write the timings to the associated output stream and clear all timers.
206+
// We need to provide another stream because the TimingManager will attempt
207+
// to print in its destructor even if it has been cleared. By the time that
208+
// destructor runs, the output streams will have been destroyed, so give it
209+
// a null stream.
210+
timingMgr.print();
211+
timingMgr.setOutput(
212+
Fortran::support::createTimingFormatterText(mlir::thread_safe_nulls()));
213+
214+
// This prints the timings in "reverse" order, starting from code
215+
// generation, followed by LLVM-IR optimizations, then MLIR optimizations
216+
// and transformations and the frontend. If any of the steps are disabled,
217+
// for instance because code generation was not performed, the strings
218+
// will be empty.
219+
if (!timingStreamCodeGen->str().empty())
220+
llvm::errs() << timingStreamCodeGen->str() << "\n";
221+
222+
if (!timingStreamLLVM->str().empty())
223+
llvm::errs() << timingStreamLLVM->str() << "\n";
224+
225+
if (!timingStreamMLIR->str().empty())
226+
llvm::errs() << timingStreamMLIR->str() << "\n";
227+
}
228+
179229
return !getDiagnostics().getClient()->getNumErrors();
180230
}
181231

flang/lib/Frontend/CompilerInvocation.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1436,6 +1436,10 @@ bool CompilerInvocation::createFromArgs(
14361436
}
14371437
}
14381438

1439+
// Process the timing-related options.
1440+
if (args.hasArg(clang::driver::options::OPT_ftime_report))
1441+
invoc.enableTimers = true;
1442+
14391443
invoc.setArgv0(argv0);
14401444

14411445
return success;

0 commit comments

Comments
 (0)