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

[Clarification] Does std::chrono::milliseconds use 45 bits or does it wrap around at 32 bits? (IDFGH-1605) #3860

Closed
ssilverman opened this issue Aug 1, 2019 · 5 comments

Comments

@ssilverman
Copy link

ssilverman commented Aug 1, 2019

The C++ spec says that the std::chrono::milliseconds type should be at least 45 bits (https://en.cppreference.com/w/cpp/chrono/duration). Since the HAL (esp32-hal.h) defines millis() as returning unsigned long, and since that's only defined to be "at least 32 bits" in the C++ spec (https://en.cppreference.com/w/cpp/language/types), I just want to confirm that retrieving the milliseconds using the chrono library doesn't wrap around at 32 bits, and it is a true 64-bit value.

Example code:

  auto now = std::chrono::steady_clock::now().time_since_epoch();
  auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(now).count();

Side question: Where do I find where the C++ core libraries use the ESP32 HAL to implement everything? For example, mutexes or yield() or the chrono library. I'd like to read the source so I can confirm these things myself.

@github-actions github-actions bot changed the title [Clarification] Does std::chrono::milliseconds use 45 bits or does it wrap around at 32 bits? [Clarification] Does std::chrono::milliseconds use 45 bits or does it wrap around at 32 bits? (IDFGH-1605) Aug 1, 2019
@projectgus
Copy link
Contributor

projectgus commented Aug 1, 2019

The short answer is that std::chrono::duration_cast<std::chrono::milliseconds>(now).count() should not wrap before 2038-01-18 (and an ESP-IDF update will be available well before this date, as per #584 linked by @negativekelvin - thanks.)

The long answer is that the question mentions a number of timekeeping features, but they're not all related to each other:

  • esp32-hal.h and its millis() function is part of ESP32 Arduino. The C++ STL functionality does not depend on any Arduino library functionality, libstdc++ is a lower layer in the system and Arduino doesn't implement the C++ standard. So anything implemented in the Arduino code is unrelated.
  • std::chrono:milliseconds is a signed 64-bit type on ESP32. You can confirm this by checking the chrono header in the toolchain's include directory: typedef duration<int64_t, milli> milliseconds;. So this type can represent something like +/- 2.9*10^8 years (pretty long duration!), but this doesn't mean that steady_clock::now() can return this range of times.
  • ESP-IDF uses GNU libstdc++ (part of gcc) for libstdc++ functionality. The steady_clock::now() implementation will call the libc (newlib) standard function gettimeofday() and then store this result internally.
  • So, when will the result of gettimeofday() wrap? This function currently uses a 64-bit type with a 32-bit seconds field and a 32-bit microseconds field. The "tv_sec" (seconds) field is signed 32-bit so this is the limiting factor in the range of times which can be represented (2038 problem, as linked by @negativekelvin above).
  • You can read the actual implementation of gettimeofday() here. The full implementation is a little hard to follow, as ESP-IDF supports different hardware clock sources for gettimeofday. However rollovers in the hardware timers themselves are accounted for by storing offsets (if relevant, the default timer is a 64-bit microsecond precision timer so no rollover is needed), so effectively the input clocks have 64-bit microsecond precision.
  • If you write C++ code using chrono::system_clock or chrono::steady_clock now and update ESP-IDF once the 2038 problem is solved, the code should keep working after 2038 with just a recompile against the newer libc & libstdc++.

For future reference, as this is a question rather than an bug report/feature request/etc for ESP-IDF then the best place to ask it would be the https://esp32.com forums.

@ssilverman
Copy link
Author

Thank you very much for the detailed response (and your patience with my question here). I've already started the process of becoming Arduino-free and am trying to disentangle myself from that system and API as much as I can. There are obviously some misunderstandings I still have.

In the future I'll take these sorts of questions to the forums. Thanks again for all the details.

@projectgus
Copy link
Contributor

@ssilverman Glad that the answer was helpful. Good luck with your continued journey into embedded C++ land. :)

@ssilverman
Copy link
Author

It's just that all these Arduino-related classes are so handy: AsyncUDP, ESPAsyncWebServer, IPAddress, Print, WiFi, FastLED, Preferences, etc. All those rely on some Arduino something or other. That's why I'm having a bumpy time moving completely to ESP-IDF.

@brettdavidsilverman
Copy link

ssilverman, I have experimented with ESP-IDF. It uses modules. There is a usable "Arduino" module which you can plug into your project. This allows libc compilation whilst still using your favourite Arduino bits.

Kind regards, and good luck with your endevours.

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

No branches or pull requests

3 participants