linker, tests

上级 754f6f27
# from features import Tool
# from utils import AbstractFunctionError
from utils import AbstractFunctionError
class Linker:
def __init__(self, env):
self.env = env
self.thunk = None
def compile(self):
raise AbstractFunctionError()
def run(self):
self.thunk()
def __call__(self):
self.thunk()
class PerformLinker(Linker):
def compile(self):
order = self.env.toposort()
thunks = [op.perform for op in order]
def f():
for thunk in thunks:
thunk()
self.thunk = f
self.order = order
self.thunks = thunks
class ProfilePerformLinker(Linker):
def compile(self):
order = self.env.toposort()
thunks = [op.perform for op in order]
self.n_calls = 0
self.n_thunks = 0
self.times = [0.0 for op in self.order]
def f():
for thunk in thunks:
thunk()
self.thunk = f
self.order = order
self.thunks = thunks
def slow_call(self):
"""Run the program, timing each thunk."""
for i, thunk in enumerate(self.thunks):
start_time = time.time()
thunk()
self.times[i] += time.time() - start_time
self.n_thunks += 1
self.n_calls += 1
def fast_call(self):
"""Run the program, but only time the entire loop."""
start_time = time.time()
for thunk in self.thunks:
thunk()
self.n_thunks += len(self.thunks)
self.n_calls += 1
self.times[0] += time.time() - start_time
__call__ = slow_call
def dump(self, proportion=True):
"""Print statistics accumulated so far."""
total_time = sum(self.times)
print self.n_calls, 'calls took', total_time, 'seconds to evaluate',
print self.n_thunks, 'thunks'
if 0:
print 'Proportion of CPU per op'
for op, t in zip(self.order, self.times):
s_op = str(op).split()[0][1:]
print " %-35s %4.5f"% (s_op, t/total_time)
print 'Proportion of CPU per op class'
dct = {}
for op, t in zip(self.order, self.times):
s_op = str(op).split()[0][1:]
dct[s_op] = dct.get(s_op, 0.0) + t
for t, s_op in reversed(sorted([(t,op) for op, t in dct.items()])):
if proportion:
print " %-35s %4.5f"% (s_op, t/total_time)
else:
print " %-35s %4.5f"% (s_op, t)
# class Linker(Tool):
......
......@@ -4,19 +4,40 @@ from env import Env
from utils import AbstractFunctionError
class Linker:
class Prog:
def __init__(self, env):
self.env = env
self.thunk = None
def __init__(self, inputs, outputs, optimizer, linker_class, features = []):
self.inputs = inputs
if isinstance(outputs, dict):
for name, output in outputs.items():
setattr(self, name, output)
self.outputs = outputs.values()
else:
self.outputs = outputs
self.optimizer = optimizer
self.env = Env(self.inputs, self.outputs, features, False)
self.env.add_feature(EquivTool)
self.linker = linker_class(self.env)
def compile(self):
raise AbstractFunctionError()
def build(self):
self.optimizer.optimize(self.env)
def run(self):
self.thunk()
def equiv(self, r):
return self.env.equiv(r)
def __getitem__(self, r):
if isinstance(r, str):
return getattr(self, r)
else:
return self.equiv(r)
def __setitem__(self, r, value):
if isinstance(r, tuple):
for a, b in zip(r, value):
self.__setitem__(a, b)
else:
self[r].data = value
......
......@@ -145,38 +145,37 @@ class ResultBase(object):
raise AbstractFunctionError()
#
# alloc
#
# #
# # alloc
# #
def alloc(self):
"""Create self.data from data_alloc, and set state to Allocated
# def alloc(self):
# """Create self.data from data_alloc, and set state to Allocated
Graph routines like the linker will ask Ops to allocate outputs. The
Ops, in turn, usually call this function. Results that are involved in
destroy maps and view maps are exceptions to the usual case.
"""
self.data = self.data_alloc() #might raise exception
self.state = Allocated
# Graph routines like the linker will ask Ops to allocate outputs. The
# Ops, in turn, usually call this function. Results that are involved in
# destroy maps and view maps are exceptions to the usual case.
# """
# self.data = self.data_alloc() #might raise exception
# self.state = Allocated
def data_alloc(self):
"""(abstract) Return an appropriate _data based on self.
# def data_alloc(self):
# """(abstract) Return an appropriate _data based on self.
If a subclass overrides this function, then that overriding
implementation will be used in alloc() to produce a data object.
# If a subclass overrides this function, then that overriding
# implementation will be used in alloc() to produce a data object.
"""
raise AbstractFunctionError()
# """
# raise AbstractFunctionError()
#
# C code generators
#
def c_type(self):
def c_declare(self):
"""
Return a string naming the C type that Ops must use to manipulate
this Result.
Declares variables that will be instantiated by c_data_extract.
"""
raise AbstractFunctionError()
......@@ -185,23 +184,39 @@ class ResultBase(object):
PyObject* py_%(name)s = PyList_GET_ITEM(%(name)s_storage, 0);
Py_XINCREF(py_%(name)s);
"""
return self.c_data_extract() + get_from_list
return get_from_list + self.c_data_extract()
def c_data_extract(self):
"""
The code returned from this function must be templated using
"%(name)s", representing the name that the caller wants to
call this Result. The Python object self.data is in a
variable called "py_%(name)s" and this code must declare a
variable named "%(name)s" of type "%(type)s" where "%(type)s"
will be replaced by the return value of
self.c_type(). Additional variables and typedefs can be
produced. If the data is improper, set an appropriate error
message and insert "%(fail)s".
# The code returned from this function must be templated using
# "%(name)s", representing the name that the caller wants to
# call this Result. The Python object self.data is in a
# variable called "py_%(name)s" and this code must declare a
# variable named "%(name)s" of type "%(type)s" where "%(type)s"
# will be replaced by the return value of
# self.c_type(). Additional variables and typedefs may not be
# produced. If the data is improper, set an appropriate error
# message and insert "%(fail)s".
"""
raise AbstractFunctionError()
def c_sync(self, var_name):
def c_cleanup(self):
decref = """
Py_XDECREF(py_%(name)s);
"""
return self.c_data_cleanup() + decref
def c_data_cleanup(self):
"""
This returns C code that should deallocate whatever
c_data_extract allocated or decrease the reference counts. Do
not decrease py_%(name)s's reference count.
Note: EITHER c_cleanup OR c_sync will be called.
"""
raise AbstractFunctionError()
def c_sync(self):
set_in_list = """
PyList_SET_ITEM(%(name)s_storage, 0, py_%(name)s);
Py_XDECREF(py_%(name)s);
......@@ -231,6 +246,13 @@ class ResultBase(object):
"""
return []
def c_support(self):
"""
Return utility code for use by this Result or Ops manipulating this
Result.
"""
raise AbstractFunctionError()
#
# name
#
......@@ -277,7 +299,8 @@ class ResultBase(object):
def same_properties(self, other):
raise AbstractFunction()
#################
# NumpyR Compatibility
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论