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.
This commit is contained in:
Renz Bagaporo 2020-04-24 21:57:05 +08:00
parent 44d1c90d25
commit ccbca45709
2 changed files with 65 additions and 3 deletions

View File

@ -322,8 +322,6 @@ class GenerationModel:
return scheme_dictionary return scheme_dictionary
def generate_rules(self, sdkconfig, sections_infos): def generate_rules(self, sdkconfig, sections_infos):
placement_rules = collections.defaultdict(list)
scheme_dictionary = self._build_scheme_dictionary() scheme_dictionary = self._build_scheme_dictionary()
# Generate default rules # Generate default rules
@ -373,14 +371,19 @@ class GenerationModel:
for mapping_rules in all_mapping_rules.values(): for mapping_rules in all_mapping_rules.values():
self._create_exclusions(mapping_rules, default_rules, sections_infos) self._create_exclusions(mapping_rules, default_rules, sections_infos)
placement_rules = collections.defaultdict(list)
# Add the default rules grouped by target # Add the default rules grouped by target
for default_rule in default_rules: for default_rule in default_rules:
existing_rules = placement_rules[default_rule.target] existing_rules = placement_rules[default_rule.target]
if default_rule.get_section_names(): if default_rule.get_section_names():
existing_rules.append(default_rule) 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 # 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: for mapping_rule in mapping_rules:
existing_rules = placement_rules[mapping_rule.target] existing_rules = placement_rules[mapping_rule.target]
if mapping_rule.get_section_names(): if mapping_rule.get_section_names():

View File

@ -1176,6 +1176,65 @@ class GenerationModelTest(unittest.TestCase):
self._compare_rules(expected, actual) 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__": if __name__ == "__main__":
unittest.main() unittest.main()