优化(重新编译)继承每个派生的虚拟方法 class
Optimize (recompile) inherit virtual methods for each derived class
假设我们有一个“master”class,它有一个名为“Bulk”的方法来通过虚拟方法执行 N 次交互。
此虚拟方法可以被许多 class 覆盖,但只能被覆盖一次。
出于性能原因,我们必须尽可能地减少 calling/vtable 分辨率的成本。 (示例:++10Gb 网络数据包生成)
我解决这个问题的一个想法是使方法 Bulk 虚拟化,并“以某种方式”强制它在每个派生的 class 上重新编译,这样我们就可以只进行一次 VTABLE 搜索而不是 N 次搜索,并且从 inlining/SSE/etc 获得一些改进。
然而,阅读 de ASM 我只得到一个通用的“批量”方法,它再次在 vtable 中搜索 N 次。
¿您知道有什么方法可以强制该方法重新编译(当然不需要在每个派生的 class 上复制粘贴它的代码)或任何其他方法来减少调用和 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;
};
derived1.hpp
#pragma once
#include "master.hpp"
class derived1 final: public master
{
virtual inline unsigned once() final { return 7; }
};
derived2.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;
}
我正在使用的编译命令:g++ main.cpp -S -O3 --std=gnu++17
已编译的批量循环:
movq 0(%rbp), %rax
movq %rbp, %rdi
call *8(%rax)
addl %eax, %r12d
subl , %ebx
jne .L2
我不是很理解你的问题 ;)
但是,我建议在您不需要虚拟分派时避免使用虚拟分派,而不是尝试围绕虚拟 table 进行优化(这是一个实现细节,因此优化不会针对 table) .也许 CRTP 是一个选项。
万一你想多态地使用 derivedX
,你可以添加一个公共基础 class:
#include <iostream>
#include <string>
using namespace std;
struct base {
virtual std::string Bulk(unsigned n) = 0;
virtual ~base(){}
};
template <typename T>
struct master : base {
virtual std::string Bulk(unsigned n) {
std::string ret = "";
auto ptr = static_cast<T*>(this);
for (int i = 0; i < n; ++i) ret += ptr->once();
return ret;
}
};
struct derived1 final : public master<derived1> {
std::string once() { return "a"; }
};
struct derived2 final : public master<derived2> {
std::string once() { return "b"; }
};
int main()
{
derived1 d1;
derived2 d2;
cout << d1.Bulk(3) << endl;
cout << d2.Bulk(3) << endl;
}
假设我们有一个“master”class,它有一个名为“Bulk”的方法来通过虚拟方法执行 N 次交互。
此虚拟方法可以被许多 class 覆盖,但只能被覆盖一次。 出于性能原因,我们必须尽可能地减少 calling/vtable 分辨率的成本。 (示例:++10Gb 网络数据包生成)
我解决这个问题的一个想法是使方法 Bulk 虚拟化,并“以某种方式”强制它在每个派生的 class 上重新编译,这样我们就可以只进行一次 VTABLE 搜索而不是 N 次搜索,并且从 inlining/SSE/etc 获得一些改进。 然而,阅读 de ASM 我只得到一个通用的“批量”方法,它再次在 vtable 中搜索 N 次。
¿您知道有什么方法可以强制该方法重新编译(当然不需要在每个派生的 class 上复制粘贴它的代码)或任何其他方法来减少调用和 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;
};
derived1.hpp
#pragma once
#include "master.hpp"
class derived1 final: public master
{
virtual inline unsigned once() final { return 7; }
};
derived2.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;
}
我正在使用的编译命令:g++ main.cpp -S -O3 --std=gnu++17
已编译的批量循环:
movq 0(%rbp), %rax
movq %rbp, %rdi
call *8(%rax)
addl %eax, %r12d
subl , %ebx
jne .L2
我不是很理解你的问题 ;)
但是,我建议在您不需要虚拟分派时避免使用虚拟分派,而不是尝试围绕虚拟 table 进行优化(这是一个实现细节,因此优化不会针对 table) .也许 CRTP 是一个选项。
万一你想多态地使用 derivedX
,你可以添加一个公共基础 class:
#include <iostream>
#include <string>
using namespace std;
struct base {
virtual std::string Bulk(unsigned n) = 0;
virtual ~base(){}
};
template <typename T>
struct master : base {
virtual std::string Bulk(unsigned n) {
std::string ret = "";
auto ptr = static_cast<T*>(this);
for (int i = 0; i < n; ++i) ret += ptr->once();
return ret;
}
};
struct derived1 final : public master<derived1> {
std::string once() { return "a"; }
};
struct derived2 final : public master<derived2> {
std::string once() { return "b"; }
};
int main()
{
derived1 d1;
derived2 d2;
cout << d1.Bulk(3) << endl;
cout << d2.Bulk(3) << endl;
}