c++ - 为什么动态链接要花这么多时间?
问题描述
所以我写了一个非常非常基本的虚拟机,它运行在 c- 的一个小子集上。我正在对其进行分析以尝试查看瓶颈是什么,结果真的让我感到困惑。dl_relocate_object 函数中使用了 73% 的时间。在该函数中,85% 用于 _dl_lookup_symbol_x。
我对动态库的内部了解不多,但我觉得有些不对劲。基于一点点搜索,这意味着 75% 的时间,我的程序正在通过动态库搜索函数。这对我来说听起来很荒谬。
当我静态链接二进制文件时,速度提高了 2 倍以上,最差的功能变成了我的 VM::run 功能,达到 90%。在该功能中,75% 用于 ifstream。
基本上我想知道是否有人知道为什么会发生这种情况,或者这是否正常。当我动态链接时,我的程序的运行速度与必须对原始文本进行 lex 和解析的程序的解释版本大致相同。
这是我的代码:
#include <iostream>
#include <vector>
#include <fstream>
using namespace std;
enum opcodes{halt, loadInt, storeVar, loadVar, readVar, writeInt, writeString,
add, sub, mul, divide, eq, neq, leq, ls, gr, geq, notVal, andVal, orVal};
class VM {
unsigned long pc;
vector<int> stack;
ifstream imem;
char buf[1024*64];
int var[256];
public:
VM(char* file){
imem.open(file);
imem >> noskipws;
imem.rdbuf()->pubsetbuf(buf, 1024*64);
}
void run(){
int x, y;
char c;
char instruction;
while(imem >> instruction){
switch(instruction){
case halt:
goto exit_loop;
case writeString:
imem >> c;
while(c != 0){
cout << c;
imem >> c;
}
cout << endl;
break;
case loadInt:
imem >> c;
x = (c << 24);
imem >> c;
x |= (c << 16);
imem >> c;
x |= (c << 8);
imem >> c;
x |= c;
stack.push_back(x);
break;
case storeVar:
imem >> c;
var[(int)c] = stack.back();
stack.pop_back();
break;
case loadVar:
imem >> c;
stack.push_back(var[(int)c]);
break;
case readVar:
imem >> c;
cin >> var[(int)c];
break;
case writeInt:
x = stack.back();
stack.pop_back();
cout << x << endl;
break;
case add:
y = stack.back();
stack.pop_back();
x =stack.back();
stack.pop_back();
stack.push_back(x + y);
break;
case sub:
y = stack.back();
stack.pop_back();
x =stack.back();
stack.pop_back();
stack.push_back(x - y);
break;
case mul:
y = stack.back();
stack.pop_back();
x =stack.back();
stack.pop_back();
stack.push_back(x * y);
break;
case divide:
y = stack.back();
stack.pop_back();
x =stack.back();
stack.pop_back();
stack.push_back(x / y);
break;
case eq:
y = stack.back();
stack.pop_back();
x =stack.back();
stack.pop_back();
stack.push_back((int)(x == y));
break;
case neq:
y = stack.back();
stack.pop_back();
x =stack.back();
stack.pop_back();
stack.push_back((int)(x != y));
break;
case leq:
y = stack.back();
stack.pop_back();
x =stack.back();
stack.pop_back();
stack.push_back((int)(x <= y));
break;
case ls:
y = stack.back();
stack.pop_back();
x =stack.back();
stack.pop_back();
stack.push_back((int)(x < y));
break;
case gr:
y = stack.back();
stack.pop_back();
x =stack.back();
stack.pop_back();
stack.push_back((int)(x > y));
break;
case geq:
y = stack.back();
stack.pop_back();
x =stack.back();
stack.pop_back();
stack.push_back((int)(x >= y));
break;
case notVal:
x = stack.back();
stack.pop_back();
stack.push_back((int)(!x));
break;
case andVal:
y = stack.back();
stack.pop_back();
x =stack.back();
stack.pop_back();
stack.push_back((int)(x && y));
break;
case orVal:
y = stack.back();
stack.pop_back();
x =stack.back();
stack.pop_back();
stack.push_back((int)(x || y));
break;
default:
cout << "Error: Unknown Instruction" << endl;
goto exit_loop;
}
}
exit_loop: ;
};
};
int main(int argc, char** argv) {
if(argc <= 1){
cout << "Bad input" << endl;
}
VM vm(argv[1]);
vm.run();
}
旁注,我尝试在 VM 初始化期间将整个文件加载到 char[] 中,然后在运行期间使用 char[] 而不是 ifstream。我也尝试过使用 int[] 作为堆栈。这些变化都没有任何区别。
解决方案
感谢上面的一些评论和这个链接DLL 比静态链接慢吗?我决定用更大的输入进行测试并得到预期的结果。显然循环迭代是如此之快,以至于即使有 1_000 次迭代,动态链接仍然需要大部分时间。通过 1_000_000 次迭代,代码按预期执行。静态和动态都在非常相似的时间运行。此外,在查看 1_000_000 指令时,它的运行速度比解释器快 9 倍。
旁注,我最初在 while 循环之后有说明,这就是我有 goto 的原因。我后来删除了它们。我想它现在已经过时了。
推荐阅读
- apache-spark - 跨多个列搜索子字符串
- java - 使用 Jackson 将其反序列化为对象后,如何访问我的 GeoJSON 数据
- java - 数据库中的值每天递增一
- php - Symfony 4 - 将 VichUploader 与 Dompdf 一起使用?
- angular - Ionic 4 通过 GUI (ion-datetime) 自动更改日期设置
- c++ - 如何生成总和为 0.0 的 n 大小的随机浮点数组?
- javascript - 使用 JavaScript 在现有的本地 XML 中添加新元素
- spring-boot - Thymeleaf #aggregates.sum 具有多个条件
- dataframe - 从当前数据框的架构中为 Spark 数据框(在代码中)编写架构
- python - Nan在Python中没有辍学