Example #1
0
    def emit(self):
        # Do not touch pointer registers
        reserved_registers = ["X0", "X1", "X2", "X3", "X4", "X8"]

        instructions_not_found = [
            i for i in self.args.instructions if i not in
            [ix.name for ix in self.target.isa.instructions.values()]
        ]
        if instructions_not_found:
            raise MicroprobeException(
                str.format('Instructions {} not available',
                           instructions_not_found))

        if not os.path.exists(self.args.output_dir):
            os.makedirs(self.args.output_dir)

        valid_instrs = [
            i for i in self.target.isa.instructions.values()
            if i.name in self.args.instructions
        ]

        microbenchmarks = []
        for instr in valid_instrs:
            for d in self.args.dependency_distances:
                cwrapper = get_wrapper('RiscvTestsP')
                synth = Synthesizer(
                    self.target,
                    # Remove the endless parameter to not generate
                    # an endless loop
                    cwrapper(endless=True),
                    value=0b01010101,
                )
                passes = [
                    structure.SimpleBuildingBlockPass(self.args.loop_size),
                    instruction.SetRandomInstructionTypePass([instr]),
                    initialization.ReserveRegistersPass(reserved_registers),
                    branch.BranchNextPass(),
                    memory.GenericMemoryStreamsPass([[0, 1024, 1, 32, 1]]),
                    register.DefaultRegisterAllocationPass(dd=d)
                ]

                for p in passes:
                    synth.add_pass(p)

                microbenchmark = instr.name + '_' + str(d)
                print("Generating %s ..." % microbenchmark)
                bench = synth.synthesize()
                synth.save(str.format('{}/{}', self.args.output_dir,
                                      microbenchmark),
                           bench=bench)
                microbenchmarks += [microbenchmark]

        # Emit a Makefile fragment (tests.d) that identifies all tests
        # created
        f = open(str.format('{}/tests.d', self.args.output_dir), 'w')
        f.write(
            str.format('# Autogenerated by {}\n', sys.argv[0]) +
            'tests = \\\n\t' + '\\\n\t'.join([m for m in microbenchmarks]))
        f.close()
