Пример #1
0
class P4Distinct(P4Operator):
    def __init__(self, qid, operator_id, meta_init_name, drop_action,
                 nop_action, keys, p4_raw_fields):
        super(P4Distinct, self).__init__('Distinct', qid, operator_id, keys,
                                         p4_raw_fields)

        self.threshold = 0
        self.comp_func = '<='  # bitwise and
        self.update_func = '&'  # bitwise and

        # create METADATA to store index and value
        fields = [('value', REGISTER_WIDTH),
                  ('index', REGISTER_NUM_INDEX_BITS)]
        self.metadata = MetaData(self.operator_name, fields)

        # create REGISTER to keep track of counts
        self.register = Register(self.operator_name, REGISTER_WIDTH,
                                 REGISTER_INSTANCE_COUNT)

        # Add map init
        hash_init_fields = list()
        for fld in self.keys:
            if fld == 'qid':
                hash_init_fields.append(
                    P4Field(layer=None,
                            target_name="qid",
                            sonata_name="qid",
                            size=QID_SIZE))
            elif fld == 'count':
                hash_init_fields.append(
                    P4Field(layer=None,
                            target_name="count",
                            sonata_name="count",
                            size=COUNT_SIZE))
            else:
                hash_init_fields.append(
                    self.p4_raw_fields.get_target_field(fld))
        # create HASH for access to register
        hash_fields = list()
        for field in hash_init_fields:
            if '/' in field.sonata_name:
                self.logger.error('found a / in the key')
                raise NotImplementedError
            else:
                hash_fields.append(
                    '%s.%s' %
                    (meta_init_name, field.target_name.replace(".", "_")))
        self.hash = HashFields(self.operator_name, hash_fields, 'crc16',
                               REGISTER_NUM_INDEX_BITS)

        # name of metadata field where the index of the count within the register is stored
        self.index_field_name = '%s.index' % self.metadata.get_name()
        # name of metadata field where the count is kept temporarily
        self.value_field_name = '%s.value' % self.metadata.get_name()

        # create ACTION and TABLE to compute hash and get value
        primitives1 = list()
        primitives1.append(
            ModifyFieldWithHashBasedOffset(self.index_field_name, 0,
                                           self.hash.get_name(),
                                           REGISTER_INSTANCE_COUNT))
        primitives1.append(
            RegisterRead(self.value_field_name, self.register.get_name(),
                         self.index_field_name))

        self.action1 = Action('do_init_%s' % self.operator_name, primitives1)

        # create ACTION and TABLE to bit_or value & write back
        primitives2 = list()
        primitives2.append(
            BitOr(self.value_field_name, self.value_field_name, 1))
        primitives2.append(
            RegisterWrite(self.register.get_name(), self.index_field_name,
                          self.value_field_name))
        self.action2 = Action('do_update_%s' % self.operator_name, primitives2)

        table_name = 'init_%s' % self.operator_name
        self.init_table = Table(table_name, self.action1.get_name(), [], None,
                                1)

        table_name = 'update_%s' % self.operator_name
        self.update_table = Table(table_name, self.action2.get_name(), [],
                                  None, 1)

        # create two TABLEs that implement reduce operation: if count <= THRESHOLD, update count and drop, else let it
        # pass through
        table_name = 'pass_%s' % self.operator_name
        self.pass_table = Table(table_name, nop_action, [], None, 1)
        table_name = 'drop_%s' % self.operator_name
        self.drop_table = Table(table_name, drop_action, [], None, 1)

    def __repr__(self):
        return '.Distinct(keys=' + ', '.join([x for x in self.keys]) + ')'

    def get_code(self):
        out = ''
        out += '// %s %i of query %i\n' % (self.name, self.operator_id,
                                           self.query_id)
        out += self.metadata.get_code()
        out += self.hash.get_code()
        out += self.register.get_code()
        out += self.action1.get_code()
        out += self.action2.get_code()
        out += self.update_table.get_code()
        out += self.init_table.get_code()
        out += self.pass_table.get_code()
        out += self.drop_table.get_code()
        out += '\n'
        return out

    def get_commands(self):
        commands = list()
        commands.append(self.init_table.get_default_command())
        commands.append(self.update_table.get_default_command())
        commands.append(self.pass_table.get_default_command())
        commands.append(self.drop_table.get_default_command())
        return commands

    def get_control_flow(self, indent_level):
        indent = '\t' * indent_level
        out = ''
        out += '%sapply(%s);\n' % (indent, self.init_table.get_name())
        out += '%sif (%s %s %i) {\n' % (indent, self.value_field_name,
                                        self.comp_func, self.threshold)
        out += '%s\tapply(%s);\n' % (indent, self.pass_table.get_name())
        out += '%s\tapply(%s);\n' % (indent, self.update_table.get_name())
        out += '%s}\n' % (indent, )
        out += '%selse {\n' % (indent, )
        out += '%s\tapply(%s);\n' % (indent, self.drop_table.get_name())
        out += '%s}\n' % (indent, )
        return out

    def get_init_keys(self):
        return self.keys
