Measuring Code Performance
Benchmark with chrono.
Measuring Code Performance is a free C++ Academy lesson on CoddyKit. This is lesson 3 of 4. Any 3 lessons of this learning path are free to read in full — after that, CoddyKit PRO unlocks every lesson, plus hands-on practice with a built-in code editor and a 24/7 AI tutor. It is part of the C++ Academy learning path, and your progress syncs across the web and the CoddyKit app. The C++ Academy course includes 4 lessons in total.
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.
Learn C++ with an AI tutor — free
Write and run real code in your browser, get instant help from a 24/7 AI tutor, and pick up where you left off on the web or in the app.
- Courses
- 51
- Lessons
- 203
Frequently Asked Questions
Is the “Measuring Code Performance” lesson free?
Yes — any 3 lessons of the C++ Academy learning path, including “Measuring Code Performance”, are free to read in full here on the web. After that, CoddyKit PRO unlocks every lesson, plus interactive practice with a built-in code editor and a 24/7 AI tutor. The C++ Academy course includes 4 lessons in total.
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, so you can start here or from the beginning and move at your own pace. This is lesson 3 of 4.
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