1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "phase_impl.h"
17 #include <cstdlib>
18 #include "mpl_timer.h"
19
20 namespace maple {
21 // ========== FuncOptimizeImpl ==========
FuncOptimizeImpl(MIRModule & mod,KlassHierarchy * kh,bool currTrace)22 FuncOptimizeImpl::FuncOptimizeImpl(MIRModule &mod, KlassHierarchy *kh, bool currTrace)
23 : klassHierarchy(kh), trace(currTrace), module(&mod)
24 {
25 builder = new (std::nothrow) MIRBuilderExt(module);
26 CHECK_FATAL(builder != nullptr, "New fail in FuncOptimizeImpl ctor!");
27 }
28
~FuncOptimizeImpl()29 FuncOptimizeImpl::~FuncOptimizeImpl()
30 {
31 if (builder != nullptr) {
32 delete builder;
33 builder = nullptr;
34 }
35 klassHierarchy = nullptr;
36 currFunc = nullptr;
37 module = nullptr;
38 }
39
CreateLocalBuilder(pthread_mutex_t & mtx)40 void FuncOptimizeImpl::CreateLocalBuilder(pthread_mutex_t &mtx)
41 {
42 // Each thread needs to use its own MIRBuilderExt.
43 builder = new (std::nothrow) MIRBuilderExt(module, &mtx);
44 CHECK_FATAL(builder != nullptr, "New fail in CreateLocalBuilder ctor!");
45 }
46
ProcessFunc(MIRFunction * func)47 void FuncOptimizeImpl::ProcessFunc(MIRFunction *func)
48 {
49 currFunc = func;
50 SetCurrentFunction(*func);
51 if (func->GetBody() != nullptr) {
52 ProcessBlock(*func->GetBody());
53 }
54 }
55
ProcessBlock(StmtNode & stmt)56 void FuncOptimizeImpl::ProcessBlock(StmtNode &stmt)
57 {
58 switch (stmt.GetOpCode()) {
59 case OP_if: {
60 ProcessStmt(stmt);
61 IfStmtNode &ifStmtNode = static_cast<IfStmtNode &>(stmt);
62 if (ifStmtNode.GetThenPart() != nullptr) {
63 ProcessBlock(*ifStmtNode.GetThenPart());
64 }
65 if (ifStmtNode.GetElsePart() != nullptr) {
66 ProcessBlock(*ifStmtNode.GetElsePart());
67 }
68 break;
69 }
70 case OP_while:
71 case OP_dowhile: {
72 ProcessStmt(stmt);
73 WhileStmtNode &whileStmtNode = static_cast<WhileStmtNode &>(stmt);
74 if (whileStmtNode.GetBody() != nullptr) {
75 ProcessBlock(*whileStmtNode.GetBody());
76 }
77 break;
78 }
79 case OP_block: {
80 BlockNode &block = static_cast<BlockNode &>(stmt);
81 for (StmtNode *stmtNode = block.GetFirst(), *next = nullptr; stmtNode != nullptr; stmtNode = next) {
82 SetCurrentBlock(block);
83 ProcessBlock(*stmtNode);
84 next = stmtNode->GetNext();
85 }
86 break;
87 }
88 default: {
89 ProcessStmt(stmt);
90 break;
91 }
92 }
93 }
94
95 // ========== FuncOptimizeIterator ==========
96 thread_local FuncOptimizeImpl *FuncOptimizeIterator::phaseImplLocal = nullptr;
97
FuncOptimizeIterator(const std::string & phaseName,std::unique_ptr<FuncOptimizeImpl> phaseImpl)98 FuncOptimizeIterator::FuncOptimizeIterator(const std::string &phaseName, std::unique_ptr<FuncOptimizeImpl> phaseImpl)
99 : MplScheduler(phaseName), phaseImpl(std::move(phaseImpl))
100 {
101 char *envStr = getenv("MP_DUMPTIME");
102 mplDumpTime = (envStr != nullptr && atoi(envStr) == 1);
103 }
104
105 FuncOptimizeIterator::~FuncOptimizeIterator() = default;
106
Run(uint32 threadNum,bool isSeq)107 void FuncOptimizeIterator::Run(uint32 threadNum, bool isSeq)
108 {
109 if (threadNum == 1) {
110 RunSerial();
111 } else {
112 RunParallel(threadNum, isSeq);
113 }
114 }
115
116 constexpr double kMicroseconds2Milli = 1000.0;
RunSerial()117 void FuncOptimizeIterator::RunSerial()
118 {
119 MPLTimer timer;
120 if (mplDumpTime) {
121 timer.Start();
122 }
123
124 CHECK_NULL_FATAL(phaseImpl);
125 for (MIRFunction *func : phaseImpl->GetMIRModule().GetFunctionList()) {
126 auto dumpPhase = [this, func](bool dumpOption, std::string &&s) {
127 if (dumpOption) {
128 LogInfo::MapleLogger() << ">>>>> Dump " << s << schedulerName << " <<<<<\n";
129 func->Dump();
130 LogInfo::MapleLogger() << ">>>>> Dump " << s << schedulerName << " end <<<<<\n";
131 }
132 };
133 bool dumpFunc = (Options::dumpFunc == "*" || Options::dumpFunc == func->GetName()) &&
134 (Options::dumpPhase == "*" || Options::dumpPhase == schedulerName);
135 dumpPhase(Options::dumpBefore && dumpFunc, "before ");
136 phaseImpl->SetDump(dumpFunc);
137 phaseImpl->ProcessFunc(func);
138 dumpPhase(Options::dumpAfter && dumpFunc, "after ");
139 }
140
141 phaseImpl->Finish();
142
143 if (mplDumpTime) {
144 timer.Stop();
145 INFO(kLncInfo, "FuncOptimizeIterator::RunSerial (%s): %lf ms", schedulerName.c_str(),
146 timer.ElapsedMicroseconds() / kMicroseconds2Milli);
147 }
148 }
149
RunParallel(uint32 threadNum,bool isSeq)150 void FuncOptimizeIterator::RunParallel(uint32 threadNum, bool isSeq)
151 {
152 MPLTimer timer;
153 if (mplDumpTime) {
154 timer.Start();
155 }
156 Reset();
157
158 CHECK_NULL_FATAL(phaseImpl);
159 for (MIRFunction *func : phaseImpl->GetMIRModule().GetFunctionList()) {
160 std::unique_ptr<Task> task = std::make_unique<Task>(*func);
161 ASSERT_NOT_NULL(task);
162 AddTask(*task.get());
163 tasksUniquePtr.emplace_back(std::move(task));
164 }
165
166 if (mplDumpTime) {
167 timer.Stop();
168 INFO(kLncInfo, "FuncOptimizeIterator::RunParallel (%s): AddTask() = %lf ms", schedulerName.c_str(),
169 timer.ElapsedMicroseconds() / kMicroseconds2Milli);
170
171 timer.Start();
172 }
173
174 int ret = RunTask(threadNum, isSeq);
175 CHECK_FATAL(ret == 0, "RunTask failed");
176 phaseImpl->Finish();
177 Reset();
178
179 if (mplDumpTime) {
180 timer.Stop();
181 INFO(kLncInfo, "FuncOptimizeIterator::RunParallel (%s): RunTask() = %lf ms", schedulerName.c_str(),
182 timer.ElapsedMicroseconds() / kMicroseconds2Milli);
183 }
184 }
185 } // namespace maple
186