From ccbca4570926b11083c14e3c1f24937e530a23f2 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 | 59 +++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 3 deletions(-) diff --git a/tools/ldgen/generation.py b/tools/ldgen/generation.py index 32855845d..4c0f1a8c4 100644 --- a/tools/ldgen/generation.py +++ b/tools/ldgen/generation.py @@ -322,8 +322,6 @@ class GenerationModel: return scheme_dictionary def generate_rules(self, sdkconfig, sections_infos): - placement_rules = collections.defaultdict(list) - scheme_dictionary = self._build_scheme_dictionary() # Generate default rules @@ -373,14 +371,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(), key=lambda a: a.replace("_a", ".a")) + + 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 bc8566e76..2fd2ed654 100755 --- a/tools/ldgen/test/test_generation.py +++ b/tools/ldgen/test/test_generation.py @@ -1176,6 +1176,65 @@ class GenerationModelTest(unittest.TestCase): 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 + rules_order_mapping_1 = """ + [mapping] + archive: libfreertos2.a + entries: + croutine2 (noflash_text) + croutine (noflash_text) + """ + + rules_order_mapping_2 = """ + [mapping] + archive: libfreertos.a + entries: + croutine:prvCheckPendingReadyList (noflash_text) + croutine:prvCheckDelayedList (noflash_text) + """ + + self._add_mapping(rules_order_mapping_2) + self._add_mapping(rules_order_mapping_1) + + actual = self.model.generate_rules(self.sdkconfig, 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"]) + if __name__ == "__main__": unittest.main()