Example #2
0
    def emit(self):

        # Reserve a couple of register to control
        # the branch behavior
        #
        # X0 reserved to avoid using constant 0
        # X5 will be used to store the local branch pattern
        # X6 will be used to store the loop count
        # X7 will be used to store current branch
        # X8 will be used to store constant 1 (we already have
        #    X0 with constant 0)
        reserved_registers = ["X0", "X5", "X6", "X7", "X8"]

        if not os.path.exists(self.args.output_dir):
            os.makedirs(self.args.output_dir)

        # Pick some instructions to add between branches
        valid_instrs = [
            i for i in self.target.isa.instructions.values()
            if i.name in ['ADD_V0', 'MUL_V0', 'LW_V0']
        ]

        valid_instrs_names = [
            i.name for i in self.target.isa.instructions.values()
            if i.name in ['ADD_V0', 'MUL_V0', 'LW_V0']
        ]

        # Add conditional branches
        branch_instrs_names = [
            i.name for i in self.target.isa.instructions.values()
            if i.branch_conditional
        ]

        branch_instrs = [
            i for i in self.target.isa.instructions.values()
            if i.branch_conditional
        ]

        microbenchmarks = []
        cwrapper = get_wrapper('RiscvTestsP')
        synth = Synthesizer(
            self.target,
            cwrapper(endless=True),
            value=0b01010101,
        )

        # Add a building block
        p = structure.SimpleBuildingBlockPass(self.args.loop_size)
        synth.add_pass(p)

        # Reserve registers
        p = initialization.ReserveRegistersPass(reserved_registers)
        synth.add_pass(p)

        # Set instruction type
        random = self.args.random_ins
        if not random:
            sequence = []
            for elem in branch_instrs:
                sequence.extend(valid_instrs)
                sequence.append(elem)
            p = instruction.SetInstructionTypeBySequencePass(sequence)
        else:
            p = instruction.SetRandomInstructionTypePass([
                self.target.isa.instructions[elem]
                for elem in valid_instrs_names + branch_instrs_names
            ])

        synth.add_pass(p)

        p = initialization.InitializeRegistersPass(value=RNDINT,
                                                   fp_value=RNDINT)
        synth.add_pass(p)

        # Initialize X5 to local branch pattern
        p = initialization.InitializeRegisterPass(
            "X5", int(self.args.local_branch_pattern, 2))
        synth.add_pass(p)

        # Initialize X6 to 0 (loop count)
        p = initialization.InitializeRegisterPass("X6", 0)
        synth.add_pass(p)

        # Initialize X7 to current branch
        p = initialization.AddInitializationAssemblyPass("andi x7, x5, 1")
        synth.add_pass(p)

        # Initialize X8 to 1
        p = initialization.InitializeRegisterPass("X8", 1)
        synth.add_pass(p)

        #
        # Set operands of the conditional branch instructions
        #

        # Operand 1 of all branches will be X7, which contains the
        # current branch value (which changes every iteration)
        p = instruction.SetInstructionOperandsByOpcodePass(
            branch_instrs_names,
            1,
            self.target.isa.registers["X7"],
        )
        synth.add_pass(p)

        # Operand 2 of all branches will be X0 (0) / X8 (1)
        # based on the global pattern provided
        global_pattern_regs = []
        for char in self.args.global_branch_pattern:
            if char == "0":
                global_pattern_regs.append(self.target.isa.registers["X0"])
            else:
                global_pattern_regs.append(self.target.isa.registers["X8"])

        p = instruction.SetInstructionOperandsByOpcodePass(
            branch_instrs_names, 2, global_pattern_regs)
        synth.add_pass(p)

        # Randomize branches for BGT 0 every N branches
        p = branch.RandomizeByTypePass(
            branch_instrs,  # instructions to replace
            self.target.isa.instructions['BGE_V0'],  # new instruction
            self.args.random_branch,  # every N instructions or if a value
            # between [0,1] the probability of a
            # branch to be random
            "slli @@BRREG@@, @@REG@@, @@COUNT@@",  # randomization code
            # to add before branch
            distance=30,  # distance between randomization code and branch
            musage=62,  # max. time @@REG@@ can be used before reset. Do not
            # set above 63
            reset=('rnd', (-0x7ff, 0x7ff))  # method to randomize register
        )
        synth.add_pass(p)

        # At the end of each iteration, update the loop count
        if not self.args.switch_pattern:
            p = initialization.AddFinalizationAssemblyPass(
                "addi x6, x6, 1 \n" +  # Add +1
                # Compare and reset based on pattern length
                "slti x7, x6, %d\n" %
                min(64, len(self.args.local_branch_pattern)) +
                "bne x7, x0, 8 \n" +  #
                "addi x6, x0, 0 \n" +  # Reset to zero
                "addi x0, x0, 0"  # nop
            )
            synth.add_pass(p)
        else:
            p = initialization.AddFinalizationAssemblyPass(
                "addi x6, x6, 1 \n" +  # Add +1
                # Compare and reset based on pattern length
                "slti x7, x6, %d\n" %
                min(64, len(self.args.local_branch_pattern)) +
                "bne x7, x0, 12 \n" +  #
                "addi x6, x0, 0 \n" +  # Reset to zero
                "xori x5, x5, -1 \n" +  # switch branch pattern
                "addi x0, x0, 0"  # nop
            )
            synth.add_pass(p)

        # At the end of each iteration, update the current
        # branch register based on loop count
        p = initialization.AddFinalizationAssemblyPass("srl x7, x5, x6 \n" +
                                                       "andi x7, x7, 1")
        synth.add_pass(p)

        # Model memory operations to ensure correctness
        p = memory.GenericMemoryStreamsPass([[0, 1024, 1, 32, 1, 0, (1, 0)]])
        synth.add_pass(p)

        # Model dependency distance (no dependencies)
        p = register.DefaultRegisterAllocationPass(dd=0)
        synth.add_pass(p)

        # Set target of branches (regarless of taken not taken,
        # branch to next instruction)
        p = address.UpdateInstructionAddressesPass()
        synth.add_pass(p)

        braid = self.args.braid
        if braid:
            p = branch.BranchBraidNextPass(force=True)
            synth.add_pass(p)
        else:
            p = branch.BranchNextPass(force=True)
            synth.add_pass(p)

        microbenchmark = "branch_%s_%s_%d" % (self.args.global_branch_pattern,
                                              self.args.local_branch_pattern,
                                              self.args.switch_pattern)

        print("Generating %s ..." % microbenchmark)
        bench = synth.synthesize()
        synth.save(str.format('{}/{}', self.args.output_dir, microbenchmark),
                   bench=bench)
        print(cwrapper().outputname(
            str.format('{}/{}', self.args.output_dir, microbenchmark)) +
              " saved!")
        microbenchmarks += [microbenchmark]

        # Emit a Makefile fragment (tests.d) that identifies all tests
        # created
        f = open(str.format('{}/tests.d', self.args.output_dir), 'w')
        f.write(
            str.format('# Autogenerated by {}\n', sys.argv[0]) +
            'tests = \\\n\t' + '\\\n\t'.join([m for m in microbenchmarks]))
        f.close()
