-2

I am trying to optimize my code for my homework. I need to reduce total energy output by minimum 5 percent. I have included my code below. So far, I have only been able to reduce the energy output by 2 percent. This was achieved by adjusting my sub $t0,$t0, 32 and introducing another register($t8) initialized to -32 and replacing the above code with add $t0,$t0,$t8.This line of code is under the label LowerCasePoint.

The purpose of the code is to enter a sentence and have the character count for specific letters and then display that count numerically and with pound signs.

I have been staring at my code for hours trying to figure out what i can do and nothing is jumping out at me. Any help would be appreciated.

Thank you

#NAme
#Comp Org
#Homework 2A

.data
string: .asciiz "\nEnter A String:"     #prompts the user to input a string
input: .space 1000
.text


li $v0,4            #printing the string
la $a0,string           #prompt for the string
syscall             #executing

li $v0,8 
la $a0,input            #prompting for the users input
li $a1,1000                 #loading 1000 into the register
syscall
move $s0,$a0                #moving the data into the new register

li $t0,0 #this register will be used for the count of c
li $t1,0 #this register will be used for the count of h
li $t2,0 #this register will be used for the count of a
li $t3,0 #this register will be used for the count of r
li $t4,0 #this register will be used for the count of e 
li $t5,0 #this register will be used for the count of o
li $t6,0 #this register will be used for the count of n
li $t7,0 #this register will be used for the count of g

li $t8,-32  #this will be used for the addition
loop: #loop for the string

lb $a0,0($s0) #load the first character into $a0
addi $s0,$s0,1 #used as an index and increments by 1
beq $a0,$zero,done #used as the else clause
sge $s5,$a0,'a' #checks for the lowercase range
sle $s6,$a0,'z' #checks for the lowercase range 
and $s5,$s5,$s6 #and condition used to check between the range of lowercase
beq $s5,1,lowercaseCount #branch to lowercase label

j calculate #jump to calculate label

lowercaseCount:
add $a0,$a0,$t8   #subtracts 32 from the value stored in $a0

calculate:

beq $a0,'C',cCount      #branching and checking for capital occurences for each one
beq $a0,'H',hCount
beq $a0,'A',aCount
beq $a0,'R',rCount
beq $a0,'E',eCount
beq $a0,'O',oCount
beq $a0,'G',gCount
beq $a0,'N',nCount

j exitCount

gCount:
add $t7,$t7,1 #incrementing gCount by 1
j exitCount

cCount:
add $t0,$t0,1 #Incrementing cCount by 1
j exitCount

hCount:
add $t1,$t1,1 #incrementing hCount by 1
j exitCount

aCount:
add $t2,$t2,1 #Incrementing aCount by 1
j exitCount

rCount:
add $t3,$t3,1 #incrementing rCount by 1
j exitCount

eCount:
add $t4,$t4,1 #Incrementing eCount by 1
j exitCount

oCount:
add $t5,$t5,1 #incrementing oCount by 1
j exitCount

nCount:
add $t6,$t6,1 #incrementing nCount by 1
exitCount:

j loop


done:

li $a0,'C' #checks for the uppercase letter and moves into the new register
move $a1,$t0 #and moves into the new register
jal printCount


li $a0,'H' #checks for the uppercase letter and moves into the new register
move $a1,$t1 #and moves into the new register
jal printCount

li $a0,'A' #checks for the uppercase letter and moves into the new register
move $a1,$t2 #and moves into the new register
jal printCount

li $a0,'R' #checks for the uppercase letter and moves into the new register
move $a1,$t3 #and moves into the new register
jal printCount

#li $a0,'G' #checks for the uppercase letter and moves into the new register
#move $a1,$t7 #and moves into the new register
#jal printCount


li $a0,'E' #checks for the uppercase letter and moves into the new register
move $a1,$t4 #and moves into the new register
jal printCount

li $a0,'O' #checks for the uppercase letter and moves into the new register
move $a1,$t5 #and moves into the new register
jal printCount

li $a0,'N' #checks for the uppercase letter and moves into the new register
move $a1,$t6 #and moves into the new register
jal printCount

li $a0,'G' #checks for the uppercase letter and moves into the new register
move $a1,$t7 #and moves into the new register
jal printCount


move $v0,$a0        #moves the register
li $v0,11       #prints the character
syscall



li $a0, 'C'     #loads C into register
move $a1,$t0        #moves value of $t0 into a1
syscall
jal printhash       #jump and link to printhash

li $a0, 'H'     #loads H into register
move $a1,$t1        #moves value of $t1 into $a1
syscall 
jal printhash       #jump n link to printhash

li $a0, 'A'     #loads A into register
move $a1,$t2        #move the register from $t2 into $a1
syscall
jal printhash

li $a0, 'R'     #loads R into register
move $a1,$t3        #move the register from $t3 into $a1
syscall
jal printhash       #jumps to printhash
    
li $a0,'E'      #loads E into register
move $a1,$t4        #move the register from $t4 into $a1
syscall
jal printhash       #jumps to printhash

li $a0, 'O'     #loads O into register
move $a1,$t5        #move the register from $t5 into $a1
syscall
jal printhash       #jumps to print hash

li $a0,'N'      #loads N into register
move $a1,$t6        #move the register from $t6 into $a1
syscall
jal printhash       #jumps to printhash

li $a0, 'G'     #loads G into register
move $a1,$t7        #move the register from $t7 into $a1
syscall
jal printhash       #jumps to printhash

li $v0,10       #syscall to terminate the program once this loop has been executed
syscall

printCount:

move $v0,$a0 #prints the character
li $v0,11
syscall

