c - Koden er langsommere på Linux sammenlignet med Windows

Indlæg af Hanne Mølgaard Plasc

Problem



Efter at have ændret min C-kode, (skrevet oprindeligt til Windows og compiled under VS 2008), kørte jeg den på Linux. Til min overraskelse er det nu mindst 10 gange langsommere end Windows-versionen.


Ved hjælp af Profiler-værktøjer fandt jeg ud af, at følgende funktion bruger det meste af tiden i programmet:


/* advance by n bits */

void Flush\_Buffer(N)
int N;
{
 int Incnt;


 ld->Bfr <<= N;

Incnt = ld->Incnt -= N;

if (Incnt <= 24)
{
if (System\_Stream\_Flag && (ld->Rdptr >= ld->Rdmax-4))
{
do
{
if (ld->Rdptr >= ld->Rdmax)
      Next\_Packet();
    ld->Bfr |= Get\_Byte() << (24 - Incnt);
    Incnt += 8;
  }
  while (Incnt <= 24);
}
else if (ld->Rdptr < ld->Rdbfr+2044)
{
  do
  {
    ld->Bfr |= *ld->Rdptr++ << (24 - Incnt);
    Incnt += 8;
  }
  while (Incnt <= 24);
}
else
{
  do
  {
    if (ld->Rdptr >= ld->Rdbfr+2048)
      Fill\_Buffer();
    ld->Bfr |= *ld->Rdptr++ << (24 - Incnt);
    Incnt += 8;
  }
  while (Incnt <= 24);
}
ld->Incnt = Incnt;
}

}


Denne funktion tog ubetydelig tid på vinduer. på Linux tager det næsten 14 sekunder. Hvad forkert har jeg begået her?


Der er ingen systemopkald her, så denne kodeafdeling skal være uafhængig af OS-specifikke opkald og skal således køre i samme tid.


(Min guess: Denne funktion bliver kaldt flere gange, så det kan være, at profileren akkumulerer tiden for samtlige opkald. I et sådant tilfælde tror jeg, at et af problemerne kan være, at funktionen ikke hurtigt får sin input parameter som sammenlignet med Windows-tilfælde.)


Hvad forkert har jeg begået her? Nogen gæt?


Rgrds,


H

Bedste reference


Du kan prøve at annotere alle kodeveje i din kode med tællere. I slutningen af ​​programmet indeholder hver tæller information om, hvor mange gange kodebanen er blevet udført. Sammenligning af disse tal line-by-line mellem Windows-versionen og Linux-versionen kan afslører, at programmet følger forskellige kodeveje. Afhængig af karakteren af ​​kodevejene kan forskellene muligvis forklare, hvorfor Linux-versionen er langsommere end Windows-versionen.


int count[100];

// Call this function at the end of program 
void PrintCounts() {
    int i;
    for(i=0; i<100; i++) printf("\%d
", count[i]);
}

void Flush\_Buffer(int N) {
  int Incnt;

  ld->Bfr <<= N;

  Incnt = ld->Incnt -= N;

  if (Incnt <= 24) {
    count[0]++;
    if (System\_Stream\_Flag && (ld->Rdptr >= ld->Rdmax-4)) {
      count[1]++;
      do {
         count[2]++;
         ...

Andre referencer 1


Dette er mere end et svar, men det passer ikke helt ind i en kommentar, så jeg håber du vil ikke holde det imod mig.


Udtrykket 'profilering' har flere relaterede men forskellige betydninger. I en abstrakt sammenhæng betyder det at 'måle' dit program, normalt med hensyn til visse runtime data. Det er dog ikke det samme som at 'timing' dit program. Timing er en form for profilering, men der er mange andre.


Antag for eksempel, at du er usikker på, om en datastruktur skal være en std::set (et træ) eller et std::unordered\_set (et hashbord). Der er ikke et universelt svar, da det afhænger af hvad du brug det til, og hvilke data du behandler. Det er helt muligt, at du ikke kan kende det rigtige svar, indtil du angiver de faktiske, virkelige data, som du vil bruge. I så fald betyder 'profil og beslutning', at du laver to versioner af dit program, kør dem både mod dine rigtige data og måler runtime. Jo hurtigere er sandsynligvis den du ønsker.


På den anden side har GCC et værktøj, der kaldes 'profiler', der tjener et helt andet formål. Det er en eksekutionsvejsprofil, hvis du vil, som fortæller dig hvor (dvs. i hvilken funktion) dit program bruger mest af det er tid. Hvis du har en kompleks algoritme med masser af subrutiner, kan du ikke vide, hvilke der er de vigtigste, og igen kan dette faktisk afhænge af din virkelige input. I så fald kan profileren hjælpe dig med at bestemme hvilke funktioner der kaldes mest givet dine inputdata , og du kan koncentrere optimeringsindsatsen på disse funktioner. Nu 'profil før optimering' betyder, at du skal bestemme prioriteterne, før du kommer i arbejde.


Når det er sagt, for den sammenligning, du har i tankerne, må du ikke bruge GCC profiler. Udvikle i stedet på begge platforme med alle optimeringer aktiverede og under frigivelsesbetingelser, og måler derefter runtime på det samme sæt inputdata.