Wie viel Aufwand kann das-fPIC-flag hinzufügen?

Frage

Teste ich einen einfachen code, der berechnet Mandelbrot-Fraktale. Ich habe die überprüfung seiner Leistung abhängig von der Anzahl der Iterationen in der Funktion, die prüft, ob ein Punkt gehört zur Mandelbrot-Menge oder nicht.
Die überraschende Sache ist, dass ich immer einen großen Unterschied in den Zeiten nach dem hinzufügen der -fPIC Flagge. Von was ich gelesen, der overhead ist in der Regel vernachlässigbar und die höchste überkopf-ich gestoßen bin, war etwa 6%. Ich gemessen um 30% overhead. Jede Beratung wird geschätzt!

Details zu meinem Projekt

Ich die -O3 Flagge, gcc 4.7.2, Ubuntu 12.04.2, x86_64.
Die Ergebnisse sehen wie folgt

 #iter C (fPIC) C C/C(fPIC) 
1 0.01 0.01 1.00 
100 0.04 0.03 0.75 
200 0.06 0.04 0.67 
500 0.15 0.1 0.67 
1000 0.28 0.19 0.68 
2000 0.56 0.37 0.66 
4000 1.11 0.72 0.65 
8000 2.21 1.47 0.67 
16000 2.88 4.42 0.65 
32000 8.8 5.77 0.66 
64000 17.6 11.53 0.66 

Befehle, die ich verwenden:

gcc -O3 -fPIC fractalMain.c fractal.c -o ffpic
gcc -O3 fractalMain.c fractal.c -o f

Code: fractalMain.c

#include <time.h>
#include <stdio.h>
#include <stdbool.h>
#include "fractal.h"

int main()
{
    int iterNumber[] = {1, 100, 200, 500, 1000, 2000, 4000, 8000, 16000, 32000, 64000};
    int it;
    for(it = 0; it < 11; ++it)
    {
        clock_t start = clock();
        fractal(iterNumber[it]);
        clock_t end = clock();
        double millis = (end - start)*1000 / CLOCKS_PER_SEC/(double)1000;
        printf("Iter: %d, time: %lf \n", iterNumber[it], millis);
    }
    return 0;
}

Code: Fraktale.h

#ifndef FRACTAL_H
#define FRACTAL_H
    void fractal(int iter);
#endif

Code: Fraktale.c

#include <stdio.h>
#include <stdbool.h>
#include "fractal.h"

void multiplyComplex(double a_re, double a_im, double b_re, double b_im, double* res_re, double* res_im)
{
    *res_re = a_re*b_re - a_im*b_im;
    *res_im = a_re*b_im + a_im*b_re;
}

void sqComplex(double a_re, double a_im, double* res_re, double* res_im)
{
    multiplyComplex(a_re, a_im, a_re, a_im, res_re, res_im);
} 

bool isInSet(double P_re, double P_im, double C_re, double C_im, int iter)
{
    double zPrev_re = P_re;
    double zPrev_im = P_im;
    double zNext_re = 0;
    double zNext_im = 0;
    double* p_zNext_re = &zNext_re;
    double* p_zNext_im = &zNext_im;
    int i;  
    for(i = 1; i <= iter; ++i)
    {
        sqComplex(zPrev_re, zPrev_im, p_zNext_re, p_zNext_im);
        zNext_re = zNext_re + C_re;
        zNext_im = zNext_im + C_im;
        if(zNext_re*zNext_re+zNext_im*zNext_im > 4)
        {
            return false;
        }
        zPrev_re = zNext_re;
        zPrev_im = zNext_im;
    }
    return true;
}

bool isMandelbrot(double P_re, double P_im, int iter)
{
    return isInSet(0, 0, P_re, P_im, iter);
}
void fractal(int iter)
{
    int noIterations = iter;
    double xMin = -1.8;
    double xMax = 1.6;
    double yMin = -1.3;
    double yMax = 0.8;
    int xDim = 512;
    int yDim = 384;
    double P_re, P_im;
    int nop;
    int x, y;

    for(x = 0; x < xDim; ++x)
        for(y = 0; y < yDim; ++y)
        {
            P_re = (double)x*(xMax-xMin)/(double)xDim+xMin;
            P_im = (double)y*(yMax-yMin)/(double)yDim+yMin;
            if(isMandelbrot(P_re, P_im, noIterations))
                nop = x+y;
        }
        printf("%d", nop);
}

Geschichte hinter dem Vergleich

