Acelere las ejecuciones de código con la ayuda de Pragma en C/C++

El objetivo principal de un compilador es reducir el costo de la compilación y hacer que la depuración produzca los resultados esperados. No todas las optimizaciones están controladas directamente por una bandera, a veces necesitamos declarar banderas explícitamente para producir optimizaciones. Por defecto, las optimizaciones están suprimidas. Para usar optimizaciones suprimidas usaremos pragmas

Ejemplo de programa no optimizado: Consideremos un ejemplo para calcular números primos hasta 10000000 .

A continuación se muestra el código sin optimización:  

C++

// C++ program to calculate the Prime
// Numbers upto 10000000 using Sieve
// of Eratosthenes with NO optimization
 
#include <cmath>
#include <iostream>
#include <vector>
#define N 10000005
using namespace std;
 
// Boolean array for Prime Number
vector<bool> prime(N, true);
 
// Sieve implemented to find Prime
// Number
void sieveOfEratosthenes()
{
    for (int i = 2; i <= sqrt(N); ++i) {
        if (prime[i]) {
            for (int j = i * i; j <= N; j += i) {
                prime[j] = false;
            }
        }
    }
}
 
// Driver Code
int main()
{
    // Initialise clock to calculate
    // time required to execute without
    // optimization
    clock_t start, end;
 
    // Start clock
    start = clock();
 
    // Function call to find Prime Numbers
    sieveOfEratosthenes();
 
    // End clock
    end = clock();
 
    // Calculate the time difference
    double time_taken
        = double(end - start)
          / double(CLOCKS_PER_SEC);
 
    // Print the Calculated execution time
    cout << "Execution time: " << time_taken
         << " secs";
 
    return 0;
}
Producción: 

Execution time: 0.592183 secs

 

Las siguientes son las Optimizaciones: 

1. O1: la optimización de la compilación en O1 incluye más tiempo y memoria para desglosar funciones más grandes. El compilador intenta reducir tanto el código como el tiempo de ejecución. En O1, casi ninguna optimización produce grandes resultados, pero O1 es un revés para un intento de mejores optimizaciones.

A continuación se muestra la implementación del programa anterior con optimización O1 :

C++

// C++ program to calculate the Prime
// Numbers upto 10000000 using Sieve
// of Eratosthenes with O1 optimization
 
// To see the working of controlled
// optimization "O1"
#pragma GCC optimize("O1")
 
#include <cmath>
#include <iostream>
#include <vector>
#define N 10000005
using namespace std;
 
// Boolean array for Prime Number
vector<bool> prime(N, true);
 
// Sieve implemented to find Prime
// Number
void sieveOfEratosthenes()
{
    for (int i = 2; i <= sqrt(N); ++i) {
        if (prime[i]) {
            for (int j = i * i; j <= N; j += i) {
                prime[j] = false;
            }
        }
    }
}
 
// Driver Code
int main()
{
    // Initialise clock to calculate
    // time required to execute without
    // optimization
    clock_t start, end;
 
    // Start clock
    start = clock();
 
    // Function call to find Prime Numbers
    sieveOfEratosthenes();
 
    // End clock
    end = clock();
 
    // Calculate the time difference
    double time_taken
        = double(end - start)
          / double(CLOCKS_PER_SEC);
 
    // Print the Calculated execution time
    cout << "Execution time: " << time_taken
         << " secs.";
 
    return 0;
}
Producción: 

Execution time: 0.384945 secs.

 

2. O2: Optimizar la compilación en O2 optimizar en mayor medida. En comparación con O1 , esta opción aumenta tanto el tiempo de compilación como el rendimiento del código generado. O2 activa todos los indicadores de optimización especificados por O1 .

A continuación se muestra la implementación del programa anterior con optimización de O2 :

C++

// C++ program to calculate the Prime
// Numbers upto 10000000 using Sieve
// of Eratosthenes with O2 optimization
 
