简体   繁体   中英

Using static variables Vs automatic doesn't impact the run-time performance

GCC keeps me baffled by its strange optimizations. The execution speeds of the two functions below ( calculate_with_static_vars and calculate_with_stack_vars ) don't have any meaningful difference.

Here is the MRE code:

#include <iostream>
#include <cstddef>
#include <cmath>
#include <chrono>


// just a simple timer, DON't PAY ATTENTION TO THIS
struct ScopedTimer
{
    const std::chrono::time_point< std::chrono::steady_clock > start { std::chrono::steady_clock::now( ) };
          std::chrono::time_point< std::chrono::steady_clock > end;

    ScopedTimer( ) = default;
    ~ScopedTimer( )
    {
        end = std::chrono::steady_clock::now( );
        std::clog << "\nTimer took "
                  << std::chrono::duration< double, std::milli>( end - start ).count( )
                  << " ms\n";
    }
    ScopedTimer( const ScopedTimer& ) = delete;
    ScopedTimer& operator=( const ScopedTimer& ) = delete;
};

// this is the custom struct
struct Point3D
{
    float x, y, z;
};

// the candidate 1
float calculate_with_static_vars( const Point3D point5 )
{
    static constexpr Point3D point1 { 1.5f, 4.83f, 2.01f }; // static vars
    static constexpr Point3D point2 { 2.5f, 5.83f, 3.01f };
    static constexpr Point3D point3 { 3.5f, 6.83f, 4.01f };
    static constexpr Point3D point4 { 4.5f, 7.83f, 5.01f };

    const auto dist1 { std::hypot( point1.x - point2.x,
                                   point1.y - point2.y,
                                   point1.z - point2.z ) };

    const auto dist2 { std::hypot( point2.x - point3.x,
                                   point2.y - point3.y,
                                   point2.z - point3.z ) };

    const auto dist3 { std::hypot( point3.x - point4.x,
                                   point3.y - point4.y,
                                   point3.z - point4.z ) };

    const auto dist4 { std::hypot( point4.x - point5.x,
                                   point4.y - point5.y,
                                   point4.z - point5.z ) };

    return dist1 + dist2 + dist3 + dist4;
}

// the candidate 2
float calculate_with_stack_vars( const Point3D point5 )
{
    constexpr Point3D point1 { 1.5f, 4.83f, 2.01f }; // stack vars
    constexpr Point3D point2 { 2.5f, 5.83f, 3.01f };
    constexpr Point3D point3 { 3.5f, 6.83f, 4.01f };
    constexpr Point3D point4 { 4.5f, 7.83f, 5.01f };

    const auto dist1 { std::hypot( point1.x - point2.x,
                                   point1.y - point2.y,
                                   point1.z - point2.z ) };

    const auto dist2 { std::hypot( point2.x - point3.x,
                                   point2.y - point3.y,
                                   point2.z - point3.z ) };

    const auto dist3 { std::hypot( point3.x - point4.x,
                                   point3.y - point4.y,
                                   point3.z - point4.z ) };

    const auto dist4 { std::hypot( point4.x - point5.x,
                                   point4.y - point5.y,
                                   point4.z - point5.z ) };

    return dist1 + dist2 + dist3 + dist4;
}

// a function that decides which of the above functions to call based on the branch_flag
inline float testFunc( const bool branch_flag, const bool arg_flag )
{
    bool isStatic { branch_flag };
    Point3D point2;
    if ( arg_flag ) { point2 = { 3.5f, 7.33f, 9.04f }; }
    else            { point2 = { 2.5f, 6.33f, 8.04f }; }

    float dist;
    constexpr size_t numOfIterations { 1'000'000'000 };

    if ( isStatic )
    {
        for ( size_t counter { }; counter < numOfIterations; ++counter )
        {
            dist = calculate_with_static_vars( point2 );
        }
    }
    else
    {
        for ( size_t counter { }; counter < numOfIterations; ++counter )
        {
            dist = calculate_with_stack_vars( point2 );
        }
    }

    return dist;
}


int main( )
{
    bool branch_flag;
    std::cin >> branch_flag;
    bool arg_flag;
    std::cin >> arg_flag;

    float dist;
    {
    ScopedTimer timer;
    dist = testFunc( branch_flag, arg_flag );
    }

    std::cout << "Sum of the distances of the four points: " << dist << '\n';
}

The two functions are doing the same work (calculating the distances between 4 points and returning their sum) the only difference they have is that one uses static variables meanwhile the other one uses stack variables (aka automatic).

The user has two enter two boolean values on the console (1st one is for deciding which function to run and the 2nd one which is not important is for deciding which argument to pass to the function being called). Like this:

true    // runs the function with static vars
true    // passes the first point to it

or

false   // runs the function with automatic vars
true    // passes the first point to it

And then the loop inside testFunc calls the chosen function 1 billion times.

Now one might wonder why is there this much bloat in this code. The reason is that I wanted to prevent GCC from doing aggressive compile-time optimizations. Otherwise, it would make the two functions implicitly consteval and that would defeat the purpose of my test.

So the question is how are these functions taking the same amount of time to run (~22 sec on my old machine)? Shouldn't the static version be considerably faster since it allocates storage and then initializes its variables only once?

So the question is how are these functions taking the same amount of time to run (~22 sec on my old machine)?

Because they can be compiled to identical assembly.

Shouldn't the static version be considerably faster since it allocates storage and then initializes its variables only once?

No. The variables are compile time constant. In practice, the compiler can avoid providing them any storage whatsoever.

With constant-folding optimisation, both functions are effectively equivalent to:

return 5.19615269  // dist1 + dist2 + dist3
    + std::hypot(
          4.5f  - point5.x,
          7.83f - point5.y,
          5.01f - point5.z);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM