You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
mindspore/mindspore/ccsrc/backend/session/kernel_build_client.h

295 lines
9.0 KiB

/**
* Copyright 2020-2021 Huawei Technologies Co., Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MINDSPORE_CCSRC_BACKEND_SESSION_KERNEL_BUILD_CLIENT_H_
#define MINDSPORE_CCSRC_BACKEND_SESSION_KERNEL_BUILD_CLIENT_H_
#include <vector>
#include <string>
#include <cstring>
#include <cstdlib>
#include <memory>
#include "common/duplex_pipe.h"
#include "utils/log_adapter.h"
#include "utils/ms_context.h"
namespace mindspore {
namespace kernel {
void ReplaceStr(std::string *dest, const std::string &replace, char new_char);
constexpr inline static int kBufferSize = 4096;
constexpr inline static auto kEnv = "python";
// The TAG as prefix of real command from remote.
constexpr inline static auto kTag = "[~]";
static std::string GetPyExe() {
// get real python executable path
auto ms_context = MsContext::GetInstance();
if (ms_context == nullptr) {
return kEnv;
}
auto env = ms_context->get_param<std::string>(MS_CTX_PYTHON_EXE_PATH);
if (env.empty()) {
return kEnv;
}
return env;
}
class KernelBuildClient {
public:
// Send Finish request to server
constexpr inline static auto kFinish = "FINISH";
constexpr inline static auto kAkgStart = "AKG/START";
constexpr inline static auto kAkgData = "AKG/DATA";
constexpr inline static auto kAkgWait = "AKG/WAIT";
// Receive the response from server
constexpr inline static auto kAck = "ACK";
constexpr inline static auto kErr = "ERR";
constexpr inline static auto kTrue = "True";
constexpr inline static auto kSuccess = "Success";
// Revert \n, \r, [space].
constexpr inline static auto kLF = "[LF]";
constexpr inline static auto kCR = "[CR]";
constexpr inline static auto kSP = "[SP]";
constexpr inline static unsigned int kTimeOutSeconds = 350;
virtual std::string GetEnv() = 0;
virtual std::string GetScript() = 0;
void Open() {
if (!init_) {
// Exception's thrown if open failed
if (dp_->Open({GetEnv(), GetScript()}, true) != -1) {
dp_->SetFinalizeCallback(std::make_shared<std::function<void()>>([this]() { Close(); }));
init_ = true;
}
}
}
void Close() {
if (init_) {
dp_->Close();
init_ = false;
}
}
// Send a request and fetch its response
std::string SendRequest(std::string data) {
Request(data);
return Response();
}
void Request(std::string req) {
if (!init_) {
MS_LOG(EXCEPTION) << "Try to send request before Open()";
}
MS_LOG(DEBUG) << "\t[" << req << "]";
*dp_ << req;
}
std::string Response() {
if (!init_) {
MS_LOG(EXCEPTION) << "Try to get response before Open()";
}
std::string res;
*dp_ >> res;
// Filter out the interference
if (res.empty()) {
MS_LOG(EXCEPTION) << "Response is empty";
}
auto start = res.find(kTag);
if (start == std::string::npos) {
MS_LOG(EXCEPTION) << "Response seems incorrect, res: " << res;
}
auto pos = start + std::strlen(kTag);
if (pos > res.size()) { // Safe check for codedex
MS_LOG(EXCEPTION) << "Response seems incorrect, res(" << res.size() << "): {" << res << "}, start: " << start;
}
res = res.substr(pos);
// Revert the line feed and space
if (res != kSuccess && res != kAck && res != kErr && res != kTrue) {
ReplaceStr(&res, kLF, '\n');
ReplaceStr(&res, kSP, ' ');
}
MS_LOG(DEBUG) << "\t[" << res << "]";
return res;
}
// Run AKG building.
bool AkgStart(int process_num, int wait_time);
bool AkgSendData(const std::vector<std::string> &jsons);
bool AkgWait();
protected:
KernelBuildClient() : init_(false), dp_(std::make_shared<DuplexPipe>()) {}
virtual ~KernelBuildClient() = default;
private:
bool init_;
std::shared_ptr<DuplexPipe> dp_;
};
static std::string GetScriptFilePath(const std::string cmd_env, const std::string &cmd_script) {
std::string cmd = cmd_env;
(void)cmd.append(1, ' ').append(cmd_script);
FILE *fpipe = popen(cmd.c_str(), "r");
if (fpipe == nullptr) {
MS_LOG(EXCEPTION) << "popen failed, errno: " << errno;
}
bool start = false;
std::string result;
char buf[kBufferSize];
while (std::fgets(buf, sizeof(buf), fpipe) != nullptr) {
auto len = std::strlen(buf);
if (len == 0 || len >= kBufferSize) {
// Safe check for codedex
// Should never reach here
MS_LOG(EXCEPTION) << "fgets() failed, len: " << len << ", errno: " << errno;
}
if (std::strncmp(buf, kTag, std::strlen(kTag)) == 0) {
start = true;
}
// Filter with 'kTAG' and '\n'
if (start) {
bool line_end = buf[len - 1] == '\n';
result.append(buf, line_end ? len - 1 : len);
if (line_end) {
break;
}
}
}
pclose(fpipe);
const std::string py_suffix = ".py";
if (result.empty() || result.rfind(py_suffix) != (result.length() - py_suffix.length())) {
MS_LOG(EXCEPTION) << "py file seems incorrect, result: {" << result << "}";
}
if (strlen(kTag) > result.size()) { // Safe check for codedex
MS_LOG(EXCEPTION) << "result size seems incorrect, result(" << result.size() << "): {" << result << "}";
}
result = result.substr(strlen(kTag));
MS_LOG(DEBUG) << "result: " << result;
return result;
}
class AscendKernelBuildClient : public KernelBuildClient {
public:
// Server configure
constexpr inline static auto kGetPathScript =
"-c "
"\""
"import pkgutil;"
"path = pkgutil"
".get_loader(\\\"mindspore._extends.remote.kernel_build_server_ascend\\\")" // Server module name
".get_filename();"
"print('[~]' + path)"
"\"";
// Receive the response from server
constexpr inline static auto kFailed = "-1";
// Send building request to server
constexpr inline static auto kContinue = "CONTINUE"; // More transactions to be continued
constexpr inline static auto kTbePre = "TBE/PRE";
constexpr inline static auto kTbeStart = "TBE/START";
constexpr inline static auto kTbeWait = "TBE/WAIT";
constexpr inline static auto kTbeReset = "TBE/RESET";
constexpr inline static auto kTbeTune = "TBE/TUNE";
// Send server info. query to server
constexpr inline static auto kFormat = "FORMAT";
constexpr inline static auto kSupport = "SUPPORT";
static AscendKernelBuildClient &Instance() {
static AscendKernelBuildClient instance;
return instance;
}
std::string GetEnv() override { return GetPyExe(); }
std::string GetScript() override {
auto env = GetPyExe();
return GetScriptFilePath(env, kGetPathScript);
}
// Before building.
std::string SelectFormat(const std::string &json);
bool CheckSupported(const std::string &json);
// Run TBE building.
int TbeStart(const std::string &json, const std::string &mode);
bool TbeWait(int *task_id, std::string *task_result, std::string *pre_build_result);
void TbeReset();
AscendKernelBuildClient(const AscendKernelBuildClient &) = delete;
AscendKernelBuildClient &operator=(const AscendKernelBuildClient &) = delete;
AscendKernelBuildClient(AscendKernelBuildClient &&) = delete;
AscendKernelBuildClient &operator=(AscendKernelBuildClient &&) = delete;
private:
bool TbePre(const std::string &mode);
AscendKernelBuildClient() { Open(); }
~AscendKernelBuildClient() override { Close(); }
};
class GpuKernelBuildClient : public KernelBuildClient {
public:
// Server configure
constexpr inline static auto kGetPathScript =
"-c "
"\""
"import pkgutil;"
"path = pkgutil"
".get_loader(\\\"mindspore._extends.remote.kernel_build_server_gpu\\\")" // Server module name
".get_filename();"
"print('[~]' + path)"
"\"";
// Send building request to server
constexpr inline static auto kAkgPid = "AKG/PID";
constexpr inline static auto kAkgCompileOp = "AKG/COMPILE"; // Compile a single op
static GpuKernelBuildClient &Instance() {
static GpuKernelBuildClient instance;
return instance;
}
std::string GetEnv() override { return GetPyExe(); }
std::string GetScript() override {
auto env = GetPyExe();
return GetScriptFilePath(env, kGetPathScript);
}
// Fetch pid(pid_t) from remote.
int AkgGetPid();
// Run AKG building.
bool AkgCompileSingle(const std::string json);
GpuKernelBuildClient(const GpuKernelBuildClient &) = delete;
GpuKernelBuildClient &operator=(const GpuKernelBuildClient &) = delete;
GpuKernelBuildClient(GpuKernelBuildClient &&) = delete;
GpuKernelBuildClient &operator=(GpuKernelBuildClient &&) = delete;
private:
GpuKernelBuildClient() { Open(); }
~GpuKernelBuildClient() override { Close(); }
};
} // namespace kernel
} // namespace mindspore
#endif // MINDSPORE_CCSRC_BACKEND_SESSION_KERNEL_BUILD_CLIENT_H_