Timing a piece of code in C++ comes down to three steps: take a time point before the work, take another after it, and convert the difference into whatever unit you want. The <chrono> header gives you all three.
Picking the right clock
<chrono> offers three clocks, and the choice matters more than it looks.
| Clock | Steady? | Use it for |
|---|---|---|
steady_clock | Yes | Measuring elapsed time |
system_clock | No | Wall-clock timestamps you want to display or store |
high_resolution_clock | Depends | Nothing — it is an alias for one of the other two |
"Steady" means the clock only ever moves forward at a constant rate. system_clock tracks civil time, so an NTP correction or a daylight-saving change can move it backwards mid-measurement and hand you a negative duration. steady_clock cannot do that, which is exactly why it is the one you want here.
NOTE
high_resolution_clock sounds like the obvious pick and is a trap. The standard permits it to be an alias for either of the others, and implementations differ — on the machine I ran this on, std::is_same<high_resolution_clock, steady_clock> is true, but you cannot rely on that. Name the clock you actually mean.
The program
#include <iostream>
#include <chrono>
#include <thread>
int main() {
auto start = std::chrono::steady_clock::now();
std::this_thread::sleep_for(std::chrono::seconds(2));
auto end = std::chrono::steady_clock::now();
auto elapsed = end - start;
std::cout << "Elapsed time in microseconds: "
<< std::chrono::duration_cast<std::chrono::microseconds>(elapsed).count()
<< " us\n";
std::cout << "Elapsed time in milliseconds: "
<< std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count()
<< " ms\n";
std::cout << "Elapsed time in nanoseconds: "
<< std::chrono::duration_cast<std::chrono::nanoseconds>(elapsed).count()
<< " ns\n";
std::cout << "Elapsed time in seconds: "
<< std::chrono::duration_cast<std::chrono::seconds>(elapsed).count()
<< " s\n";
return 0;
}Elapsed time in microseconds: 2005044 us
Elapsed time in milliseconds: 2005 ms
Elapsed time in nanoseconds: 2005044792 ns
Elapsed time in seconds: 2 sReading the output
sleep_for pauses for two seconds, so every reading is about two seconds expressed in its own unit. The interesting part is the extra 5 milliseconds. Sleeping is a request to the scheduler, not a guarantee — the thread becomes eligible to run again after two seconds and actually runs some time after that. Timing code will always show you that overhead, which is the whole reason to measure rather than assume.
Note also that the seconds line reads exactly 2, not 2.005. duration_cast truncates toward zero rather than rounding, so a coarse unit quietly discards the remainder. Cast to a floating-point duration if you want the fraction:
std::chrono::duration<double> seconds = elapsed;
std::cout << seconds.count() << " s\n";TIP
Earlier versions of this program used sleep() from <unistd.h>, which is POSIX-only and will not compile on Windows. std::this_thread::sleep_for is standard C++ since C++11 and portable everywhere, so prefer it.
One caveat about timing small things
For anything that finishes in microseconds, a single measurement tells you very little — scheduler noise, cache state, and CPU frequency scaling all swamp the signal. Run the work in a loop many times, measure the whole loop, and divide. And build with optimisations on, or you are timing the debug build rather than the one you ship.