Example #3
0
    def emit(self):
        # Do not touch pointer registers
        reserved_registers = ["X0", "X1", "X2", "X3", "X4", "X8"]

        instructions_not_found = [
            i for i in self.args.instructions if i not in
            [ix.name for ix in self.target.isa.instructions.values()]
        ]
        if instructions_not_found:
            raise MicroprobeException(
                str.format('Instructions {} not available',
                           instructions_not_found))

        if not os.path.exists(self.args.output_dir):
            os.makedirs(self.args.output_dir)

        valid_instrs = [
            i for i in self.target.isa.instructions.values()
            if i.name in self.args.instructions
        ]

        # Generate permutations of instruction sequences and randomize order
        random.seed(rs)
        instr_seq_count = len(valid_instrs)
        print("Instruction sequence count: " + str(instr_seq_count))

        # Select instruction sequence permutations
        if (self.args.num_permutations > math.factorial(
                min(instr_seq_count, MAX_INSTR_PERM_LENGTH))):
            print("ERROR: Selected sequences cannot exceed num. permutations")
            sys.exit()

        # Check if number of instructions exceeds maximum permutation length
        # -- Fix to prevent permutation function from hanging
        if (instr_seq_count > MAX_INSTR_PERM_LENGTH):
            print("WARNING: Instruction sequence is too long...\
                   Selecting from reduced number of permutations!!")
            reduced_instrs = valid_instrs[0:MAX_INSTR_PERM_LENGTH]
            reduced_instr_seq = list(
                it.permutations(reduced_instrs, len(reduced_instrs)))
            random.shuffle(reduced_instr_seq)
            selected_valid_instr_seq = reduced_instr_seq[:][0:self.args.
                                                            num_permutations]

            # Append remaining instructions to each of the sequences in list
            rem_instr_seq = valid_instrs[MAX_INSTR_PERM_LENGTH:instr_seq_count]
            for s in range(0, len(selected_valid_instr_seq)):
                selected_valid_instr_seq[s] = list(
                    selected_valid_instr_seq[s]) + rem_instr_seq
        else:
            # Generate complete list of permutations
            valid_instr_seq = list(it.permutations(valid_instrs))
            random.shuffle(valid_instr_seq)
            selected_valid_instr_seq = valid_instr_seq[:][0:self.args.
                                                          num_permutations]

        microbenchmarks = []

        # Loop over selected sequence permutations
        for vi in range(0, len(selected_valid_instr_seq)):
            vi_seq = selected_valid_instr_seq[:][vi]
            for d in self.args.dependency_distances:
                microbenchmark = ''
                cwrapper = get_wrapper('RiscvTestsP')
                synth = Synthesizer(
                    self.target,
                    # Remove the endless parameter to not generate
                    # an endless loop
                    cwrapper(endless=True),
                    value=0b01010101,
                )
                passes = [
                    structure.SimpleBuildingBlockPass(self.args.loop_size),
                    instruction.SetInstructionTypeBySequencePass(vi_seq),
                    initialization.ReserveRegistersPass(reserved_registers),
                    branch.BranchNextPass(),
                    memory.GenericMemoryStreamsPass([[0, 1024, 1, 32, 1]]),
                    register.DefaultRegisterAllocationPass(dd=d)
                ]

                for p in passes:
                    synth.add_pass(p)

                if (not self.args.microbenchmark_name):
                    for instr in vi_seq:
                        microbenchmark = microbenchmark
                        +instr.name + '_DD' + str(d)
                else:
                    microbenchmark = self.args.microbenchmark_name \
                        + '_DD' + str(d) + '_' + str(vi)

                print("Generating %s ..." % microbenchmark)
                bench = synth.synthesize()

                synth.save(str.format('{}/{}', self.args.output_dir,
                                      microbenchmark),
                           bench=bench)
                microbenchmarks += [microbenchmark]

        # Print out microbenchmark names
        print("Generating microbenchmarks named:")
        print(microbenchmarks)

        # Emit a Makefile fragment (tests.d) that identifies all tests
        # created
        f = open(
            str.format('{}/' + self.args.microbenchmark_name + '_tests.d',
                       self.args.output_dir), 'w')
        f.write(
            str.format('# Autogenerated by {}\n', sys.argv[0]) +
            'tests = \\\n\t' + '\\\n\t'.join([m for m in microbenchmarks]))
        f.close()
