tum-ei-eda / etiss

Extendable Translating Instruction Set Simulator
https://tum-ei-eda.github.io/etiss/
Other
29 stars 36 forks source link

bare_etiss_processor/get_metrics.py: Invalid stats for Stack/Heap usage since memory map refactoring #68

Closed PhilippvK closed 2 years ago

PhilippvK commented 3 years ago

The script get_metrics.py is useful to get information in the usage of memory in ETISS.

I recently discovered that the reported stack usage is always zero and the heap non-zero instead. Here is an example:

Model,Cycles,ROM,RAM,ROM read-only,ROM code,RAM data,RAM zero-init data,RAM stack,RAM heap
resnet,652858000,160542,70749,100564,59830,2201,66168,0,2380

Using the following memsegs.ini and MIN_STACK_SIZE=0x4000:

[IntConfigurations]
simple_mem_system.memseg_origin_00=0x0
simple_mem_system.memseg_length_00=0x100000
simple_mem_system.memseg_origin_01=0x100000
simple_mem_system.memseg_length_01=0x5000000

After having a look at the generated binary using readelf I figured out what is going on:

The Memory size of the RAM memory segment is not equal to the specified RAM_SIZE anymore which leads to the fact that it’s value can not be used to figure out the end of the ram and therefore the start/end of the stack section.

See before…

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x001000 0x00000000 0x00000000 0x03f0c 0x03f0c R E 0x1000
  LOAD           0x005000 0x00100000 0x00100000 0x0088c 0x5000000 RW  0x1000

… and after #61:

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x001000 0x00000000 0x00000000 0x2aaa8 0x2aaa8 R E 0x1000
  LOAD           0x02c000 0x00100000 0x00100000 0x00954 0x18bd4 RW  0x1000

Therefore the following code in the aforementioned script is invalid:

ramSize = e.get_segment(1)['p_memsz']

A rather “hacky” workaround would be parsing the value of the symbol VALUE_ram_size similar to the way, the stackSize and heapStart is determined.

PhilippvK commented 3 years ago

@wysiwyng @rafzi If my workaround is fine, I can open a PR with this very small fix. Let me know if I have overlooked anything…

PhilippvK commented 3 years ago

If also realized that using the minStackSize to split up the heap and ram would not be correct if the initial stack size is increased by the linker. Do you have an idea on how to cope with that?

wysiwyng commented 3 years ago

The Memory size of the RAM memory segment is not equal to the specified RAM_SIZE anymore which leads to the fact that it’s value can not be used to figure out the end of the ram and therefore the start/end of the stack section.

See PRs #61 and #54 for longer reasoning behind this. In short: Requiring the RAM segment of the ELF file to be as long as the actual RAM is non-standard, breaking ETISS when ELF-files from projects where the linker behavior cannot be changed easily have to be used.

If also realized that using the minStackSize to split up the heap and ram would not be correct if the initial stack size is increased by the linker. Do you have an idea on how to cope with that?

VAR_min_stack and VAR_min_heap (in link.ld) are exclusively used to make ld throw an error if there would not be enough space for stack and/or heap, e.g. when the RAM is used up otherwise. The linker does not really care about stack and heap size at all in a bare-metal target like this, stack and heap management happens at program runtime.

A rather "hacky" workaround would be parsing the value of the symbol VALUE_ram_size similar to the way, the stackSize and heapStart is determined.

I would instead pass the total RAM size to the metrics script via command line, or implement a parser for the .ini files ETISS uses anyways. Remember, you can only read the minimum reserved stack/heap size from the ELF file and linker script, the actual usage has to be determined at runtime.

Please do open a PR when you implement a solution.

rafzi commented 3 years ago

@PhilippvK since I also don't see a way to reliably get the memory layout from an arbitrary ELF file, I'd go with the suggestion to use the memsegs.ini file as input to this script. this should also be pretty simple to integrate in ml_on_mcu, since that file is already required for the etiss invocation anyways.

PhilippvK commented 3 years ago

@rafzi Yes, think we can go with that approach. Should the path to the memsegs.ini file be mandatory or should I define some defaults as a fallback?

But even if we know the RAM size, the tracing of the Heap and Stack Usage is not so trivial as mentioned by @wysiwyng. Using the MIN_STACK_SIZE as the indicator for the end of the heap does not guarantee anything at runtime. However we should still be able to get meaningful tracing results if we just ensure that the RAM_SIZE and accordingly MIN_STACK_SIZE are both large enough to easily fit the maximum used stack size. So in my opinion we do not have to change anything here, except letting users know about this when relying on get_metrics.py.

rafzi commented 3 years ago

@PhilippvK

Defaults that are compatible with the ELFs from the examples here would be useful.

For stack size, it would be nice not to rely on non-standard symbols like _min_stack, so that we are compatible with arbitrary ELFs. So I'd go for a 4K or 16K stack size default and if the user finds that this is fully utilized, he may configure it to be larger.