c++ - 为什么动态链接需要这么长时间?

标签 c++ linux performance static-linking dynamic-linking

所以我编写了一个非常非常基本的虚拟机,它运行在 c- 的一个小子集上。我正在对其进行分析,试图看看瓶颈是什么,结果真的让我感到困惑。 73%的时间用在了dl_relocate_object函数中。在该函数中,85% 花费在 _dl_lookup_symbol_x 上。

我对动态库的内部了解不多,但感觉有些不对劲。根据一点点搜索,这意味着 75% 的时间,我的程序正在通过动态库搜索函数。这对我来说听起来很荒谬。

当我静态链接二进制文件时,速度提高了 2 倍以上,最差的函数成为我的 VM::run 函数,速度为 90%。在该函数中,75% 花费在 ifstream 中。

基本上我想知道是否有人知道为什么会发生这种情况或者这是否正常。当我动态链接时,我的程序的运行速度与必须对原始文本进行词法分析和解析的程序的解释版本的运行速度大致相同。

这是我的代码:

#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[] 作为堆栈。这些更改都没有任何区别。

最佳答案

感谢上面的一些评论和此链接 Is a DLL slower than a static link?我决定用更大的输入进行测试并得到了预期的结果。显然,循环迭代非常快,即使迭代了 1_000 次,动态链接仍然花费了大部分时间。经过 1_000_000 次迭代,代码按预期执行。静态和动态的运行时间非常相似。此外,当查看 1_000_000 条指令时,它的运行速度比解释器快大约 9 倍。

旁注,我最初在 while 循环之后有指令,这就是我有 goto 的原因。后来我把它们去掉了。我想它现在已经过时了。

关于c++ - 为什么动态链接需要这么长时间?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54661086/

相关文章:

c++ - FindFirstFile 未记录的通配符或错误?

linux - 在核心转储中检查自旋锁是否被持有

linux - 如何删除图案线之间的所有线

java - 当索引的范围通过 and 限制时,Hotspot 可以消除边界检查吗?

javascript - 在 canvas javascript 上绘制 10,000 个对象

c++模板enable_if无法将函数定义与现有声明匹配

android - 在 Android 中升级 OpenSSL

C++: 0xC0000005: 访问冲突写入位置 0x00000000

linux - 无法在QT中打开sqlite3数据库

android - 使用 libgdx 绘制大背景图像 - 最佳实践?