// To see the working of controlled
// optimization "O2"
#pragma GCC optimize("O2")
 
#include <cmath>
#include <iostream>
#include <vector>
#define N 10000005
using namespace std;
 
// Boolean array for Prime Number
vector<bool> prime(N, true);
 
// Sieve implemented to find Prime
// Number
void sieveOfEratosthenes()
{
    for (int i = 2; i <= sqrt(N); ++i) {
        if (prime[i]) {
            for (int j = i * i; j <= N; j += i) {
                prime[j] = false;
            }
        }
    }
}
 
// Driver Code
int main()
{
    // Initialise clock to calculate
    // time required to execute without
    // optimization
    clock_t start, end;
 
    // Start clock
    start = clock();
 
    // Function call to find Prime Numbers
    sieveOfEratosthenes();
 
    // End clock
    end = clock();
 
    // Calculate the time difference
    double time_taken
        = double(end - start)
          / double(CLOCKS_PER_SEC);
 
    // Print the Calculated execution time
    cout << "Execution time: " << time_taken
         << " secs.";
 
    return 0;
}
Producción: 

Execution time: 0.288337 secs.

 

3. O3: todas las optimizaciones en el nivel O2 están especificadas por O3 y también se habilita una lista de otras banderas. Algunas de las banderas que se incluyen en O3 son flop-interchange -flop-unroll-jam y -fpeel-loops.

A continuación se muestra la implementación del programa anterior con optimización O3 :

C++

// C++ program to calculate the Prime
// Numbers upto 10000000 using Sieve
// of Eratosthenes with O3 optimization
 
// To see the working of controlled
// optimization "O3"
#pragma GCC optimize("O3")
 
#include <cmath>
#include <iostream>
#include <vector>
#define N 10000005
using namespace std;
 
// Boolean array for Prime Number
vector<bool> prime(N, true);
 
// Sieve implemented to find Prime
// Number
void sieveOfEratosthenes()
{
    for (int i = 2; i <= sqrt(N); ++i) {
        if (prime[i]) {
            for (int j = i * i; j <= N; j += i) {
                prime[j] = false;
            }
        }
    }
}
 
// Driver Code
int main()
{
    // Initialise clock to calculate
    // time required to execute without
    // optimization
    clock_t start, end;
 
    // Start clock
    start = clock();
 
    // Function call to find Prime Numbers
    sieveOfEratosthenes();
 
    // End clock
    end = clock();
 
    // Calculate the time difference
    double time_taken
        = double(end - start)
          / double(CLOCKS_PER_SEC);
 
    // Print the Calculated execution time
    cout << "Execution time: " << time_taken
         << " secs.";
 
    return 0;
}
Producción: 

Execution time: 0.580154 secs.

 

4. Os: está optimizado para el tamaño. Os habilita todas las optimizaciones de O2 excepto las que tienen un mayor tamaño de código. También habilita las funciones -finline-, hace que el compilador ajuste el tamaño del código en lugar de la velocidad de ejecución y realiza más optimizaciones diseñadas para reducir el tamaño del código.

A continuación se muestra la implementación del programa anterior con optimización de Os :

C++

// C++ program to calculate the Prime
// Numbers upto 10000000 using Sieve
// of Eratosthenes with Os optimization
 
// To see the working of controlled
// optimization "Os"
#pragma GCC optimize("Os")
 
#include <cmath>
#include <iostream>
#include <vector>
#define N 10000005
using namespace std;
 
// Boolean array for Prime Number
vector<bool> prime(N, true);
 
// Sieve implemented to find Prime
// Number
void sieveOfEratosthenes()
{
    for (int i = 2; i <= sqrt(N); ++i) {
        if (prime[i]) {
            for (int j = i * i; j <= N; j += i) {
                prime[j] = false;
            }
        }
    }
}
 
