Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test_stopwatch: fix on mingw #2415

Merged
merged 1 commit into from
Jun 26, 2022
Merged

test_stopwatch: fix on mingw #2415

merged 1 commit into from
Jun 26, 2022

Conversation

neheb
Copy link
Contributor

@neheb neheb commented Jun 24, 2022

There are some timing shenanigans with GCC's chrono that make this
unreliable. Add a start/stop and test for that to work around.

Signed-off-by: Rosen Penev rosenp@gmail.com

@tt4g
Copy link
Contributor

tt4g commented Jun 24, 2022

@neheb Could you also fix the test case "stopwatch2"? It should have the same problem.

@neheb
Copy link
Contributor Author

neheb commented Jun 24, 2022

Having trouble figuring that out. stopwatch2 deals with doubles whereas std::chrono::milliseconds deals with long_int. Some weird conversion is needed.

@tt4g
Copy link
Contributor

tt4g commented Jun 24, 2022

In GCC std::chrono::duration_cast<duration>(milliseconds(250)) works.
Does it not work in MinGW?

Wandbox

#include <iostream>
#include <cstdlib>

#include <chrono>
#include <thread>

int main()
{
    using std::chrono::milliseconds;
    using std::chrono::duration_cast;
    using clock = std::chrono::steady_clock;
    using duration = clock::duration;

    duration wait_duration(milliseconds(250));
    duration tolerance_duration(milliseconds(250));

    auto start_duration = clock::now();
    std::this_thread::sleep_for(wait_duration);
    auto stop_duration = clock::now();

    auto diff_duration = stop_duration - start_duration;

    std::cout << duration_cast<duration>(milliseconds(250)).count() << "\n";
    std::cout << duration_cast<milliseconds>(diff_duration).count() << "\n";
    std::cout << diff_duration.count() << "\n";
    std::cout << (diff_duration + tolerance_duration).count() << "\n";
}

@tt4g
Copy link
Contributor

tt4g commented Jun 25, 2022

I noticed that spdlog::stopwatch::elapsed() returns std::chrono::duration<double> (I had overlooked this).
@neheb Would the following code allow MinGW to pass the test as well?

TEST_CASE("stopwatch2", "[stopwatch]")
{
    using spdlog::sinks::test_sink_st;
    using std::chrono::duration_cast;
    using std::chrono::milliseconds;
    using clock = std::chrono::steady_clock;

    clock::duration wait_duration(milliseconds(250));
    clock::duration tolerance_duration(milliseconds(250));

    auto test_sink = std::make_shared<test_sink_st>();

    auto start = clock::now();
    spdlog::stopwatch sw;
    spdlog::logger logger("test-stopwatch", test_sink);
    logger.set_pattern("%v");
    std::this_thread::sleep_for(wait_duration);
    auto stop = clock::now();
    logger.info("{}", sw);
    std::cout << test_sink->lines()[0] << "\n";
    auto val = std::stod(test_sink->lines()[0]);
    auto diff_duration = duration_cast<std::chrono::duration<double>>(stop - start);

    REQUIRE(val >= diff_duration.count());
    REQUIRE(val <= (diff_duration + tolerance_duration).count());
}
Diff
 TEST_CASE("stopwatch2", "[stopwatch]")
 {
     using spdlog::sinks::test_sink_st;
+    using std::chrono::duration_cast;
+    using std::chrono::milliseconds;
+    using clock = std::chrono::steady_clock;

-    std::chrono::duration<double> wait_duration(0.250);
-    std::chrono::duration<double> tolerance_duration(0.250);
+    clock::duration wait_duration(milliseconds(250));
+    clock::duration tolerance_duration(milliseconds(250));

     auto test_sink = std::make_shared<test_sink_st>();

+    auto start = clock::now();
     spdlog::stopwatch sw;
     spdlog::logger logger("test-stopwatch", test_sink);
     logger.set_pattern("%v");
     std::this_thread::sleep_for(wait_duration);
+    auto stop = clock::now();
     logger.info("{}", sw);
+    std::cout << test_sink->lines()[0] << "\n";
     auto val = std::stod(test_sink->lines()[0]);
+    auto diff_duration = duration_cast<std::chrono::duration<double>>(stop - start);

-    REQUIRE(val >= wait_duration.count());
-    REQUIRE(val <= (wait_duration + tolerance_duration).count());
+    REQUIRE(val >= diff_duration.count());
+    REQUIRE(val <= (diff_duration + tolerance_duration).count());
 }

@neheb
Copy link
Contributor Author

neheb commented Jun 25, 2022

It already passes. Just test one had issues.

edit: nvm just failed:

0.2499963 >= 0.25

@neheb
Copy link
Contributor Author

neheb commented Jun 25, 2022

Updated.

@tt4g
Copy link
Contributor

tt4g commented Jun 25, 2022

Oh wait, the source code I pasted still has the statement for debugging.
Sorry. Please remove std::cout << test_sink->lines()[0] << "\n";.

@neheb
Copy link
Contributor Author

neheb commented Jun 25, 2022

I don’t think that’s the error here.

@neheb
Copy link
Contributor Author

neheb commented Jun 25, 2022

Ah I have a stoll call.

There are some timing shenanigans with GCC's chrono that make this
unreliable. Add a start/stop and test for that to work around.

Signed-off-by: Rosen Penev <rosenp@gmail.com>
logger.info("{}", sw);
auto val = std::stod(test_sink->lines()[0]);
auto diff_duration = duration_cast<std::chrono::duration<double>>(stop - start);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets please use same diff method in both functions.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is needed because test2 uses a double.

@gabime gabime merged commit d7690d8 into gabime:v1.x Jun 26, 2022
@gabime
Copy link
Owner

gabime commented Jun 26, 2022

Thanks @neheb and @tt4g

@neheb neheb deleted the mingw branch June 26, 2022 23:38
@neheb
Copy link
Contributor Author

neheb commented Aug 12, 2022

@tt4g found out why this was an issue.

LLVM's libc++ calls the proper windows APIs directly instead of going through clock_gettime. libstdc++ uses clock_gettime. The difference is that clock_gettime as implemented in winpthreads calls GetSystemTimeAsFileTime. libc++ uses GetSystemTimePreciseAsFileTime and falls back to GetSystemTimeAsFileTime for Windows versions older than 8.

@tt4g
Copy link
Contributor

tt4g commented Aug 12, 2022

@neheb Great!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants