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,75 @@ 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 }
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" }
568
+ tree_bss = {"name" : ".bss" }
569
+ tree_data = {"name" : ".data" }
570
+ for name , dct in self .modules .items ():
571
+ if ".text" not in dct :
572
+ continue
573
+ cur_text = tree_text
574
+ cur_bss = tree_bss
575
+ cur_data = tree_data
576
+ modules = name .split (sep )
577
+ while True :
578
+ cur_text .setdefault ("value" , 0 )
579
+ cur_data .setdefault ("value" , 0 )
580
+ cur_bss .setdefault ("value" , 0 )
581
+ try :
582
+ cur_text ["value" ] += dct ['.text' ]
583
+ except KeyError :
584
+ pass
585
+ try :
586
+ cur_bss ["value" ] += dct ['.bss' ]
587
+ except KeyError :
588
+ pass
589
+ try :
590
+ cur_data ["value" ] += dct ['.data' ]
591
+ except KeyError :
592
+ pass
593
+ if not modules :
594
+ break
595
+ next_module = modules .pop (0 )
596
+ cur_text = self ._move_up_tree (cur_text , next_module )
597
+ cur_data = self ._move_up_tree (cur_data , next_module )
598
+ cur_bss = self ._move_up_tree (cur_bss , next_module )
599
+
600
+ jinja_loader = FileSystemLoader (dirname (abspath (__file__ )))
601
+ jinja_environment = Environment (loader = jinja_loader ,
602
+ undefined = StrictUndefined )
603
+
604
+ template = jinja_environment .get_template ("memap_flamegraph.html" )
605
+ name , _ = splitext (basename (file_desc .name ))
606
+ if name .endswith ("_map" ):
607
+ name = name [:- 4 ]
608
+ if self .tc_name :
609
+ name = "%s %s" % (name , self .tc_name )
610
+ data = {
611
+ "name" : name ,
612
+ "text" : json .dumps (tree_text ),
613
+ "data" : json .dumps (tree_data ),
614
+ "bss" : json .dumps (tree_bss ),
615
+ }
616
+ file_desc .write (template .render (data ))
617
+ return None
618
+
543
619
def generate_json (self , file_desc ):
544
620
"""Generate a json file from a memory map
545
621
@@ -655,6 +731,7 @@ def parse(self, mapfile, toolchain):
655
731
mapfile - the file name of the memory map file
656
732
toolchain - the toolchain used to create the file
657
733
"""
734
+ self .tc_name = toolchain .title ()
658
735
if toolchain in ("ARM" , "ARM_STD" , "ARM_MICRO" , "ARMC6" ):
659
736
parser = _ArmccParser ()
660
737
elif toolchain == "GCC_ARM" or toolchain == "GCC_CR" :
0 commit comments