add naive windows support

This commit is contained in:
Dun Liang 2021-08-15 19:58:18 +08:00
parent a6830de216
commit 4fd355202c
45 changed files with 858 additions and 258 deletions

View File

@ -0,0 +1,10 @@
jittor.attention
=====================
这里是Jittor的 数据变换 模块的API文档您可以通过`from jittor import attention`来获取该模块。
```eval_rst
.. automodule:: jittor.attention
:members:
:undoc-members:
```

View File

@ -8,6 +8,7 @@ import subprocess as sp
import os
import re
import sys
import glob
import inspect
import datetime
import threading
@ -49,7 +50,21 @@ def compile(compiler, flags, inputs, output, combind_build=False):
run_cmd(cmd)
return True
link = link_flags
base_output = output.split('/')[-1].split('.')[0]
base_output = os.path.basename(output).split('.')[0]
if os.name == 'nt':
# initialize order in windows seems reversed
inputs = list(inputs[::-1])
# windows need libxxx.a
afile = os.path.join(cache_path, f"lib{base_output}.a")
link = link + f' -Wl,--export-all-symbols,--out-implib,"{afile}" '
if base_output == "jit_utils_core":
pass
elif base_output == "jittor_core":
inputs.append(os.path.join(cache_path, f"libjit_utils_core.a"))
else:
inputs.append(os.path.join(cache_path, f"libjit_utils_core.a"))
inputs.append(os.path.join(cache_path, f"libjittor_core.a"))
# if output is core, add core_link_flags
if output.startswith("jittor_core"):
link = link + core_link_flags
@ -58,7 +73,7 @@ def compile(compiler, flags, inputs, output, combind_build=False):
obj_files = []
new_inputs = []
for name in inputs:
if name.endswith(".o"):
if name[-1] in 'oa':
obj_files.append(name)
else:
new_inputs.append(os.path.join(jittor_path, name))
@ -67,7 +82,7 @@ def compile(compiler, flags, inputs, output, combind_build=False):
inputs = new_inputs
if len(inputs) == 1 or combind_build:
cmd = f"{compiler} {' '.join(inputs)} {flags} {link} -o {output}"
cmd = f"\"{compiler}\" {' '.join(inputs)} {flags} {link} -o {output}"
return do_compile(cmd)
# split compile object file and link
# remove -l -L flags when compile object files
@ -89,20 +104,21 @@ def compile(compiler, flags, inputs, output, combind_build=False):
cmd = cmd.replace("-Ofast", "-O2")
cmds.append(cmd)
jit_utils.run_cmds(cmds, cache_path, jittor_path, "Compiling "+base_output)
cmd = f"{compiler} {' '.join(obj_files)} {flags} {lto_flags} {link} -o {output}"
cmd = f"\"{compiler}\" {' '.join(obj_files)} {flags} {lto_flags} {link} -o {output}"
return do_compile(cmd)
def gen_jit_tests():
all_src = run_cmd('find -L src/ | grep "cc$"', jittor_path).splitlines()
# all_src = run_cmd('find -L src/ | grep "cc$"', jittor_path).splitlines()
# all_src = glob.glob(os.path.join(jittor_path,"src","**","*.cc"), recursive=True)
all_src = glob.glob(jittor_path+"/src/**/*.cc", recursive=True)
jit_declares = []
re_def = re.compile("JIT_TEST\\((.*?)\\)")
names = set()
test_defs = []
for src_name in all_src:
src_name = os.path.join(jittor_path, src_name)
with open(src_name) as f:
src = f.read()
with open(src_name, 'rb') as f:
src = f.read().decode('utf8')
defs = re_def.findall(src)
for name in defs:
LOG.vv(f"Find test {name} from {src_name}")
@ -143,7 +159,8 @@ def gen_jit_tests():
f.write(jit_src)
def gen_jit_flags():
all_src = run_cmd('find -L src/ | grep "cc$"', jittor_path).splitlines()
# all_src = run_cmd('find -L src/ | grep "cc$"', jittor_path).splitlines()
all_src = glob.glob(jittor_path+"/src/**/*.cc", recursive=True)
jit_declares = []
re_def = re.compile("DEFINE_FLAG(_WITH_SETTER)?\\((.*?)\\);", re.DOTALL)
@ -151,9 +168,8 @@ def gen_jit_flags():
visit = {}
for src_name in all_src:
src_name = os.path.join(jittor_path, src_name)
with open(src_name) as f:
src = f.read()
with open(src_name, 'rb') as f:
src = f.read().decode("utf8")
defs = re_def.findall(src)
for _, args in defs:
args = args.split(",")
@ -360,13 +376,13 @@ def gen_jit_op_maker(op_headers, export=False, extra_flags=""):
# XxxXxxOp
name2 = map(lambda s:s[:1].upper() + s[1:], name.split('_'))
name2 = "".join(name2)
with open(os.path.join(jittor_path, header), encoding='utf8') as f:
with open(header, encoding='utf8') as f:
src = f.read()
# XxxXxxOp(args)
res = re.findall(pybind_attrs_reg + '[^~]('+name2+"\\([^\\n]*\\))", src, re.S)
assert len(res) >= 1, "Wrong op args in " + header
# registe op
cc_name = os.path.join(jittor_path, header[:-2] + ".cc")
cc_name = header[:-2] + ".cc"
constructors = []
for i in range(len(res)):
name = 'make_'+func_name+'_'*i
@ -440,10 +456,10 @@ def gen_jit_op_maker(op_headers, export=False, extra_flags=""):
vh2v_src = "_op->set_inputs({" + ", ".join(vh2v_src) + "});" + \
"".join(more_src)
LOG.vvvv(f"Find op: {name2} args: {new_args}")
if header.startswith("src/"):
jit_headers += f"#include \"{header[4:]}\"\n"
else:
jit_headers += f"#include \"{header}\"\n"
# if header.startswith("src/"):
# jit_headers += f"#include \"{header[4:]}\"\n"
# else:
jit_headers += f"#include \"{header}\"\n"
add_src(
func_name+'_'*hid,
new_args_def,
@ -657,7 +673,7 @@ def compile_custom_ops(
for name in pyjt_includes:
LOG.i("handle pyjt_include", name)
bname = name.split("/")[-1].split(".")[0]
bname = os.path.basename(name).split(".")[0]
gen_src_fname = os.path.join(cache_path, "custom_ops", gen_name+"_"+bname+".cc")
pyjt_compiler.compile_single(name, gen_src_fname)
builds.insert(1, gen_src_fname)
@ -786,7 +802,10 @@ def check_cache_compile():
"src/utils/log.cc",
"src/utils/tracer.cc",
"src/utils/jit_utils.cc",
"src/utils/str_utils.cc",
]
if os.name == 'nt':
files = [ x.replace('/', '\\') for x in files ]
global jit_utils_core_files
jit_utils_core_files = files
recompile = compile(cc_path, cc_flags+f" {opt_flags} ", files, 'jit_utils_core'+extension_suffix, True)
@ -866,13 +885,14 @@ python_path = sys.executable
ex_python_path = python_path + '.' + str(sys.version_info.minor)
if os.path.isfile(ex_python_path):
python_path = ex_python_path
py3_config_path = jit_utils.py3_config_path
nvcc_path = env_or_try_find('nvcc_path', 'nvcc') or try_find_exe('/usr/local/cuda/bin/nvcc') or try_find_exe('/usr/bin/nvcc')
if not nvcc_path:
cuda_driver = install_cuda.get_cuda_driver()
nvcc_path = install_cuda.install_cuda()
if nvcc_path:
nvcc_path = try_find_exe(nvcc_path)
if nvcc_path is None:
nvcc_path = ""
gdb_path = try_find_exe('gdb')
addr2line_path = try_find_exe('addr2line')
has_pybt = check_pybt(gdb_path, python_path)
@ -885,6 +905,20 @@ link_flags = " -lstdc++ -ldl -shared "
core_link_flags = ""
opt_flags = ""
kernel_opt_flags = os.environ.get("kernel_flags", "") + opt_flags + " -fopenmp "
if os.name == 'nt':
link_flags = link_flags.replace('-ldl', '')
py3_link_path = '-L"' + os.path.join(
os.path.dirname(sys.executable),
"libs"
) + f'" -lpython3{sys.version_info.minor} '
core_link_flags = py3_link_path
link_flags += core_link_flags
# link_flags += " -Wl,--unresolved-symbols=ignore-all "
# cc_flags += " -Xlinker --allow-shlib-undefined "
cc_flags = cc_flags.replace('-std=c++14', '-std=c++17')
link_flags += " -fopenmp "
kernel_opt_flags += f" {cache_path}\\libjit_utils_core.a "
kernel_opt_flags += f" {cache_path}\\libjittor_core.a "
if ' -O' not in cc_flags:
opt_flags += " -O2 "
@ -898,9 +932,9 @@ if os.environ.get("enable_lto") == "1":
else:
lto_flags = " -flto "
py_include = run_cmd(py3_config_path+" --includes")
py_include = jit_utils.get_py3_include_path()
LOG.i(f"py_include: {py_include}")
extension_suffix = run_cmd(py3_config_path+" --extension-suffix")
extension_suffix = jit_utils.get_py3_extension_suffix()
LOG.i(f"extension_suffix: {extension_suffix}")
make_cache_dir(cache_path)
@ -911,7 +945,7 @@ ck_path = os.path.join(cache_path, "checkpoints")
make_cache_dir(ck_path)
# build cache_compile
cc_flags += f" -I{jittor_path}/src "
cc_flags += f" -I{os.path.join(jittor_path, 'src')} "
cc_flags += py_include
check_cache_compile()
LOG.v(f"Get cache_compile: {jit_utils.cc}")
@ -943,7 +977,8 @@ if has_cuda:
# build core
gen_jit_flags()
gen_jit_tests()
op_headers = run_cmd('find -L src/ops/ | grep "op.h$"', jittor_path).splitlines()
op_headers = glob.glob(jittor_path+"/src/ops/**/*op.h", recursive=True)
# op_headers = run_cmd('find -L src/ops/ | grep "op.h$"', jittor_path).splitlines()
jit_src = gen_jit_op_maker(op_headers)
LOG.vvvv(jit_src)
with open(os.path.join(cache_path, "gen", "jit_op_maker.h"), 'w') as f:
@ -958,8 +993,10 @@ pyjt_gen_src = pyjt_compiler.compile(cache_path, jittor_path)
# 3. op_utils
# 4. other
files2 = pyjt_gen_src
grep_args = '"c[cu]$"' if has_cuda else '"cc$"'
files4 = run_cmd('find -L src | grep '+grep_args, jittor_path).splitlines()
ext_args = 'c[cu]' if has_cuda else 'cc'
files4 = glob.glob(jittor_path+"/src/**/*."+ext_args, recursive=True)
files4 = [ f[len(jittor_path)+1:] for f in files4 ]
# files4 = run_cmd('find -L src | grep '+grep_args, jittor_path).splitlines()
at_beginning = [
"src/ops/op_utils.cc",
"src/event_queue.cc",
@ -969,16 +1006,14 @@ at_beginning = [
at_last = [
"src/profiler/profiler.cc",
"src/executor.cc",
"src/fetcher.cc",
]
if os.name == 'nt':
at_beginning = [ x.replace('/','\\') for x in at_beginning ]
at_last = [ x.replace('/','\\') for x in at_last ]
for i in range(len(at_beginning)):
if at_beginning[i] not in files4:
continue
files4.remove(at_beginning[i])
files4.insert(i, at_beginning[i])
for v in at_last:
if v not in files4:
continue
files4.remove(v)
files4.append(v)
registers = [ name for name in files4 if "register" in name ]
@ -988,22 +1023,24 @@ for file in jit_utils_core_files:
files.remove(file)
LOG.vv("compile order:", files)
# manual Link omp using flags(os.RTLD_NOW | os.RTLD_GLOBAL)
# if cc_type=="icc":
# os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE"
libname = {"clang":"omp", "icc":"iomp5", "g++":"gomp"}[cc_type]
libname = ctypes.util.find_library(libname)
assert libname is not None, "openmp library not found"
ctypes.CDLL(libname, os.RTLD_NOW | os.RTLD_GLOBAL)
if os.name != 'nt':
# manual Link omp using flags(os.RTLD_NOW | os.RTLD_GLOBAL)
# if cc_type=="icc":
# os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE"
libname = {"clang":"omp", "icc":"iomp5", "g++":"gomp"}[cc_type]
libname = ctypes.util.find_library(libname)
assert libname is not None, "openmp library not found"
ctypes.CDLL(libname, os.RTLD_NOW | os.RTLD_GLOBAL)
# get os release
with open("/etc/os-release", "r", encoding='utf8') as f:
s = f.read().splitlines()
os_release = {}
for line in s:
a = line.split('=')
if len(a) != 2: continue
os_release[a[0]] = a[1].replace("\"", "")
# get os release
with open("/etc/os-release", "r", encoding='utf8') as f:
s = f.read().splitlines()
os_release = {}
for line in s:
a = line.split('=')
if len(a) != 2: continue
os_release[a[0]] = a[1].replace("\"", "")
os_type = {
"ubuntu": "ubuntu",

View File

@ -9,6 +9,7 @@ import os
from jittor_utils import LOG, run_cmd, simple_timer
import json
from collections import OrderedDict
import glob
def parse_attrs(s):
'''parse @attrs(..., x=y) syntax'''
@ -847,7 +848,7 @@ def compile_src(src, h, basename):
return src_code
def compile_single(head_file_name, src_file_name, src=None):
basename = head_file_name.split("/")[-1].split(".")[0]
basename = os.path.basename(head_file_name).split(".")[0]
if src==None:
with open(head_file_name, 'r') as f:
src = f.read()
@ -860,22 +861,22 @@ def compile_single(head_file_name, src_file_name, src=None):
return True
def compile(cache_path, jittor_path):
headers1 = run_cmd('find -L src/ | grep ".h$"', jittor_path).splitlines()
headers2 = run_cmd('find gen/ | grep ".h$"', cache_path).splitlines()
headers = [ os.path.join(jittor_path, h) for h in headers1 ] + \
[ os.path.join(cache_path, h) for h in headers2 ]
headers1 = glob.glob(jittor_path+"/src/**/*.h", recursive=True)
headers2 = glob.glob(cache_path+"/gen/**/*.h", recursive=True)
headers = headers1 + headers2
basenames = []
pyjt_names = []
for h in headers:
with open(h, 'r') as f:
src = f.read()
bh = os.path.basename(h)
# jit_op_maker.h merge compile with var_holder.h
if h.endswith("src/var_holder.h"): continue
if h.endswith("jit_op_maker.h"):
if bh == "var_holder.h": continue
if bh == "jit_op_maker.h":
with open(os.path.join(jittor_path, "src", "var_holder.h"), "r") as f:
src = f.read() + src
basename = h.split("/")[-1].split(".")[0]
basename = bh.split(".")[0]
fname = "pyjt_"+basename+".cc"
fname = os.path.join(cache_path, "gen", fname)
check = compile_single(h, fname, src)

View File

@ -8,6 +8,7 @@
namespace jittor {
#ifdef HAS_CUDA
EventQueue event_queue;
void EventQueue::Worker::start() {
@ -25,6 +26,20 @@ void EventQueue::Worker::start() {
}
}
void EventQueue::Worker::stop() {
LOGv << "stoping event queue worker...";
event_queue.worker.run(nullptr);
event_queue.worker.thread.join();
LOGv << "stopped event queue worker.";
}
extern vector<void(*)()> cleanup_callback;
EventQueue::Worker::Worker() : thread(EventQueue::Worker::start) {
cleanup_callback.push_back(&EventQueue::Worker::stop);
}
void EventQueue::worker_caller() {
int status = OK;
try {
@ -39,5 +54,7 @@ void EventQueue::worker_caller() {
}
}
#endif
} // jittor

View File

@ -12,18 +12,29 @@
namespace jittor {
#ifdef HAS_CUDA
struct EventQueue {
static constexpr int RUNNING = 0;
static constexpr int OK = 1;
static constexpr int ERROR = 2;
typedef void(*Func)();
list<Func> tasks;
std::condition_variable cv;
std::mutex mtx;
Func func;
volatile int run_sync_done;
struct Worker {
Func todo;
std::condition_variable cv;
std::mutex mtx;
std::thread thread = std::thread(Worker::start);
std::thread thread;
static void start();
static void stop();
Worker();
inline void run(Func func) {
{
@ -32,19 +43,8 @@ struct EventQueue {
}
cv.notify_one();
}
inline ~Worker() {
run(nullptr);
thread.join();
}
} worker;
list<Func> tasks;
std::condition_variable cv;
std::mutex mtx;
Func func;
volatile int run_sync_done;
inline void flush() {
list<Func> ts;
{
@ -57,7 +57,7 @@ struct EventQueue {
static void worker_caller();
int run_sync(Func func) {
inline int run_sync(Func func) {
// send work to worker and do something by self
std::unique_lock<std::mutex> l(mtx);
this->func = func;
@ -90,4 +90,6 @@ struct EventQueue {
extern EventQueue event_queue;
#endif
} // jittor

View File

@ -29,10 +29,14 @@ int current_seed;
// fron fetch_op.cc
extern list<VarPtr> fetcher;
extern list<VarPtr> fetcher_to_free;
extern vector<void(*)()> cleanup_callback;
void cleanup() {
fetcher_to_free.clear();
fetcher.clear();
for (auto cb : cleanup_callback)
cb();
cleanup_callback.clear();
}
static void init_cuda_devices() {

View File

@ -7,7 +7,11 @@
#include <fstream>
#include <streambuf>
#include <stdlib.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <dlfcn.h>
#endif
#include "jit_compiler.h"
#include "op.h"
@ -30,16 +34,25 @@ DEFINE_FLAG(int, rewrite_op, 1, "Rewrite source file of jit operator or not");
namespace jit_compiler {
jit_op_entry_t load_jit_lib(string name, string symbol_name="jit_entry") {
const char* msg = "";
LOGvv << "Opening jit lib:" << name;
// void* handle = dlopen(name.c_str(), RTLD_NOW | RTLD_DEEPBIND | RTLD_LOCAL);
// RTLD_DEEPBIND and openmp cause segfault
void* handle = dlopen(name.c_str(), RTLD_NOW | RTLD_LOCAL | RTLD_DEEPBIND);
CHECK(handle) << "Cannot open library" << name << ":" << dlerror();
#ifdef _WIN32
void* handle = (void*)LoadLibrary(name.c_str());
#else
void* handle = dlopen(name.c_str(), RTLD_LAZY | RTLD_DEEPBIND | RTLD_LOCAL);
msg = dlerror();
#endif
CHECK(handle) << "Cannot open library" << name << ":" << msg;
#ifdef _WIN32
auto jit_entry = (jit_op_entry_t)GetProcAddress((HINSTANCE)handle, symbol_name.c_str());
#else
//dlerror();
auto jit_entry = (jit_op_entry_t)dlsym(handle, symbol_name.c_str());
const char* dlsym_error = dlerror();
CHECK(!dlsym_error) << "Loading symbol jit_entry from" << name << "failed:" << dlsym_error;
msg = dlerror();
#endif
CHECK(jit_entry) << "Loading symbol" << symbol_name << "from" << name << "failed:" << msg;
return jit_entry;
}
@ -66,26 +79,30 @@ jit_op_entry_t compile(const string& jit_key, const string& src, const bool is_c
// compiler do not allowed filename too long
CHECK(cc_path.size());
string jit_src_path = Op::get_filename_from_jit_key(jit_key, ".cc");
#ifdef _WIN32
string jit_lib_path = Op::get_filename_from_jit_key(jit_key, ".dll");
#else
string jit_lib_path = Op::get_filename_from_jit_key(jit_key, ".so");
string other_src = " "+join(jittor_path, "src/op.cc")+" "+
join(jittor_path, "src/var.cc")+" ";
other_src = "";
#endif
string other_src;
LOGvvv << "Generate" << jit_src_path >> "\n" >> src;
if (rewrite_op || !file_exist(jit_src_path))
write(jit_src_path, src);
string cmd;
if (is_cuda_op) {
cmd = nvcc_path
+ " '" + jit_src_path + "'" + other_src
+ " \"" + jit_src_path + "\"" + other_src
+ nvcc_flags + extra_flags
+ " -o '" + jit_lib_path + "'";
+ " -o \"" + jit_lib_path + "\"";
} else {
cmd = cc_path
+ " '" + jit_src_path + "'" + other_src
+ " \"" + jit_src_path + "\"" + other_src
+ cc_flags + extra_flags
+ " -o '" + jit_lib_path + "'";
+ " -o \"" + jit_lib_path + "\"";
#ifndef _WIN32
cmd = python_path+" "+jittor_path+"/utils/asm_tuner.py "
"--cc_path=" + cmd;
#endif
}
cache_compile(cmd, cache_path, jittor_path);
auto symbol_name = get_symbol_name(jit_key);

View File

@ -4,7 +4,9 @@
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.
// ***************************************************************
#ifndef _WIN32
#include <sys/mman.h>
#endif
#include <sstream>
#include "jit_key.h"
#include "utils/str_utils.h"
@ -28,17 +30,23 @@ static size_t get_buffer_end_page(size_t buffer_end) {
}
JitKey::JitKey() {
(void)get_buffer_end_page;
#ifndef _WIN32
auto buffer_end_page = get_buffer_end_page((size_t)&buffer[buffer_size-1]);
LOGvv << "protect page" << (void*)buffer_end_page;
ASSERT(0==mprotect((void*)buffer_end_page, page_size, PROT_NONE));
// windows assign extern thread_local var cause fault, FIX IT
protected_page = buffer_end_page;
#endif
}
JitKey::~JitKey() {
#ifndef _WIN32
auto buffer_end_page = get_buffer_end_page((size_t)&buffer[buffer_size-1]);
LOGvv << "un-protect page" << (void*)buffer_end_page;
mprotect((void*)buffer_end_page, page_size, PROT_READ|PROT_WRITE|PROT_EXEC);
protected_page = 0;
#endif
}
static void hex_to_dec(string& s) {

View File

@ -165,10 +165,12 @@ inline JK& operator<<(JK& jk, int64 c) {
}
return jk << JK::hex(c);
}
#ifndef _WIN32
// win32 cause redefinition error
inline JK& operator<<(JK& jk, long long int c) {
return jk << (int64)c;
}
#endif
inline JK& operator<<(JK& jk, uint64 c) {
return jk << JK::hex(c);

View File

@ -9,6 +9,10 @@
// ***************************************************************
#include <stdio.h>
#include <unistd.h>
#ifdef _WIN32
#include <fileapi.h>
#else
#endif
#include <fcntl.h>
#include <errno.h>
@ -27,6 +31,11 @@ void set_lock_path(string path) {
void lock() {
ASSERT(lock_fd >= 0);
#ifdef _WIN32
OVERLAPPED offset = {0, 0, 0, 0, NULL};
auto hfile = (HANDLE)_get_osfhandle(lock_fd);
ASSERT(LockFileEx(hfile, 2, 0, -0x10000, 0, &offset));
#else
struct flock lock = {
.l_type = F_WRLCK,
.l_whence = SEEK_SET,
@ -34,12 +43,18 @@ void lock() {
.l_len = 0
};
ASSERT(fcntl(lock_fd, F_SETLKW, &lock) == 0);
#endif
_has_lock = 1;
LOGvv << "LOCK Pid:" << getpid();
}
void unlock() {
ASSERT(lock_fd >= 0);
#ifdef _WIN32
OVERLAPPED offset = {0, 0, 0, 0, NULL};
auto hfile = (HANDLE)_get_osfhandle(lock_fd);
ASSERT(UnlockFileEx(hfile, 0, -0x10000, 0, &offset));
#else
struct flock lock = {
.l_type = F_UNLCK,
.l_whence = SEEK_SET,
@ -47,6 +62,7 @@ void unlock() {
.l_len = 0
};
ASSERT(fcntl(lock_fd, F_SETLKW, &lock) == 0);
#endif
_has_lock = 0;
LOGvv << "UNLOCK Pid:" << getpid();
}

View File

@ -14,7 +14,11 @@ AlignedAllocator aligned_allocator;
const char* AlignedAllocator::name() const {return "aligned";}
void* AlignedAllocator::alloc(size_t size, size_t& allocation) {
#ifndef _WIN32
return aligned_alloc(alignment, size);
#else
return _aligned_malloc(size, alignment);
#endif
}
void AlignedAllocator::free(void* mem_ptr, size_t size, const size_t& allocation) {

View File

@ -6,7 +6,11 @@
// ***************************************************************
#include <iomanip>
#include <algorithm>
#ifndef _WIN32
#include <sys/sysinfo.h>
#else
#include <windows.h>
#endif
#include "var.h"
#include "op.h"
@ -152,9 +156,15 @@ void display_memory_info(const char* fileline, bool dump_var, bool red_color) {
}
MemInfo::MemInfo() {
#ifndef _WIN32
struct sysinfo info = {0};
sysinfo(&info);
total_cpu_ram = info.totalram;
#else
MEMORYSTATUSEX statex;
GlobalMemoryStatusEx (&statex);
total_cpu_ram = statex.ullTotalPhys;
#endif
total_cuda_ram = 0;
#ifdef HAS_CUDA
cudaDeviceProp prop;

View File

@ -14,7 +14,6 @@
#include "mem/allocator/sfrl_allocator.h"
#include <iomanip>
#include <algorithm>
#include <sys/sysinfo.h>
#include <sstream>
#include "pybind/py_var_tracer.h"

View File

@ -22,7 +22,8 @@ namespace jittor {
m(float32) \
m(float64)
#define map_size(T) {#T, ffs(sizeof(T))-1},
#define map_size(T) {#T, __builtin_ffs(sizeof(T))-1},
unordered_map<string, size_t> dsize_map = {FOR_ALL_TYPES(map_size)};
// TODO: make all static

View File

@ -6,7 +6,9 @@
// ***************************************************************
#include <chrono>
#include <thread>
#ifndef _WIN32
#include <sys/mman.h>
#endif
#include "common.h"
#include "misc/ring_buffer.h"
@ -41,7 +43,13 @@ RingBuffer* RingBuffer::make_ring_buffer(uint64 size, bool multiprocess) {
uint64 total_size = sizeof(RingBuffer) + size;
void* ptr = multiprocess ?
// mmap(NULL, total_size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS | MAP_HUGETLB, -1, 0) :
mmap(NULL, total_size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0) :
#ifndef _WIN32
mmap(NULL, total_size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0)
#else
// TODO: multiprocess ring buffer in windows
(void*)malloc(total_size)
#endif
:
// mmap(NULL, total_size, PROT_READ | PROT_WRITE, MAP_SHARED, -1, 0) :
(void*)malloc(total_size);
std::memset(ptr, 0, total_size);
@ -55,7 +63,12 @@ void RingBuffer::free_ring_buffer(RingBuffer* rb) {
auto is_multiprocess = rb->is_multiprocess;
rb->~RingBuffer();
if (is_multiprocess) {
#ifndef _WIN32
munmap(rb, total_size);
#else
free((void*)rb);
#endif
(void)total_size;
} else {
free((void*)rb);
}

View File

@ -6,7 +6,6 @@
// ***************************************************************
#pragma once
#include <pthread.h>
#include <sys/mman.h>
#include <cstring>
#include "common.h"
@ -48,10 +47,14 @@ struct RingBuffer {
}
inline ~Cond() {
#ifndef _WIN32
// a dirty hack
// ref: https://stackoverflow.com/questions/20439404/pthread-conditions-and-process-termination
// cv.__data.__wrefs = 0;
cv.__data = {0};
#else
// cv.__data = 0;
#endif
pthread_cond_destroy(&cv);
}

View File

@ -201,10 +201,10 @@ string Op::get_filename_from_jit_key(const string& jit_key, const string& suffix
string s = iter==jit_key_mapper.end() ? jit_key : iter->second;
std::stringstream ss;
if (s.size() > 100) {
ss << s.substr(0, 90) << "...hash:"
ss << s.substr(0, 90) << "...hash_"
<< std::hex << std::hash<string>()(s);
} else {
ss << s << "_hash:" <<
ss << s << "_hash_" <<
std::hex << std::hash<string>()(s);
}
s = ss.str();
@ -212,10 +212,14 @@ string Op::get_filename_from_jit_key(const string& jit_key, const string& suffix
if (c=='[' || c==']' || c=='<' || c=='>'
|| c=='{' || c=='}' || c=='(' || c==')' || c==','
|| c=='\n' || c=='\t' || c==' ' || c=='&' || c=='|'
|| c=='/')
|| c=='/' || c==':')
c = '_';
}
#ifndef _WIN32
string filename = cache_path + "/jit/";
#else
string filename = cache_path + "\\jit\\";
#endif
filename += s;
filename += "_op";
filename += suffix;

View File

@ -144,7 +144,7 @@ void GetitemOp::infer_slices(
out_shape_j = (slice.stop - slice.start - 1) / slice.step + 1;
else
out_shape_j = (slice.start - slice.stop - 1) / -slice.step + 1;
out_shape_j = std::max(0l, out_shape_j);
out_shape_j = std::max((int64)0, out_shape_j);
}
out_shape.push_back(out_shape_j);
}

View File

@ -19,7 +19,7 @@ struct ReshapeOp : Op {
/**
Returns a tensor with the same data and number of elements as input, but with the specified shape.
A single dimension may be -1, in which case its inferred from the remaining dimensions and the number of elements in input.
A single dimension may be -1, in which case it's inferred from the remaining dimensions and the number of elements in input.
----------------

View File

@ -69,11 +69,20 @@ struct SimpleThread {
}
};
struct SimpleThreads;
extern SimpleThreads threads;
extern vector<void(*)()> cleanup_callback;
struct SimpleThreads {
list<SimpleThread> threads;
SimpleThreads(int n) {
static void stop() {
jittor::threads.threads.clear();
}
void create_threads(int n) {
if (threads.size()) return;
for (int i=0; i<n; i++)
threads.emplace_back(i);
cleanup_callback.push_back(&stop);
}
void wait_all() {
for (auto& t : threads) {
@ -105,7 +114,7 @@ struct SimpleThreads {
return;
}
}
};
} threads;
static int last_compiled_op_num = 0;
static int not_compile_window = 0;
@ -190,7 +199,7 @@ void parallel_compile_all_ops(vector<int>& queue, vector<int>& range, FusedOp& f
static volatile int has_error;
static vector<vector<std::tuple<int,int,void*,string>>> op_entrys(thread_num);
// <int,int,void*,string> represents: task id, is_fused_op, entry or context, new_jit_key
static SimpleThreads threads(thread_num);
threads.create_threads(thread_num);
static std::mutex entry_lock;
ai = 0;
has_error = 0;

View File

@ -8,7 +8,11 @@
#include <algorithm>
#include <sstream>
#include <iomanip>
#ifdef _WIN32
#include <windows.h>
#else
#include <dlfcn.h>
#endif
#ifdef HAS_CUDA
#include <cuda_runtime.h>
#include "helper_cuda.h"
@ -57,14 +61,25 @@ void Profiler::stop() {
}
unique_ptr<MemoryChecker>* load_memory_checker(string name) {
const char* msg = "";
LOGvv << "Opening jit lib:" << name;
#ifdef _WIN32
void* handle = (void*)LoadLibrary(name.c_str());
#else
void* handle = dlopen(name.c_str(), RTLD_LAZY | RTLD_DEEPBIND | RTLD_LOCAL);
CHECK(handle) << "Cannot open library" << name << ":" << dlerror();
msg = dlerror();
#endif
CHECK(handle) << "Cannot open library" << name << ":" << msg;
#ifdef _WIN32
auto mm = (unique_ptr<MemoryChecker>*)GetProcAddress((HINSTANCE)handle, "memory_checker");
#else
//dlerror();
auto mm = (unique_ptr<MemoryChecker>*)dlsym(handle, "memory_checker");
const char* dlsym_error = dlerror();
CHECK(!dlsym_error) << "Loading symbol memory_checker from" << name << "failed:" << dlsym_error;
msg = dlerror();
#endif
CHECK(!msg) << "Loading symbol memory_checker from" << name << "failed:" << msg;
return mm;
}

View File

@ -7,11 +7,12 @@
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.
// ***************************************************************
#define _XOPEN_SOURCE 700
#include <fcntl.h> /* open */
#include <stdint.h> /* uint64_t */
#include <stdio.h> /* printf */
#include <stdlib.h> /* size_t */
#ifndef _WIN32
#define _XOPEN_SOURCE 700
#include <fcntl.h> /* open */
#include <unistd.h> /* pread, sysconf */
typedef struct {
@ -76,4 +77,13 @@ int virt_to_phys_user(uintptr_t* paddr, uintptr_t vaddr)
return 1;
*paddr = (entry.pfn * sysconf(_SC_PAGE_SIZE)) + (vaddr % sysconf(_SC_PAGE_SIZE));
return 0;
}
}
#else
int virt_to_phys_user(uintptr_t* paddr, uintptr_t vaddr)
{
paddr[0] = vaddr;
return 1;
}
#endif

View File

@ -4,8 +4,6 @@
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.
// ***************************************************************
#include <dlfcn.h>
#include "core.h"
#include "grad.h"
#include "pyjt/py_obj_holder.h"

View File

@ -8,6 +8,34 @@
namespace jittor {
NanoString npy2ns[] = {
ns_bool,
ns_int8, ns_uint8,
ns_int16, ns_uint16,
ns_int32, ns_uint32,
#ifdef _WIN32
ns_int32, ns_uint32,
#else
ns_int64, ns_uint64,
#endif
ns_int64, ns_uint64,
ns_float32, ns_float64, ns_float64,
ns_void, ns_void, ns_void,
ns_void
};
NPY_TYPES ns2npy[] = {
NPY_OBJECT, // placeholder for ns_void
NPY_BOOL,
#ifdef _WIN32
NPY_BYTE, NPY_SHORT, NPY_LONG, NPY_LONGLONG,
NPY_UBYTE, NPY_USHORT, NPY_ULONG, NPY_ULONGLONG,
#else
NPY_BYTE, NPY_SHORT, NPY_INT, NPY_LONGLONG,
NPY_UBYTE, NPY_USHORT, NPY_UINT, NPY_ULONGLONG,
#endif
NPY_FLOAT, NPY_DOUBLE
};
void** PyArray_API;
PyTypeObject *PyArray_Type;

View File

@ -38,53 +38,38 @@ struct PyArray_Proxy {
int flags;
};
enum NPY_TYPES {
NPY_BOOL=0,
NPY_BYTE, NPY_UBYTE,
NPY_SHORT, NPY_USHORT,
NPY_INT, NPY_UINT,
NPY_LONG, NPY_ULONG,
NPY_LONGLONG, NPY_ULONGLONG,
NPY_FLOAT, NPY_DOUBLE, NPY_LONGDOUBLE,
NPY_CFLOAT, NPY_CDOUBLE, NPY_CLONGDOUBLE,
NPY_OBJECT=17,
};
extern NanoString npy2ns[];
extern NPY_TYPES ns2npy[];
#define NPY_ARRAY_C_CONTIGUOUS 0x0001
#define NPY_ARRAY_ALIGNED 0x0100
#define NPY_ARRAY_WRITEABLE 0x0400
// NPY_ARRAY_C_CONTIGUOUS=1
inline bool is_c_style(PyArray_Proxy* obj) { return obj->flags & 1; }
inline NanoString get_type_str(PyArray_Proxy* obj) {
auto type = obj->descr->type;
// bool ?
if (type=='?') return ns_bool;
// int8 b
if (type=='b') return ns_int8;
// int16 h
if (type=='h') return ns_int16;
// int32 i
if (type=='i') return ns_int32;
// int64 l
if (type=='l') return ns_int64;
// uint8 B
if (type=='B') return ns_uint8;
// uint16 H
if (type=='H') return ns_uint16;
// uint32 I
if (type=='I') return ns_uint32;
// uint64 L
if (type=='L') return ns_uint64;
// float32 f
if (type=='f') return ns_float32;
// float64 d
if (type=='d') return ns_float64;
LOGf << "Unsupport numpy type char:'" << type << '\'';
return ns_float64;
NanoString type = ns_void;
if (obj->descr->type_num < NPY_OBJECT)
type = npy2ns[obj->descr->type_num];
CHECK(type != ns_void) << "Numpy type not support, type_num:"
<< obj->descr->type_num
<< "type_char:" << obj->descr->type;
return type;
}
inline int get_typenum(NanoString ns) {
if (ns == ns_bool) return 0;
if (ns == ns_int8) return 1;
if (ns == ns_uint8) return 2;
if (ns == ns_int16) return 3;
if (ns == ns_uint16) return 4;
if (ns == ns_int32) return 5;
if (ns == ns_uint32) return 6;
if (ns == ns_int64) return 7;
if (ns == ns_uint64) return 8;
if (ns == ns_float32) return 11;
if (ns == ns_float64) return 12;
LOGf << ns;
return -1;
return ns2npy[ns.index()];
}
typedef Py_intptr_t npy_intp;

View File

@ -6,7 +6,11 @@
// ***************************************************************
#pragma once
#include <Python.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <dlfcn.h>
#endif
#include <vector>
#include <list>
#include <map>

View File

@ -6,8 +6,12 @@
// ***************************************************************
#include <fstream>
#include <streambuf>
#ifdef _WIN32
#include <filesystem>
#endif
#include "misc/hash.h"
#include "utils/cache_compile.h"
#include "utils/str_utils.h"
namespace jittor {
namespace jit_compiler {
@ -15,7 +19,7 @@ namespace jit_compiler {
#ifndef TEST
string read_all(const string& fname) {
std::ifstream ifs(fname);
if (ifs)
if (ifs && ifs.good())
return string((std::istreambuf_iterator<char>(ifs)),
(std::istreambuf_iterator<char>()));
return "";
@ -65,7 +69,7 @@ void find_names(string cmd, vector<string>& input_names, string& output_name, ma
auto substr = [&](size_t i, size_t j) -> string {
string s;
for (size_t k=i; k<j; k++)
if (cmd[k]!='\'') s += cmd[k];
if (cmd[k]!='\'' && cmd[k]!='"') s += cmd[k];
return s;
};
while (i<cmd.size()) {
@ -164,6 +168,29 @@ void process(string src, vector<string>& input_names) {
}
}
static inline void check_win_file(const string& name) {
#ifdef _WIN32
// win32 not allowed so file change when load
// but we can rename it
if (!file_exist(name)) return;
if (!(endswith(name, ".pyd") || endswith(name, ".dll")))
return;
string new_name = name+".bk";
LOGv << "move file" << name << "-> " << new_name;
if (file_exist(new_name))
std::filesystem::remove(new_name);
std::filesystem::rename(name, new_name);
#endif
}
static inline bool is_full_path(const string& name) {
#ifdef _WIN32
return name.size()>=2 && name[1]==':';
#else
return name.size() && name[0]=='/';
#endif
}
bool cache_compile(const string& cmd, const string& cache_path, const string& jittor_path) {
vector<string> input_names;
map<string,vector<string>> extra;
@ -172,10 +199,12 @@ bool cache_compile(const string& cmd, const string& cache_path, const string& ji
string output_cache_key;
bool ran = false;
output_cache_key = read_all(output_name+".key");
string cd_cmd = cache_path.size() ? "cd " + cache_path + " && " + cmd : cmd;
// string cd_cmd = cache_path.size() ? "cd " + cache_path + " && " + cmd : cmd;
string cd_cmd = cmd;
if (output_cache_key.size() == 0) {
LOGvv << "Cache key of" << output_name << "not found.";
LOGvvv << "Run cmd:" << cmd;
check_win_file(output_name);
system_with_check(cd_cmd.c_str());
ran = true;
}
@ -197,7 +226,7 @@ bool cache_compile(const string& cmd, const string& cache_path, const string& ji
string full_name;
if (name.substr(0, 4) == "jit/" || name.substr(0, 4) == "gen/")
full_name = join(cache_path, name);
else if (name.size() && name[0]=='/')
else if (is_full_path(name))
full_name = name;
else
full_name = join(src_path, name);
@ -225,6 +254,7 @@ bool cache_compile(const string& cmd, const string& cache_path, const string& ji
if (output_cache_key.size() != 0 && output_cache_key != cache_key) {
LOGvv << "Cache key of" << output_name << "changed.";
LOGvvv << "Run cmd:" << cmd;
check_win_file(output_name);
system_with_check(cd_cmd.c_str());
ran = true;
}

View File

@ -12,7 +12,9 @@
#endif
#ifdef __GNUC__
#endif
#ifndef _WIN32
#include <sys/prctl.h>
#endif
#include <signal.h>
#include <iterator>
#include <algorithm>
@ -21,7 +23,9 @@
namespace jittor {
void init_subprocess() {
#ifndef _WIN32
prctl(PR_SET_PDEATHSIG, SIGKILL);
#endif
}
static void __log(
@ -169,14 +173,14 @@ public:
}
};
static void ostream_redirect(bool stdout, bool stderr) {
if (stdout) {
static void ostream_redirect(bool _stdout, bool _stderr) {
if (_stdout) {
PyObjHolder a(PyImport_ImportModule("sys"));
PyObjHolder b(PyObject_GetAttrString(a.obj,"stdout"));
auto buf = new pythonbuf(b.obj);
std::cout.rdbuf(buf);
}
if (stderr) {
if (_stderr) {
PyObjHolder a(PyImport_ImportModule("sys"));
PyObjHolder b(PyObject_GetAttrString(a.obj,"stderr"));
auto buf = new pythonbuf(b.obj);

View File

@ -11,6 +11,10 @@
#include <thread>
#include <unordered_map>
#include <unistd.h>
#ifdef _WIN32
#include <wchar.h>
#include <windows.h>
#endif
#include "utils/log.h"
#include "utils/mwsr_list.h"
#include "utils/str_utils.h"
@ -38,11 +42,19 @@ uint32_t get_tid() {
}
static bool supports_color() {
bool term_supports_color = false;
#ifdef _WIN32
// TODO: windows color not supported yet.
term_supports_color = false;
#else
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
if (hOut == INVALID_HANDLE_VALUE) return 0;
DWORD dwMode = 0;
if (!GetConsoleMode(hOut, &dwMode)) return 0;
dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
if (!SetConsoleMode(hOut, dwMode)) return 0;
return 1;
#endif
bool term_supports_color = false;
const char* const term = getenv("TERM");
if (term != NULL && term[0] != '\0') {
term_supports_color =
@ -57,7 +69,6 @@ static bool supports_color() {
!strcmp(term, "linux") ||
!strcmp(term, "cygwin");
}
#endif
return term_supports_color;
}
bool g_supports_color = supports_color();
@ -66,7 +77,8 @@ struct timeval start_tv;
struct tm get_start_tm() {
gettimeofday (&start_tv, NULL);
return *localtime(&start_tv.tv_sec);
time_t t = start_tv.tv_sec;
return *localtime(&t);
}
struct tm start_tm = get_start_tm();
@ -107,7 +119,9 @@ void print_prefix(std::ostream* out) {
*out << ' ';
}
#ifdef LOG_ASYNC
MWSR_LIST(log, std::ostringstream);
#endif
DECLARE_FLAG(int, log_sync);
std::mutex sync_log_m;
@ -157,7 +171,9 @@ void send_log(std::ostringstream&& out) {
log_capture(out.str());
if (log_silent) return;
if (!log_sync) {
#if LOG_ASYNC
mwsr_list_log::push(move(out));
#endif
} else {
std::lock_guard<std::mutex> lk(sync_log_m);
// std::cerr << "[SYNC]";
@ -168,7 +184,9 @@ void send_log(std::ostringstream&& out) {
void flush_log() {
if (!log_sync) {
#if LOG_ASYNC
mwsr_list_log::flush();
#endif
} else {
std::cerr.flush();
}
@ -187,7 +205,15 @@ size_t thread_local protected_page = 0;
int segfault_happen = 0;
string thread_local thread_name;
static int _pid = getpid();
vector<void(*)()> cleanup_callback;
#ifdef _WIN32
void handle_signal(int signal) {
std::cerr << "Caught SIGNAL " << signal << ", quick exit";
std::cerr.flush();
abort();
}
#else
void segfault_sigaction(int signal, siginfo_t *si, void *arg) {
if (signal == SIGINT) {
if (_pid == getpid()) {
@ -218,9 +244,16 @@ void segfault_sigaction(int signal, siginfo_t *si, void *arg) {
segfault_happen = 1;
exit(1);
}
#endif
int register_sigaction() {
#ifdef _WIN32
signal(SIGINT, handle_signal);
signal(SIGTERM, handle_signal);
// signal(SIGABRT, handle_signal);
signal(SIGSEGV, handle_signal);
signal(SIGFPE, handle_signal);
#else
struct sigaction sa;
memset(&sa, 0, sizeof(struct sigaction));
@ -237,12 +270,20 @@ int register_sigaction() {
sigaction(SIGBUS, &sa, NULL);
sigaction(SIGQUIT, &sa, NULL);
// sigaction(SIGABRT, &sa, NULL);
#endif
return 0;
}
void log_main() {
static int log_init() {
register_sigaction();
std::atexit(log_exiting);
return 1;
}
int _log_init = log_init();
void log_main() {
#ifdef LOG_ASYNC
mwsr_list_log::reduce([&](const std::ostringstream& out) {
#ifdef TEST_LOG
string s = out.str();
@ -253,6 +294,7 @@ void log_main() {
}, [&]() {
std::cerr.flush();
});
#endif
}
unordered_map<uint64_t, int> vprefix_map;
@ -260,9 +302,9 @@ void stream_hash(uint64_t& hash, char c) {
hash = hash * 257 + (uint8_t)c;
}
DEFINE_FLAG(int, log_sync, 1, "Set log printed synchronously.");
DEFINE_FLAG(int, log_silent, 0, "The log will be completely silent.");
DEFINE_FLAG(int, log_v, 0, "Verbose level of logging");
DEFINE_FLAG(int, log_sync, 1, "Set log printed synchronously.");
DEFINE_FLAG_WITH_SETTER(string, log_vprefix, "",
"Verbose level of logging prefix\n"
"example: log_vprefix='op=1,node=2,executor.cc:38$=1000'");
@ -322,6 +364,90 @@ but you can hot fix it by this command:
)";
}
#ifdef _WIN32
int system_popen(const char *cmd) {
HANDLE g_hChildStd_OUT_Rd = NULL;
HANDLE g_hChildStd_OUT_Wr = NULL;
SECURITY_ATTRIBUTES saAttr;
// Set the bInheritHandle flag so pipe handles are inherited.
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
// Create a pipe for the child process's STDOUT.
if (!CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0))
LOGf << "StdoutRd CreatePipe error";
// Ensure the read handle to the pipe for STDOUT is not inherited.
if (!SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0))
LOGf << "Stdout SetHandleInformation error";
// Create the child process.
PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartInfo;
BOOL bSuccess = FALSE;
// Set up members of the PROCESS_INFORMATION structure.
ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION));
// Set up members of the STARTUPINFO structure.
// This structure specifies the STDIN and STDOUT handles for redirection.
ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.hStdError = g_hChildStd_OUT_Wr;
siStartInfo.hStdOutput = g_hChildStd_OUT_Wr;
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
// Create the child process.
bSuccess = CreateProcess(NULL,
(char *)cmd, // command line
NULL, // process security attributes
NULL, // primary thread security attributes
TRUE, // handles are inherited
0, // creation flags
NULL, // use parent's environment
NULL, // use parent's current directory
&siStartInfo, // STARTUPINFO pointer
&piProcInfo); // receives PROCESS_INFORMATION
// If an error occurs, exit the application.
if (!bSuccess)
LOGf << "CreateProcess error";
// Close handles to the stdin and stdout pipes no longer needed by the child process.
// If they are not explicitly closed, there is no way to recognize that the child process has ended.
CloseHandle(g_hChildStd_OUT_Wr);
DWORD dwRead, dwWritten;
CHAR chBuf[BUFSIZ];
HANDLE hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
string output;
for (;;)
{
bSuccess = ReadFile(g_hChildStd_OUT_Rd, chBuf, BUFSIZ, &dwRead, NULL);
if (!bSuccess || dwRead == 0)
break;
output += chBuf;
bSuccess = WriteFile(hParentStdOut, chBuf,
dwRead, &dwWritten, NULL);
if (!bSuccess)
break;
}
WaitForSingleObject(piProcInfo.hProcess, INFINITE);
DWORD ec;
GetExitCodeProcess(piProcInfo.hProcess, &ec);
// Close handles to the child process and its primary thread.
// Some applications might keep these handles to monitor the status
// of the child process, for example.
CloseHandle(piProcInfo.hProcess);
CloseHandle(piProcInfo.hThread);
if (ec) {
check_cuda_unsupport_version(output);
}
return ec;
}
#else
int system_popen(const char* cmd) {
char buf[BUFSIZ];
string cmd2;
@ -345,6 +471,7 @@ int system_popen(const char* cmd) {
}
return ret;
}
#endif
void system_with_check(const char* cmd) {
auto ret = system_popen(cmd);
@ -354,18 +481,34 @@ void system_with_check(const char* cmd) {
CHECKop(ret,==,0) << "Run cmd failed:" << cmd;
}
#ifdef LOG_ASYNC
std::thread log_thread(log_main);
#endif
void log_exiting() {
if (exited) return;
exited = true;
for (auto cb : cleanup_callback)
cb();
cleanup_callback.clear();
#ifdef LOG_ASYNC
mwsr_list_log::stop();
log_thread.join();
#endif
}
} // jittor
void expect_error(std::function<void()> func) {
try {
func();
} catch (...) {
return;
}
LOGf << "Missing error";
}
#ifdef TEST_LOG
#include <chrono>

View File

@ -38,6 +38,29 @@ extern "C" uint32_t get_tid();
extern "C" bool g_supports_color;
extern "C" void print_prefix(std::ostream* out);
#ifdef _WIN32
constexpr char green[] = "\x1b[1;32m";
constexpr char red[] = "\x1b[1;31m";
constexpr char yellow[] = "\x1b[1;33m";
static void get_color(char level, int verbose, const char*& color_begin, const char*& color_end) {
if (level == 'i') {
if (verbose == 0) color_begin = "\x1b[1;32m"; else
if (verbose < 10) color_begin = "\x1b[1;32m"; else
if (verbose < 100) color_begin = "\x1b[1;32m"; else
if (verbose < 1000) color_begin = "\x1b[1;32m";
else color_begin = "\x1b[1;32m";
} else if (level == 'w')
color_begin = yellow;
else if (level == 'e')
color_begin = red;
else // level == 'f'
color_begin = red;
color_end = "\x1b[m";
}
#else
constexpr char green[] = "\033[38;5;2m";
constexpr char red[] = "\033[38;5;1m";
constexpr char yellow[] = "\033[38;5;3m";
@ -58,6 +81,8 @@ static void get_color(char level, int verbose, const char*& color_begin, const c
color_end = "\033[m";
}
#endif
extern "C" void send_log(std::ostringstream&& out);
extern "C" void flush_log();
extern "C" void log_capture_start();

View File

@ -6,10 +6,14 @@
// ***************************************************************
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#ifndef _WIN32
#include <sys/prctl.h>
#include <execinfo.h>
#include <sys/wait.h>
#else
#include <windows.h>
#endif
#include <unistd.h>
#include <iostream>
#include "utils/tracer.h"
@ -24,6 +28,24 @@ DEFINE_FLAG_WITH_SETTER(int, gdb_attach, 0, "gdb attach self process.");
string _extra_gdb_cmd;
int system_popen(const char* cmd);
#ifdef _WIN32
string get_cmds(const vector<const char*>& argv) {
auto cmds = gdb_path;
for (auto p : argv) {
if (!p) continue;
string cmd = p;
cmds += " ";
if (cmd.find(' ') != string::npos && cmd[0] != '"')
cmds += '"' + cmd + '"';
else
cmds += cmd;
}
return cmds;
}
#endif
void setter_gdb_attach(int v) {
if (v && gdb_path.size()) {
static int gdb_attached = 0;
@ -32,30 +54,71 @@ void setter_gdb_attach(int v) {
// using gdb to print the stack trace
char pid_buf[30];
sprintf(pid_buf, "%d", getpid());
char name_buf[512];
name_buf[readlink("/proc/self/exe", name_buf, 511)]=0;
int child_pid = fork();
if (!child_pid) {
LOGi << "gdb attach for" << name_buf << "pid=" >> pid_buf;
vector<const char*> argv{
gdb_path.c_str(),
"-ex", "catch throw"
};
if (auto n = extra_gdb_cmd.size()) {
_extra_gdb_cmd = extra_gdb_cmd;
_extra_gdb_cmd += '\0';
argv.push_back("-ex");
argv.push_back(&_extra_gdb_cmd[0]);
for (uint i=0; i<n; i++) {
if (_extra_gdb_cmd[i]==';') {
argv.push_back("-ex");
_extra_gdb_cmd[i] = '\0';
argv.push_back(&_extra_gdb_cmd[i+1]);
}
vector<const char*> argv{
gdb_path.c_str(),
"-ex", "catch throw"
};
if (auto n = extra_gdb_cmd.size()) {
_extra_gdb_cmd = extra_gdb_cmd;
_extra_gdb_cmd += '\0';
argv.push_back("-ex");
argv.push_back(&_extra_gdb_cmd[0]);
for (uint i=0; i<n; i++) {
if (_extra_gdb_cmd[i]==';') {
argv.push_back("-ex");
_extra_gdb_cmd[i] = '\0';
argv.push_back(&_extra_gdb_cmd[i+1]);
}
}
argv.insert(argv.end(), {name_buf, pid_buf, NULL});
}
// argv.insert(argv.end(), {name_buf, pid_buf, NULL});
argv.insert(argv.end(), {"-p", pid_buf, NULL});
LOGi << "gdb attach for" << "pid=" >> pid_buf << argv;
#ifdef _WIN32
// _spawnvp(_P_OVERLAY, gdb_path.c_str(), (char* const*)&argv[0]);
// system_popen((gdb_path+" -p "+pid_buf).c_str());
auto cmds = get_cmds(argv);
// Create the child process.
PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartInfo;
BOOL bSuccess = false;
// Set up members of the PROCESS_INFORMATION structure.
ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION));
// Set up members of the STARTUPINFO structure.
// This structure specifies the STDIN and STDOUT handles for redirection.
ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
siStartInfo.cb = sizeof(STARTUPINFO);
// siStartInfo.hStdError = g_hChildStd_OUT_Wr;
// siStartInfo.hStdOutput = g_hChildStd_OUT_Wr;
siStartInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
siStartInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
// Create the child process.
bSuccess = CreateProcess(
NULL,
(char *)&cmds[0], // command line
NULL, // process security attributes
NULL, // primary thread security attributes
true, // handles are inherited
0, // creation flags
NULL, // use parent's environment
NULL, // use parent's current directory
&siStartInfo, // STARTUPINFO pointer
&piProcInfo); // receives PROCESS_INFORMATION
// If an error occurs, exit the application.
if (!bSuccess)
LOGf << "CreateProcess error, command:" << cmds;
// sleep 5s, wait gdb attach
sleep(5);
#else
int child_pid = fork();
if (!child_pid) {
auto ret = execvp(gdb_path.c_str(), (char* const*)&argv[0]);
LOGf << "execvp failed return" << ret << gdb_path << extra_gdb_cmd;
exit(1);
@ -65,6 +128,7 @@ void setter_gdb_attach(int v) {
// sleep 5s, wait gdb attach
sleep(5);
}
#endif
}
}
@ -86,34 +150,34 @@ void print_trace() {
sprintf(pid_buf, "%d", getpid());
char st_buf[30];
sprintf(st_buf, "set backtrace limit %d", trace_depth);
char name_buf[512];
name_buf[readlink("/proc/self/exe", name_buf, 511)]=0;
int child_pid = fork();
if (!child_pid) {
std::cerr << "stack trace for " << name_buf << " pid=" << pid_buf << std::endl;
vector<const char*> argv{
gdb_path.c_str(), "--batch", "-n",
"-ex", "thread",
"-ex", st_buf, // "set backtrace limit 10",
"-ex", "bt",
};
if (has_pybt)
argv.insert(argv.end(), {"-ex", "set backtrace limit 0", "-ex", "py-bt"});
if (auto n = extra_gdb_cmd.size()) {
_extra_gdb_cmd = extra_gdb_cmd;
_extra_gdb_cmd += '\0';
argv.push_back("-ex");
argv.push_back(&_extra_gdb_cmd[0]);
for (uint i=0; i<n; i++) {
if (_extra_gdb_cmd[i]==';') {
argv.push_back("-ex");
_extra_gdb_cmd[i] = '\0';
argv.push_back(&_extra_gdb_cmd[i+1]);
}
LOGi << "stack trace for pid=" << pid_buf;
vector<const char*> argv{
gdb_path.c_str(), "--batch", "-n",
"-ex", "thread",
"-ex", st_buf, // "set backtrace limit 10",
"-ex", "bt",
};
if (has_pybt)
argv.insert(argv.end(), {"-ex", "set backtrace limit 0", "-ex", "py-bt"});
if (auto n = extra_gdb_cmd.size()) {
_extra_gdb_cmd = extra_gdb_cmd;
_extra_gdb_cmd += '\0';
argv.push_back("-ex");
argv.push_back(&_extra_gdb_cmd[0]);
for (uint i=0; i<n; i++) {
if (_extra_gdb_cmd[i]==';') {
argv.push_back("-ex");
_extra_gdb_cmd[i] = '\0';
argv.push_back(&_extra_gdb_cmd[i+1]);
}
}
argv.insert(argv.end(), {name_buf, pid_buf, NULL});
}
argv.insert(argv.end(), {"-p", pid_buf, NULL});
#ifndef _WIN32
int child_pid = fork();
if (!child_pid) {
execvp(gdb_path.c_str(), (char* const*)&argv[0]);
exit(0);
} else {
@ -121,7 +185,14 @@ void print_trace() {
prctl(PR_SET_PTRACER, child_pid, 0, 0, 0);
waitpid(child_pid,NULL,0);
}
} else {
#else
auto cmds = get_cmds(argv);
LOGv << cmds;
system_popen(cmds.c_str());
#endif
}
#ifndef _WIN32
else {
void *trace[16];
char **messages = (char **)NULL;
int i, trace_size = 0;
@ -149,6 +220,7 @@ void print_trace() {
(void)ret;
}
}
#endif
}
} // jittor
} // jittor

View File

@ -11,18 +11,7 @@ using namespace std;
void test_main();
void on_error() {
throw std::exception();
}
void expect_error(function<void()> func) {
try {
func();
} catch (...) {
return;
}
CHECK(0) << "Missing error";
}
void expect_error(function<void()> func);
int main() {
try {

View File

@ -175,5 +175,24 @@ class TestArray(unittest.TestCase):
assert b.dtype == "float64"
def test_all_type(self):
with jt.flag_scope(auto_convert_64_to_32=0):
types = [
"bool",
"int8", "uint8",
"int16", "uint16",
"int32", "uint32",
"int64", "uint64",
"float32", "float64",
]
for t in types:
a = np.random.random(1000).astype(t)
b = jt.array(a)
assert str(b.dtype) == t
c = b.numpy()
assert str(c.dtype) == t
np.testing.assert_allclose(a, c)
if __name__ == "__main__":
unittest.main()

View File

@ -20,7 +20,7 @@ import random
pass_this_test = False
msg = ""
mid = 0
if os.uname()[1] == "jittor-ce":
if hasattr(os, "uname") and os.uname()[1] == "jittor-ce":
mid = 1
try:
traindir = ["/data1/cjld/imagenet/train/","/home/cjld/imagenet/train/"][mid]

View File

@ -15,7 +15,7 @@ import random
pass_this_test = False
msg = ""
mid = 0
if os.uname()[1] == "jittor-ce":
if hasattr(os, "uname") and os.uname()[1] == "jittor-ce":
mid = 1
try:
# check can we run this test

View File

@ -11,7 +11,7 @@ from .test_core import expect_error
import os
mid = 0
if "jittor" in os.uname()[1]:
if hasattr(os, "uname") and "jittor" in os.uname()[1]:
mid = 1
class TestNanoString(unittest.TestCase):

View File

@ -24,7 +24,7 @@ except:
skip_this_test = True
mid = 0
if "jittor" in os.uname()[1]:
if hasattr(os, "uname") and "jittor" in os.uname()[1]:
mid = 1
def resize_and_crop(x, bbox, interpolation="nearest", out_size=[224,224]):

View File

@ -6,15 +6,30 @@
# ***************************************************************
import unittest
import jittor as jt
import os
import subprocess as sp
import sys
class TestTracer(unittest.TestCase):
def test_print_trace(self):
jt.print_trace()
# force use addr2line
jt.flags.gdb_path = ""
with jt.flag_scope(gdb_path=""):
jt.print_trace()
if os.name != 'nt':
# force use addr2line
with jt.flag_scope(gdb_path=""):
jt.print_trace()
def test_breakpoint(self):
fname = os.path.join(jt.flags.cache_path, "test_breakpoint.py")
with open(fname, 'w') as f:
f.write("""
import jittor as jt
with jt.flag_scope(extra_gdb_cmd="c;q"):
jt.flags.gdb_attach = 1
""")
out = sp.getoutput(sys.executable+' '+fname)
print(out)
assert "Attaching to" in out
if __name__ == "__main__":

View File

@ -44,7 +44,7 @@ def init(cc_path,s_path):
global file_idx
file_idx=0
file_name=cc_path.split("/")[-1]
file_name=os.path.basename(cc_path)
idx=0
for line in s_content:

View File

@ -21,7 +21,7 @@ def check(dirname, fname):
src = src.replace(a, b)
found = True
if ac not in src and not found: return
n = len(dirname.split('/'))-1
n = len(dirname.split(os.path.sep))-1
s = '.' + '/..' * n
new_src = ""
i = -1

View File

@ -80,7 +80,7 @@ for os_name in ['ubuntu', 'centos']:
obj_files = []
for name in data_files:
name = name.split("/")[-1]
name = os.path.basename(name)
fname = f"{obj_path}/{name}.o"
assert os.path.isfile(fname), fname
obj_files.append(fname)

View File

@ -98,10 +98,12 @@ def simple_timer(name):
@contextlib.contextmanager
def import_scope(flags):
prev = sys.getdlopenflags()
sys.setdlopenflags(flags)
if os.name != 'nt':
prev = sys.getdlopenflags()
sys.setdlopenflags(flags)
yield
sys.setdlopenflags(prev)
if os.name != 'nt':
sys.setdlopenflags(prev)
def try_import_jit_utils_core(silent=None):
global cc
@ -126,7 +128,10 @@ def run_cmd(cmd, cwd=None, err_msg=None, print_error=True):
r = sp.run(cmd, cwd=cwd, shell=True, stdout=sp.PIPE, stderr=sp.STDOUT)
else:
r = sp.run(cmd, shell=True, stdout=sp.PIPE, stderr=sp.STDOUT)
s = r.stdout.decode('utf8')
try:
s = r.stdout.decode('utf8')
except:
s = r.stdout.decode('gbk')
if r.returncode != 0:
if print_error:
sys.stderr.write(s)
@ -156,6 +161,7 @@ def pool_cleanup():
del p
def pool_initializer():
try_import_jit_utils_core()
cc.init_subprocess()
def run_cmds(cmds, cache_path, jittor_path, msg="run_cmds"):
@ -163,12 +169,22 @@ def run_cmds(cmds, cache_path, jittor_path, msg="run_cmds"):
bk = mp.current_process()._config.get('daemon')
mp.current_process()._config['daemon'] = False
if pool_size == 0:
mem_bytes = os.sysconf('SC_PAGE_SIZE') * os.sysconf('SC_PHYS_PAGES')
mem_bytes = get_total_mem()
mem_gib = mem_bytes/(1024.**3)
pool_size = min(16,max(int(mem_gib // 3), 1))
LOG.i(f"Total mem: {mem_gib:.2f}GB, using {pool_size} procs for compiling.")
if os.name == 'nt':
# a hack way to by pass windows
# multiprocess spawn init_main_from_path.
# check spawn.py:get_preparation_data
spec_bk = sys.modules['__main__'].__spec__
tmp = lambda x:x
tmp.name = '__main__'
sys.modules['__main__'].__spec__ = tmp
p = Pool(pool_size, initializer=pool_initializer)
p.__enter__()
if os.name == 'nt':
sys.modules['__main__'].__spec__ = spec_bk
import atexit
atexit.register(pool_cleanup)
cmds = [ [cmd, cache_path, jittor_path] for cmd in cmds ]
@ -212,7 +228,7 @@ def find_cache_path():
for c in " (){}": cache_name = cache_name.replace(c, "_")
except:
pass
for name in cache_name.split("/"):
for name in os.path.normpath(cache_name).split(os.path.sep):
dirs.insert(-1, name)
os.environ["cache_name"] = cache_name
LOG.v("cache_name", cache_name)
@ -275,6 +291,84 @@ def get_cc_type(cc_path):
if "g++" in bname: return "g++"
LOG.f(f"Unknown cc type: {bname}")
def get_py3_config_path():
global _py3_config_path
if _py3_config_path:
return _py3_config_path
if os.name == 'nt':
return None
else:
# Linux
py3_config_paths = [
os.path.dirname(sys.executable) + f"/python3.{sys.version_info.minor}-config",
sys.executable + "-config",
f"/usr/bin/python3.{sys.version_info.minor}-config",
os.path.dirname(sys.executable) + "/python3-config",
]
if "python_config_path" in os.environ:
py3_config_paths.insert(0, os.environ["python_config_path"])
for py3_config_path in py3_config_paths:
if os.path.isfile(py3_config_path):
break
else:
raise RuntimeError(f"python3.{sys.version_info.minor}-config "
f"not found in {py3_config_paths}, please specify "
f"enviroment variable 'python_config_path',"
f" or apt install python3.{sys.version_info.minor}-dev")
_py3_config_path = py3_config_path
return py3_config_path
def get_py3_include_path():
global _py3_include_path
if _py3_include_path:
return _py3_include_path
if os.name == 'nt':
# Windows
_py3_include_path = '-I"' + os.path.join(
os.path.dirname(sys.executable),
"include"
) + '"'
else:
_py3_include_path = run_cmd(get_py3_config_path()+" --includes")
return _py3_include_path
def get_py3_extension_suffix():
global _py3_extension_suffix
if _py3_extension_suffix:
return _py3_extension_suffix
if os.name == 'nt':
# Windows
_py3_extension_suffix = f".cp3{sys.version_info.minor}-win_amd64.pyd"
else:
_py3_extension_suffix = run_cmd(get_py3_config_path()+" --extension-suffix")
return _py3_extension_suffix
def get_total_mem():
if os.name == 'nt':
from ctypes import Structure, c_int32, c_uint64, sizeof, byref, windll
class MemoryStatusEx(Structure):
_fields_ = [
('length', c_int32),
('memoryLoad', c_int32),
('totalPhys', c_uint64),
('availPhys', c_uint64),
('totalPageFile', c_uint64),
('availPageFile', c_uint64),
('totalVirtual', c_uint64),
('availVirtual', c_uint64),
('availExtendedVirtual', c_uint64)]
def __init__(self):
self.length = sizeof(self)
m = MemoryStatusEx()
assert windll.kernel32.GlobalMemoryStatusEx(byref(m))
return m.totalPhys
else:
return os.sysconf('SC_PAGE_SIZE') * os.sysconf('SC_PHYS_PAGES')
is_in_ipynb = in_ipynb()
cc = None
@ -285,21 +379,14 @@ os.environ["cc_path"] = cc_path
cc_type = get_cc_type(cc_path)
cache_path = find_cache_path()
_py3_config_path = None
_py3_include_path = None
_py3_extension_suffix = None
py3_config_paths = [
os.path.dirname(sys.executable) + f"/python3.{sys.version_info.minor}-config",
sys.executable + "-config",
f"/usr/bin/python3.{sys.version_info.minor}-config",
os.path.dirname(sys.executable) + "/python3-config",
]
if "python_config_path" in os.environ:
py3_config_paths.insert(0, os.environ["python_config_path"])
for py3_config_path in py3_config_paths:
if os.path.isfile(py3_config_path):
break
else:
raise RuntimeError(f"python3.{sys.version_info.minor}-config "
f"not found in {py3_config_paths}, please specify "
f"enviroment variable 'python_config_path',"
f" or apt install python3.{sys.version_info.minor}-dev")
if os.name == 'nt':
os.RTLD_NOW = os.RTLD_GLOBAL = os.RTLD_DEEPBIND = 0
path = os.path.dirname(cc_path).replace('/', '\\')
sys.path.insert(0, path)
os.environ["PATH"] = path+';'+os.environ["PATH"]
if hasattr(os, "add_dll_directory"):
os.add_dll_directory(path)

View File

@ -19,11 +19,11 @@ if __name__ == "__main__":
s = ""
# base should be something like python3.7m python3.8
base = jittor_utils.run_cmd(jittor_utils.py3_config_path + " --includes").split()[0]
base = jittor_utils.get_py3_include_path().split()[0]
base = "python3" + base.split("python3")[-1]
for arg in sys.argv[1:]:
if arg == "--include-flags":
s += jittor_utils.run_cmd(jittor_utils.py3_config_path + " --includes")
s += jittor_utils.get_py3_include_path()
s += " -I"+os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "jittor", "src"))
s += " "
elif arg == "--libs-flags":
@ -31,6 +31,8 @@ if __name__ == "__main__":
libpath = libbase + f"/lib{base}.so"
assert os.path.isfile(libpath), f"lib not exist: {libpath}"
s += f" -L{libbase} -l{base} -ldl "
if os.name == 'nt'
s = s.replace('-ldl', '')
elif arg == "--cxx-flags":
s += " --std=c++17 "
elif arg == "--cxx-example":

View File

@ -29,6 +29,8 @@ def get_cuda_driver():
def install_cuda():
cuda_driver_version = get_cuda_driver()
if not cuda_driver_version:
return None
LOG.i("cuda_driver_version: ", cuda_driver_version)
cuda_tgz = "cuda10.2_cudnn7_linux.tgz"

View File

@ -1,4 +1,11 @@
import fcntl
try:
import fcntl
except ImportError:
fcntl = None
import win32file
import pywintypes
_OVERLAPPED = pywintypes.OVERLAPPED()
import os
from jittor_utils import cache_path, LOG
@ -8,13 +15,21 @@ class Lock:
LOG.v(f'OPEN LOCK path: {filename} PID: {os.getpid()}')
self.is_locked = False
def lock(self):
fcntl.flock(self.handle, fcntl.LOCK_EX)
def lock(self):
if fcntl:
fcntl.flock(self.handle, fcntl.LOCK_EX)
else:
hfile = win32file._get_osfhandle(self.handle.fileno())
win32file.LockFileEx(hfile, 2, 0, -0x10000, _OVERLAPPED)
self.is_locked = True
LOG.vv(f'LOCK PID: {os.getpid()}')
def unlock(self):
fcntl.flock(self.handle, fcntl.LOCK_UN)
def unlock(self):
if fcntl:
fcntl.flock(self.handle, fcntl.LOCK_UN)
else:
hfile = win32file._get_osfhandle(self.handle.fileno())
win32file.UnlockFileEx(hfile, 0, -0x10000, _OVERLAPPED)
self.is_locked = False
LOG.vv(f'UNLOCK PID: {os.getpid()}')