Er sieht zwar etwas künstlich hinzuzufügen -fPIC flag beim erstellen ausführbare Datei (wie in einem der Kommentare). So, ein paar Worte der Erklärung: zuerst habe ich nur die kompilierte Programm als ausführbare Datei und wollte vergleichen, um meine Lua-code, die fordert, die isMandelbrot Funktion von C. So habe ich eine shared-object zu nennen, die aus lua - und hatte großen Unterschiede. Aber Sie konnte nicht verstehen, warum Sie wuchsen mit der Anzahl der Iterationen. Am Ende fand heraus, dass es war, weil der -fPIC. Wenn ich ein kleines c-Programm, das ruft mein lua-Skript (also effektiv ich mache das gleiche, nur nicht brauchen, die .so) - die Zeiten sind sehr ähnlich zu C (ohne -fPIC). Also ich habe es in ein paar Konfigurationen in den letzten paar Tagen und es konsequent zeigt zwei Sätze von sehr ähnlichen Ergebnissen: schneller ohne -fPIC und langsamer mit ihm.

  • Nicht reproduzieren kann mit gcc 4.7.2 auf x86_64 (OS/X).
  • Du hast vergessen zu geben, die fractal.h header
  • Haben Sie etwas in CFLAGS?
  • also sind Sie immer ähnlich, mal unabhängig von der Flagge?
  • Ja, fast identischen timings (z.B. 10.985 vs 10.976).
  • Ich bin ein bisschen überrascht über Ihre Ergebnisse. Du bist nicht wirklich testen -fPIC overhead Weg. Da baut man eine ausführbare Datei, gcc kann machen einige Annahmen über den Ort der endgültigen Aufruf der Funktion. Sie brauchen, um zu bauen ein Teil Ihrer Anwendung als shared library, und der Aufwand wird in den anrufen, die Sie brauchen, um aus der primären Anwendung in der gemeinsam genutzten Bibliothek. Obwohl, in der Sie aktuelle aufgeteilt, auch dies wäre ein deutlicher Unterschied. Man müsste entweder multiplyComplex oder sqComplex in die gemeinsam genutzte Bibliothek, um wirklich zu sehen, beginnen einen Einfluss.
  • FWIW, ich auch bekommen ähnliche timings zwischen den Pisten, wie @OlaM.
  • Starynkevitch: Hinzugefügt den Kopf auf die Frage.
  • Nein, checked 'echo $CFLAGS' - es ist leer.
  • Ich bekomme die Meldung: gcc 12.78/18.23 -- clang 13.73 / 13.75
  • Interessant. Ich sehe den Unterschied auch unter Linux. Alles in fractal.c statische außer fractal() die gibt die timings die gleichen zwischen-Implementierungen. Ich bin mir nicht sicher, warum gcc ist nicht die Optimierung dieser besser unter Linux.
  • Ich fügte hinzu, die Erklärung, wo das problem begann, auf die Frage - haben Sie überprüft auch den Aufbau einer ordnungsgemäßen .so.
  • Werfen Sie einen Blick auf die objdump -d Ausgabe für jede ausführbare Datei. Sie können sehen, dass einige Optimierungen sind ausgeschlossen in der -fPIC version in den fractal() Funktion. Was genau wollen Sie zur Messung der Leistung von hier? Der overhead für den Aufruf fractal() wenn es kompiliert mit -fPIC? Oder machst du den fraktalen funktioniert in Lua und ruft auf der unteren Ebene Routinen? Ein Grund, warum die nicht-fPIC-version so viel besser ist, weil eine Menge Arbeit ist eingebettet in fractal(). In der -fPIC version, ist es nicht. Wieder, können Sie beheben, indem die Helfer statisch.
  • vielen Dank für den Kommentar. Was ich Suche ist fair performance-Vergleich zwischen der reinen C und mein lua+C-Programme. Und Frage mich, ob der overhead nicht mit meiner unvollkommenen Umsetzung - die it sieht aus wie es ist: du hast Recht, die Hilfsfunktionen, die sollte statisch sein, und es wird verhindert, dass der overhead. Auch aus den anderen Kommentaren sieht es aus wie clang ist besser bei der Optimierung unvollkommen code selbst.
  • Blöde Frage, aber Sie sind ganz sicher, dass Sie die Kompilierung als 64-bit-code, richtig? Die IA-32-Befehlssatz nicht für die position-independent code, und es wäre normal, zu sehen, diese Art von Unterschied, wenn Sie versehentlich benutzen. x86_64 war entworfen, um position-independent code so schnell wie position-dependent code, und die normale situation ist, dass kein messbarer Unterschied (wie NPE und anderen gefunden)
  • Cuoq: ja, Target: x86_64-linux-gnu. Und ja, ich lese auch, dass der Unterschied sollte vernachlässigbar sein, insbesondere für 64-bit...
  • Man kann auch -flto sowohl zur compile-und link-Zeit (neben der -O3), und Sie könnten auch geben -mtune=native
  • Mit gcc-4.8 und GLibc 2.17 auf einem Linux-kernel 3.8.5 (x86-64 i3770K, Debian/Sid/AMD64 mit ein bisschen experimentell) ich bin immer 27.55 s für PIC und 18.24 s für nonPIC; ich habe keine Ahnung, warum so ein großer Unterschied...
  • Allerdings, wenn Sie kompilieren mit gcc-4.8 -flto -O3 -mtune=native mit oder ohne -fPIC ich bin immer nur 18.28 sec für nicht-PIC und 18.36 für PIC. Also ich empfehle -flto -mtune=native -O3 mit oder ohne -fPIC
  • OS X setzt position-unabhängigen code in den ausführbaren Dateien, nicht nur Bibliotheken. Also gcc ist gezwungen, Sie zu aktivieren -fPIE für die ausführbaren Dateien, nicht nur Bibliotheken. (Auf x86-64, ich glaube nicht, dass es viel wenn ein Unterschied zwischen -fPIC und -fPIE, aber -fPIE könnte in der Lage sein, um die Vorteile zu nehmen von Dingen, die code-Bibliothek konnte nicht). Linux und Windows haben nicht diese Anforderung, so macht es Sinn, dass wenn es einen Unterschied gibt, ist es nicht reproduzierbar auf OS X.

InformationsquelleAutor Ola M | 2013-04-07
Schreibe einen Kommentar