Лучший способ заменить использование тяжелых исключений? - PullRequest
4 голосов
/ 30 января 2010

У меня есть старый проект C ++, который я сделал некоторое время назад. Ну, это эмулятор процессора. Всякий раз, когда происходит сбой процессора (например, деление на ноль, отладка прерывания точки останова и т. Д.) В моем коде, он просто делает throw, а в моем основном цикле у меня происходит что-то вроде этого:

try{
    *(uint32_t*)&op_cache=ReadDword(cCS,eip);
    (this->*Opcodes[op_cache[0]])();
    eip=(uint16_t)eip+1;
}
catch(CpuInt_excp err){
    err.code&=0x00FF;
    switch(err.code){
        case 0:
        case 1: //.....
        Int16(err.code);
        break;
        default:
        throw CpuPanic_excp("16bit Faults",(err.code|0xF000)|TRIPLE_FAULT_EXCP);
        break;
    }
}

И простой пример кода операции (вытащенный из воздуха)

if(**regs16[AX]==0){
  throw CpuInt_excp(0); //throw divide by zero error
}

Что этот код делает в основном, так это просто читает код операции и, если возникла исключительная ситуация, затем вызывает соответствующее прерывание (в ЦПУ, которое просто меняет EIP)

Что ж, в основном цикле накладные расходы try{}catch{} действительно складываются. Это не преждевременная оптимизация, я профилировал ее и вспомогательные функции исключений gcc (даже без каких-либо сбоев и, следовательно, без сбоев), а вспомогательные функции занимали более 10% от общего времени выполнения долго эмулируемой программы.

Так! Что было бы лучшим способом замены исключений в этом случае? Я бы предпочел не отслеживать отслеживаемые значения, потому что у меня уже написана тонна кода и потому, что отслеживать их действительно сложно когда функции становятся действительно глубокими.

Ответы [ 3 ]

3 голосов
/ 30 января 2010

Вы не показали свой цикл, но я предполагаю, что в псевдокоде это:

while (some_condition) {
    // Your try..catch block:
    try {
        // Do an op
    }
    catch (CpuInt_excp err) {
        // Handle the exception
    }
}

Вы можете переместить try..catch на уровень:

done = false;
while (!done) {
    try {
        while (some_condition) {
            // Do an op
        }
        done = true;
    }
    catch (CpuInt_excp err) {
        // Handle the exception
    }
}

Там я включил два цикла, потому что я предполагаю, что если возникнет исключение, вы захотите продолжить (трудно сказать, не зная, что вы делаете в Int16, но я думаю, что вы позволяете продолжая после непанических исключений). Естественно, если вам не нужно продолжать, вам нужен только один цикл.

Внешний цикл просто перезапускает вещи после исключения. Он может проверять то же условие, что и внутренний цикл, если это условие не дорого проверять (например, это программный счетчик или что-то в этом роде), или может иметь флаг, как указано выше, если условие дорого проверять.

1 голос
/ 30 января 2010

Как насчет перемещения try / catch из вашего внутреннего цикла?Потребовалось бы больше бухгалтерии в улове и некоторые дополнительные издержки, возвращающиеся в ваш внутренний цикл, не начиная с вершины, но вы заплатили бы только тогда, когда исключение действительно сработало, а не все время.

0 голосов
/ 30 января 2010

Похоже, вы записываете состояние процессора в переменных-членах, поскольку ваши методы кода операции не принимают никаких параметров. С риском констатировать очевидное, почему бы не сделать то же самое для состояния исключения? Тогда вам не придется иметь дело с возвращаемым значением. Вместо этого вам просто понадобятся функции кода операции, чтобы установить состояние исключения, вернуть и позволить основному циклу проверить состояние исключения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...