5
5
6
6
from abc import abstractmethod , ABCMeta
7
7
from sys import stdout , exit , argv
8
- from os import sep
8
+ from os import sep , rename , remove
9
9
from os .path import (basename , dirname , join , relpath , abspath , commonprefix ,
10
- splitext )
10
+ splitext , exists )
11
11
import re
12
12
import csv
13
13
import json
20
20
21
21
from .utils import (argparse_filestring_type , argparse_lowercase_hyphen_type ,
22
22
argparse_uppercase_type )
23
+ from .settings import COMPARE_FIXED
23
24
24
25
25
26
class _Parser (object ):
@@ -455,6 +456,7 @@ class MemapParser(object):
455
456
"""
456
457
457
458
print_sections = ('.text' , '.data' , '.bss' )
459
+ delta_sections = ('.text-delta' , '.data-delta' , '.bss-delta' )
458
460
459
461
460
462
# sections to print info (generic for all toolchains)
@@ -466,6 +468,7 @@ def __init__(self):
466
468
# list of all modules and their sections
467
469
# full list - doesn't change with depth
468
470
self .modules = dict ()
471
+ self .old_modules = None
469
472
# short version with specific depth
470
473
self .short_modules = dict ()
471
474
@@ -510,8 +513,17 @@ def reduce_depth(self, depth):
510
513
new_name = join (* split_name [:depth ])
511
514
self .short_modules .setdefault (new_name , defaultdict (int ))
512
515
for section_idx , value in v .items ():
513
- self .short_modules [new_name ].setdefault (section_idx , 0 )
514
516
self .short_modules [new_name ][section_idx ] += self .modules [module_name ][section_idx ]
517
+ self .short_modules [new_name ][section_idx + '-delta' ] += self .modules [module_name ][section_idx ]
518
+ if self .old_modules :
519
+ for module_name , v in self .old_modules .items ():
520
+ split_name = module_name .split (sep )
521
+ if split_name [0 ] == '' :
522
+ split_name = split_name [1 :]
523
+ new_name = join (* split_name [:depth ])
524
+ self .short_modules .setdefault (new_name , defaultdict (int ))
525
+ for section_idx , value in v .items ():
526
+ self .short_modules [new_name ][section_idx + '-delta' ] -= self .old_modules [module_name ][section_idx ]
515
527
516
528
export_formats = ["json" , "csv-ci" , "html" , "table" ]
517
529
@@ -557,7 +569,7 @@ def _move_up_tree(tree, next_module):
557
569
if child ["name" ] == next_module :
558
570
return child
559
571
else :
560
- new_module = {"name" : next_module , "value" : 0 }
572
+ new_module = {"name" : next_module , "value" : 0 , "delta" : 0 }
561
573
tree ["children" ].append (new_module )
562
574
return new_module
563
575
@@ -567,9 +579,9 @@ def generate_html(self, file_desc):
567
579
Positional arguments:
568
580
file_desc - the file to write out the final report to
569
581
"""
570
- tree_text = {"name" : ".text" , "value" : 0 }
571
- tree_bss = {"name" : ".bss" , "value" : 0 }
572
- tree_data = {"name" : ".data" , "value" : 0 }
582
+ tree_text = {"name" : ".text" , "value" : 0 , "delta" : 0 }
583
+ tree_bss = {"name" : ".bss" , "value" : 0 , "delta" : 0 }
584
+ tree_data = {"name" : ".data" , "value" : 0 , "delta" : 0 }
573
585
for name , dct in self .modules .items ():
574
586
cur_text = tree_text
575
587
cur_bss = tree_bss
@@ -578,14 +590,17 @@ def generate_html(self, file_desc):
578
590
while True :
579
591
try :
580
592
cur_text ["value" ] += dct ['.text' ]
593
+ cur_text ["delta" ] += dct ['.text' ]
581
594
except KeyError :
582
595
pass
583
596
try :
584
597
cur_bss ["value" ] += dct ['.bss' ]
598
+ cur_bss ["delta" ] += dct ['.bss' ]
585
599
except KeyError :
586
600
pass
587
601
try :
588
602
cur_data ["value" ] += dct ['.data' ]
603
+ cur_data ["delta" ] += dct ['.data' ]
589
604
except KeyError :
590
605
pass
591
606
if not modules :
@@ -594,15 +609,44 @@ def generate_html(self, file_desc):
594
609
cur_text = self ._move_up_tree (cur_text , next_module )
595
610
cur_data = self ._move_up_tree (cur_data , next_module )
596
611
cur_bss = self ._move_up_tree (cur_bss , next_module )
612
+ if self .old_modules :
613
+ for name , dct in self .old_modules .items ():
614
+ cur_text = tree_text
615
+ cur_bss = tree_bss
616
+ cur_data = tree_data
617
+ modules = name .split (sep )
618
+ while True :
619
+ try :
620
+ cur_text ["delta" ] -= dct ['.text' ]
621
+ except KeyError :
622
+ pass
623
+ try :
624
+ cur_bss ["delta" ] -= dct ['.bss' ]
625
+ except KeyError :
626
+ pass
627
+ try :
628
+ cur_data ["delta" ] -= dct ['.data' ]
629
+ except KeyError :
630
+ pass
631
+ if not modules :
632
+ break
633
+ next_module = modules .pop (0 )
634
+ if not any (cld ['name' ] == next_module for cld in cur_text ['children' ]):
635
+ break
636
+ cur_text = self ._move_up_tree (cur_text , next_module )
637
+ cur_data = self ._move_up_tree (cur_data , next_module )
638
+ cur_bss = self ._move_up_tree (cur_bss , next_module )
597
639
598
640
tree_rom = {
599
641
"name" : "ROM" ,
600
642
"value" : tree_text ["value" ] + tree_data ["value" ],
643
+ "delta" : tree_text ["delta" ] + tree_data ["delta" ],
601
644
"children" : [tree_text , tree_data ]
602
645
}
603
646
tree_ram = {
604
647
"name" : "RAM" ,
605
648
"value" : tree_bss ["value" ] + tree_data ["value" ],
649
+ "delta" : tree_bss ["delta" ] + tree_data ["delta" ],
606
650
"children" : [tree_bss , tree_data ]
607
651
}
608
652
@@ -634,6 +678,14 @@ def generate_json(self, file_desc):
634
678
file_desc .write ('\n ' )
635
679
return None
636
680
681
+ RAM_FORMAT_STR = (
682
+ "Total Static RAM memory (data + bss): {}({:+}) bytes\n "
683
+ )
684
+
685
+ ROM_FORMAT_STR = (
686
+ "Total Flash memory (text + data): {}({:+}) bytes\n "
687
+ )
688
+
637
689
def generate_csv (self , file_desc ):
638
690
"""Generate a CSV file from a memoy map
639
691
@@ -646,7 +698,7 @@ def generate_csv(self, file_desc):
646
698
module_section = []
647
699
sizes = []
648
700
for i in sorted (self .short_modules ):
649
- for k in self .print_sections :
701
+ for k in self .print_sections + self . delta_sections :
650
702
module_section .append ((i + k ))
651
703
sizes += [self .short_modules [i ][k ]]
652
704
@@ -681,23 +733,29 @@ def generate_table(self, file_desc):
681
733
row = [i ]
682
734
683
735
for k in self .print_sections :
684
- row .append (self .short_modules [i ][k ])
736
+ row .append ("{}({:+})" .format (self .short_modules [i ][k ],
737
+ self .short_modules [i ][k + "-delta" ]))
685
738
686
739
table .add_row (row )
687
740
688
741
subtotal_row = ['Subtotals' ]
689
742
for k in self .print_sections :
690
- subtotal_row .append (self .subtotal [k ])
743
+ subtotal_row .append ("{}({:+})" .format (
744
+ self .subtotal [k ], self .subtotal [k + '-delta' ]))
691
745
692
746
table .add_row (subtotal_row )
693
747
694
748
output = table .get_string ()
695
749
output += '\n '
696
750
697
- output += "Total Static RAM memory (data + bss): %s bytes\n " % \
698
- str (self .mem_summary ['static_ram' ])
699
- output += "Total Flash memory (text + data): %s bytes\n " % \
700
- str (self .mem_summary ['total_flash' ])
751
+ output += self .RAM_FORMAT_STR .format (
752
+ self .mem_summary ['static_ram' ],
753
+ self .mem_summary ['static_ram_delta' ]
754
+ )
755
+ output += self .ROM_FORMAT_STR .format (
756
+ self .mem_summary ['total_flash' ],
757
+ self .mem_summary ['total_flash_delta' ]
758
+ )
701
759
702
760
return output
703
761
@@ -706,16 +764,24 @@ def generate_table(self, file_desc):
706
764
def compute_report (self ):
707
765
""" Generates summary of memory usage for main areas
708
766
"""
709
- for k in self .sections :
710
- self .subtotal [k ] = 0
767
+ self .subtotal = defaultdict (int )
711
768
712
769
for mod in self .modules .values ():
713
770
for k in self .sections :
714
771
self .subtotal [k ] += mod [k ]
772
+ self .subtotal [k + '-delta' ] += mod [k ]
773
+ if self .old_modules :
774
+ for mod in self .old_modules .values ():
775
+ for k in self .sections :
776
+ self .subtotal [k + '-delta' ] -= mod [k ]
715
777
716
778
self .mem_summary = {
717
- 'static_ram' : (self .subtotal ['.data' ] + self .subtotal ['.bss' ]),
779
+ 'static_ram' : self .subtotal ['.data' ] + self .subtotal ['.bss' ],
780
+ 'static_ram_delta' :
781
+ self .subtotal ['.data-delta' ] + self .subtotal ['.bss-delta' ],
718
782
'total_flash' : (self .subtotal ['.text' ] + self .subtotal ['.data' ]),
783
+ 'total_flash_delta' :
784
+ self .subtotal ['.text-delta' ] + self .subtotal ['.data-delta' ],
719
785
}
720
786
721
787
self .mem_report = []
@@ -724,7 +790,8 @@ def compute_report(self):
724
790
self .mem_report .append ({
725
791
"module" : name ,
726
792
"size" :{
727
- k : sizes .get (k , 0 ) for k in self .print_sections
793
+ k : sizes .get (k , 0 ) for k in (self .print_sections +
794
+ self .delta_sections )
728
795
}
729
796
})
730
797
@@ -741,16 +808,26 @@ def parse(self, mapfile, toolchain):
741
808
"""
742
809
self .tc_name = toolchain .title ()
743
810
if toolchain in ("ARM" , "ARM_STD" , "ARM_MICRO" , "ARMC6" ):
744
- parser = _ArmccParser ()
811
+ parser = _ArmccParser
745
812
elif toolchain == "GCC_ARM" or toolchain == "GCC_CR" :
746
- parser = _GccParser ()
813
+ parser = _GccParser
747
814
elif toolchain == "IAR" :
748
- parser = _IarParser ()
815
+ parser = _IarParser
749
816
else :
750
817
return False
751
818
try :
752
819
with open (mapfile , 'r' ) as file_input :
753
- self .modules = parser .parse_mapfile (file_input )
820
+ self .modules = parser ().parse_mapfile (file_input )
821
+ try :
822
+ with open ("%s.old" % mapfile , 'r' ) as old_input :
823
+ self .old_modules = parser ().parse_mapfile (old_input )
824
+ except IOError :
825
+ self .old_modules = None
826
+ if not COMPARE_FIXED :
827
+ old_mapfile = "%s.old" % mapfile
828
+ if exists (old_mapfile ):
829
+ remove (old_mapfile )
830
+ rename (mapfile , old_mapfile )
754
831
return True
755
832
756
833
except IOError as error :
0 commit comments