为什么动态链接需要这么多时间?

时间:2019-02-13 01:18:07

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

因此,我写了一个非常基本的虚拟机,该虚拟机在c-的一小部分上运行。我对它进行了性能分析,以尝试查看瓶颈所在,结果使我感到困惑。 dl_relocate_object函数使用了73%的时间。在该函数中,_dl_lookup_symbol_x花费了85%。

我对动态库的内部了解不多,但是我觉得有些问题。基于一点点搜索,这意味着我的程序有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 []作为堆栈。这些变化都没有任何改变。

1 个答案:

答案 0 :(得分:0)

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

请注意,我最初在while循环后使用了指令,这就是为什么要使用goto的原因。后来我删除了它们。我想它已经过时了。

相关问题