C ++ kompilatoren optimalisering av bestått argumenter

stemmer
9

Jeg bruker en logging modul som kan ha rapportering aktiveres / deaktiveres under kjøring. Samtaler generelt går noe sånt som:

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

Jeg bruker en innebygd funksjon for WARN, men jeg er nysgjerrig på hvor mye optimalisering som skjer bak kulissene - evaluering av argumentene gjennom hele programmet ville bli kostbart. Den WARNfunksjonen går noe sånt som dette:

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

Gitt at bygging av strengen argumentet har ingen bivirkninger, vil kompilatoren optimalisere den ut? Er en viss grad av optimalisering kreves ( -Oxi g++for noen x)?

Publisert på 12/11/2008 klokken 00:13
kilden bruker
På andre språk...                            


5 svar

stemmer
1

Jeg vil gjette at den bare har en sjanse til å optimalisere det ut om det kan bevise at det ikke er noen bivirkninger (som kan være vanskelig for kompilatoren å gjøre for en dyr funksjonskall).

Jeg er ikke et løft ekspert, men jeg gjetter det er en måte å konstruere en lambda som bare vil bli vurdert å generere strengen hvis WARNINGS_ENABLED er sant. Noe som...

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...)
Svarte 12/11/2008 kl. 00:21
kilden bruker

stemmer
6

Du kan sjekke hva GCC / G ++ gjøre ved hjelp av S -alternativet. Dette vil generere koden før det faktisk blir satt sammen - se gcc (1) .

GCC og G ++ mer eller mindre oppfører seg det samme i dette tilfellet. Så jeg først oversatte kode i C til å gjøre noen flere tester:

char WARNINGS_ENABLED = 0;

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

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

kjøre gcc -O3 -S file.c og se inn i utdatafilen ' file.s '
Du vil se at GCC ikke fjerne noe !

Det er ikke det du ba om, men for å gi kompilatoren muligheten til å optimalisere den koden ut, ville du ha å gjøre WARNINGS_ENABLED konstant . Et alternativ er å gjøre det statisk og ikke endrer verdien i den filen. Men : gjør det statisk har bivirkning at symbolet ikke blir eksportert.

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 deretter helt renser opp koden.

Svarte 12/11/2008 kl. 00:37
kilden bruker

stemmer
0

Kan du ikke bare definere hele greia ut ved hjelp av preprosessor?

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

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

Dette er bare hvordan den ASSERT () makro fungerer. All koden inne i parentes i advare ikke engang gjøre det gjennom preprosessor til kompilatoren. Det betyr at du kan gjøre andre ting som

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

Og det vil kompilere begge veier.

Som for å få optimiser å innse at det ikke er noen bivirkninger i parentes, kan du sette noen ganske komplekse uttalelser i det (dvs. høy streng manipulasjon) som er vanskelig å bevise uansett.

Svarte 12/11/2008 kl. 00:45
kilden bruker

stemmer
12

Hvis du trenger å være i stand til å selektivt aktivere og deaktivere advarslene på driftstid, vil kompilatoren ikke være i stand til å optimalisere ut samtalen.

Det du trenger er å endre navnet på funksjonen til WARN2og legge en makro noe sånt som:

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

Dette vil hindre at evalueringen av s ved kjøring med mindre du har advarsler aktivert.

Gjør-mens ting er et triks som gjør at den kan brukes hvor som helst i koden (naken regnskap, innen avstivet if-blokken, føres som en uavstivet if-blokken, avstivet og uavstivet mens uttalelser og så videre).

Svarte 12/11/2008 kl. 00:52
kilden bruker

stemmer
1

Nei, kompilatoren bør ikke optimalisere koden i alle fall hvis den globale WARNING_ENABLED er erklært konst.

BTW, hvis WARN er inline-funksjonen, vil du fortsatt betale prisen for meldingen konstruksjon (som er svært ineffektive i ditt eksempel med lexical_cast og operatør + på strenger), selv om det er deaktivert.

Her er noen effektive (minimal (nær null med gren forutsi CPU) overhead når runtime deaktivert) logging makroer som støtter både funksjon og stream stil logging.

Svarte 12/11/2008 kl. 01:35
kilden bruker

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more