【发布时间】:2020-12-17 11:02:23
【问题描述】:
假设我们有一个“主”类,其中包含一个名为“Bulk”的方法,用于通过虚拟方法执行 N 次交互。
这个虚方法可以被许多类覆盖,但只能覆盖一次。 出于性能原因,我们必须尽可能减少调用/vtable 解析的成本。 (示例:++10Gb 网络数据包生成)
我解决这个问题的一个想法是使方法 Bulk 虚拟并“以某种方式”强制它在每个派生类上重新编译,因此我们可以只进行一次 VTABLE 搜索而不是 N 并且还可以从内联/上证所/等 但是,阅读 de ASM 我只得到的是一个通用的“批量”方法,它再次在 vtable 中搜索 N 次。
¿您是否知道强制重新编译该方法的任何方法(当然无需在每个派生类上复制粘贴其代码)或任何其他方法来减少调用和 VTABLE 搜索?我认为应该经常询问类似的要求,但我没有找到任何东西......
可玩的示例代码:
master.hpp
#pragma once
#include <string>
class master
{
public:
virtual unsigned Bulk(unsigned n)
{
unsigned ret = 0;
for (int i = 0; i < 144; ++i)
ret += once();
return ret;
}
virtual unsigned once() = 0;
};
派生1.hpp
#pragma once
#include "master.hpp"
class derived1 final: public master
{
virtual inline unsigned once() final { return 7; }
};
派生2.hpp
#pragma once
#include "master.hpp"
class derived2 final: public master
{
virtual inline unsigned once() final { return 5; }
};
main.cpp
#include "derived1.hpp"
#include "derived2.hpp"
#include <iostream>
using namespace std;
int main()
{
derived1 d1;
derived2 d2;
cout << d1.Bulk(144) << endl;
cout << d2.Bulk(144) << endl;
return 0;
}
编译我正在使用的cmd:g++ main.cpp -S -O3 --std=gnu++17
编译的批量循环:
movq 0(%rbp), %rax
movq %rbp, %rdi
call *8(%rax)
addl %eax, %r12d
subl $1, %ebx
jne .L2
【问题讨论】:
-
实际上需要
once和public吗?还是仅在Bulk中调用?如果是后者,或许一开始就不需要虚拟化? -
调用虚函数几乎没有性能开销(它只会多读两次指针)。并且一个理智的编译器在重复调用虚函数时不会重复读取指针。
-
感谢您的评论@largest_prime_is_463035818。将
once设为私有是没有问题的,但是,如果它不是虚拟的,则无法从Bulk正确调用它 -
感谢您的评论@Sprite。我已经编辑了帖子并包含了循环 ASM 代码。除非我错了,否则我认为每次迭代都会检查 VTABLE。此外,在任何情况下,显式的“调用”都不允许进一步优化
标签: c++ optimization g++ vtable