From ee0f8adaed94ac51b0e9ddd5c329cc12d73720b5 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 686defc3aa..5e08e177d3 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 7be3c3ad5d..50bed4aee5 100755 --- a/tools/ldgen/test/test_generation.py +++ b/tools/ldgen/test/test_generation.py @@ -1366,6 +1366,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()