Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
P
pytensor
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
testgroup
pytensor
Commits
6ec9db61
提交
6ec9db61
authored
3月 05, 2008
作者:
olivier@olivier-desktop
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
cc.py is now in working order
上级
5147d5fc
隐藏空白字符变更
内嵌
并排
正在显示
6 个修改的文件
包含
879 行增加
和
103 行删除
+879
-103
_test_cc.py
gof/_test_cc.py
+47
-10
cc.py
gof/cc.py
+731
-54
cutils.py
gof/cutils.py
+29
-0
env.py
gof/env.py
+0
-1
op.py
gof/op.py
+40
-15
result.py
gof/result.py
+32
-23
没有找到文件。
gof/_test_cc.py
浏览文件 @
6ec9db61
...
@@ -18,21 +18,46 @@ class Double(ResultBase):
...
@@ -18,21 +18,46 @@ class Double(ResultBase):
def
__repr__
(
self
):
def
__repr__
(
self
):
return
self
.
name
return
self
.
name
def
c_type
(
self
):
# def c_is_simple(self): return True
return
"double"
def
c_declare
(
self
):
return
"double
%(name)
s; void*
%(name)
s_bad_thing;"
def
c_init
(
self
):
return
"""
%(name)
s = 0;
%(name)
s_bad_thing = malloc(100000);
printf("Initializing
%(name)
s
\\
n");
"""
def
c_literal
(
self
):
return
str
(
self
.
data
)
def
c_
data_
extract
(
self
):
def
c_extract
(
self
):
return
"""
return
"""
%(type)
s
%(name)
s = PyFloat_AsDouble(py_
%(name)
s);
if (!PyFloat_Check(py_
%(name)
s)) {
%(fail)
s
PyErr_SetString(PyExc_TypeError, "not a double!");
%(fail)
s
}
%(name)
s = PyFloat_AsDouble(py_
%(name)
s);
%(name)
s_bad_thing = NULL;
printf("Extracting
%(name)
s
\\
n");
"""
"""
def
c_
data_
sync
(
self
):
def
c_sync
(
self
):
return
"""
return
"""
Py_XDECREF(py_
%(name)
s);
Py_XDECREF(py_
%(name)
s);
py_
%(name)
s = PyFloat_FromDouble(
%(name)
s);
py_
%(name)
s = PyFloat_FromDouble(
%(name)
s);
if (!py_
%(name)
s)
if (!py_
%(name)
s)
py_
%(name)
s = Py_None;
py_
%(name)
s = Py_None;
printf("Syncing
%(name)
s
\\
n");
"""
def
c_cleanup
(
self
):
return
"""
printf("Cleaning up
%(name)
s
\\
n");
if (
%(name)
s_bad_thing)
free(
%(name)
s_bad_thing);
"""
"""
...
@@ -95,10 +120,22 @@ class _test_CLinker(unittest.TestCase):
...
@@ -95,10 +120,22 @@ class _test_CLinker(unittest.TestCase):
def
test_0
(
self
):
def
test_0
(
self
):
x
,
y
,
z
=
inputs
()
x
,
y
,
z
=
inputs
()
e
=
mul
(
add
(
x
,
y
),
div
(
x
,
y
))
e
=
add
(
mul
(
add
(
x
,
y
),
div
(
x
,
y
)),
sub
(
sub
(
x
,
y
),
z
))
lnk
=
CLinker
(
env
([
x
,
y
,
z
],
[
e
]))
lnk
=
CLinker
(
env
([
x
,
y
,
z
],
[
e
]),
[
x
.
r
,
y
.
r
,
z
.
r
],
[
e
.
r
])
print
lnk
.
code_gen
()
cgen
=
lnk
.
code_gen
()
fn
=
lnk
.
make_function
([
x
.
r
,
y
.
r
,
z
.
r
],
[
e
.
r
])
print
fn
(
2.0
,
2.0
,
2.0
)
# fn = 0
def
test_1
(
self
):
x
,
y
,
z
=
inputs
()
z
.
r
.
constant
=
True
e
=
add
(
mul
(
add
(
x
,
y
),
div
(
x
,
y
)),
sub
(
sub
(
x
,
y
),
z
))
lnk
=
CLinker
(
env
([
x
,
y
],
[
e
]),
[
x
.
r
,
y
.
r
],
[
e
.
r
])
cgen
=
lnk
.
code_gen
()
fn
=
lnk
.
make_function
([
x
.
r
,
y
.
r
],
[
e
.
r
])
print
fn
(
2.0
,
2.0
)
# fn = 0
if
__name__
==
'__main__'
:
if
__name__
==
'__main__'
:
unittest
.
main
()
unittest
.
main
()
gof/cc.py
浏览文件 @
6ec9db61
from
link
import
Linker
from
link
import
Linker
from
copy
import
copy
from
copy
import
copy
from
utils
import
AbstractFunctionError
import
md5
import
sys
import
os
import
platform
from
scipy
import
weave
import
cutils
import
utils
def
compile_dir
():
"""Return the directory in which scipy.weave should store code objects.
If the environment variable OMEGA_COMPILEDIR is set, its value is returned.
If not, a directory of the form $HOME/.omega/compiledir_<platform Id>.
As a test, this function touches the file __init__.py in the returned
directory, and raises OSError if there's a problem.
A directory coming from OMEGA_COMPILEDIR is not created automatically, but
a directory in $HOME/.omega is created automatically.
This directory is appended to the sys.path search path before being
returned, if the touch was successful.
"""
if
os
.
getenv
(
'OMEGA_COMPILEDIR'
):
cachedir
=
os
.
getenv
(
'OMEGA_COMPILEDIR'
)
else
:
# use (and possibly create) a default code cache location
platform_id
=
platform
.
platform
()
+
'-'
+
platform
.
processor
()
import
re
platform_id
=
re
.
sub
(
"[
\
(
\
)
\
s]+"
,
"_"
,
platform_id
)
cachedir
=
os
.
path
.
join
(
os
.
getenv
(
'HOME'
),
'.omega'
,
'compiledir_'
+
platform_id
)
if
not
os
.
access
(
cachedir
,
os
.
R_OK
|
os
.
W_OK
):
#this may raise a number of problems, I think all of which are serious.
os
.
makedirs
(
cachedir
,
7
<<
6
)
cachedir_init
=
cachedir
+
'/__init__.py'
touch
=
os
.
system
(
'touch '
+
cachedir_init
)
if
touch
:
raise
OSError
(
'touch
%
s returned
%
i'
%
(
cachedir_init
,
touch
))
if
cachedir
not
in
sys
.
path
:
sys
.
path
.
append
(
cachedir
)
return
cachedir
class
CodeBlock
:
class
CodeBlock
:
...
@@ -8,9 +53,13 @@ class CodeBlock:
...
@@ -8,9 +53,13 @@ class CodeBlock:
def
__init__
(
self
,
declare
,
behavior
,
cleanup
,
sub
):
def
__init__
(
self
,
declare
,
behavior
,
cleanup
,
sub
):
self
.
declare
=
declare
%
sub
self
.
declare
=
declare
%
sub
behavior_sub
=
copy
(
sub
)
behavior_sub
=
copy
(
sub
)
behavior_sub
[
'fail'
]
=
"{
goto __label_
%(id)
i
}"
%
sub
behavior_sub
[
'fail'
]
=
"{
%(failure_var)
s =
%(id)
s; goto __label_
%(id)
i;
}"
%
sub
self
.
behavior
=
behavior
%
behavior_sub
self
.
behavior
=
behavior
%
behavior_sub
self
.
cleanup
=
(
"__label_
%(id)
i:
\n
"
+
cleanup
)
%
sub
# the dummy is because gcc throws an error when a label's right next to a closing
# brace (maybe there's an ignore flag for that...)
# we need the label even if cleanup is empty because the behavior block jumps there
# on failure
self
.
cleanup
=
(
"__label_
%(id)
i:
\n
"
+
cleanup
+
"
\n
double __DUMMY_
%(id)
i;
\n
"
)
%
sub
def
code_gen
(
blocks
):
def
code_gen
(
blocks
):
...
@@ -31,8 +80,8 @@ def struct_gen(args, struct_builders, blocks, sub):
...
@@ -31,8 +80,8 @@ def struct_gen(args, struct_builders, blocks, sub):
struct_init_head
=
""
struct_init_head
=
""
struct_init_tail
=
""
struct_init_tail
=
""
struct_cleanup
=
""
struct_cleanup
=
""
for
block
in
block
s
:
for
block
in
struct_builder
s
:
struct_decl
+=
block
.
declare
struct_decl
+=
block
.
declare
struct_init_head
=
struct_init_head
+
(
"
\n
{
\n
%
s"
%
block
.
behavior
)
struct_init_head
=
struct_init_head
+
(
"
\n
{
\n
%
s"
%
block
.
behavior
)
struct_init_tail
=
(
"
%
s
\n
}
\n
"
%
block
.
cleanup
)
+
struct_init_tail
struct_init_tail
=
(
"
%
s
\n
}
\n
"
%
block
.
cleanup
)
+
struct_init_tail
...
@@ -40,82 +89,710 @@ def struct_gen(args, struct_builders, blocks, sub):
...
@@ -40,82 +89,710 @@ def struct_gen(args, struct_builders, blocks, sub):
behavior
=
code_gen
(
blocks
)
behavior
=
code_gen
(
blocks
)
args
=
", "
.
join
([
"PyObject*
%
s"
%
arg
for
arg
in
args
])
storage_decl
=
"
\n
"
.
join
([
"PyObject*
%
s;"
%
arg
for
arg
in
args
])
# we're borrowing the references to the storage pointers because Python
# has (needs) references to them to feed inputs or get the results
storage_set
=
"
\n
"
.
join
([
"this->
%
s =
%
s;"
%
(
arg
,
arg
)
for
arg
in
args
])
args_names
=
", "
.
join
(
args
)
args_decl
=
", "
.
join
([
"PyObject*
%
s"
%
arg
for
arg
in
args
])
do_return
=
"""
if (
%(failure_var)
s) {
// When there is a failure, this code puts the exception
// in __ERROR.
PyObject* err_type = NULL;
PyObject* err_msg = NULL;
PyObject* err_traceback = NULL;
PyErr_Fetch(&err_type, &err_msg, &err_traceback);
if (!err_type) err_type = Py_None;
if (!err_msg) err_msg = Py_None;
if (!err_traceback) err_traceback = Py_None;
PyObject* old_err_type = PyList_GET_ITEM(__ERROR, 0);
PyObject* old_err_msg = PyList_GET_ITEM(__ERROR, 1);
PyObject* old_err_traceback = PyList_GET_ITEM(__ERROR, 2);
PyList_SET_ITEM(__ERROR, 0, err_type);
PyList_SET_ITEM(__ERROR, 1, err_msg);
PyList_SET_ITEM(__ERROR, 2, err_traceback);
Py_XDECREF(old_err_type);
Py_XDECREF(old_err_msg);
Py_XDECREF(old_err_traceback);
}
// The failure code is returned to index what code block failed.
return
%(failure_var)
s;
"""
%
sub
sub
=
copy
(
sub
)
sub
.
update
(
locals
())
# TODO: add some error checking to make sure storage_<x> are 1-element lists
# and __ERROR is a 3-elements list.
struct_code
=
"""
struct_code
=
"""
struct __struct_
%%(id)
s {
struct
%%(name)
s {
PyObject* __ERROR;
%(storage_decl)
s
%(struct_decl)
s
%(struct_decl)
s
__struct_
%%(id)
s(void
) {}
%%(name)
s(
) {}
~
__struct_
%%(id
)
s(void) {
~
%%(name
)
s(void) {
cleanup();
cleanup();
}
}
void init(
%(args)
s) {
int init(PyObject* __ERROR,
%(args_decl)
s) {
%(storage_set)
s
int
%(failure_var)
s = 0;
%(struct_init_head)
s
%(struct_init_head)
s
return;
this->__ERROR = __ERROR;
return 0;
%(struct_init_tail)
s
%(struct_init_tail)
s
%(do_return)
s
return
%(failure_var)
s;
}
}
void cleanup(void) {
void cleanup(void) {
%(struct_cleanup)
s
%(struct_cleanup)
s
}
}
void run(void) {
int run(void) {
int
%(failure_var)
s = 0;
%(behavior)
s
%(behavior)
s
%(do_return)
s
}
}
};
};
"""
%
locals
()
"""
%
sub
return
struct_code
return
struct_code
def
get_nothing
(
r
):
return
""
def
get_c_declare
(
r
):
pre
=
"""
PyObject* py_
%(name)
s;
"""
return
pre
+
r
.
c_declare
()
def
get_c_init
(
r
):
pre
=
""
"""
py_
%(name)
s = Py_None;
"""
return
pre
+
r
.
c_init
()
def
get_c_extract
(
r
):
pre
=
"""
py_
%(name)
s = PyList_GET_ITEM(storage_
%(name)
s, 0);
Py_XINCREF(py_
%(name)
s);
"""
return
pre
+
r
.
c_extract
()
def
get_c_cleanup
(
r
):
post
=
"""
Py_XDECREF(py_
%(name)
s);
"""
return
r
.
c_cleanup
()
+
post
def
get_c_sync
(
r
):
return
"""
if (!
%%(failure_var)
s) {
%(sync)
s
PyObject* old = PyList_GET_ITEM(storage_
%%(name)
s, 0);
Py_XINCREF(py_
%%(name)
s);
PyList_SET_ITEM(storage_
%%(name)
s, 0, py_
%%(name)
s);
Py_XDECREF(old);
}
"""
%
dict
(
sync
=
r
.
c_sync
())
def
apply_policy
(
policy
,
r
):
if
isinstance
(
r
,
(
list
,
tuple
)):
ret
=
""
for
sub_policy
in
policy
:
ret
+=
sub_policy
(
r
)
return
policy
(
r
)
def
struct_result_codeblocks
(
result
,
policies
,
id
,
symbol_table
,
sub
):
name
=
"V
%
i"
%
id
symbol_table
[
result
]
=
name
sub
=
copy
(
sub
)
sub
[
'name'
]
=
name
sub
[
'id'
]
=
id
struct_builder
=
CodeBlock
(
*
[
apply_policy
(
policy
,
result
)
for
policy
in
policies
[
0
]]
+
[
sub
])
# struct_declare, struct_behavior, struct_cleanup, sub)
sub
[
'id'
]
=
id
+
1
block
=
CodeBlock
(
*
[
apply_policy
(
policy
,
result
)
for
policy
in
policies
[
1
]]
+
[
sub
])
# run_declare, run_behavior, run_cleanup, sub)
return
struct_builder
,
block
class
CLinker
(
Linker
):
class
CLinker
(
Linker
):
def
__init__
(
self
,
env
):
def
__init__
(
self
,
env
,
inputs
=
None
,
outputs
=
None
):
self
.
env
=
env
self
.
env
=
env
self
.
inputs
=
inputs
self
.
outputs
=
outputs
def
extract_sync
(
self
,
to_extract
,
to_sync
,
to_cleanup
):
def
fetch_results
(
self
):
pass
env
=
self
.
env
results
=
env
.
results
()
if
self
.
inputs
:
assert
set
(
self
.
inputs
)
==
set
(
env
.
inputs
)
inputs
=
self
.
inputs
else
:
inputs
=
env
.
inputs
if
self
.
outputs
:
assert
set
(
self
.
outputs
)
==
set
(
env
.
outputs
)
outputs
=
self
.
outputs
else
:
outputs
=
env
.
outputs
outputs
=
env
.
outputs
orphans
=
env
.
orphans
()
temps
=
results
.
difference
(
inputs
)
.
difference
(
outputs
)
.
difference
(
orphans
)
return
results
,
inputs
,
outputs
,
orphans
,
temps
def
code_gen
(
self
,
reuse_storage
=
True
):
def
code_gen
(
self
):
env
=
self
.
env
env
=
self
.
env
order
=
env
.
toposort
()
op_order
=
env
.
toposort
()
to_extract
=
env
.
inputs
.
union
(
env
.
outputs
)
.
union
(
env
.
orphans
())
head
=
""
results
,
inputs
,
outputs
,
orphans
,
temps
=
self
.
fetch_results
()
tail
=
""
label_id
=
0
consts
=
[]
name_id
=
0
symbol
=
{}
result_names
=
{}
for
result
in
env
.
results
():
init_tasks
=
[]
name
=
"__v_
%
i"
%
name_id
tasks
=
[]
result_names
[
result
]
=
name
name_id
+=
1
init_blocks
=
[]
blocks
=
[]
for
result
in
to_extract
:
head
+=
"""
failure_var
=
"__failure"
{
id
=
0
%(extract)
s
"""
sub
=
dict
(
failure_var
=
failure_var
)
tail
=
"""
__label_
%(label_id)
s:
for
result
in
results
:
%(sync)
s
if
getattr
(
result
,
'constant'
,
False
):
}
if
result
in
outputs
or
result
in
temps
:
"""
+
tail
raise
Exception
(
"Temporaries and outputs should not be marked constant. Check your graph."
)
name
=
result_names
[
result
]
try
:
type
=
result
.
c_type
()
symbol
[
result
]
=
result
.
c_literal
()
head
%=
dict
(
extract
=
result
.
c_extract
())
consts
.
append
(
result
)
head
%=
dict
(
name
=
name
,
if
result
in
inputs
:
type
=
type
,
print
"Warning: input
%
s is marked as constant and has been compiled as a literal."
%
result
fail
=
"{goto __label_
%
i;}"
%
label_id
)
elif
result
in
orphans
:
tail
%=
dict
(
sync
=
result
.
c_sync
(),
orphans
.
remove
(
result
)
label_id
=
label_id
)
continue
tail
%=
dict
(
name
=
name
,
except
AbstractFunctionError
:
type
=
type
)
pass
label_id
+=
1
# policy = [[what to declare in the struct, what to do at construction, what to do at destruction],
# [what to declare in each run, what to do at the beginning of each run, what to do at the end of each run]]
for
op
in
order
:
if
result
in
inputs
:
inames
,
onames
=
op
.
c_var_names
()
# we need to extract the new inputs at each run
# they do not need to be relayed to Python, so we don't sync
policy
=
[[
get_nothing
,
get_nothing
,
get_nothing
],
[
get_c_declare
,
get_c_extract
,
get_c_cleanup
]]
elif
result
in
orphans
:
# orphans are not inputs so we'll just get fetch them when we initialize the struct and assume they stay the same
policy
=
[[
get_c_declare
,
get_c_extract
,
get_c_cleanup
],
[
get_nothing
,
get_nothing
,
get_nothing
]]
elif
result
in
temps
or
not
reuse_storage
:
# temps don't need to be extracted from Python, so we call c_init rather than c_extract
# they do not need to be relayed to Python, so we don't sync
if
result
.
c_is_simple
()
or
not
reuse_storage
:
policy
=
[[
get_nothing
,
get_nothing
,
get_nothing
],
[
get_c_declare
,
get_c_init
,
get_c_cleanup
]]
else
:
# it is useful for complex temps to reuse storage at each run, so we only clean up in the destructor
policy
=
[[
get_c_declare
,
get_c_init
,
get_c_cleanup
],
[
get_nothing
,
get_nothing
,
get_nothing
]]
elif
result
in
outputs
:
# outputs don't need to be extracted from Python, so we call c_init rather than c_extract
if
result
.
c_is_simple
()
or
not
reuse_storage
:
policy
=
[[
get_nothing
,
get_nothing
,
get_nothing
],
[
get_c_declare
,
get_c_init
,
(
get_c_sync
,
get_c_cleanup
)]]
else
:
# it is useful for complex outputs to reuse storage at each run, so we only clean up in the destructor
policy
=
[[
get_c_declare
,
get_c_init
,
get_c_cleanup
],
[
get_nothing
,
get_nothing
,
get_c_sync
]]
builder
,
block
=
struct_result_codeblocks
(
result
,
policy
,
id
,
symbol
,
sub
)
init_tasks
.
append
((
result
,
'init'
))
init_blocks
.
append
(
builder
)
tasks
.
append
((
result
,
'get'
))
blocks
.
append
(
block
)
id
+=
2
print
symbol
for
op
in
op_order
:
ivnames
,
ovnames
=
op
.
c_var_names
()
sub
=
dict
(
failure_var
=
failure_var
)
for
result
,
vname
in
zip
(
op
.
inputs
+
op
.
outputs
,
ivnames
+
ovnames
):
sub
[
vname
]
=
symbol
[
result
]
# c_validate_update
try
:
validate_behavior
=
op
.
c_validate_update
()
except
AbstractFunctionError
:
validate_behavior
=
""
try
:
validate_behavior
=
op
.
c_validate_update_cleanup
()
except
AbstractFunctionError
:
validate_cleanup
=
""
sub
[
'id'
]
=
id
blocks
.
append
(
CodeBlock
(
""
,
validate_behavior
,
validate_cleanup
,
sub
))
tasks
.
append
((
op
,
'validate_update'
))
id
+=
1
# c_code
behavior
=
op
.
c_code
()
# this one must be implemented!
try
:
cleanup
=
op
.
c_code_cleanup
()
except
AbstractFunctionError
:
cleanup
=
""
sub
[
'id'
]
=
id
blocks
.
append
(
CodeBlock
(
""
,
behavior
,
cleanup
,
sub
))
tasks
.
append
((
op
,
'code'
))
id
+=
1
args
=
[]
in_arg_order
=
[]
for
result
in
list
(
inputs
):
in_arg_order
.
append
(
result
)
args
.
append
(
"storage_
%
s"
%
symbol
[
result
])
out_arg_order
=
[]
for
result
in
list
(
outputs
):
out_arg_order
.
append
(
result
)
args
.
append
(
"storage_
%
s"
%
symbol
[
result
])
orphan_arg_order
=
[]
for
result
in
list
(
orphans
):
orphan_arg_order
.
append
(
result
)
args
.
append
(
"storage_
%
s"
%
symbol
[
result
])
struct_code
=
struct_gen
(
args
,
init_blocks
,
blocks
,
dict
(
failure_var
=
failure_var
))
hash
=
md5
.
md5
(
struct_code
)
.
hexdigest
()
struct_name
=
'__struct_compiled_op_
%
s'
%
hash
struct_code
%=
dict
(
name
=
struct_name
)
self
.
struct_code
=
struct_code
self
.
struct_name
=
struct_name
self
.
hash
=
hash
self
.
args
=
args
self
.
inputs
=
in_arg_order
self
.
outputs
=
out_arg_order
self
.
orphans
=
orphan_arg_order
self
.
r2symbol
=
symbol
self
.
init_blocks
=
init_blocks
self
.
init_tasks
=
init_tasks
self
.
blocks
=
blocks
self
.
tasks
=
tasks
return
struct_code
def
find_task
(
self
,
failure_code
):
n
=
len
(
self
.
init_tasks
)
if
failure_code
<
2
*
n
:
return
[
self
.
init_tasks
,
self
.
tasks
][
failure_code
%
2
][
failure_code
/
2
]
else
:
return
self
.
tasks
[
failure_code
-
n
]
def
support_code
(
self
):
ret
=
""
for
x
in
self
.
env
.
results
()
.
union
(
self
.
env
.
ops
()):
try
:
ret
+=
x
.
c_support_code
()
except
AbstractFunctionError
:
pass
return
ret
def
compile_args
(
self
):
ret
=
set
()
for
x
in
self
.
env
.
results
()
.
union
(
self
.
env
.
ops
()):
try
:
ret
.
update
(
x
.
c_compile_args
())
except
AbstractFunctionError
:
pass
return
ret
def
headers
(
self
):
ret
=
set
()
for
x
in
self
.
env
.
results
()
.
union
(
self
.
env
.
ops
()):
try
:
ret
.
update
(
x
.
c_headers
())
except
AbstractFunctionError
:
pass
return
ret
def
libraries
(
self
):
ret
=
set
()
for
x
in
self
.
env
.
results
()
.
union
(
self
.
env
.
ops
()):
try
:
ret
.
update
(
x
.
c_libraries
())
except
AbstractFunctionError
:
pass
return
ret
def
make_function
(
self
,
in_order
,
out_order
):
nin
=
len
(
self
.
inputs
)
nout
=
len
(
self
.
outputs
)
if
nin
!=
len
(
in_order
):
raise
TypeError
(
"Wrong number of inputs."
)
if
nout
!=
len
(
out_order
):
raise
TypeError
(
"Wrong number of outputs."
)
return
head
+
tail
in_storage
=
[]
out_storage
=
[]
cthunk_in_args
=
[
None
]
*
nin
cthunk_out_args
=
[
None
]
*
nout
for
result
in
in_order
:
idx
=
self
.
inputs
.
index
(
result
)
storage
=
[
None
]
cthunk_in_args
[
idx
]
=
storage
in_storage
.
append
(
storage
)
for
result
in
out_order
:
idx
=
self
.
outputs
.
index
(
result
)
storage
=
[
None
]
cthunk_out_args
[
idx
]
=
storage
out_storage
.
append
(
storage
)
for
arg
in
cthunk_in_args
+
cthunk_out_args
:
if
arg
is
None
:
raise
Exception
(
"The inputs or outputs are underspecified."
)
error_storage
=
[
None
,
None
,
None
]
cthunk
=
self
.
cthunk_factory
(
error_storage
,
cthunk_in_args
,
cthunk_out_args
)
def
execute
(
*
args
):
for
arg
,
storage
in
zip
(
args
,
in_storage
):
storage
[
0
]
=
arg
failure
=
cutils
.
run_cthunk
(
cthunk
)
if
failure
:
raise
error_storage
[
0
],
error_storage
[
1
]
+
" "
+
str
(
self
.
find_task
(
failure
-
1
))
return
utils
.
to_return_values
([
storage
[
0
]
for
storage
in
out_storage
])
return
execute
def
cthunk_factory
(
self
,
error_storage
,
in_storage
,
out_storage
):
cthunk
=
object
()
module_name
=
self
.
hash
mod
=
weave
.
ext_tools
.
ext_module
(
module_name
)
argnames
=
[
"i
%
i"
%
i
for
i
in
xrange
(
len
(
in_storage
))]
\
+
[
"o
%
i"
%
i
for
i
in
xrange
(
len
(
out_storage
))]
\
+
[
"orph
%
i"
%
i
for
i
in
xrange
(
len
(
self
.
orphans
))]
code
=
"""
%(struct_name)
s* struct_ptr = new
%(struct_name)
s();
struct_ptr->init(error_storage,
%(args)
s);
PyObject* thunk = PyCObject_FromVoidPtrAndDesc((void*)(&
%(struct_name)
s_executor), struct_ptr,
%(struct_name)
s_destructor);
return thunk;
// return_val = thunk; // oh my god weave why does this leak >:
\
"""
%
dict
(
struct_name
=
self
.
struct_name
,
args
=
", "
.
join
(
argnames
))
d
=
dict
(
error_storage
=
object
())
for
argname
in
argnames
:
d
[
argname
]
=
object
()
instantiate
=
weave
.
ext_tools
.
ext_function
(
'instantiate'
,
code
,
[
'error_storage'
]
+
argnames
,
local_dict
=
d
,
global_dict
=
{})
static
=
"""
int
%(struct_name)
s_executor(
%(struct_name)
s* self) {
return self->run();
}
void
%(struct_name)
s_destructor(void* executor, void* self) {
printf("doing cleanup
\\
n");
((
%(struct_name)
s*)self)->cleanup();
free(self);
}
"""
%
dict
(
struct_name
=
self
.
struct_name
)
instantiate
.
customize
.
add_support_code
(
self
.
support_code
()
+
self
.
struct_code
+
static
)
for
arg
in
self
.
compile_args
():
instantiate
.
customize
.
add_extra_compile_arg
(
arg
)
for
header
in
self
.
headers
():
instantiate
.
customize
.
add_header
(
header
)
for
lib
in
self
.
libraries
():
instantiate
.
customize
.
add_library
(
lib
)
mod
.
add_function
(
instantiate
)
mod
.
compile
(
location
=
compile_dir
())
module
=
__import__
(
"
%
s"
%
(
module_name
),
{},
{},
[
module_name
])
ret
=
module
.
instantiate
(
error_storage
,
*
(
in_storage
+
out_storage
+
[
orphan
.
_data
for
orphan
in
self
.
orphans
]))
assert
sys
.
getrefcount
(
ret
)
==
2
# refcount leak check
return
ret
# def c_thunk_factory(self):
# self.refresh()
# d, names, code, struct, converters = self.c_code()
# cthunk = object()
# module_name = md5.md5(code).hexdigest()
# mod = weave.ext_tools.ext_module(module_name)
# instantiate = weave.ext_tools.ext_function('instantiate',
# code,
# names,
# local_dict = d,
# global_dict = {},
# type_converters = converters)
# instantiate.customize.add_support_code(self.c_support_code() + struct)
# for arg in self.c_compile_args():
# instantiate.customize.add_extra_compile_arg(arg)
# for header in self.c_headers():
# instantiate.customize.add_header(header)
# for lib in self.c_libs():
# instantiate.customize.add_library(lib)
# #add_library_dir
# #print dir(instantiate.customize)
# #print instantiate.customize._library_dirs
# if os.getenv('OMEGA_BLAS_LD_LIBRARY_PATH'):
# instantiate.customize.add_library_dir(os.getenv('OMEGA_BLAS_LD_LIBRARY_PATH'))
# mod.add_function(instantiate)
# mod.compile(location = _compile_dir())
# module = __import__("%s" % (module_name), {}, {}, [module_name])
# def creator():
# return module.instantiate(*[x.data for x in self.inputs + self.outputs])
# return creator
# def code_gen(self, reuse_storage = True):
# env = self.env
# op_order = env.toposort()
# to_extract = env.inputs.union(env.orphans())
# to_sync = env.outputs
# temporaries = env.results().difference(to_extract).difference(to_sync)
# symbol = {}
# init_tasks = []
# tasks = []
# init_blocks = []
# blocks = []
# failure_var = "__failure"
# id = 0
# sub = dict(failure_var = failure_var)
# on_stack = [result for result in temporaries.union(to_sync) if not reuse_storage or result.c_is_simple()]
# for result_set, type in [[to_extract, 'input'],
# [to_sync, 'output'],
# [temporaries, 'temporary']]:
# for result in result_set:
# builder, block = struct_result_codeblocks(result, type, id, symbol, sub, on_stack)
# init_tasks.append((result, 'init'))
# init_blocks.append(builder)
# tasks.append((result, 'get'))
# blocks.append(block)
# id += 2
# for op in op_order:
# ivnames, ovnames = op.c_var_names()
# sub = dict(failure_var = failure_var)
# for result, vname in zip(op.inputs + op.outputs, ivnames + ovnames):
# sub[vname] = symbol[result]
# # c_validate_update
# try: validate_behavior = op.c_validate_update()
# except AbstractFunctionError:
# validate_behavior = ""
# try: validate_behavior = op.c_validate_update_cleanup()
# except AbstractFunctionError:
# validate_cleanup = ""
# sub['id'] = id
# blocks.append(CodeBlock("", validate_behavior, validate_cleanup, sub))
# tasks.append((op, 'validate_update'))
# id += 1
# # c_code
# behavior = op.c_code() # this one must be implemented!
# try: cleanup = op.c_code_cleanup()
# except AbstractFunctionError:
# cleanup = ""
# sub['id'] = id
# blocks.append(CodeBlock("", behavior, cleanup, sub))
# tasks.append((op, 'code'))
# id += 1
# args = []
# in_arg_order = []
# for result in list(to_extract):
# in_arg_order.append(result)
# args.append("storage_%s" % symbol[result])
# out_arg_order = []
# for result in to_sync:
# out_arg_order.append(result)
# args.append("storage_%s" % symbol[result])
# struct_code = struct_gen(args, init_blocks, blocks, dict(failure_var = failure_var))
# hash = md5.md5(struct_code).hexdigest()
# struct_name = 'compiled_op_%s' % hash
# struct_code %= dict(name = struct_name)
# self.struct_code = struct_code
# self.struct_name = struct_name
# self.hash = hash
# self.args = args
# self.inputs = in_arg_order
# self.outputs = out_arg_order
# self.r2symbol = symbol
# self.init_blocks = init_blocks
# self.init_tasks = init_tasks
# self.blocks = blocks
# self.tasks = tasks
# return struct_code
# def extract_sync(self, to_extract, to_sync, to_cleanup):
# pass
# def code_gen(self):
# env = self.env
# order = env.toposort()
# to_extract = env.inputs.union(env.outputs).union(env.orphans())
# head = ""
# tail = ""
# label_id = 0
# name_id = 0
# result_names = {}
# for result in env.results():
# name = "__v_%i" % name_id
# result_names[result] = name
# name_id += 1
# for result in to_extract:
# head += """
# {
# %(extract)s
# """
# tail = """
# __label_%(label_id)s:
# %(sync)s
# }
# """ + tail
# name = result_names[result]
# type = result.c_type()
# head %= dict(extract = result.c_extract())
# head %= dict(name = name,
# type = type,
# fail = "{goto __label_%i;}" % label_id)
# tail %= dict(sync = result.c_sync(),
# label_id = label_id)
# tail %= dict(name = name,
# type = type)
# label_id += 1
# for op in order:
# inames, onames = op.c_var_names()
# return head + tail
# def struct_result_codeblocks(result, type, id, symbol_table, sub, on_stack):
# if type == 'output':
# sync = get_c_sync(result)
# else:
# sync = ""
# if type == 'input':
# struct_declare = ""
# run_declare = result.c_declare()
# struct_behavior = ""
# run_behavior = get_c_extract(result)
# struct_cleanup = ""
# run_cleanup = get_c_cleanup(result)
# else:
# if result in on_stack:
# struct_declare = ""
# run_declare = result.c_declare()
# struct_behavior = ""
# run_behavior = result.c_init()
# struct_cleanup = ""
# run_cleanup = sync + get_c_cleanup(result)
# else:
# struct_declare = result.c_declare()
# run_declare = ""
# struct_behavior = result.c_init()
# run_behavior = ""
# struct_cleanup = get_c_cleanup(result)
# run_cleanup = sync
# name = "V%i" % id
# symbol_table[result] = name
# sub = copy(sub)
# sub['name'] = name
# sub['id'] = id
# struct_builder = CodeBlock(struct_declare, struct_behavior, struct_cleanup, sub)
# sub['id'] = id + 1
# block = CodeBlock(run_declare, run_behavior, run_cleanup, sub)
# return struct_builder, block
gof/cutils.py
0 → 100644
浏览文件 @
6ec9db61
try
:
from
cutils_ext
import
*
except
ImportError
:
from
scipy
import
weave
single_runner
=
"""
if (!PyCObject_Check(py_cthunk)) {
PyErr_SetString(PyExc_ValueError,
"Argument to run_cthunk must be a PyCObject.");
return NULL;
}
void * ptr_addr = PyCObject_AsVoidPtr(py_cthunk);
int (*fn)(void*) = reinterpret_cast<int (*)(void*)>(ptr_addr);
void* it = PyCObject_GetDesc(py_cthunk);
int failure = fn(it);
return_val = failure;
"""
cthunk
=
object
()
mod
=
weave
.
ext_tools
.
ext_module
(
'cutils_ext'
)
fun
=
weave
.
ext_tools
.
ext_function
(
'run_cthunk'
,
single_runner
,
[
'cthunk'
])
fun
.
customize
.
add_extra_compile_arg
(
'--permissive'
)
mod
.
add_function
(
fun
)
mod
.
compile
()
from
cutils_ext
import
*
gof/env.py
浏览文件 @
6ec9db61
...
@@ -161,7 +161,6 @@ class Env(graph.Graph):
...
@@ -161,7 +161,6 @@ class Env(graph.Graph):
if
do_import
:
if
do_import
:
for
op
in
self
.
io_toposort
():
for
op
in
self
.
io_toposort
():
try
:
try
:
# print op
feature
.
on_import
(
op
)
feature
.
on_import
(
op
)
except
AbstractFunctionError
:
except
AbstractFunctionError
:
pass
pass
...
...
gof/op.py
浏览文件 @
6ec9db61
...
@@ -126,7 +126,7 @@ class Op(object):
...
@@ -126,7 +126,7 @@ class Op(object):
return
[[
"i
%
i"
%
i
for
i
in
xrange
(
len
(
self
.
inputs
))],
return
[[
"i
%
i"
%
i
for
i
in
xrange
(
len
(
self
.
inputs
))],
[
"o
%
i"
%
i
for
i
in
xrange
(
len
(
self
.
outputs
))]]
[
"o
%
i"
%
i
for
i
in
xrange
(
len
(
self
.
outputs
))]]
def
c_validate
(
self
):
def
c_validate
_update
(
self
):
"""
"""
Returns C code that checks that the inputs to this function
Returns C code that checks that the inputs to this function
can be worked on. If a failure occurs, set an Exception
can be worked on. If a failure occurs, set an Exception
...
@@ -136,27 +136,27 @@ class Op(object):
...
@@ -136,27 +136,27 @@ class Op(object):
"""
"""
raise
AbstractFunctionError
()
raise
AbstractFunctionError
()
def
c_validate_cleanup
(
self
):
def
c_validate_
update_
cleanup
(
self
):
"""
"""
Clean up things allocated by c_validate().
Clean up things allocated by c_validate().
"""
"""
raise
AbstractFunctionError
()
raise
AbstractFunctionError
()
def
c_update
(
self
):
#
def c_update(self):
"""
#
"""
Returns C code that allocates and/or updates the outputs
#
Returns C code that allocates and/or updates the outputs
(eg resizing, etc.) so they can be manipulated safely
#
(eg resizing, etc.) so they can be manipulated safely
by c_code.
#
by c_code.
You may use the variable names defined by c_var_names()
#
You may use the variable names defined by c_var_names()
"""
#
"""
raise
AbstractFunctionError
()
#
raise AbstractFunctionError()
def
c_update_cleanup
(
self
):
#
def c_update_cleanup(self):
"""
#
"""
Clean up things allocated by c_update().
#
Clean up things allocated by c_update().
"""
#
"""
raise
AbstractFunctionError
()
#
raise AbstractFunctionError()
def
c_code
(
self
):
def
c_code
(
self
):
"""
"""
...
@@ -174,6 +174,31 @@ class Op(object):
...
@@ -174,6 +174,31 @@ class Op(object):
"""
"""
raise
AbstractFunctionError
()
raise
AbstractFunctionError
()
def
c_compile_args
(
self
):
"""
Return a list of compile args recommended to manipulate this Op.
"""
raise
AbstractFunctionError
()
def
c_headers
(
self
):
"""
Return a list of header files that must be included from C to manipulate
this Op.
"""
raise
AbstractFunctionError
()
def
c_libraries
(
self
):
"""
Return a list of libraries to link against to manipulate this Op.
"""
raise
AbstractFunctionError
()
def
c_support_code
(
self
):
"""
Return utility code for use by this Op.
"""
raise
AbstractFunctionError
()
class
GuardedOp
(
Op
):
class
GuardedOp
(
Op
):
...
...
gof/result.py
浏览文件 @
6ec9db61
...
@@ -149,20 +149,23 @@ class ResultBase(object):
...
@@ -149,20 +149,23 @@ class ResultBase(object):
# C code generators
# C code generators
#
#
def
c_is_simple
(
self
):
return
False
def
c_declare
(
self
):
def
c_declare
(
self
):
"""
"""
Declares variables that will be instantiated by c_data_extract.
Declares variables that will be instantiated by c_data_extract.
"""
"""
raise
AbstractFunctionError
()
raise
AbstractFunctionError
()
def
c_extract
(
self
):
#
def c_extract(self):
get_from_list
=
"""
#
get_from_list = """
PyObject* py_
%(name)
s = PyList_GET_ITEM(
%(name)
s_storage, 0);
# //
PyObject* py_%(name)s = PyList_GET_ITEM(%(name)s_storage, 0);
Py_XINCREF(py_
%(name)
s);
# //
Py_XINCREF(py_%(name)s);
"""
#
"""
return
get_from_list
+
self
.
c_data_extract
()
#
return get_from_list + self.c_data_extract()
def
c_
data_
extract
(
self
):
def
c_extract
(
self
):
"""
"""
# The code returned from this function must be templated using
# The code returned from this function must be templated using
# "
%(name)
s", representing the name that the caller wants to
# "
%(name)
s", representing the name that the caller wants to
...
@@ -176,13 +179,13 @@ class ResultBase(object):
...
@@ -176,13 +179,13 @@ class ResultBase(object):
"""
"""
raise
AbstractFunctionError
()
raise
AbstractFunctionError
()
def
c_cleanup
(
self
):
#
def c_cleanup(self):
decref
=
"""
#
decref = """
Py_XDECREF(py_
%(name)
s);
# //
Py_XDECREF(py_%(name)s);
"""
#
"""
return
self
.
c_data_cleanup
()
+
decref
#
return self.c_data_cleanup() + decref
def
c_
data_
cleanup
(
self
):
def
c_cleanup
(
self
):
"""
"""
This returns C code that should deallocate whatever
This returns C code that should deallocate whatever
c_data_extract allocated or decrease the reference counts. Do
c_data_extract allocated or decrease the reference counts. Do
...
@@ -192,14 +195,14 @@ class ResultBase(object):
...
@@ -192,14 +195,14 @@ class ResultBase(object):
"""
"""
raise
AbstractFunctionError
()
raise
AbstractFunctionError
()
def
c_sync
(
self
):
#
def c_sync(self):
set_in_list
=
"""
#
set_in_list = """
PyList_SET_ITEM(
%(name)
s_storage, 0, py_
%(name)
s);
# //
PyList_SET_ITEM(%(name)s_storage, 0, py_%(name)s);
Py_XDECREF(py_
%(name)
s);
# //
Py_XDECREF(py_%(name)s);
"""
#
"""
return
self
.
c_data_sync
()
+
set_in_list
#
return self.c_data_sync() + set_in_list
def
c_
data_
sync
(
self
):
def
c_sync
(
self
):
"""
"""
The code returned from this function must be templated using "
%(name)
s",
The code returned from this function must be templated using "
%(name)
s",
representing the name that the caller wants to call this Result.
representing the name that the caller wants to call this Result.
...
@@ -209,20 +212,26 @@ class ResultBase(object):
...
@@ -209,20 +212,26 @@ class ResultBase(object):
"""
"""
raise
AbstractFunctionError
()
raise
AbstractFunctionError
()
def
c_compile_args
(
self
):
"""
Return a list of compile args recommended to manipulate this Result.
"""
raise
AbstractFunctionError
()
def
c_headers
(
self
):
def
c_headers
(
self
):
"""
"""
Return a list of header files that must be included from C to manipulate
Return a list of header files that must be included from C to manipulate
this Result.
this Result.
"""
"""
r
eturn
[]
r
aise
AbstractFunctionError
()
def
c_libraries
(
self
):
def
c_libraries
(
self
):
"""
"""
Return a list of libraries to link against to manipulate this Result.
Return a list of libraries to link against to manipulate this Result.
"""
"""
r
eturn
[]
r
aise
AbstractFunctionError
()
def
c_support
(
self
):
def
c_support
_code
(
self
):
"""
"""
Return utility code for use by this Result or Ops manipulating this
Return utility code for use by this Result or Ops manipulating this
Result.
Result.
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论