Example #4
0
    def emit(self):

        # Reserve a couple of register to control
        # the branch behavior
        #
        # X5 will be used to store the local branch pattern
        # X6 will be used to store the loop count
        # X7 will be used to store current branch
        # X8 will be used to store constant 1 (we already have
        #    X0 with constant 0)
        reserved_registers = ["X5", "X6", "X7"]

        if not os.path.exists(self.args.output_dir):
            os.makedirs(self.args.output_dir)

        # Pick some instructions to add between branches
        valid_instrs = [
            i.name for i in self.target.isa.instructions.values()
            if i.name in ['ADD_V0', 'MUL_V0']
        ]

        # Add conditional branches
        branch_instrs = [
            i.name for i in self.target.isa.instructions.values()
            if i.branch_conditional
        ]

        microbenchmarks = []
        cwrapper = get_wrapper('RiscvTestsP')
        synth = Synthesizer(
            self.target,
            cwrapper(endless=True),
            value=0b01010101,
        )

        # Add a building block
        p = structure.SimpleBuildingBlockPass(self.args.loop_size)
        synth.add_pass(p)

        # Reserve registers
        p = initialization.ReserveRegistersPass(reserved_registers)
        synth.add_pass(p)

        # Set instruction type
        p = instruction.SetRandomInstructionTypePass(valid_instrs +
                                                     branch_instrs)
        synth.add_pass(p)

        # Initialize X5 to local branch pattern
        p = initialization.InitializeRegisterPass(
            "X5", int(self.args.local_branch_pattern, 2))
        synth.add_pass(p)

        # Initialize X6 to 0 (loop count)
        p = initialization.InitializeRegisterPass("X6", 0)
        synth.add_pass(p)

        # Initialize X7 to current branch
        p = initialization.AddInitializationAssemblyPass("andi x7, x5, 1")
        synth.add_pass(p)

        # Initialize X8 to 1
        p = initialization.InitializeRegisterPass("X8", 1)
        synth.add_pass(p)

        #
        # Set operands of the conditional branch instructions
        #

        # Operand 1 of all branches will be X7, which contains the
        # current branch value (which changes every iteration)
        p = instruction.SetInstructionOperandsByOpcodePass(
            branch_instrs,
            1,
            self.target.isa.registers["X7"],
        )
        synth.add_pass(p)

        # Operand 2 of all branches will be X0 (0) / X8 (1)
        # based on the global pattern provided

        global_pattern_regs = []
        for char in self.args.global_branch_pattern:
            if char == "0":
                global_pattern_regs.append(self.target.isa.registers["X0"])
            else:
                global_pattern_regs.append(self.target.isa.registers["X8"])

        p = instruction.SetInstructionOperandsByOpcodePass(
            branch_instrs, 2, global_pattern_regs)
        synth.add_pass(p)

        # Set target of branches (regarless of taken not taken,
        # branch to next instruction)
        p = branch.BranchNextPass()
        synth.add_pass(p)

        # At the end of each iteration, update the loop count
        if not self.args.switch_pattern:
            p = initialization.AddFinalizationAssemblyPass(
                "addi x6, x6, 1 \n" +  # Add +1
                # Compare and reset based on pattern length
                "slti x7, x6, %d\n" %
                min(64, len(self.args.local_branch_pattern)) +
                "bne x7, x0, 8 \n" +  #
                "addi x6, x0, 0 \n" +  # Reset to zero
                "addi x0, x0, 0"  # nop
            )
            synth.add_pass(p)
        else:
            p = initialization.AddFinalizationAssemblyPass(
                "addi x6, x6, 1 \n" +  # Add +1
                # Compare and reset based on pattern length
                "slti x7, x6, %d\n" %
                min(64, len(self.args.local_branch_pattern)) +
                "bne x7, x0, 12 \n" +  #
                "addi x6, x0, 0 \n" +  # Reset to zero
                "xori x5, x5, -1 \n" +  # switch branch pattern
                "addi x0, x0, 0"  # nop
            )
            synth.add_pass(p)

        # At the end of each iteration, update the current
        # branch register based on loop count
        p = initialization.AddFinalizationAssemblyPass("srl x7, x5, x6")
        synth.add_pass(p)

        # Model memory operations to ensure correctness
        p = memory.GenericMemoryStreamsPass([[0, 1024, 1, 32, 1]])
        synth.add_pass(p)
        # Model dependency distance (no dependencies)
        p = register.DefaultRegisterAllocationPass(dd=0)
        synth.add_pass(p)

        microbenchmark = "branch_%s_%s_%d" % (self.args.global_branch_pattern,
                                              self.args.local_branch_pattern,
                                              self.args.switch_pattern)

        print("Generating %s ..." % microbenchmark)
        bench = synth.synthesize()
        synth.save(str.format('{}/{}', self.args.output_dir, microbenchmark),
                   bench=bench)
        microbenchmarks += [microbenchmark]

        # Emit a Makefile fragment (tests.d) that identifies all tests
        # created
        f = open(str.format('{}/tests.d', self.args.output_dir), 'w')
        f.write(
            str.format('# Autogenerated by {}\n', sys.argv[0]) +
            'tests = \\\n\t' + '\\\n\t'.join([m for m in microbenchmarks]))
        f.close()