You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

utils.cpp 8.6 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. /**
  2. * \file src/jit/impl/utils.cpp
  3. * MegEngine is Licensed under the Apache License, Version 2.0 (the "License")
  4. *
  5. * Copyright (c) 2014-2020 Megvii Inc. All rights reserved.
  6. *
  7. * Unless required by applicable law or agreed to in writing,
  8. * software distributed under the License is distributed on an
  9. * "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. */
  11. #include "megbrain_build_config.h"
  12. #if MGB_JIT
  13. #include "megbrain/utils/debug.h"
  14. #include "megbrain/jit/utils.h"
  15. #include <atomic>
  16. #ifdef __linux__
  17. #include <dlfcn.h>
  18. #include <ftw.h>
  19. #include <link.h>
  20. #include <sys/stat.h>
  21. #include <sys/types.h>
  22. #include <unistd.h>
  23. #include <cerrno>
  24. #include <cstdio>
  25. #include <cstdlib>
  26. #include <cstring>
  27. #endif // __linux__
  28. using namespace mgb;
  29. using namespace jit;
  30. /* ====================== str_util ====================== */
  31. void str_util::replace_all_pairs_inplace(
  32. std::string& text,
  33. const std::vector<std::pair<std::string, std::string>>& replace) {
  34. using str = std::string;
  35. auto repl_one = [&text](const str& from, const str& to) {
  36. mgb_assert(!from.empty());
  37. size_t pos = 0;
  38. while ((pos = text.find(from, pos)) != str::npos) {
  39. text.replace(pos, from.size(), to);
  40. pos += to.size();
  41. }
  42. };
  43. for (auto&& i : replace) {
  44. repl_one(i.first, i.second);
  45. }
  46. }
  47. /* ====================== ExecutableHelper ====================== */
  48. bool ExecutableHelper::keep_interm() {
  49. static bool ret = MGB_GETENV("MGB_JIT_KEEP_INTERM");
  50. return ret;
  51. }
  52. namespace {
  53. #ifdef __linux__
  54. class ExecutableHelperImpl final : public ExecutableHelper {
  55. bool m_workdir_need_rm = false;
  56. //! workdir setting, end with /
  57. std::string m_workdir;
  58. //! execute command and check if exit code is zero
  59. static void check_exec(const std::string& cmd) {
  60. #if MGB_ENABLE_DEBUG_UTIL
  61. debug::ScopedForkWarningSupress no_fork_warning;
  62. #endif
  63. std::string out;
  64. std::array<char, 128> buffer;
  65. FILE* pipe = popen((cmd + " 2>&1").c_str(), "r");
  66. mgb_throw_if(!pipe, SystemError, "popen() for cmd %s failed: %s",
  67. cmd.c_str(), strerror(errno));
  68. std::unique_ptr<FILE, int (*)(FILE*)> pipe_close{pipe, ::pclose};
  69. while (fgets(buffer.data(), buffer.size(), pipe) != nullptr) {
  70. out += buffer.data();
  71. }
  72. pipe_close.release();
  73. int ret = pclose(pipe);
  74. mgb_throw_if(ret, SystemError,
  75. "command %s failed: return code=%d; captured output:\n%s",
  76. cmd.c_str(), ret, out.c_str());
  77. }
  78. public:
  79. ExecutableHelperImpl() {
  80. if (auto set = MGB_GETENV("MGB_JIT_WORKDIR")) {
  81. struct stat sb;
  82. if (!(stat(set, &sb) == 0 && S_ISDIR(sb.st_mode))) {
  83. int err = mkdir(set, 0700);
  84. mgb_throw_if(err, SystemError, "failed to create dir %s: %s",
  85. set, strerror(errno));
  86. m_workdir_need_rm = true;
  87. }
  88. m_workdir = set;
  89. } else {
  90. char name[] = "/tmp/mgbjit-XXXXXX";
  91. auto ptr = mkdtemp(name);
  92. mgb_throw_if(!ptr, SystemError, "failed to create temp dir: %s",
  93. strerror(errno));
  94. m_workdir = ptr;
  95. m_workdir_need_rm = true;
  96. }
  97. struct stat sb;
  98. mgb_throw_if(
  99. !(stat(m_workdir.c_str(), &sb) == 0 && S_ISDIR(sb.st_mode)),
  100. SystemError, "%s is not a dir", m_workdir.c_str());
  101. mgb_log("use JIT workdir: %s", m_workdir.c_str());
  102. if (m_workdir.back() != '/')
  103. m_workdir.append("/");
  104. }
  105. ~ExecutableHelperImpl() {
  106. if (!m_workdir_need_rm || keep_interm())
  107. return;
  108. // remove work dir
  109. auto cb_rm = [](const char* fpath, const struct stat* sb, int typeflag,
  110. struct FTW* ftwbuf) -> int {
  111. int err = ::remove(fpath);
  112. if (err) {
  113. mgb_log_error("failed to remove %s: %s", fpath,
  114. strerror(errno));
  115. } else {
  116. mgb_log_debug("removed temp file in workdir: %s", fpath);
  117. }
  118. return err;
  119. };
  120. int err = nftw(m_workdir.c_str(), cb_rm, 64, FTW_DEPTH | FTW_PHYS);
  121. if (err) {
  122. mgb_log_error("failed to cleanup workdir %s", m_workdir.c_str());
  123. }
  124. }
  125. void* load_lib(const std::string& name) override {
  126. auto ret = dlopen(realpath(name).c_str(), RTLD_LAZY | RTLD_LOCAL);
  127. mgb_throw_if(!ret, SystemError, "failed to load library %s: %s",
  128. name.c_str(), dlerror());
  129. return ret;
  130. }
  131. void* resolve_func(void* handle, const std::string& func_name) override {
  132. auto ret = dlsym(handle, func_name.c_str());
  133. mgb_throw_if(!ret, SystemError, "failed to resolve %s: %s",
  134. func_name.c_str(), dlerror());
  135. return ret;
  136. }
  137. void unload_lib(void* handle) override {
  138. if (handle) {
  139. struct link_map* lmap;
  140. std::string path;
  141. bool path_good;
  142. if (dlinfo(handle, RTLD_DI_LINKMAP, &lmap)) {
  143. path_good = false;
  144. path = ssprintf("<RTLD_DI_ORIGIN failed: %s>", dlerror());
  145. } else {
  146. path_good = true;
  147. path = lmap->l_name;
  148. }
  149. if (dlclose(handle)) {
  150. mgb_log_error("failed to close %s: %s", path.c_str(),
  151. dlerror());
  152. }
  153. if (path_good) {
  154. auto h1 = dlopen(path.c_str(), RTLD_NOLOAD | RTLD_LOCAL);
  155. if (h1) {
  156. dlclose(h1);
  157. mgb_log_warn("library %s is not totally released",
  158. path.c_str());
  159. }
  160. }
  161. }
  162. }
  163. std::string compile_cpp_source_secondary(const char* source,
  164. const char* out_name) override {
  165. std::string uniq_name{out_name};
  166. uniq_name.append("-");
  167. uniq_name.append(std::to_string(
  168. XXHash{}.update(source, strlen(source)).digest()));
  169. auto src_name = uniq_name + ".cpp", obj_name = uniq_name + ".o";
  170. write_file(src_name, source);
  171. check_exec(ssprintf("g++ -O2 -fPIC -std=c++11 '%s' -o '%s' -c",
  172. realpath(src_name).c_str(),
  173. realpath(obj_name).c_str()));
  174. return obj_name;
  175. }
  176. void link(const SmallVector<std::string>& inp_names,
  177. const std::string& out_name) override {
  178. std::string cmd{"g++ -shared -std=c++11 -o '"};
  179. cmd.append(realpath(out_name));
  180. cmd.append("'");
  181. for (auto&& i : inp_names) {
  182. cmd.append(" '");
  183. cmd.append(realpath(i));
  184. cmd.append("'");
  185. }
  186. check_exec(cmd);
  187. }
  188. std::string realpath(const std::string& name) override {
  189. mgb_assert(name.find('/') == std::string::npos);
  190. return m_workdir + name;
  191. }
  192. void remove(const std::string& name) override {
  193. int err = unlink(realpath(name).c_str());
  194. mgb_throw_if(err, SystemError, "failed to unlink %s: %s", name.c_str(),
  195. strerror(errno));
  196. }
  197. };
  198. #endif // __linux__
  199. } // anonymous namespace
  200. void ExecutableHelper::write_file(const std::string& name,
  201. const std::string& data) {
  202. auto full_name = realpath(name);
  203. FILE* fptr = fopen(full_name.c_str(), "wb");
  204. mgb_throw_if(!fptr, SystemError, "failed to open %s: %s", full_name.c_str(),
  205. strerror(errno));
  206. std::unique_ptr<FILE, int (*)(FILE*)> fptr_close{fptr, ::fclose};
  207. auto done = fwrite(data.data(), 1, data.size(), fptr);
  208. mgb_throw_if(done != data.size(), SystemError,
  209. "failed to write file: req=%zu written=%zu: %s", data.size(),
  210. done, strerror(errno));
  211. fptr_close.release();
  212. int err = fclose(fptr);
  213. mgb_throw_if(err, SystemError, "failed to close file: %s", strerror(errno));
  214. }
  215. ExecutableHelper& ::ExecutableHelper::get() {
  216. static ExecutableHelperImpl inst;
  217. return inst;
  218. }
  219. std::string jit::next_kernel_name() {
  220. static std::atomic_uint_fast64_t cnt;
  221. return "fusion" + std::to_string(cnt.fetch_add(1));
  222. }
  223. #endif // MGB_JIT
  224. // vim: syntax=cpp.doxygen foldmethod=marker foldmarker=f{{{,f}}}

MegEngine 安装包中集成了使用 GPU 运行代码所需的 CUDA 环境,不用区分 CPU 和 GPU 版。 如果想要运行 GPU 程序,请确保机器本身配有 GPU 硬件设备并安装好驱动。 如果你想体验在云端 GPU 算力平台进行深度学习开发的感觉,欢迎访问 MegStudio 平台