Measuring Code Performance
Benchmark with chrono.
Measuring Code Performance is a free C++ Academy lesson on CoddyKit — lesson 3 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the C++ Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
Why Benchmark?
Measuring how long code runs helps you find bottlenecks and verify optimizations. With <chrono> you get portable, type-safe timing.
- Measure before optimizing.
- Use a steady clock for reliable intervals.
#include <iostream>
#include <chrono>
int main() {
using namespace std::chrono;
auto start = steady_clock::now();
auto end = steady_clock::now();
std::cout << "Timed a block: " << ((end - start).count() >= 0) << '\n';
return 0;
}The Basic Pattern
The benchmarking pattern is always the same: capture now() before the work, run it, capture now() after, and subtract.
#include <iostream>
#include <chrono>
int main() {
using namespace std::chrono;
auto start = steady_clock::now();
long sum = 0;
for (int i = 0; i < 100000; ++i) sum += i;
auto end = steady_clock::now();
std::cout << "Sum: " << sum << ", elapsed >= 0: " << ((end - start).count() >= 0) << '\n';
return 0;
}Choosing the Unit
Pick the unit that fits the workload. Use microseconds or nanoseconds for fast loops, milliseconds for larger tasks.
#include <iostream>
#include <chrono>
int main() {
using namespace std::chrono;
auto start = steady_clock::now();
long sum = 0;
for (int i = 0; i < 500000; ++i) sum += i;
auto end = steady_clock::now();
auto us = duration_cast<microseconds>(end - start);
std::cout << "Result: " << sum << ", us non-negative: " << (us.count() >= 0) << '\n';
return 0;
}Floating-Point Timing
For human-readable seconds with fractions, use a duration<double> so you keep sub-second precision.
#include <iostream>
#include <chrono>
int main() {
using namespace std::chrono;
auto start = steady_clock::now();
long sum = 0;
for (int i = 0; i < 200000; ++i) sum += i % 7;
auto end = steady_clock::now();
duration<double> secs = end - start;
std::cout << "Computed " << sum << ", seconds >= 0: " << (secs.count() >= 0) << '\n';
return 0;
}A Reusable Timer
Wrap the pattern in a small helper so you can time any callable cleanly and avoid repeating yourself.
#include <iostream>
#include <chrono>
long long timeWork() {
using namespace std::chrono;
auto s = steady_clock::now();
long acc = 0;
for (int i = 0; i < 100000; ++i) acc += i;
auto e = steady_clock::now();
return duration_cast<microseconds>(e - s).count();
}
int main() {
std::cout << "Microseconds non-negative: " << (timeWork() >= 0) << '\n';
return 0;
}Avoid Dead-Code Elimination
Compilers may delete work whose result is unused, ruining benchmarks. Always consume the result, for example by printing it or accumulating into a visible variable.
#include <iostream>
#include <chrono>
int main() {
using namespace std::chrono;
auto s = steady_clock::now();
volatile long sink = 0;
for (int i = 0; i < 100000; ++i) sink += i;
auto e = steady_clock::now();
std::cout << "Sink used: " << (sink > 0) << ", elapsed >= 0: " << ((e - s).count() >= 0) << '\n';
return 0;
}Warm-Up Runs
The first run can be slower due to caches and lazy initialization. Do a warm-up pass before measuring for steadier numbers.
#include <iostream>
#include <chrono>
long work() {
long a = 0;
for (int i = 0; i < 50000; ++i) a += i;
return a;
}
int main() {
using namespace std::chrono;
work();
auto s = steady_clock::now();
long r = work();
auto e = steady_clock::now();
std::cout << r << " measured, ok: " << ((e - s).count() >= 0) << '\n';
return 0;
}Averaging Multiple Runs
A single measurement is noisy. Run the work many times, sum the elapsed durations, and divide for a stable average.
#include <iostream>
#include <chrono>
int main() {
using namespace std::chrono;
long long total = 0;
const int runs = 5;
for (int r = 0; r < runs; ++r) {
auto s = steady_clock::now();
long acc = 0;
for (int i = 0; i < 100000; ++i) acc += i;
auto e = steady_clock::now();
total += duration_cast<microseconds>(e - s).count();
}
std::cout << "Average us non-negative: " << ((total / runs) >= 0) << '\n';
return 0;
}Comparing Two Approaches
Benchmarking shines when comparing implementations. Time each one the same way and compare the resulting durations.
#include <iostream>
#include <chrono>
#include <vector>
int main() {
using namespace std::chrono;
std::vector<int> v;
auto s1 = steady_clock::now();
for (int i = 0; i < 10000; ++i) v.push_back(i);
auto e1 = steady_clock::now();
v.clear();
v.reserve(10000);
auto s2 = steady_clock::now();
for (int i = 0; i < 10000; ++i) v.push_back(i);
auto e2 = steady_clock::now();
std::cout << "Both timed: " << (((e1 - s1).count() >= 0) && ((e2 - s2).count() >= 0)) << '\n';
return 0;
}Beware of Resolution
If the measured work is shorter than the clock's tick, you may read zero. Loop the work enough times to exceed the clock resolution.
#include <iostream>
#include <chrono>
int main() {
using namespace std::chrono;
auto s = steady_clock::now();
int x = 1 + 1;
auto e = steady_clock::now();
auto ns = duration_cast<nanoseconds>(e - s).count();
std::cout << "x=" << x << ", tiny work may read low: " << (ns >= 0) << '\n';
return 0;
}Reporting Results
Convert the final duration to a readable unit and print it. Keep the consumed result visible so the optimizer cannot remove the work.
#include <iostream>
#include <chrono>
int main() {
using namespace std::chrono;
auto s = steady_clock::now();
long acc = 0;
for (int i = 0; i < 300000; ++i) acc += (i * 3) % 11;
auto e = steady_clock::now();
auto ms = duration_cast<milliseconds>(e - s).count();
std::cout << "acc=" << acc << ", ms >= 0: " << (ms >= 0) << '\n';
return 0;
}Quick Check
Test your understanding of benchmarking pitfalls.
Recap
You learned how to benchmark code with <chrono>:
- capture
steady_clock::now()before and after, then subtract - choose an appropriate unit with
duration_cast - warm up, average multiple runs, and consume results to defeat dead-code elimination
- watch out for clock resolution on tiny workloads
Next, you will explore the C++20 calendar and time zone types.
Frequently asked questions
Is the “Measuring Code Performance” lesson free?
Yes — the full text of “Measuring Code Performance” is free to read here on the web, and the C++ Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the C++ Academy course, upgrade to CoddyKit PRO.
What will I learn in “Measuring Code Performance”?
Benchmark with chrono. You practise C++ Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start C++ Academy?
No prior experience is required. C++ Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 3 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Measuring Code Performance” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this C++ Academy lesson?
Yes. Every C++ Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- Durations and Clocks
- Time Points
- Measuring Code Performance
- Calendar and Time Zones