// Driver Code
int main()
{
    // Initialise clock to calculate
    // time required to execute without
    // optimization
    clock_t start, end;
 
    // Start clock
    start = clock();
 
    // Function call to find Prime Numbers
    sieveOfEratosthenes();
 
    // End clock
    end = clock();
 
    // Calculate the time difference
    double time_taken
        = double(end - start)
          / double(CLOCKS_PER_SEC);
 
    // Print the Calculated execution time
    cout << "Execution time: " << time_taken
         << " secs.";
 
    return 0;
}
Producción: 

Execution time: 0.317845 secs.

 

5. Ofast: Ofast habilita todas las optimizaciones de O3 . También tiene la cantidad de banderas habilitadas que producen resultados súper optimizados. Ofast combina optimizaciones producidas por cada uno de los niveles de O anteriores . Muchos programadores de la competencia suelen preferir esta optimización y, por lo tanto, se recomienda. En caso de que se declaren más de una optimización, se habilita la última declarada.

A continuación se muestra la implementación del programa anterior con la optimización de Ofast :

C++

// C++ program to calculate the Prime
// Numbers upto 10000000 using Sieve
// of Eratosthenes with Ofast optimization
 
// To see the working of controlled
// optimization "Ofast"
#pragma GCC optimize("Ofast")
 
#include <cmath>
#include <iostream>
#include <vector>
#define N 10000005
using namespace std;
 
// Boolean array for Prime Number
vector<bool> prime(N, true);
 
// Sieve implemented to find Prime
// Number
void sieveOfEratosthenes()
{
    for (int i = 2; i <= sqrt(N); ++i) {
        if (prime[i]) {
            for (int j = i * i; j <= N; j += i) {
                prime[j] = false;
            }
        }
    }
}
 
// Driver Code
int main()
{
    // Initialise clock to calculate
    // time required to execute without
    // optimization
    clock_t start, end;
 
    // Start clock
    start = clock();
 
    // Function call to find Prime Numbers
    sieveOfEratosthenes();
 
    // End clock
    end = clock();
 
    // Calculate the time difference
    double time_taken
        = double(end - start)
          / double(CLOCKS_PER_SEC);
 
    // Print the Calculated execution time
    cout << "Execution time: " << time_taken
         << " secs.";
 
    return 0;
}
Producción: 

Execution time: 0.303287 secs.

 

Para lograr más optimizaciones a nivel de arquitectura, podemos usar objetivos con pragmas . Estas optimizaciones pueden producir resultados sorprendentes. Sin embargo, se recomienda utilizar target con cualquiera de las optimizaciones especificadas anteriormente. 

A continuación se muestra la implementación del programa anterior con Target

C++14

// C++ program to calculate the Prime
// Numbers upto 10000000 using Sieve
// of Eratosthenes with Ofast optimization along with target optimizations
 
// To see the working of controlled
// optimization "Ofast"
#pragma GCC optimize("Ofast")
#pragma GCC target("avx,avx2,fma")
 
#include <cmath>
#include <iostream>
#include <vector>
#define N 10000005
using namespace std;
 
// Boolean array for Prime Number
vector<bool> prime(N, true);
 
// Sieve implemented to find Prime
// Number
void sieveOfEratosthenes()
{
    for (int i = 2; i <= sqrt(N); ++i) {
        if (prime[i]) {
            for (int j = i * i; j <= N; j += i) {
                prime[j] = false;
            }
        }
    }
}
 
// Driver Code
int main()
{
    // Initialise clock to calculate
    // time required to execute without
    // optimization
    clock_t start, end;
 
    // Start clock
    start = clock();
 
    // Function call to find Prime Numbers
    sieveOfEratosthenes();
 
    // End clock
    end = clock();
 
    // Calculate the time difference
    double time_taken
        = double(end - start)
        / double(CLOCKS_PER_SEC);
 
    // Print the Calculated execution time
    cout << "Execution time: " << time_taken
        << " secs.";
 
    return 0;
}
Producción: 

Execution time: 0.292147 secs.

 

Publicación traducida automáticamente

Artículo escrito por executable y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *