From 40113939202e99eb604267f840883b60cfa7b009 Mon Sep 17 00:00:00 2001 From: Renz Bagaporo Date: Fri, 24 Apr 2020 21:57:05 +0800 Subject: [PATCH] ldgen: determinism in mapping rule order This MR imposes some determinism in the mapping rule order in the output file. For each section, the archives are arranged alphabetically (ascending), and the mapping rules in each archive are arranged by increasing specificity then alphabetically (ascending). The default rules remain the very first rule for each section. --- tools/ldgen/generation.py | 9 +++-- tools/ldgen/test/test_generation.py | 56 +++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 3 deletions(-) diff --git a/tools/ldgen/generation.py b/tools/ldgen/generation.py index 686defc3a..5e08e177d 100644 --- a/tools/ldgen/generation.py +++ b/tools/ldgen/generation.py @@ -322,8 +322,6 @@ class GenerationModel: return scheme_dictionary def generate_rules(self, sections_infos): - placement_rules = collections.defaultdict(list) - scheme_dictionary = self._build_scheme_dictionary() # Generate default rules @@ -353,14 +351,19 @@ class GenerationModel: for mapping_rules in all_mapping_rules.values(): self._create_exclusions(mapping_rules, default_rules, sections_infos) + placement_rules = collections.defaultdict(list) + # Add the default rules grouped by target for default_rule in default_rules: existing_rules = placement_rules[default_rule.target] if default_rule.get_section_names(): existing_rules.append(default_rule) - for mapping_rules in all_mapping_rules.values(): + archives = sorted(all_mapping_rules.keys()) + + for archive in archives: # Add the mapping rules grouped by target + mapping_rules = sorted(all_mapping_rules[archive], key=lambda m: (m.specificity, str(m))) for mapping_rule in mapping_rules: existing_rules = placement_rules[mapping_rule.target] if mapping_rule.get_section_names(): diff --git a/tools/ldgen/test/test_generation.py b/tools/ldgen/test/test_generation.py index ec5de6728..4ecd0dc93 100755 --- a/tools/ldgen/test/test_generation.py +++ b/tools/ldgen/test/test_generation.py @@ -1349,6 +1349,62 @@ entries: self.compare_rules(expected, actual) + def test_rules_order(self): + # The fragments are structured such that ldgen will: + # - parse freertos2 mapping first + # - entry for prvCheckPendingReadyList is parsed first before prvCheckDelayedList + # We expect that despite this, ldgen will output rules in a set order: + # by increasing specificity and alphabetically + test = u""" +[mapping:freertos2] +archive: libfreertos2.a +entries: + croutine2 (noflash_text) + croutine (noflash_text) + +[mapping:freertos] +archive: libfreertos.a +entries: + croutine:prvCheckPendingReadyList (noflash_text) + croutine:prvCheckDelayedList (noflash_text) +""" + self.add_fragments(test) + + actual = self.model.generate_rules(self.sections_info) + + expected = self.generate_default_rules() + + flash_text_default = self.get_default("flash_text", expected) + + iram0_text_E1 = PlacementRule("libfreertos2.a", "croutine2", None, self.model.sections["text"].entries, "iram0_text") + iram0_text_E2 = PlacementRule("libfreertos2.a", "croutine", None, self.model.sections["text"].entries, "iram0_text") + iram0_text_E3 = PlacementRule("libfreertos.a", "croutine", "prvCheckPendingReadyList", self.model.sections["text"].entries, "iram0_text") + iram0_text_E4 = PlacementRule("libfreertos.a", "croutine", "prvCheckDelayedList", self.model.sections["text"].entries, "iram0_text") + + flash_text_extra = PlacementRule("libfreertos.a", "croutine", None, [".text.*", ".literal.*"], "flash_text") + + # Add the exclusions + flash_text_default.add_exclusion(iram0_text_E1, self.sections_info) + flash_text_default.add_exclusion(iram0_text_E2, self.sections_info) + + flash_text_default.add_exclusion(flash_text_extra, self.sections_info) + flash_text_extra.add_exclusion(iram0_text_E3, self.sections_info) + flash_text_extra.add_exclusion(iram0_text_E4, self.sections_info) + + # Add the rules, arranged by expected order + expected["flash_text"].append(flash_text_extra) + expected["iram0_text"].append(iram0_text_E4) + expected["iram0_text"].append(iram0_text_E3) + expected["iram0_text"].append(iram0_text_E2) + expected["iram0_text"].append(iram0_text_E1) + + # Perform general comparison for all sections + self.compare_rules(expected, actual) + + # Perform ordered comparison + self.assertListEqual(actual["flash_text"], expected["flash_text"]) + self.assertListEqual(actual["iram0_text"], expected["iram0_text"]) + if __name__ == "__main__": unittest.main()