Пример #2
0
class P4Reduce(P4Operator):
    def __init__(self, qid, operator_id, meta_init_name, drop_action, keys,
                 values, threshold, read_register, p4_raw_fields):
        super(P4Reduce, self).__init__('Reduce', qid, operator_id, keys,
                                       p4_raw_fields)

        if threshold == '-1':
            self.threshold = int(THRESHOLD)
        else:
            self.threshold = int(threshold)

        self.read_register = read_register

        if self.read_register:
            self.out_headers += ['index']
        else:
            self.out_headers += ['count']

        # create METADATA to store index and value
        fields = [('value', REGISTER_WIDTH),
                  ('index', REGISTER_NUM_INDEX_BITS)]
        self.metadata = MetaData(self.operator_name, fields)

        # create REGISTER to keep track of counts
        self.register = Register(self.operator_name, REGISTER_WIDTH,
                                 REGISTER_INSTANCE_COUNT)

        self.values = values

        # Add map init
        hash_init_fields = list()
        for fld in self.keys:
            if fld == 'qid':
                hash_init_fields.append(
                    P4Field(layer=None,
                            target_name="qid",
                            sonata_name="qid",
                            size=QID_SIZE))
            elif fld == 'count':
                hash_init_fields.append(
                    P4Field(layer=None,
                            target_name="count",
                            sonata_name="count",
                            size=COUNT_SIZE))
            elif fld == 'index':
                hash_init_fields.append(
                    P4Field(layer=None,
                            target_name="index",
                            sonata_name="index",
                            size=INDEX_SIZE))
            else:
                hash_init_fields.append(
                    self.p4_raw_fields.get_target_field(fld))
        # create HASH for access to register
        hash_fields = list()
        for field in hash_init_fields:
            if '/' in field.sonata_name:
                self.logger.error('found a / in the key')
                raise NotImplementedError
            else:
                hash_fields.append(
                    '%s.%s' %
                    (meta_init_name, field.target_name.replace(".", "_")))
        self.hash = HashFields(self.operator_name, hash_fields, 'crc16',
                               REGISTER_NUM_INDEX_BITS)

        # name of metadata field where the index of the count within the register is stored
        self.index_field_name = '%s.index' % self.metadata.get_name()
        # name of metadata field where the count is kept temporarily
        self.value_field_name = '%s.value' % self.metadata.get_name()

        # create ACTION and TABLE to compute hash and get value
        primitives = list()
        primitives.append(
            ModifyFieldWithHashBasedOffset(self.index_field_name, 0,
                                           self.hash.get_name(),
                                           REGISTER_INSTANCE_COUNT))
        primitives.append(
            RegisterRead(self.value_field_name, self.register.get_name(),
                         self.index_field_name))

        if self.values[0] == 'count':
            if self.threshold <= 1:
                self.threshold = '1'

            primitives.append(
                ModifyField(self.value_field_name,
                            '%s + %i' % (self.value_field_name, 1)))
        else:
            target_fld = self.p4_raw_fields.get_target_field(self.values[0])
            if self.threshold <= 1:
                self.threshold = '%s.%s' % (
                    meta_init_name, target_fld.target_name.replace(".", "_"))

            primitives.append(
                ModifyField(
                    self.value_field_name,
                    '%s + %s' % (self.value_field_name, '%s.%s' %
                                 (meta_init_name,
                                  target_fld.target_name.replace(".", "_")))))

        primitives.append(
            RegisterWrite(self.register.get_name(), self.index_field_name,
                          self.value_field_name))
        self.init_action = Action('do_init_%s' % self.operator_name,
                                  primitives)
        table_name = 'init_%s' % self.operator_name
        self.init_table = Table(table_name, self.init_action.get_name(), [],
                                None, 1)

        # create three TABLEs that implement reduce operation
        # if count <= THRESHOLD, update count and drop,
        table_name = 'drop_%s' % self.operator_name
        self.drop_table = Table(table_name, drop_action, [], None, 1)

        # if count == THRESHOLD, pass through with current count
        field_to_modified = None
        if not self.read_register:
            field_to_modified = ModifyField('%s.count' % meta_init_name,
                                            self.value_field_name)
        else:
            field_to_modified = ModifyField('%s.index' % meta_init_name,
                                            self.index_field_name)

        self.set_count_action = Action('set_count_%s' % self.operator_name,
                                       field_to_modified)
        table_name = 'first_pass_%s' % self.operator_name
        self.first_pass_table = Table(table_name,
                                      self.set_count_action.get_name(), [],
                                      None, 1)

        if not self.read_register:
            # if count > THRESHOLD, let it pass through with count set to 1
            self.reset_count_action = Action(
                'reset_count_%s' % self.operator_name,
                ModifyField('%s.count' % meta_init_name, 1))
            table_name = 'pass_%s' % self.operator_name
            self.pass_table = Table(table_name,
                                    self.reset_count_action.get_name(), [],
                                    None, 1)

    def __repr__(self):
        return '.Reduce(keys=' + ','.join(
            [x
             for x in self.keys]) + ', threshold=' + str(self.threshold) + ')'

    def get_code(self):
        out = ''
        out += '// %s %i of query %i\n' % (self.name, self.operator_id,
                                           self.query_id)
        out += self.metadata.get_code()
        out += self.hash.get_code()
        out += self.register.get_code()
        out += self.init_action.get_code()
        out += self.set_count_action.get_code()
        if not self.read_register:
            out += self.reset_count_action.get_code()
            out += self.pass_table.get_code()

        out += self.init_table.get_code()
        out += self.first_pass_table.get_code()
        out += self.drop_table.get_code()
        out += '\n'
        return out

    def get_commands(self):
        commands = list()
        commands.append(self.init_table.get_default_command())
        commands.append(self.first_pass_table.get_default_command())
        if not self.read_register:
            commands.append(self.pass_table.get_default_command())
        commands.append(self.drop_table.get_default_command())
        return commands

    def get_control_flow(self, indent_level):
        indent = '\t' * indent_level
        out = ''
        out += '%sapply(%s);\n' % (indent, self.init_table.get_name())
        out += '%sif (%s == %s) {\n' % (indent, self.value_field_name,
                                        self.threshold)
        out += '%s\tapply(%s);\n' % (indent, self.first_pass_table.get_name())
        out += '%s}\n' % (indent, )

        if not self.read_register:
            out += '%selse if (%s > %s) {\n' % (indent, self.value_field_name,
                                                self.threshold)
            out += '%s\tapply(%s);\n' % (indent, self.pass_table.get_name())
            out += '%s}\n' % (indent, )

        out += '%selse {\n' % (indent, )
        out += '%s\tapply(%s);\n' % (indent, self.drop_table.get_name())
        out += '%s}\n' % (indent, )
        return out

    def get_init_keys(self):

        return self.keys + self.values