Pergunta

Eu estou usando um módulo de registro que pode ter relatórios ativado / desativado durante a execução. Chamadas geralmente algo como:

WARN(
     "Danger Will Robinson! There are "
     + boost::lexical_cast<string>(minutes)
     + " minutes of oxygen left!"
);

Eu estou usando uma função inline para WARN, mas estou curioso para saber o quanto a otimização está acontecendo nos bastidores - a avaliação dos argumentos ao longo de todo o programa seria caro. A função WARN é algo como isto:

bool WARNINGS_ENABLED = false;
inline void WARN(const string &message) {
    if (!WARNINGS_ENABLED) {
       return;
    }
    // ...
}

Tendo em conta que a construção do argumento string não tem efeitos colaterais, vai a otimizar compilador-lo? É um certo nível de otimização necessária (-Ox em g++ por algum x)?

Foi útil?

Solução

Se você precisa ser capaz de ativar e desativar os avisos em tempo de execução seletiva, o compilador não ser capaz de otimizar a chamada.

O que você precisa é mudar o nome função para WARN2 e adicionar uma macro algo como:

#define WARN(s) do {if (WARNINGS_ENABLED) WARN2(s);} while (false)

Isso vai evitar que a avaliação de s em tempo de execução se não tiver advertências habilitado.

O do-while material é um truque que lhe permite estar em qualquer lugar usado no código (declaração nu, instrução dentro de um preparei se-bloco, a declaração dentro de um bloco se-unbraced, preparou e unbraced enquanto declarações e assim por diante) .

Outras dicas

Você pode verificar o GCC / G ++ fazer usando o S opção. A saída será o código antes que ele realmente é montado -. Consulte gcc (1)

GCC e G ++ mais ou menos se comportam da mesma neste caso. Então, eu primeiro traduziu o código em C para fazer alguns testes adicionais:

char WARNINGS_ENABLED = 0;

inline void WARN(const char* message) {
    if (!WARNINGS_ENABLED) {
        return;
    }
    puts(message);
}

int main() {
    WARN("foo");
    return 0;
}

Executar gcc O3 -S file.c e olhar para o arquivo de saída ' file.s '
Você vai ver que GCC não remover qualquer coisa !

Isso não é o que você pediu, mas, a fim de dar o compilador a oportunidade de otimizar esse código, você teria que fazer WARNINGS_ENABLED constante . Uma alternativa é fazer com que estática e não alterar o valor dentro desse arquivo. e :. Tornando-se estática tem o efeito colateral que o símbolo não é exportado

static const char WARNINGS_ENABLED = 0;

inline void WARN(const char* message) {
  if (!WARNINGS_ENABLED) {
      return;
  }
  puts(message);
}

int main() {
    WARN("foo");
    return 0;
}

GCC, em seguida, limpa completamente o código.

Eu acho que ele só tem uma chance para otimizá-lo se ele pode provar que não existem efeitos colaterais (que pode ser difícil para o compilador para fazer por uma chamada de função caro).

Eu não sou um especialista impulso, mas eu estou supondo que há uma maneira de construir um lambda que só serão avaliados para gerar a string se WARNINGS_ENABLED é verdade. Algo como ...

inline void warnFunc(some_boost_lambda &message_generator) {
  if (WARNINGS_ENABLED) {
    cerr << message_generator() << endl;
  }
}

#define WARN(msg) warnFunc(...insert boost magic here to turn msg into a lambda...)

Não, compilador deve const não otimizar o código em qualquer caso a menos que o WARNING_ENABLED global está declarado.

BTW, se WARN é função inline, você ainda vai pagar o preço de construção de mensagem (que é muito ineficiente no seu exemplo com lexical_cast e operador + em cordas), mesmo que seja desativado.

Aqui estão alguns eficiente (mínimo (próximo de zero com filial CPU prevendo) sobrecarga ao tempo de execução desativado) macros madeireiras que o apoio tanto a função e estilo fluxo de registro.

Você não pode apenas definir a coisa toda usando o pré-processador?

void inline void LogWarning(const string &message) 
{
  //Warning
}

#ifdef WARNINGS_ENABLED
#define WARN(a) LogWarning(a)
#else
#define WARN(a)
#endif

Esta é apenas a forma como o ASSERT () macro funciona. Todo o código dentro dos parênteses em WARN nem sequer fazê-lo através do pré-processador para o compilador. Isso significa que você pode fazer outras coisas como

#ifdef WARNINGS_ENABLED
// Extra setup for warning
#endif
//....
WARN(uses setup variables)

E ele irá compilar em ambos os sentidos.

Como para obter o otimizador para perceber que não há efeitos colaterais nos suportes, você pode colocar algumas declarações muito complexos lá (ou seja alto nível manipulação de string) que são difíceis de provar de qualquer maneira.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top