Zig Profiling Counts
Profile by counting is a way to find slow code by counting how many times each part runs. It needs no clock, only counters that are printed at the end.
Count the additions
A counter beside a loop records every addition. This loop adds five numbers, so the count is five.
const std = @import("std");
pub fn main() !void {
const out = std.io.getStdOut().writer();
const data = [_]u32{ 3, 1, 4, 1, 5 };
var sum: u32 = 0;
var adds: u32 = 0;
for (data) |v| {
sum += v;
adds += 1;
}
try out.print("sum {d} adds {d}\n", .{ sum, adds });
}Count until found
Counting comparisons shows how far a search goes. The target sits at index 2, so the search makes three comparisons.
const std = @import("std");
pub fn main() !void {
const out = std.io.getStdOut().writer();
const data = [_]u32{ 9, 7, 4, 2, 8 };
const target: u32 = 4;
var comparisons: u32 = 0;
var found: usize = 0;
for (data, 0..) |v, i| {
comparisons += 1;
if (v == target) {
found = i;
break;
}
}
try out.print("{d} {d}\n", .{ comparisons, found });
}Counters in a struct
A struct can hold several counters at once. Each field counts one kind of operation.
const std = @import("std");
const Counters = struct {
adds: u32,
hits: u32,
};
pub fn main() !void {
const out = std.io.getStdOut().writer();
const data = [_]u32{ 5, 1, 5, 2 };
var counters = Counters{ .adds = 0, .hits = 0 };
for (data) |v| {
counters.adds += 1;
if (v == 5) counters.hits += 1;
}
try out.print("{d} {d}\n", .{ counters.adds, counters.hits });
}Example
const std = @import("std");
pub fn main() !void {
const out = std.io.getStdOut().writer();
const data = [_]u32{ 2, 4, 6, 8, 10, 12, 14, 16 };
var sum: u32 = 0;
var adds: u32 = 0;
for (data) |v| {
sum += v;
adds += 1;
}
var comparisons: u32 = 0;
for (data) |v| {
comparisons += 1;
if (v == 14) break;
}
try out.print("{d} {d} {d}\n", .{ sum, adds, comparisons });
}Key points
- Profile by counting: profile by counting is measuring code by counting operations instead of timing it.
- Counter: a counter is a number that grows by one each time an operation runs.
- Hot spot: a hot spot is the part of a program that runs most often.
- Operation: an operation is one small step of work, such as one addition.
- Fixed input: a fixed input is the same data used for every measurement, so counts can be compared.
- Counting pass: a counting pass is a run of a program that only collects counts.
The sum loop adds eight numbers, so its count is eight. The search reaches the target after seven comparisons. The counts show the search runs almost as often as the sum, even though it does less work.
Try it Yourself
Edit the code, then press Run.
Running is simulated
Exercise
What does profile by counting use instead of a clock?