• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright 2020-2023 Huawei Technologies Co., Ltd
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef MINDSPORE_CCSRC_BACKEND_SESSION_KERNEL_BUILD_CLIENT_H_
18 #define MINDSPORE_CCSRC_BACKEND_SESSION_KERNEL_BUILD_CLIENT_H_
19 
20 #include <vector>
21 #include <string>
22 #include <cstring>
23 #include <memory>
24 #include <mutex>
25 
26 #include "include/common/duplex_pipe.h"
27 #include "include/backend/visible.h"
28 #include "utils/log_adapter.h"
29 #include "utils/ms_context.h"
30 
31 namespace mindspore {
32 namespace kernel {
33 void ReplaceStr(std::string *dest, const std::string &replace, char new_char);
34 
35 constexpr inline static int kBufferSize = 4096;
36 constexpr inline static auto kEnv = "python";
37 // The TAG as prefix of real command from remote.
38 constexpr inline static auto kTag = "[~]";
39 BACKEND_EXPORT std::string GetPyExe();
40 BACKEND_EXPORT std::string GetCmdResult();
41 
42 class BACKEND_EXPORT KernelBuildClient {
43  public:
44   // Send Finish request to server
45   constexpr inline static auto kFinish = "FINISH";
46   constexpr inline static auto kCompilerStart = "AKG/START";
47   constexpr inline static auto kCompilerData = "AKG/DATA";
48   constexpr inline static auto kCompilerAttr = "AKG/ATTR";
49   constexpr inline static auto kCompilerWait = "AKG/WAIT";
50   // Receive the response from server
51   constexpr inline static auto kAck = "ACK";
52   constexpr inline static auto kErr = "ERR";
53   constexpr inline static auto kTrue = "True";
54   constexpr inline static auto kSuccess = "Success";
55 
56   // Revert \n, \r, [space].
57   constexpr inline static auto kLF = "[LF]";
58   constexpr inline static auto kCR = "[CR]";
59   constexpr inline static auto kSP = "[SP]";
60 
61   virtual std::string GetEnv() = 0;
62   virtual std::string GetScript() = 0;
63 
Open()64   void Open() {
65     if (!init_) {
66       // Exception's thrown if open failed
67       if (dp_->Open({GetEnv(), GetScript()}, true) != -1) {
68         dp_->SetFinalizeCallback(std::make_shared<std::function<void()>>([this]() { Close(); }));
69         init_ = true;
70       }
71     }
72   }
Close()73   void Close() noexcept {
74     if (init_) {
75       dp_->Close();
76       init_ = false;
77     }
78   }
IsOpen()79   bool IsOpen() const { return init_; }
80 
81   // Send a request and fetch its response
SendRequest(const std::string & data)82   std::string SendRequest(const std::string &data) {
83     std::lock_guard<std::mutex> locker(mutex_);
84     Request(data);
85     return Response();
86   }
Request(const std::string & req)87   void Request(const std::string &req) {
88     if (!init_) {
89       MS_LOG(EXCEPTION) << "Try to send request before Open(). For more details, please refer to this FAQ: "
90                         << "https://www.mindspore.cn/tutorials/zh-CN/master/advanced/error_analysis/mindrt_debug.html";
91     }
92     *dp_ << req;
93   }
Response()94   std::string Response() {
95     if (!init_) {
96       MS_LOG(EXCEPTION) << "Try to get response before Open(). For more details, please refer to this FAQ: "
97                         << "https://www.mindspore.cn/tutorials/zh-CN/master/advanced/error_analysis/mindrt_debug.html";
98     }
99     std::string res;
100     *dp_ >> res;
101     // Filter out the interference
102     if (res.empty()) {
103       MS_LOG(EXCEPTION) << "Response is empty. For more details, please refer to this FAQ: "
104                         << "https://www.mindspore.cn/tutorials/zh-CN/master/advanced/error_analysis/mindrt_debug.html";
105     }
106     auto start = res.find(kTag);
107     if (start == std::string::npos) {
108       MS_LOG(EXCEPTION) << "Response seems incorrect, res: " << res;
109     }
110     auto pos = start + std::strlen(kTag);
111     if (pos > res.size()) {  // Safe check for codedex
112       MS_LOG(EXCEPTION) << "Response seems incorrect, res(" << res.size() << "): {" << res << "}, start: " << start;
113     }
114     res = res.substr(pos);
115     // Revert the line feed and space
116     if (res != kSuccess && res != kAck && res != kErr && res != kTrue) {
117       ReplaceStr(&res, kLF, '\n');
118       ReplaceStr(&res, kSP, ' ');
119     }
120     return res;
121   }
122 
123   // Run Kernel Compiler building.
124   bool CompilerStart(int process_num, int wait_time, const std::string &platform);
125   bool CompilerSendAttr(const std::string &attr);
126   bool CompilerSendData(const std::vector<std::string> &jsons);
127   bool CompilerWait();
128 
129  protected:
KernelBuildClient()130   KernelBuildClient() : init_(false), dp_(std::make_shared<DuplexPipe>()) {}
131   virtual ~KernelBuildClient() = default;
132 
133  private:
134   // Support multi-thread.
135   std::mutex mutex_;
136   bool init_;
137   std::shared_ptr<DuplexPipe> dp_;
138 };
139 
GetCmdResult(const std::string & cmd)140 static std::string GetCmdResult(const std::string &cmd) {
141 #ifdef _MSC_VER
142   FILE *fpipe = _popen(cmd.c_str(), "r");
143 #else
144   FILE *fpipe = popen(cmd.c_str(), "r");
145 #endif
146   if (fpipe == nullptr) {
147     MS_LOG(EXCEPTION) << "popen failed, errno: " << errno;
148   }
149   bool start = false;
150   std::string result;
151   char buf[kBufferSize];
152   while (std::fgets(buf, sizeof(buf), fpipe) != nullptr) {
153     auto len = std::strlen(buf);
154     if (len == 0 || len >= kBufferSize) {
155       // Safe check for codedex
156       // Should never reach here
157       MS_LOG(EXCEPTION) << "fgets() failed, len: " << len << ", errno: " << errno;
158     }
159     if (std::strncmp(buf, kTag, std::strlen(kTag)) == 0) {
160       start = true;
161     }
162     // Filter with 'kTAG' and '\n'
163     if (start) {
164       bool line_end = buf[len - 1] == '\n';
165       (void)result.append(buf, line_end ? len - 1 : len);
166       if (line_end) {
167         break;
168       }
169     }
170   }
171 #ifdef _MSC_VER
172   (void)_pclose(fpipe);
173 #else
174   (void)pclose(fpipe);
175 #endif
176   return result;
177 }
178 
GetScriptFilePath(const std::string & cmd_env,const std::string & cmd_script,const std::string & server_script)179 static std::string GetScriptFilePath(const std::string &cmd_env, const std::string &cmd_script,
180                                      const std::string &server_script) {
181   auto ms_context = MsContext::GetInstance();
182   MS_EXCEPTION_IF_NULL(ms_context);
183   auto server_dir = ms_context->get_param<std::string>(MS_CTX_KERNEL_BUILD_SERVER_DIR);
184   if (!server_dir.empty()) {
185     return server_dir + server_script;
186   }
187 
188   std::string cmd = cmd_env;
189   (void)cmd.append(1, ' ').append(cmd_script);
190   auto result = GetCmdResult(cmd);
191   const std::string py_suffix = ".py";
192   if (result.empty() || result.rfind(py_suffix) != (result.length() - py_suffix.length())) {
193     MS_LOG(EXCEPTION) << "py file seems incorrect, result: {" << result << "}";
194   }
195   if (strlen(kTag) > result.size()) {  // Safe check for codedex
196     MS_LOG(EXCEPTION) << "result size seems incorrect, result(" << result.size() << "): {" << result << "}";
197   }
198   result = result.substr(strlen(kTag));
199   MS_LOG(DEBUG) << "result: " << result;
200   return result;
201 }
202 
203 class BACKEND_EXPORT AkgKernelBuildClient : public KernelBuildClient {
204  public:
205   // Server configure
206   constexpr inline static auto kGetPathScript =
207     "-c "
208     "\""
209     "import pkgutil;"
210     "path = pkgutil"
211     ".get_loader(\\\"mindspore._extends.remote.kernel_build_server_akg\\\")"  // Server module name
212     ".get_filename();"
213     "print('[~]' + path)"
214     "\"";
215 
216   constexpr inline static auto kServerScript = "kernel_build_server_akg.py";
217 
218   static AkgKernelBuildClient &Instance();
219 
GetEnv()220   std::string GetEnv() override { return GetPyExe(); }
221 
GetScript()222   std::string GetScript() override {
223     auto env = GetPyExe();
224     return GetScriptFilePath(env, kGetPathScript, kServerScript);
225   }
226 
227   AkgKernelBuildClient(const AkgKernelBuildClient &) = delete;
228   AkgKernelBuildClient &operator=(const AkgKernelBuildClient &) = delete;
229 
230   AkgKernelBuildClient(AkgKernelBuildClient &&) = delete;
231   AkgKernelBuildClient &operator=(AkgKernelBuildClient &&) = delete;
232 
233  protected:
~AkgKernelBuildClient()234   ~AkgKernelBuildClient() override { Close(); }
235 
236  private:
AkgKernelBuildClient()237   AkgKernelBuildClient() { Open(); }
238 };
239 
240 class BACKEND_EXPORT AkgV2KernelBuildClient : public KernelBuildClient {
241  public:
242   // Server configure
243   constexpr inline static auto kGetPathScript =
244     "-c "
245     "\""
246     "import pkgutil;"
247     "path = pkgutil"
248     ".get_loader(\\\"mindspore._extends.remote.kernel_build_server_akg_v2\\\")"  // Server module name
249     ".get_filename();"
250     "print('[~]' + path)"
251     "\"";
252 
253   constexpr inline static auto kServerScript = "kernel_build_server_akg_v2.py";
254 
255   static AkgV2KernelBuildClient &Instance();
256 
GetEnv()257   std::string GetEnv() override { return GetPyExe(); }
258 
GetScript()259   std::string GetScript() override {
260     auto env = GetPyExe();
261     return GetScriptFilePath(env, kGetPathScript, kServerScript);
262   }
263 
264   AkgV2KernelBuildClient(const AkgV2KernelBuildClient &) = delete;
265   AkgV2KernelBuildClient &operator=(const AkgV2KernelBuildClient &) = delete;
266 
267   AkgV2KernelBuildClient(AkgV2KernelBuildClient &&) = delete;
268   AkgV2KernelBuildClient &operator=(AkgV2KernelBuildClient &&) = delete;
269 
270  protected:
~AkgV2KernelBuildClient()271   ~AkgV2KernelBuildClient() override { Close(); }
272 
273  private:
AkgV2KernelBuildClient()274   AkgV2KernelBuildClient() { Open(); }
275 };
276 }  // namespace kernel
277 }  // namespace mindspore
278 
279 #endif  // MINDSPORE_CCSRC_BACKEND_SESSION_KERNEL_BUILD_CLIENT_H_
280