li $a0,':' #prints the character
li $v0,11
syscall
move $a0,$a1 #prints the current count

li $v0,1 
syscall

li $a0,'\n' #prints the newline 
li $v0,11
syscall

jr $ra

printhash:

#move $v0,$a0 #prints the character
#li $v0,11
#syscall

li $a0,':' #prints the character
li $v0,11
syscall
move $a0,$a1 #prints the current count

li $s7,0        #indexing for the loop

hash:
bge $s7,$a1,exithash        #loop condition branch to exit loop if equal
li $a0,'#'          #loads # into the register
syscall
addi $s7,$s7,1          #adding 1 to the value in the register $s7

j hash              #jumping back to the start of the loop

exithash:           #label  of exit loop

li $a0,'\n'         #loading new line
li $v0,11           #printing the new line
syscall             #executing syscal

jr $ra              #jumping back to register $t1



Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Etlewisg
  • 1
  • 2
  • It would probably be cheaper to use an array. Registers are great, having that chain of `beq` branches to dispatch to the right `add` instruction is likely more costly than loads and stores. (Especially if you unroll with a couple separate arrays to hide store/reload latency.) – Peter Cordes Nov 11 '21 at 19:53
  • What MIPS microarchitecture are you tuning for? Is it a real MIPS with delayed branches that your assembler is hiding for you (e.g. putting a `nop` between back-to-back `beq` instructions)? (So your code would be broken if you assembled with `.set noreorder`?) Or is it a fake MIPS without branch-delay slots? You're optimizing for energy, not raw speed? What is the cost model for this CPU? Both in terms of energy, and in cycles of latency for stuff like store/reload, and load-use latency, and pipeline width. Out-of-order exec, or do we need to manually do software-pipelineing? – Peter Cordes Nov 11 '21 at 19:57
  • I am assuming it is a fake MIPS. We are writing the code in MARS 4.5 which uses MIPS 32. The homework assignment is to reduce the total amount of energy produced by the instruction count. – Etlewisg Nov 11 '21 at 20:00
  • I looked in MARS 4.5 and didn't see any of the tools or other menu items to measure energy or power directly. So what cost model are you using? Does every instruction executed cost the same energy? That would be unrealistic, and you might as well just say "minimize the dynamic instruction count" if that's all you mean. In real CPUs, floating point instructions typically take more power than integer, making the CPU run hotter. – Peter Cordes Nov 11 '21 at 20:30
  • In MARS 4.5, we use the Instruction Statistic tool. Then we get the DIC and the energy percentages from the ALU,Branch,Memory etc. Then we have to calculate the energy from there. But the percentages that i get from using that tool have to be reduced by a total of 5% – Etlewisg Nov 11 '21 at 21:06
  • 1
    For the last time, **what is the cost model you're using?** How much energy does an ALU instruction cost relative to branch or memory? I'm sure there are some optimizations that don't depend on the details of the tradeoff, but before I spend any time looking at it, I want to know the relative costs to have some idea how much of a win it would be to convert to indexing counters in memory, for example. – Peter Cordes Nov 11 '21 at 21:09
  • Also note that static energy costs that don't depend on surrounding code is pretty unrealistic for a pipelined CPU like MIPS. Although if you're using the MARS default of no branch delay slots, maybe you're pretending it's a multi-cycle MIPS without pipelining, then that's somewhat realistic. (BTW, MIPS 32 is an ISA, not a microarchitecture. You could have a 4-wide superscalar out-of-order exec implementation of it like MIPS r10000, or a 1 instruction wide in-order pipeline like a microcontroller.) – Peter Cordes Nov 11 '21 at 21:15
  • (Forgot to explain why it's unrealistic: a real CPU uses some power even when it's stalled, and the dependencies between instructions determine when you stall or not. And more significantly, cache access patterns. So a more realistic model might be some energy per cycle regardless of instruction, plus some extra energy per instruction of each type executed.) – Peter Cordes Nov 11 '21 at 23:06

1 Answers1

2

You have:

     beq .... lowercaseCount
     j calculate
lowercaseCount:
    ...
calculate:

This beq branches around a single jump instruction. That can be optimized to remove the jump, as follows: branch instead to calculate, on the reverse condition!

    bne calculate
    ...
calculate:

Further, you have j exitCount and there it does j loop.

That's an unconditional branch to another unconditional branch, which can be optimized. Replace all j exit with j loop to skip that unnecessary hop.

Erik Eidt
  • 23,049
  • 2
  • 29
  • 53
  • Thank you very much for the guidance and explanation. We are still learning how to properly and efficiently code with MIPS, so this is very helpful! – Etlewisg Nov 15 '21 at 15:52
  • So the beq to bne worked but when i switched all of the exit counts to j loops, the code would not work properly. I removed every **j exitCount** and replaced every occurrence with **j loop** as well as changed **exitCount** to **exitloop**. I don't understand what i did wrong – Etlewisg Nov 15 '21 at 20:36
  • Ok, but you get the concept that unconditional branch to uncondutional branch can be optimized. Suggest go back to the original unoptimized, and make just one change at a time, say starting with changing just the first `j exitCount`, and try it. These are transformations that are logically equivalent, so will definitely work, just need to find a typo in doing so. Don't change too much between tests, to make it easier to find errors. – Erik Eidt Nov 15 '21 at 22:30
  • Don't mess with the labels, either, just modify the `j` instruction target, as applicaple to this optimization. – Erik Eidt Nov 15 '21 at 22:35
  • I got it! Thank you very much for your assistance! – Etlewisg Nov 16 '21 at 00:20