我有一组范围,例如{(2-8),(13-22),(380-7931),(40032-63278)}。为简单起见,我们可以假设它们不重叠(重叠范围已经合并)。
我的目标是使用一组给定的“长度”组合来“覆盖”这些范围,例如{4,64,1024,16384}。我被限制使用最多N个长度,例如N = 32。我不在乎我使用多少“长度”,只要我低于我的最大值,但我想最小化总“额外”区域 - 数字“覆盖”长度不在初始范围集中。
由(2-66)覆盖的示例{(2-8)}(使用64的一个长度)具有58个“额外”数字。 {(2-8)}覆盖{(2-6),(6-10)}(两个长度为4)只有2个“额外”数字,是优选的。
我的真实世界应用涉及对固定MMU TLB进行预编程,以确保只能访问某些范围的存储器地址(TLB未命中因此代表禁止访问,并且可以相应地处理)。我想尽可能紧密地覆盖范围,以便尽早发现违规行为,但我只有32个插槽可供使用,4个固定页面大小。我可以手动调整我的代码到足够的性能水平,但我很好奇是否有更优雅/通用的解决方案。这似乎与背包问题有关,但不同的是它很难搜索。
答案 0 :(得分:1)
这可以表示为Shortest path problem的变体。
我们需要涵盖一组总长 M 的范围,最多 N 页面。 页面可能具有 L 不同的长度,它们未对齐(可以放置在任何地址)。总“额外”区域与页面总长度之间的差异等于常量 M ,这样可以最小化页面的总长度。 / p>
让我们构建一个与此问题相关的图表。任何范围中的每个内存地址都在图中具有相应的顶点。从给定地址开始,每个顶点都有 L 传出边,对应 L 页。每条边的长度等于 page 长度。每个边都到达图中的某个顶点,具体取决于相应的 page 结束的位置:
由于结果图是DAG,因此可以通过以拓扑顺序处理顶点(或者更简单地按照相应的存储器地址的顺序)在线性时间中找到最短路径。
对于每个顶点,保留一个 N 对的数组{path-length,back-pointer}。当最短路径算法访问任何顶点时,使用路径中的跳数索引此数组,如果路径短于存储的路径长度,则替换{path-length,back-pointer}。处理每个顶点时,找到属于 destination 顶点的对数组中的最短路径,然后使用反向指针重建路径。此路径描述了最佳封面。
最坏情况时间复杂度O(L * M * N)由属于每个顶点(N)的最大边数(L * M)和数组中的元素数确定。如果范围是稀疏的,则大多数边缘到达某些范围的起始地址,大多数顶点,对应于内部地址未使用,时间复杂度要小得多。
此算法需要O(M * N)空间,但对于稀疏范围,如果我们将所有图形顶点(或者可能是所有长度/指针对)放入哈希映射中,这可能会显着减少
答案 1 :(得分:0)
考虑您想要覆盖的范围是非常低值的区间(让我们称之为“范围”),并且间隙(称之为“额外”)是非常昂贵的区间。现在我们希望以最多N个间隔(称为“覆盖”)最小化总成本,其覆盖所有“范围”并且可能包含一些“额外”。 以下算法本质上是贪婪的。
首先考虑你想要覆盖的所有间隔(“范围”)以及它们之间的“额外”。
1)从“范围”的最小值到最大值间隔很长的间隔。
2)迭代并删除之间最昂贵的“额外”(即最大跨度) 并且将该divison视为创建一个额外的“封面”,直到封面的数量变为N或者您用完了昂贵的“额外”。
答案 2 :(得分:0)
自下而上的贪婪方法,当每个长度是最后一个的倍数时起作用:
从一组最小长度间隔开始,最小限度地覆盖所有范围。迭代合并最长的运行,直到低于最大范围计数。
在你的情况下,在TLB上,你可能有对齐约束,这会使问题变得有点棘手。