In-class Demo: Three Profiling Methods on a Controlled Program

GitHub repo

Purpose of this Demo

Today’s goal is not to analyze convolution performance.
Today’s goal is to learn how to profile.

We will use a small, controlled C++ program — parallel_dnc_demo — to demonstrate three profiling approaches:

  1. Wall-clock timing with <chrono>
  2. Sampling profiling with perf (Linux)
  3. Visual profiling with Instruments Time Profiler (macOS)

You will see the tools today so that you can use them confidently in the upcoming lab.


The Demo Program: What It Does

parallel_dnc_demo implements merge sort in two modes:

  • seq — sequential merge sort
  • par — fork–join parallel merge sort using std::async

Key design choices (important for profiling):

  • Parallel recursion stops below a cutoff size
  • Maximum parallel depth is limited by hardware threads
  • The merge step is sequential

This makes the program ideal for discussing:

  • overhead
  • task granularity
  • Amdahl’s Law
  • “why parallel isn’t always faster”

Program Interface (Know This First)

parallel_dnc_demo N mode [cutoff]

N       number of integers to sort
mode    seq | par
cutoff  (parallel only) minimum subproblem size to spawn tasks

Examples:

./parallel_dnc_demo 5000000 seq
./parallel_dnc_demo 5000000 par 50000
./parallel_dnc_demo 5000000 par 2000

Interpretation:

  • Smaller cutoff → more tasks → more overhead
  • Larger cutoff → fewer tasks → less parallelism

Part 1 — Chrono Timing (Wall-Clock Measurement)

Chrono timing is already built into the program.

Demo sequence (run live)

Sequential:

./parallel_dnc_demo 5000000 seq

Parallel with reasonable cutoff:

./parallel_dnc_demo 5000000 par 50000

Parallel with tiny cutoff:

./parallel_dnc_demo 5000000 par 2000

Discussion prompts (ask students)

  • Which run was fastest?
  • Why can parallel be slower than sequential?
  • What overhead is introduced by std::async?
  • What part of the algorithm cannot be parallelized?

Key lesson:

Chrono tells us what happened, not why.


Part 2 — Sampling Profiling with perf (Linux only)

Important note (say this explicitly)

perf is a Linux-only tool.
It is not available by default on macOS.

That’s why your terminal says:

zsh: command not found: perf

This is normal.


When to use perf

Use perf when:

  • you are on Linux
  • you want low-overhead sampling
  • you want exact function-level hotspots

Demo commands (Linux system)

Build with symbols

make clean
make CXXFLAGS="-O3 -g -march=native"

Profile a run long enough to sample

perf record -g ./parallel_dnc_demo 5000000 par 2000
perf report

If the run is too short:

perf record -g ./parallel_dnc_demo 20000000 par 2000

How to interpret perf report

Focus on three things only:

  1. Top 1–3 entries
    • These dominate runtime.
    • Everything else is noise.
  2. Self vs Children
    • Self: time in this function
    • Children: time in functions it called
    • High “Children” → this function is a dispatcher
  3. Call graph (-g)
    • Expand the top hotspot
    • Identify where time is really going:
      • comparisons?
      • merges?
      • task spawning?

Key teaching moment:

If the hotspot isn’t what you expected, your mental model is wrong — not the profiler.


Part 3 — Instruments Time Profiler (macOS)

On macOS, Instruments is your primary profiler. You must install xcode wit hthe apps application on macOS.

It provides:

  • call trees
  • percent-time breakdowns
  • timelines showing execution phases

Build with symbols

make clean
make CXXFLAGS="-O3 -g"

Run Instruments

  1. Open Instruments
    • Xcode → Open Developer Tool → Instruments
  2. Choose Time Profiler
  3. Select target: parallel_dnc_demo
  4. Program arguments (This is set after you select the targetnaer the bottom of the choose target window):
500000000 par 2000
  1. Click Choose button
  2. Click Record (the red button in the top left), let it finish, then stop

What to show live in Instruments

In the Call Tree view (Click “Time Profiler in the top middle pain, then click “Call Tree” in the bottom center):

Enable:

  • ✔ Hide System Libraries
  • ✔ Invert Call Tree

Then point out:

  • top 1–3 hottest functions
  • percent time
  • difference between:
    • sorting work
    • merge work
    • task overhead

Run again with:

5000000 par 50000

Ask:

  • Did the hotspot change?
  • Did overhead move or shrink?

Key Takeaways (Connect to the Lab)

Say this explicitly at the end:

  • Chrono answers: how long did it take?
  • perf / Instruments answer: where did the time go?
  • Parallel and FFT algorithms introduce overhead
  • Whether they win depends on problem size and structure

This is exactly the mindset you will use in the convolution lab:

  • naive vs FFT
  • small kernels vs large kernels
  • measurement before conclusions
Scroll to Top