Skip to content

Instantly share code, notes, and snippets.

@mojomojomojo
Last active February 8, 2024 15:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mojomojomojo/e3e6adeeeb32ae400ac1a2d3bce89947 to your computer and use it in GitHub Desktop.
Save mojomojomojo/e3e6adeeeb32ae400ac1a2d3bce89947 to your computer and use it in GitHub Desktop.
(Attempt) to calculate the cost (in time) of creating and using timestamps.
//
// How long does it take to perform time(stamp)-related things?
//
#include <iostream>
#include <chrono>
#include <vector>
#include <string>
#include <ctime>
#include <iomanip>
#include <sstream>
template<typename ClockType>
void time_GetCurrentTimestamp( const std::string& name, uint32_t count ) {
ClockType::time_point ts;
auto started = std::chrono::high_resolution_clock::now();
for (uint32_t i=0; i<count; i++) {
ts = ClockType::now();
}
auto elapsed = std::chrono::high_resolution_clock::now() - started;
auto elapsed_total = std::chrono::duration_cast<std::chrono::nanoseconds>(elapsed).count();
double elapsed_per = static_cast<double>(elapsed_total) / count;
std::cout << "CTOR, "
<< name << ", "
<< typeid(ClockType).name() << ", "
<< count << ", "
<< elapsed_total/1E9 << " sec, "
<< elapsed_per << " ns/call"
<< "\n";
std::cout.flush();
}
uint64_t _tse_count = 0;
template<typename ClockType>
std::chrono::milliseconds time_TimeSinceEpoch( const std::string& name, uint64_t count ) {
ClockType::time_point ts = ClockType::now();
decltype(ts.time_since_epoch()) ts_int;
auto started = std::chrono::high_resolution_clock::now();
// Code optimization defeats this loop when it only operates on `ts` (unchanging).
for (uint64_t i=0; i<count; i++) {
ts_int = ts.time_since_epoch();
// This is an attempt to defeat compiler optimization that totally skips the loop.
_tse_count++;
}
auto elapsed = std::chrono::high_resolution_clock::now() - started;
auto elapsed_total = std::chrono::duration_cast<std::chrono::nanoseconds>(elapsed);
double elapsed_per = static_cast<double>(elapsed_total.count()) / count;
std::cout << "time_since_epoch, "
<< name << ", "
<< typeid(ClockType).name() << ", "
<< count << ", "
<< elapsed_total.count()/1E9 << " sec, "
<< elapsed_per << " ns/call"
<< "\n";
std::cout.flush();
return std::chrono::duration_cast<std::chrono::milliseconds>(elapsed_total);
}
template<typename ClockType>
void time_StringifyTimestamp( const std::string& name, uint32_t count ) {
const std::time_t t = ClockType::to_time_t(ClockType::now());
const std::tm tm = *std::localtime(&t);
std::stringstream buf;
auto started = std::chrono::high_resolution_clock::now();
for (uint32_t i=0; i<count; i++) {
buf.str(std::string()); // probably costs something
buf << std::put_time(&tm, "%Y-%m-%dT%H:%M:%S");
}
auto elapsed = std::chrono::high_resolution_clock::now() - started;
auto elapsed_total = std::chrono::duration_cast<std::chrono::nanoseconds>(elapsed).count();
double elapsed_per = static_cast<double>(elapsed_total) / count / 1E3; // ns -> usec
std::cout << "std::put_time, "
<< name << ", "
<< typeid(ClockType).name() << ", "
<< count << ", "
<< elapsed_total/1E9 << " sec, "
<< elapsed_per << " usec/call"
<< "\n";
std::cout.flush();
}
void test_GetCurrentTimestamp() {
// How long does it take to get the current time?
std::vector<uint32_t> iterations { 10000, 100000, 1000000, 10000000, 100000000, 500000000 };
for ( auto count : iterations) {
time_GetCurrentTimestamp<std::chrono::high_resolution_clock>("std::chrono::high_resolution_clock",count);
}
for ( auto count : iterations) {
time_GetCurrentTimestamp<std::chrono::steady_clock>("std::chrono::steady_clock",count);
}
for ( auto count : iterations) {
time_GetCurrentTimestamp<std::chrono::system_clock>("std::chrono::system_clock",count);
}
}
void test_TimeSinceEpoch() {
// How long does it take to get the seconds since the epoch out of an existing timestamp?
std::vector<uint64_t> iterations { 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 10000000000, 50000000000 };
std::chrono::milliseconds test_th(10000); // stop running larger iterations if the test takes longer than this
for ( auto count : iterations) {
if (time_TimeSinceEpoch<std::chrono::high_resolution_clock>("std::chrono::high_resolution_clock",count) > test_th) break;
}
for ( auto count : iterations) {
if (time_TimeSinceEpoch<std::chrono::steady_clock>("std::chrono::steady_clock",count) > test_th) break;
}
for ( auto count : iterations) {
if (time_TimeSinceEpoch<std::chrono::system_clock>("std::chrono::system_clock",count) > test_th) break;
}
}
void test_StringifyTimestamp() {
// How long does it take to turn a timestamp into an ISO 8601 string?
std::vector<uint32_t> iterations { 10000, 100000, 1000000, 10000000 };
for ( auto count : iterations) {
time_StringifyTimestamp<std::chrono::system_clock>("std::chrono::system_clock",count);
}
}
#define RUN_TEST(fn) \
try { \
std::cout << #fn << "\n"; \
fn(); \
} \
catch (const std::exception& e) { \
std::cerr << "Exception in " ## #fn ## ": " << e.what() << "\n"; \
}
int main( int argc, const char** argv) {
std::cout << "Compiler: " << _MSC_VER << " (" << _MSC_FULL_VER << ")\n"
;
RUN_TEST(test_GetCurrentTimestamp);
RUN_TEST(test_TimeSinceEpoch);
RUN_TEST(test_StringifyTimestamp);
return 0;
}
@mojomojomojo
Copy link
Author

Written for MSVC (compiler version macros), but should be easily adaptable to any platform.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment