Ada 记录:检测丢失的字节,提出优化建议
Ada records : detect lost bytes, propose optimisation
我正在处理一个具有显着 RAM 限制的遗留 Ada 项目。
为了节省额外功能的内存,我想分析所有记录定义,以便:
- 检测漏洞(即浪费字节)
- 提出最小化内存占用的记录声明顺序(或表示)(使用一些应该类似于Knapsack problem的算法)
请注意,我(还)没有在保存任何丢失的 bits 的过程中(这里不需要 pragma pack
,也不需要代表. 用于严格连续记录的子句,如 中)。目前只有字节。
简化示例(真实世界的记录要复杂得多,可能有判别式、标记类型):
type My_Record is record
field1 : Foo; -- enum with 3 values
field2 : Bar; -- some other record
field3 : Float; -- 32 bits
field4 : Flex;-- enum with 12 values
end record;
它的 -gnatR2s
输出看起来像(32 位世界):
for My_Record'Alignment use 4;
for My_Record use record
field1 at 0 use 0.. 7;
field2 at 4 use 0..47; -- 3 bytes lost from field 1
field3 at 12 use 0..31; -- 2 bytes lost from field 2
field4 at 16 use 0.. 7; -- another 3 bytes lost
end record;
我想做什么(内存使用优化记录):
-- rewrite record, not the preferred way since record writing order may have some human readable context purpose
type My_Record is record
field2 : Bar; -- 2 unused bytes
field1 : Foo; -- 1 byte left
field4 : Flex; -- 0 byte left
field3 : Float; -- 4 bytes used
-- 0 wasted bytes
end record;
或:
-- preferred way : keep record declaration, but force rep. clause
type My_Record is record
field1 : Foo;
field2 : Bar;
field3 : Float;
field4 : Flex;
end record;
-- optimization is here
for My_Record'alignment use 4;
for My_Record use record
field2 at 0 use 0..47;
field1 at 6 use 0.. 7; -- exploit the Bar unused bytes
field4 at 7 use 0.. 7; -- exploit the Bar unused bytes
field3 at 8 use 0..31;
end record;
(对于示例中的任何错误,我深表歉意,希望您能理解)
我该怎么做?
- ASIS(但我的技能是0%,我什至不确定它能做我想做的事)
- libadalang(不编译单元如何获取rep.clauses?)
- 只需在所有编译单元上使用
-gnatR2s
并在 python 中编写一个 .rep
解析器
- 有一个隐藏的编译选项、一个 pragma 或一个现有的 GNAT 工具可以提供帮助(比如 pragma component_alignment or pragma optimize_alignment,但我不能说他们是否解决了这个问题,因为它会影响 对齐,但不一定对齐+排序)
有关 repl 子句的上下文、Ada 参考手册和 GNAT 的细微差异,可以阅读 this link
我认为您已经说明了所有选项:使用您提到的特定于实现的 pragma,手动优化 and/or 编写一个自定义优化器来分析表示子句并使用一些(可调的)成本函数来优化它们space、访问时间等。编写自定义优化器在时间和精力方面肯定是最昂贵的。我不知道任何其他 "hidden" 选项(如果它们被隐藏,那可能是有原因的)。
我会先制定一个 space 预算(如果可能的话),然后分析每种记录类型有多少填充字节,以便更好地了解它们的分布方式并估计潜力通过删除 all 填充字节可以恢复的最大字节数(请注意实例计数:被大量实例化的小型类型可能比大型类型对内存占用产生更大的影响只实例化一次)。只有这样我才会确定减少填充字节的策略:对所有类型或仅对某些类型使用 pragma,手动优化某些记录或断定您确实需要自定义优化器。当然,时间+成本在这里很重要。如果工作必须在明天之前完成,我不建议进行广泛的分析。
为了分析,我只解析 -gnatR2
的输出。据我所知(但你可能想检查一下),libadalang
侧重于源代码(可能没有说明明确的表示条款)。关于 ASIS,我认为它可能有用,但我怀疑它是否值得付出努力。使用某种脚本语言解析 -gnatR2
的输出可能会更省时。
我正在处理一个具有显着 RAM 限制的遗留 Ada 项目。
为了节省额外功能的内存,我想分析所有记录定义,以便:
- 检测漏洞(即浪费字节)
- 提出最小化内存占用的记录声明顺序(或表示)(使用一些应该类似于Knapsack problem的算法)
请注意,我(还)没有在保存任何丢失的 bits 的过程中(这里不需要 pragma pack
,也不需要代表. 用于严格连续记录的子句,如
简化示例(真实世界的记录要复杂得多,可能有判别式、标记类型):
type My_Record is record
field1 : Foo; -- enum with 3 values
field2 : Bar; -- some other record
field3 : Float; -- 32 bits
field4 : Flex;-- enum with 12 values
end record;
它的 -gnatR2s
输出看起来像(32 位世界):
for My_Record'Alignment use 4;
for My_Record use record
field1 at 0 use 0.. 7;
field2 at 4 use 0..47; -- 3 bytes lost from field 1
field3 at 12 use 0..31; -- 2 bytes lost from field 2
field4 at 16 use 0.. 7; -- another 3 bytes lost
end record;
我想做什么(内存使用优化记录):
-- rewrite record, not the preferred way since record writing order may have some human readable context purpose
type My_Record is record
field2 : Bar; -- 2 unused bytes
field1 : Foo; -- 1 byte left
field4 : Flex; -- 0 byte left
field3 : Float; -- 4 bytes used
-- 0 wasted bytes
end record;
或:
-- preferred way : keep record declaration, but force rep. clause
type My_Record is record
field1 : Foo;
field2 : Bar;
field3 : Float;
field4 : Flex;
end record;
-- optimization is here
for My_Record'alignment use 4;
for My_Record use record
field2 at 0 use 0..47;
field1 at 6 use 0.. 7; -- exploit the Bar unused bytes
field4 at 7 use 0.. 7; -- exploit the Bar unused bytes
field3 at 8 use 0..31;
end record;
(对于示例中的任何错误,我深表歉意,希望您能理解)
我该怎么做?
- ASIS(但我的技能是0%,我什至不确定它能做我想做的事)
- libadalang(不编译单元如何获取rep.clauses?)
- 只需在所有编译单元上使用
-gnatR2s
并在 python 中编写一个 - 有一个隐藏的编译选项、一个 pragma 或一个现有的 GNAT 工具可以提供帮助(比如 pragma component_alignment or pragma optimize_alignment,但我不能说他们是否解决了这个问题,因为它会影响 对齐,但不一定对齐+排序)
.rep
解析器
有关 repl 子句的上下文、Ada 参考手册和 GNAT 的细微差异,可以阅读 this link
我认为您已经说明了所有选项:使用您提到的特定于实现的 pragma,手动优化 and/or 编写一个自定义优化器来分析表示子句并使用一些(可调的)成本函数来优化它们space、访问时间等。编写自定义优化器在时间和精力方面肯定是最昂贵的。我不知道任何其他 "hidden" 选项(如果它们被隐藏,那可能是有原因的)。
我会先制定一个 space 预算(如果可能的话),然后分析每种记录类型有多少填充字节,以便更好地了解它们的分布方式并估计潜力通过删除 all 填充字节可以恢复的最大字节数(请注意实例计数:被大量实例化的小型类型可能比大型类型对内存占用产生更大的影响只实例化一次)。只有这样我才会确定减少填充字节的策略:对所有类型或仅对某些类型使用 pragma,手动优化某些记录或断定您确实需要自定义优化器。当然,时间+成本在这里很重要。如果工作必须在明天之前完成,我不建议进行广泛的分析。
为了分析,我只解析 -gnatR2
的输出。据我所知(但你可能想检查一下),libadalang
侧重于源代码(可能没有说明明确的表示条款)。关于 ASIS,我认为它可能有用,但我怀疑它是否值得付出努力。使用某种脚本语言解析 -gnatR2
的输出可能会更省时。