diff --git a/loopy/prophormance.py b/loopy/prophormance.py deleted file mode 100755 index 8b495a63a22921c3d92fb54065b4143aaac94c9c..0000000000000000000000000000000000000000 --- a/loopy/prophormance.py +++ /dev/null @@ -1,171 +0,0 @@ -from __future__ import division -from __future__ import absolute_import -import six - -__copyright__ = "Copyright (C) 2015 James Stevens" - -__license__ = """ -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -""" - -import numpy as np -from islpy import dim_type -import loopy as lp -import pyopencl as cl -import pyopencl.array -from pymbolic.mapper.flop_counter import FlopCounter - -class ExpressionFlopCounter(FlopCounter): - - def map_reduction(self, expr): - from warnings import warn - warn("ExpressionFlopCounter counting reduction expression as 0 flops.", stacklevel=2) - return 0 - -# from pymbolic: - - def map_tagged_variable(self, expr): - return 0 - - def map_variable(self, expr): - return 0 - - def map_wildcard(self, expr): - return 0 - - def map_function_symbol(self, expr): - return 0 - - def map_call(self, expr): - return 0 - - def map_call_with_kwargs(self, expr): - return 0 - - def map_subscript(self, expr): - return self.rec(expr.index) - - def map_lookup(self, expr): - return 0 - - def map_sum(self, expr): - return 0 - - def map_product(self, expr): - return 0 - - def map_quotient(self, expr): - return 0 - - def map_floor_div(self, expr): - return 0 - - def map_remainder(self, expr): - return 0 - - def map_power(self, expr): - return 0 - - def map_left_shift(self, expr): - return 0 - - def map_right_shift(self, expr): - return 0 - - def map_bitwise_not(self, expr): - return 0 - - def map_bitwise_or(self, expr): - return 0 - - def map_bitwise_xor(self, expr): - return 0 - - def map_bitwise_and(self, expr): - return 0 - - def map_comparison(self, expr): - return 0 - - def map_logical_not(self, expr): - return 0 - - def map_logical_or(self, expr): - return 0 - - def map_logical_and(self, expr): - return 0 - - def map_if(self, expr): - return 0 - - def map_if_positive(self, expr): - return 0 - - def map_min(self, expr): - return 0 - - def map_max(self, expr): - return 0 - - def map_common_subexpression(self, expr): - return 0 - - def map_substitution(self, expr): - return 0 - - def map_derivative(self, expr): - return 0 - - def map_slice(self, expr): - return 0 - - -# to evaluate poly: poly.eval_with_dict(dictionary) -def get_flop_poly(knl): - poly = 0 - flopCounter = ExpressionFlopCounter() - for insn in knl.instructions: - # how many times is this instruction executed? - # check domain size: - insn_inames = knl.insn_inames(insn) - inames_domain = knl.get_inames_domain(knl.insn_inames(insn)) - domain = (inames_domain.project_out_except(insn_inames, [dim_type.set])) - flops = flopCounter(insn.expression()) - poly += flops*domain.card() - return poly - - -''' -class PerformanceForecaster: - - # to evaluate poly: poly.eval_with_dict(dictionary) - def get_flop_poly(self, knl): - poly = 0 - flopCounter = ExpressionFlopCounter() - for insn in knl.instructions: - # how many times is this instruction executed? - # check domain size: - insn_inames = knl.insn_inames(insn) - inames_domain = knl.get_inames_domain(knl.insn_inames(insn)) - domain = (inames_domain.project_out_except(insn_inames, [dim_type.set])) - flops = flopCounter(insn.expression()) - poly += flops*domain.card() - return poly -''' diff --git a/loopy/statistics.py b/loopy/statistics.py new file mode 100755 index 0000000000000000000000000000000000000000..b45e62efd8750902802f205fa3b45a97fb1c7c55 --- /dev/null +++ b/loopy/statistics.py @@ -0,0 +1,151 @@ +from __future__ import division +from __future__ import absolute_import +import six + +__copyright__ = "Copyright (C) 2015 James Stevens" + +__license__ = """ +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + +import numpy as np +from islpy import dim_type +import loopy as lp +import pyopencl as cl +import pyopencl.array +from pymbolic.mapper.flop_counter import FlopCounter + +class ExpressionFlopCounter(FlopCounter): + + # ExpressionFlopCounter extends FlopCounter extends CombineMapper extends RecursiveMapper + + def map_reduction(self, expr, knl): + inames_domain = knl.get_inames_domain(frozenset([expr.inames[0]])) + domain = (inames_domain.project_out_except(frozenset([expr.inames[0]]), [dim_type.set])) + if str(expr.operation) == 'sum' or str(expr.operation) == 'product' : + return domain.card()*(1+self.rec(expr.expr)) + else: + from warnings import warn + warn("ExpressionFlopCounter counting reduction operation as 0 flops.", stacklevel=2) + return domain.card()*(0+self.rec(expr.expr)) + + # from pymbolic: + + def map_tagged_variable(self, expr): + return 0 + + # def map_variable(self, expr): # implemented in FlopCounter + + def map_wildcard(self, expr): + return 0 + + def map_function_symbol(self, expr): + return 0 + + # def map_call(self, expr): # implemented in CombineMapper, recurses + # def map_call_with_kwargs(self, expr): # implemented in CombineMapper, recurses + + def map_subscript(self, expr): # implemented in CombineMapper + return self.rec(expr.index) + + # def map_lookup(self, expr): # implemented in CombineMapper, recurses + # def map_sum(self, expr) # implemented in FlopCounter + # def map_product(self, expr): # implemented in FlopCounter + # def map_quotient(self, expr): # implemented in FlopCounter + # def map_floor_div(self, expr): # implemented in FlopCounter + + def map_remainder(self, expr): # implemented in CombineMapper + return 0 + + # def map_power(self, expr): # implemented in FlopCounter, recurses; coming soon + + def map_left_shift(self, expr): # implemented in CombineMapper, recurses; coming soon + return 0 + + def map_right_shift(self, expr): # implemented in CombineMapper, maps to left_shift; coming soon + return 0 + + def map_bitwise_not(self, expr): # implemented in CombineMapper, recurses; coming soon + return 0 + + def map_bitwise_or(self, expr): # implemented in CombineMapper, maps to map_sum; coming soon + return 0 + + def map_bitwise_xor(self, expr): # implemented in CombineMapper, maps to map_sum; coming soon + return 0 + + def map_bitwise_and(self, expr): # implemented in CombineMapper, maps to map_sum; coming soon + return 0 + + def map_comparison(self, expr): # implemented in CombineMapper, recurses; coming soon + return 0 + + def map_logical_not(self, expr): # implemented in CombineMapper, maps to bitwise_not; coming soon + return 0 + + def map_logical_or(self, expr): # implemented in CombineMapper, maps to map_sum; coming soon + return 0 + + def map_logical_and(self, expr): # implemented in CombineMapper, maps to map_sum; coming soon + return 0 + + def map_if(self, expr): # implemented in CombineMapper, recurses; coming soon + return 0 + + # def map_if_positive(self, expr): # implemented in FlopCounter + + def map_min(self, expr): # implemented in CombineMapper, maps to map_sum; coming soon + return 0 + + def map_max(self, expr): # implemented in CombineMapper, maps to map_sum + return 0 + + def map_common_subexpression(self, expr): + print "TESTING-map_common_subexpression: ", expr + return 0 + + def map_substitution(self, expr): + print "TESTING-map_substitution: ", expr + return 0 + + def map_derivative(self, expr): + print "TESTING-map_derivative: ", expr + return 0 + + def map_slice(self, expr): + print "TESTING-map_slice: ", expr + return 0 + + +# to evaluate poly: poly.eval_with_dict(dictionary) +def get_flop_poly(knl): + poly = 0 + flopCounter = ExpressionFlopCounter() + for insn in knl.instructions: + # how many times is this instruction executed? + # check domain size: + insn_inames = knl.insn_inames(insn) + inames_domain = knl.get_inames_domain(insn_inames) + domain = (inames_domain.project_out_except(insn_inames, [dim_type.set])) + #flops = flopCounter(insn.expression()) + flops = flopCounter(insn.expression(),knl) + poly += flops*domain.card() + return poly + + diff --git a/test/test_statistics.py b/test/test_statistics.py new file mode 100644 index 0000000000000000000000000000000000000000..0df1865029ea145f52f225a3ef21036fb541f170 --- /dev/null +++ b/test/test_statistics.py @@ -0,0 +1,58 @@ +from __future__ import division + +__copyright__ = "Copyright (C) 2015 James Stevens" + +__license__ = """ +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + +import sys +from pyopencl.tools import ( + pytest_generate_tests_for_pyopencl + as pytest_generate_tests) +from pymbolic.mapper.flop_counter import FlopCounter +from loopy.statistics import * + + +def test_flop_counter_basic(ctx_factory): + + knl = lp.make_kernel( + "[n,m,l] -> {[i,k,j]: 0<=i<n and 0<=k<m and 0<=j<l}", + [ + """ + c[i, j, k] = a[i,j,k]*b[i,j,k]/3.0+a[i,j,k] + e[i, k] = g[i,k]*h[i,k] + """ + ], + name="weird", assumptions="n,m,l >= 1") + + poly = get_flop_poly(knl) + n=512 + m=256 + l=128 + flops = poly.eval_with_dict({'n':n, 'm':m, 'l':l}) + assert flops == n*m+3*n*m*l + + +if __name__ == "__main__": + if len(sys.argv) > 1: + exec(sys.argv[1]) + else: + from py.test.cmdline import main + main([__file__])