def test_one_factor_regression_estimator(self): data_points_str = [ 'operation { op: "kFoo" bit_count: 2 } delay: 210 delay_offset: 10', 'operation { op: "kFoo" bit_count: 4 } delay: 410 delay_offset: 10', 'operation { op: "kFoo" bit_count: 6 } delay: 610 delay_offset: 10', 'operation { op: "kFoo" bit_count: 8 } delay: 810 delay_offset: 10', 'operation { op: "kFoo" bit_count: 10 } delay: 1010 delay_offset: 10', ] result_bit_count = delay_model_pb2.DelayExpression() result_bit_count.factor.source = delay_model_pb2.DelayFactor.Source.RESULT_BIT_COUNT foo = delay_model.RegressionEstimator( 'kFoo', (result_bit_count, ), tuple(_parse_data_point(s) for s in data_points_str)) self.assertAlmostEqual(foo.operation_delay( _parse_operation('op: "kFoo" bit_count: 2')), 200, delta=2) self.assertAlmostEqual(foo.operation_delay( _parse_operation('op: "kFoo" bit_count: 3')), 300, delta=2) self.assertAlmostEqual(foo.operation_delay( _parse_operation('op: "kFoo" bit_count: 5')), 500, delta=2) self.assertAlmostEqual(foo.operation_delay( _parse_operation('op: "kFoo" bit_count: 42')), 4200, delta=2) self.assertEqualIgnoringWhitespaceAndFloats( foo.cpp_delay_code('node'), r""" return std::round( 0.0 + 0.0 * static_cast<float>(node->GetType()->GetFlatBitCount()) + 0.0 * std::log2(static_cast<float>(node->GetType()->GetFlatBitCount()))); """)
def test_regression_estimator_binop_delay_expression_divide(self): def gen_operation(result_bit_count, operand_bit_count): return 'op: "kFoo" bit_count: %d operands { } operands { bit_count: %d }' % ( result_bit_count, operand_bit_count) data_points_str = [ 'operation { %s } delay: 5 delay_offset: 0' % gen_operation(10, 2), 'operation { %s } delay: 4 delay_offset: 0' % gen_operation(4, 1), 'operation { %s } delay: 4 delay_offset: 0' % gen_operation(20, 5), 'operation { %s } delay: 7 delay_offset: 0' % gen_operation(49, 7), 'operation { %s } delay: 5 delay_offset: 0' % gen_operation(50, 10), 'operation { %s } delay: 2 delay_offset: 0' % gen_operation(30, 15), ] expression = delay_model_pb2.DelayExpression() expression.bin_op = delay_model_pb2.DelayExpression.BinaryOperation.DIVIDE expression.lhs_expression.factor.source = \ delay_model_pb2.DelayFactor.Source.RESULT_BIT_COUNT expression.rhs_expression.factor.source = \ delay_model_pb2.DelayFactor.Source.OPERAND_BIT_COUNT expression.rhs_expression.factor.operand_number = 1 foo = delay_model.RegressionEstimator( 'kFoo', (expression, ), tuple(_parse_data_point(s) for s in data_points_str)) self.assertAlmostEqual(foo.operation_delay( _parse_operation(gen_operation(15, 15.0))), 1, delta=1) # Note: operation_delay will round to nearest int. self.assertAlmostEqual(foo.operation_delay( _parse_operation(gen_operation(45, 20))), 2.25, delta=1) self.assertAlmostEqual(foo.operation_delay( _parse_operation(gen_operation(20, 45))), 0.4444, delta=1) self.assertAlmostEqual(foo.operation_delay( _parse_operation(gen_operation(81, 9))), 9, delta=1) self.assertAlmostEqual(foo.operation_delay( _parse_operation(gen_operation(256, 2))), 128, delta=1) expression_str = r"""(static_cast<float>(node->GetType()->GetFlatBitCount()) / static_cast<float>(node->operand(1)->GetType()->GetFlatBitCount()))""" self.assertEqualIgnoringWhitespaceAndFloats( foo.cpp_delay_code('node'), r""" return std::round( 0.0 + 0.0 * {expr} + 0.0 * std::log2({expr})); """.format(expr=expression_str))
def test_one_regression_estimator_operand_count(self): def gen_operation(operand_count): operands_str = 'operands { bit_count: 42 }' return 'op: "kFoo" bit_count: 42 %s' % ' '.join( [operands_str] * operand_count) data_points_str = [ 'operation { %s } delay: 10 delay_offset: 0' % gen_operation(1), 'operation { %s } delay: 11 delay_offset: 0' % gen_operation(2), 'operation { %s } delay: 12 delay_offset: 0' % gen_operation(4), 'operation { %s } delay: 13 delay_offset: 0' % gen_operation(8), ] operand_count = delay_model_pb2.DelayExpression() operand_count.factor.source = delay_model_pb2.DelayFactor.Source.OPERAND_COUNT foo = delay_model.RegressionEstimator( 'kFoo', (operand_count, ), tuple(_parse_data_point(s) for s in data_points_str)) self.assertAlmostEqual(foo.operation_delay( _parse_operation(gen_operation(1))), 10, delta=1) self.assertAlmostEqual(foo.operation_delay( _parse_operation(gen_operation(4))), 12, delta=1) self.assertAlmostEqual(foo.operation_delay( _parse_operation(gen_operation(256))), 18, delta=1) self.assertEqualIgnoringWhitespaceAndFloats( foo.cpp_delay_code('node'), r""" return std::round( 0.0 + 0.0 * static_cast<float>(node->operand_count()) + 0.0 * std::log2(static_cast<float>(node->operand_count()))); """)
def _get_rectangle_area(width_expr, height_expr): """Return the area of a rectangle of dimensions width_expr * height_expr.""" expr = delay_model_pb2.DelayExpression() _set_multiply_expression(expr) expr.lhs_expression.CopyFrom(width_expr) expr.rhs_expression.CopyFrom(height_expr) return expr
def _get_bounded_width_offset_domain(begin_expr, end_expr): """Gives the bounded offset of result_bit_count. Gives the bounded offset of result_bit_count into the range[begin_expr, end_expr] e.g.: for begin_expr = 2, end_expr = 4, we map: 1 --> 0 2 --> 0 3 --> 1 4 --> 2 5 --> 2 6 --> 2 etc. expr = min(end_expr, max(begin_expr, result_bit_count)) - begin_expr Args: begin_expr: begin of range. end_expr: end of range. Returns: Bounded offset of result_bit_count. """ expr = delay_model_pb2.DelayExpression() _set_sub_expression(expr) expr.rhs_expression.CopyFrom(begin_expr) min_expr = expr.lhs_expression _set_min_expression(min_expr) min_expr.lhs_expression.CopyFrom(end_expr) max_expr = min_expr.rhs_expression _set_max_expression(max_expr) max_expr.lhs_expression.CopyFrom(begin_expr) _set_result_bit_count_expression_factor(max_expr.rhs_expression) return expr
def _get_meaningful_width_bits_expr(): """Returns the maximum number of meaningful result bits.""" expr = delay_model_pb2.DelayExpression() _set_add_expression(expr) _set_operand_bit_count_expression_factor(expr.lhs_expression, 0) _set_operand_bit_count_expression_factor(expr.rhs_expression, 1) return expr
def _get_small_op_bitcount_expr(): """Returns smaller bit count of the two operands.""" expr = delay_model_pb2.DelayExpression() _set_min_expression(expr) _set_operand_bit_count_expression_factor(expr.lhs_expression, 0) _set_operand_bit_count_expression_factor(expr.rhs_expression, 1) return expr
def test_two_factor_regression_estimator(self): def gen_operation(result_bit_count, operand_bit_count): return 'op: "kFoo" bit_count: %d operands { } operands { bit_count: %d }' % ( result_bit_count, operand_bit_count) data_points_str = [ 'operation { %s } delay: 100 delay_offset: 0' % gen_operation(1, 2), 'operation { %s } delay: 125 delay_offset: 0' % gen_operation(4, 1), 'operation { %s } delay: 150 delay_offset: 0' % gen_operation(4, 6), 'operation { %s } delay: 175 delay_offset: 0' % gen_operation(7, 13), 'operation { %s } delay: 200 delay_offset: 0' % gen_operation(10, 12), 'operation { %s } delay: 400 delay_offset: 0' % gen_operation(30, 15), ] result_bit_count = delay_model_pb2.DelayExpression() result_bit_count.factor.source = delay_model_pb2.DelayFactor.Source.RESULT_BIT_COUNT operand_bit_count = delay_model_pb2.DelayExpression() operand_bit_count.factor.source = delay_model_pb2.DelayFactor.Source.OPERAND_BIT_COUNT operand_bit_count.factor.operand_number = 1 foo = delay_model.RegressionEstimator( 'kFoo', (result_bit_count, operand_bit_count), tuple(_parse_data_point(s) for s in data_points_str)) self.assertAlmostEqual(foo.operation_delay( _parse_operation(gen_operation(1, 2))), 100, delta=10) self.assertAlmostEqual(foo.operation_delay( _parse_operation(gen_operation(10, 12))), 200, delta=10) self.assertAlmostEqual(foo.operation_delay( _parse_operation(gen_operation(8, 8))), 200, delta=50) self.assertEqualIgnoringWhitespaceAndFloats( foo.cpp_delay_code('node'), r""" return std::round( 0.0 + 0.0 * static_cast<float>(node->GetType()->GetFlatBitCount()) + 0.0 * std::log2(static_cast<float>(node->GetType()->GetFlatBitCount())) + 0.0 * static_cast<float>(node->operand(1)->GetType()->GetFlatBitCount()) + 0.0 * std::log2(static_cast<float>(node->operand(1)->GetType()->GetFlatBitCount()))); """)
def test_regression_estimator_binop_delay_expression_multiply(self): def gen_operation(result_bit_count, operand_bit_count): return 'op: "kFoo" bit_count: %d operands { } operands { bit_count: %d }' % ( result_bit_count, operand_bit_count) data_points_str = [ 'operation { %s } delay: 2 delay_offset: 0' % gen_operation(1, 2), 'operation { %s } delay: 4 delay_offset: 0' % gen_operation(4, 1), 'operation { %s } delay: 24 delay_offset: 0' % gen_operation(4, 6), 'operation { %s } delay: 91 delay_offset: 0' % gen_operation(7, 13), 'operation { %s } delay: 120 delay_offset: 0' % gen_operation(10, 12), 'operation { %s } delay: 450 delay_offset: 0' % gen_operation(30, 15), ] expression = delay_model_pb2.DelayExpression() expression.bin_op = delay_model_pb2.DelayExpression.BinaryOperation.MULTIPLY expression.lhs_expression.factor.source = \ delay_model_pb2.DelayFactor.Source.RESULT_BIT_COUNT expression.rhs_expression.factor.source = \ delay_model_pb2.DelayFactor.Source.OPERAND_BIT_COUNT expression.rhs_expression.factor.operand_number = 1 foo = delay_model.RegressionEstimator( 'kFoo', (expression, ), tuple(_parse_data_point(s) for s in data_points_str)) self.assertAlmostEqual(foo.operation_delay( _parse_operation(gen_operation(15, 15))), 225, delta=1) self.assertAlmostEqual(foo.operation_delay( _parse_operation(gen_operation(45, 20))), 900, delta=1) self.assertAlmostEqual(foo.operation_delay( _parse_operation(gen_operation(20, 45))), 900, delta=1) self.assertAlmostEqual(foo.operation_delay( _parse_operation(gen_operation(10, 25))), 250, delta=1) self.assertAlmostEqual(foo.operation_delay( _parse_operation(gen_operation(2, 8))), 16, delta=1) expression_str = r"""(static_cast<float>(node->GetType()->GetFlatBitCount()) * static_cast<float>(node->operand(1)->GetType()->GetFlatBitCount()))""" self.assertEqualIgnoringWhitespaceAndFloats( foo.cpp_delay_code('node'), r""" return std::round( 0.0 + 0.0 * {expr} + 0.0 * std::log2({expr})); """.format(expr=expression_str))
def test_regression_estimator_binop_delay_expression_power(self): def gen_operation(result_bit_count, operand_bit_count): return 'op: "kFoo" bit_count: %d operands { } operands { bit_count: %d }' % ( result_bit_count, operand_bit_count) data_points_str = [ 'operation { %s } delay: 2 delay_offset: 0' % gen_operation(1, 2), 'operation { %s } delay: 4 delay_offset: 0' % gen_operation(2, 1), 'operation { %s } delay: 8 delay_offset: 0' % gen_operation(3, 6), 'operation { %s } delay: 16 delay_offset: 0' % gen_operation(4, 13), 'operation { %s } delay: 32 delay_offset: 0' % gen_operation(5, 12), 'operation { %s } delay: 64 delay_offset: 0' % gen_operation(6, 15), ] expression = delay_model_pb2.DelayExpression() expression.bin_op = delay_model_pb2.DelayExpression.BinaryOperation.POWER expression.lhs_expression.constant = 2 expression.rhs_expression.factor.source = \ delay_model_pb2.DelayFactor.Source.RESULT_BIT_COUNT foo = delay_model.RegressionEstimator( 'kFoo', (expression, ), tuple(_parse_data_point(s) for s in data_points_str)) self.assertAlmostEqual(foo.operation_delay( _parse_operation(gen_operation(7, 15))), 128, delta=1) self.assertAlmostEqual(foo.operation_delay( _parse_operation(gen_operation(8, 20))), 256, delta=1) self.assertAlmostEqual(foo.operation_delay( _parse_operation(gen_operation(9, 45))), 512, delta=1) self.assertAlmostEqual(foo.operation_delay( _parse_operation(gen_operation(10, 25))), 1024, delta=1) expression_str = r"""pow(static_cast<float>(2), static_cast<float>(node->GetType()->GetFlatBitCount()))""" self.assertEqualIgnoringWhitespaceAndFloats( foo.cpp_delay_code('node'), r""" return std::round( 0.0 + 0.0 * {expr} + 0.0 * std::log2({expr})); """.format(expr=expression_str))
def test_regression_estimator_constant_delay_expression(self): def gen_operation(result_bit_count, operand_bit_count): return 'op: "kFoo" bit_count: %d operands { } operands { bit_count: %d }' % ( result_bit_count, operand_bit_count) data_points_str = [ 'operation { %s } delay: 99 delay_offset: 0' % gen_operation(1, 2), 'operation { %s } delay: 99 delay_offset: 0' % gen_operation(4, 1), 'operation { %s } delay: 99 delay_offset: 0' % gen_operation(4, 6), 'operation { %s } delay: 99 delay_offset: 0' % gen_operation(7, 13), 'operation { %s } delay: 99 delay_offset: 0' % gen_operation(10, 12), 'operation { %s } delay: 99 delay_offset: 0' % gen_operation(30, 15), ] expression = delay_model_pb2.DelayExpression() expression.constant = 99 # Not especially usuful tests since regression includes a # constant variable that could mask issues... foo = delay_model.RegressionEstimator( 'kFoo', (expression, ), tuple(_parse_data_point(s) for s in data_points_str)) self.assertAlmostEqual(foo.operation_delay( _parse_operation(gen_operation(15, 15))), 99, delta=1) self.assertAlmostEqual(foo.operation_delay( _parse_operation(gen_operation(45, 20))), 99, delta=1) self.assertAlmostEqual(foo.operation_delay( _parse_operation(gen_operation(20, 45))), 99, delta=1) # This test is useful though! expression_str = r"""static_cast<float>(99)""" self.assertEqualIgnoringWhitespaceAndFloats( foo.cpp_delay_code('node'), r""" return std::round( 0.0 + 0.0 * {expr} + 0.0 * std::log2({expr})); """.format(expr=expression_str))
def _get_triangle_area(width_expr): """Return the area of a isosceles right triangle. Width_expr expression: _get_triangle_area(width_expr, width_expr) / 2 Args: width_expr: Width expression. Returns: The area of a isosceles right triangle. """ expr = delay_model_pb2.DelayExpression() _set_divide_expression(expr) sqr_expression = _get_rectangle_area(width_expr, width_expr) expr.lhs_expression.CopyFrom(sqr_expression) _set_constant_expression(expr.rhs_expression, 2) return expr
def _get_partial_triangle_area(width_expr, max_width_expr): """Return the area of a partial isosceles right triangle. | /| -| | / | | | / | | | / | | |/ | | | | | heigh = maximum_width /| | | / |area | | / | | | / | | | /____|_____| -| | |_____| width |___________| maximum_width expr = rectangle_area(width, maximum_width) - triangle_area(width) Args: width_expr: Width expression. max_width_expr: Max width expression. Returns: Area of partial isosceles right triangle. """ expr = delay_model_pb2.DelayExpression() _set_sub_expression(expr) rectangle_expr = _get_rectangle_area(width_expr, max_width_expr) expr.lhs_expression.CopyFrom(rectangle_expr) triangle_expr = _get_triangle_area(width_expr) expr.rhs_expression.CopyFrom(triangle_expr) return expr
def _get_zero_expr(): """Returns a constant 0 expression.""" expr = delay_model_pb2.DelayExpression() _set_constant_expression(expr, 0) return expr