Go Down

Topic: Code size puzzlement (Read 865 times) previous topic - next topic

westfw

#15
Sep 26, 2018, 04:42 am Last Edit: Sep 26, 2018, 04:42 am by westfw
Quote
I'm still not clear on how to generate a listing on my own.
The "avr-objdump" program is buried deep in the IDE filesystem.
C:\Users\billw>avr-objdump
'avr-objdump' is not recognized as an internal or external command, operable program or batch file.
*** (yep - not there. ***

*** We get the sketch binary directory by looking at the verbose compile log ***
C:\Users\billw>cd C:\\Users\\billw\\AppData\\Local\\Temp\\arduino_build_754126

C:\Users\billw\AppData\Local\Temp\arduino_build_754126>dir *.elf
 Volume in drive C has no label.
 Volume Serial Number is 76D1-5C84

 Directory of C:\Users\billw\AppData\Local\Temp\arduino_build_754126

09/25/2018  07:32 PM             9,696 sketch_sep25a.ino.elf
               1 File(s)          9,696 bytes
               0 Dir(s)   8,812,560,384 bytes free

C:\Users\billw\AppData\Local\Temp\arduino_build_754126>"C:\Program Files (x86)\Arduino\hardware\tools\avr\bin\avr-objdump.exe"

*** There it is ! Filename completion is your friend! ***

Usage: C:\Program Files (x86)\Arduino\hardware\tools\avr\bin\avr-objdump.exe <option(s)> <file(s)>


Also, see perhaps https://hackaday.io/project/19935-install-avr-tools

dougp

Thank you @DKWatson & @westfw.  I opted for @DKWatson's path manual modification as a first attempt.  No joy.

I appended this to the system path:

Common Files\Roxio Shared\9.0\DLLShared\;C:\Program Files (x86)\Arduino\hardware\tools\avr\bin

I used this path with and without a trailing semicolon - no difference.  Here's a snip of my result.



The command line message doesn't jibe with what I see in the folder so I must have messed something up.  It is some progress though, since at least avr-objdump seems to run.  Also, I can't get a command window with the right-click.   It happened once but I have no idea how to make it repeatable.  That's not a big deal, I can still get a window from the start button.
So two neutrinos went into a bar.  Nothing happened.  They were just passing through.

westfw

PS: could you post a current version of the "class based" code for us to try out?


dougp

PS: could you post a current version of the "class based" code for us to try out?
Please see post #12.
So two neutrinos went into a bar.  Nothing happened.  They were just passing through.

dougp

Update.

Success!  I was able to print an .asm listing at last.  I was not including 'Arduino_build_xxxx' in the path.

 :smiley-zipper:
So two neutrinos went into a bar.  Nothing happened.  They were just passing through.

DKWatson

Well done! Now, do you remember what you did?
Live as if you were to die tomorrow. Learn as if you were to live forever. - Mahatma Gandhi

dougp

Well done! Now, do you remember what you did?
Thanks.  I do remember.  But, it's only been thirty minutes or so.  So... I copied the steps to offline storage - my little book of crib notes I keep by the computer.  I also copy one the email replies to threads I started to a separate folder in Outlook should I need to refer to the subject sometime down the road.
So two neutrinos went into a bar.  Nothing happened.  They were just passing through.

Hutkikz

 Like you I have reached a point where I am interested in investigating this kind of stuff.
However I found it cumbersome to do with the arduino IDE.

 I recently finally found how to get atmel studio to work with arduino without any extra hardware. Atmel Studio 7 - Programming the Arduino Uno via the bootloader without programmer.

 Now I can quickly see the effects of any changes simply by clicking on the output files after a compilation.

dougp

I recently finally found how to get atmel studio to work with arduino without any extra hardware. Atmel Studio 7 - Programming the Arduino Uno via the bootloader without programmer.
Thanks for the info.  Sounds like a way to go but, I'm foregoing installing new software since my HDD has only  17GB remaining.  

I agree 100%, the IDE is a clunky way to get a disassembly but, since it's an infrequent thing to get down in the weeds like this, it'll do for now.

Have a good day!
So two neutrinos went into a bar.  Nothing happened.  They were just passing through.

dougp

Now that I can reliably get a sketch disassembly I can compare the two sections of code which prompted this thread.

Here's the if/else code from the class version:
Code: [Select]
   /*
        ----- condition the timer timing status
      */
      if ((_Enable or _Control) and !_Done and !_Reset) {
 40e: 2e 81        ldd r18, Y+6 ; 0x06
 410: 21 fd        sbrc r18, 1
 412: 02 c0        rjmp .+4      ; 0x418 <__LOCK_REGION_LENGTH__+0x18>
 414: 24 ff        sbrs r18, 4
 416: 06 c0        rjmp .+12      ; 0x424 <__LOCK_REGION_LENGTH__+0x24>
 418: 81 11        cpse r24, r1
 41a: 04 c0        rjmp .+8      ; 0x424 <__LOCK_REGION_LENGTH__+0x24>
 41c: 20 fd        sbrc r18, 0
 41e: 02 c0        rjmp .+4      ; 0x424 <__LOCK_REGION_LENGTH__+0x24>
        _TimerRunning = true;
 420: 91 60        ori r25, 0x01 ; 1
 422: 01 c0        rjmp .+2      ; 0x426 <__LOCK_REGION_LENGTH__+0x26>
      }
      else _TimerRunning = false;
 424: 9e 7f        andi r25, 0xFE ; 254
 426: 9b 8b        std Y+19, r25 ; 0x13
      return _Done;


And the boolean code from the class version:
Code: [Select]
     _TimerRunning = (_Enable or _Control) and !_Done and !_Reset;
 410: 9e 81        ldd r25, Y+6 ; 0x06
 412: 91 fd        sbrc r25, 1
 414: 05 c0        rjmp .+10      ; 0x420 <__LOCK_REGION_LENGTH__+0x20>
 416: 94 fb        bst r25, 4
 418: 22 27        eor r18, r18
 41a: 20 f9        bld r18, 0
 41c: 94 ff        sbrs r25, 4
 41e: 07 c0        rjmp .+14      ; 0x42e <__LOCK_REGION_LENGTH__+0x2e>
 420: 81 11        cpse r24, r1
 422: 04 c0        rjmp .+8      ; 0x42c <__LOCK_REGION_LENGTH__+0x2c>
 424: 90 95        com r25
 426: 29 2f        mov r18, r25
 428: 21 70        andi r18, 0x01 ; 1
 42a: 01 c0        rjmp .+2      ; 0x42e <__LOCK_REGION_LENGTH__+0x2e>
 42c: 20 e0        ldi r18, 0x00 ; 0
 42e: 9b 89        ldd r25, Y+19 ; 0x13
 430: 20 fb        bst r18, 0
 432: 90 f9        bld r25, 0
 434: 9b 8b        std Y+19, r25 ; 0x13
      return _Done;


It's speculation but I'm guessing the boolean version takes more memory because there's no variable (register) to work from, it's all sort of juggled 'til the final result is arrived at.  This implies it also takes more clock cycles.  It's counterintuitive to me because the C++ version of the boolean code appears simpler than the if/else code.  Go figure.
So two neutrinos went into a bar.  Nothing happened.  They were just passing through.

DKWatson

I believe (this is going to be an expressed opinion so treat it as such) that knowing and understanding assembly is fundamental in squeezing performance out of a microcontroller. While I do not suggest crafting an entire program this way, I do highly recommend getting intimate with inline assembly and the concept of stub functions. During compilation these are ignored by the compiler (as far as checks are concerned) and passed directly to the assembler. The beauty (or ugly) of this is that the code remains exactly as you've typed it. By disassembling the compiled code you can see what it (the compiler) does and then incorporate those bits of interest directly into your own code as inline or stub (with the necessary changes pertaining to constraints, clobbers, etc.) and tweak at will. It's a slippery slope but I've developed some amazingly fast functions, particularly when dealing with PROGMEM and accessing FLASH based data. You can also self-modify code (not recommended).

Where you start to get performance improvements can quickly be realized with simple branch and jump commands when you learn that rjmp is 50% (or 33% depending on which way you do the math) faster than jmp. This has only to do with whether an offset is used, which means the destination must be close, or if an address must be used for locations further away. In any event, it's a whole new world and once you realize it you know why.
Live as if you were to die tomorrow. Learn as if you were to live forever. - Mahatma Gandhi

westfw

Quote
Code: [Select]
 416: 94 fb        bst r25, 4
 418: 22 27        eor r18, r18
 41a: 20 f9        bld r18, 0
This looks like what I guessed back in message 11.

The BST/BLD is essentially "standard" AVR code for moving a bit from one position to another.
BST is "set the T status from bit 4 of r25" (probably one of the bools from your class, and BLD is "Load bit 0 of r18 (after the eor zeros it) from the T status bit."
It moves a bitwide bool in bit 4 of r25 to a byte-wide bool in r18 (cheaper than shift&mask.)

dougp

BLD is "Load bit 0 of r18 (after the eor zeros it) from the T status bit."
I wondered about that - why not use CLR?  Turns out CLR and EOR are the same instruction.

Concerning the :1 thing, I changed _Enable and _Done bools to whole byte type and there's quite a change.

as separate bytes - 1840 flash, 255 RAM
as bit fields            - 1848 flash, 225 RAM  +8 flash, -30 RAM

As with most things, it's a tradeoff.
So two neutrinos went into a bar.  Nothing happened.  They were just passing through.

dougp

The "avr-objdump" program is buried deep in the IDE filesystem.
@westfw, so then I could edit the batch file to set the path to the temp folder to save typing that labyrinthine pathname with something like,

SET PATH=%PATH%;c:\users\owner\etc.

,no?

Do you know of any batch file magic which would allow automatically naming the output file from the input file?

avr_objdump -S arduino_build_xxxxx\filename.ino.elf> <outputfilename copied from input filename>.lst.
So two neutrinos went into a bar.  Nothing happened.  They were just passing through.

bperrybap

There are many things you can do to speed and shrink code when using avr-gcc by simply changing your C code without having to resort to using inline assembly.

This is because the AVR is a an 8 bit processor and lacks certain addressing modes.

For example here are a few:
Use 8 bit variables when possible rather than ints
using an unsigned char rather than int for loop variables in small loops will generate smaller & faster code.
using separate global variables will be faster than accessing structure members within a global structure.
Avoid use of pointers to structures and their elements as pointer references are not very efficient on the AVR.

You can easily see the effects of these changes by looking at the assembler output.
What I do to easily get the assembler output is I have a bash script that runs in place of objcopy that creates the asm output then calls the real objcopy. That way I get the assembly files on each build of the sketch.

--- bill



Go Up