6
6
from abc import abstractmethod , ABCMeta
7
7
from sys import stdout , exit , argv
8
8
from os import sep
9
- from os .path import basename , dirname , join , relpath , commonprefix
9
+ from os .path import (basename , dirname , join , relpath , abspath , commonprefix ,
10
+ splitext )
10
11
import re
11
12
import csv
12
13
import json
13
14
from argparse import ArgumentParser
14
15
from copy import deepcopy
15
16
from prettytable import PrettyTable
17
+ from jinja2 import FileSystemLoader , StrictUndefined
18
+ from jinja2 .environment import Environment
16
19
17
20
from .utils import (argparse_filestring_type , argparse_lowercase_hyphen_type ,
18
21
argparse_uppercase_type )
@@ -477,6 +480,9 @@ def __init__(self):
477
480
# Flash no associated with a module
478
481
self .misc_flash_mem = 0
479
482
483
+ # Name of the toolchain, for better headings
484
+ self .tc_name = None
485
+
480
486
def reduce_depth (self , depth ):
481
487
"""
482
488
populates the short_modules attribute with a truncated module list
@@ -505,7 +511,7 @@ def reduce_depth(self, depth):
505
511
self .short_modules [new_name ].setdefault (section_idx , 0 )
506
512
self .short_modules [new_name ][section_idx ] += self .modules [module_name ][section_idx ]
507
513
508
- export_formats = ["json" , "csv-ci" , "table" ]
514
+ export_formats = ["json" , "csv-ci" , "html" , " table" ]
509
515
510
516
def generate_output (self , export_format , depth , file_output = None ):
511
517
""" Generates summary of memory map data
@@ -531,6 +537,7 @@ def generate_output(self, export_format, depth, file_output=None):
531
537
return False
532
538
533
539
to_call = {'json' : self .generate_json ,
540
+ 'html' : self .generate_html ,
534
541
'csv-ci' : self .generate_csv ,
535
542
'table' : self .generate_table }[export_format ]
536
543
output = to_call (file_desc )
@@ -540,6 +547,80 @@ def generate_output(self, export_format, depth, file_output=None):
540
547
541
548
return output
542
549
550
+ @staticmethod
551
+ def _move_up_tree (tree , next_module ):
552
+ tree .setdefault ("children" , [])
553
+ for child in tree ["children" ]:
554
+ if child ["name" ] == next_module :
555
+ return child
556
+ else :
557
+ new_module = {"name" : next_module , "value" : 0 }
558
+ tree ["children" ].append (new_module )
559
+ return new_module
560
+
561
+ def generate_html (self , file_desc ):
562
+ """Generate a json file from a memory map for D3
563
+
564
+ Positional arguments:
565
+ file_desc - the file to write out the final report to
566
+ """
567
+ tree_text = {"name" : ".text" , "value" : 0 }
568
+ tree_bss = {"name" : ".bss" , "value" : 0 }
569
+ tree_data = {"name" : ".data" , "value" : 0 }
570
+ for name , dct in self .modules .items ():
571
+ cur_text = tree_text
572
+ cur_bss = tree_bss
573
+ cur_data = tree_data
574
+ modules = name .split (sep )
575
+ while True :
576
+ try :
577
+ cur_text ["value" ] += dct ['.text' ]
578
+ except KeyError :
579
+ pass
580
+ try :
581
+ cur_bss ["value" ] += dct ['.bss' ]
582
+ except KeyError :
583
+ pass
584
+ try :
585
+ cur_data ["value" ] += dct ['.data' ]
586
+ except KeyError :
587
+ pass
588
+ if not modules :
589
+ break
590
+ next_module = modules .pop (0 )
591
+ cur_text = self ._move_up_tree (cur_text , next_module )
592
+ cur_data = self ._move_up_tree (cur_data , next_module )
593
+ cur_bss = self ._move_up_tree (cur_bss , next_module )
594
+
595
+ tree_rom = {
596
+ "name" : "ROM" ,
597
+ "value" : tree_text ["value" ] + tree_data ["value" ],
598
+ "children" : [tree_text , tree_data ]
599
+ }
600
+ tree_ram = {
601
+ "name" : "RAM" ,
602
+ "value" : tree_bss ["value" ] + tree_data ["value" ],
603
+ "children" : [tree_bss , tree_data ]
604
+ }
605
+
606
+ jinja_loader = FileSystemLoader (dirname (abspath (__file__ )))
607
+ jinja_environment = Environment (loader = jinja_loader ,
608
+ undefined = StrictUndefined )
609
+
610
+ template = jinja_environment .get_template ("memap_flamegraph.html" )
611
+ name , _ = splitext (basename (file_desc .name ))
612
+ if name .endswith ("_map" ):
613
+ name = name [:- 4 ]
614
+ if self .tc_name :
615
+ name = "%s %s" % (name , self .tc_name )
616
+ data = {
617
+ "name" : name ,
618
+ "rom" : json .dumps (tree_rom ),
619
+ "ram" : json .dumps (tree_ram ),
620
+ }
621
+ file_desc .write (template .render (data ))
622
+ return None
623
+
543
624
def generate_json (self , file_desc ):
544
625
"""Generate a json file from a memory map
545
626
@@ -655,6 +736,7 @@ def parse(self, mapfile, toolchain):
655
736
mapfile - the file name of the memory map file
656
737
toolchain - the toolchain used to create the file
657
738
"""
739
+ self .tc_name = toolchain .title ()
658
740
if toolchain in ("ARM" , "ARM_STD" , "ARM_MICRO" , "ARMC6" ):
659
741
parser = _ArmccParser ()
660
742
elif toolchain == "GCC_ARM" or toolchain == "GCC_CR" :
0 commit comments