Итак, я написал очень простую виртуальную машину, которая работает на небольшом подмножестве 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();
}
Сторонаобратите внимание, я попытался загрузить весь файл в char [] во время инициализации виртуальной машины и затем использовать char [] вместо ifstream во время выполнения.Я также попытался использовать int [] для стека.Ни одно из этих изменений не имело никакого значения.