Skip to documentation
SLOP

tiny.profiling.report.chart

Reference tiny.profiling report chart

Defined in report.

API (11)

Actions

Public operations.

Types and contracts

Public types and contracts.

No direct callersNo direct callsreportchart
Static calls · unresolved targets: unknown · external targets: unknown.

Source

Called byCallstest; no linksrc.profiling.report.charttest: chart line renders band path an...test; no linksrc.profiling.report.charttest: chart line single point centers...test; no linksrc.profiling.report.charttest: chart line skips gaps and handl...private; no linksrc.profiling.report.pageseriesChartprivate; no linksrc.profiling.report.chartemptyTextprivate; no linksrc.profiling.report.chartlineBandprivate; no linksrc.profiling.report.chartlineDotsprivate; no linksrc.profiling.report.chartlinePathprivate; no linksrc.profiling.report.chartlineTicksprivate; no linksrc.profiling.report.chartopenSvgreport.chartline
Static calls · unresolved targets: 0 · external targets: 3.
Called byCallstest; no linksrc.profiling.report.charttest: chart sequence bounds points an...test; no linksrc.profiling.report.charttest: chart sequence renders acquisit...private; no linksrc.profiling.report.pagemetricWithinRunChartprivate; no linksrc.profiling.report.chartemptyTextprivate; no linksrc.profiling.report.chartopenSvgprivate; no linksrc.profiling.report.chartsequenceDotsprivate; no linksrc.profiling.report.chartsequenceIndicesprivate; no linksrc.profiling.report.chartsequencePathprivate; no linksrc.profiling.report.chartsequenceSummaryreport.chartsequence
Static calls · unresolved targets: 0 · external targets: 4.
Called byCallstest; no linksrc.profiling.report.charttest: chart strip renders samples med...test; no linksrc.profiling.report.charttest: chart strip strides oversized s...private; no linksrc.profiling.report.pagemetricWithinRunChartprivate; no linksrc.profiling.report.chartappendEscapedTextprivate; no linksrc.profiling.report.chartappendFmtprivate; no linksrc.profiling.report.chartemptyTextprivate; no linksrc.profiling.report.chartopenSvgprivate; no linktools.smg.src.help.optionsformatreport.chartstrip
Static calls · unresolved targets: 0 · external targets: 5.
Called byCallstest; no linksrc.profiling.report.charttest: chart xy sorts by x and anchors...private; no linksrc.profiling.report.pagecausalCurveprivate; no linksrc.profiling.report.chartappendEscapedTextprivate; no linksrc.profiling.report.chartappendFmtprivate; no linksrc.profiling.report.chartemptyTextprivate; no linksrc.profiling.report.chartopenSvgprivate; no linksrc.profiling.report.chartxyXreport.chartxy
Static calls · unresolved targets: 0 · external targets: 6.

Source: src/profiling/report/chart.zig

zig
const std = @import("std");const zen = @import("zen");const Allocator = std.mem.Allocator;pub const Format = *const fn (Allocator, f64) Allocator.Error![]u8;pub const Point = struct {    label: []const u8,    value: ?f64,    low: ?f64 = null,    high: ?f64 = null,};pub const LineOptions = struct {    width: f64 = 260,    height: f64 = 64,    ticks: bool = false,    format: Format,};pub const StripOptions = struct {    width: f64 = 220,    height: f64 = 40,    format: Format,};pub const SequenceOptions = struct {    width: f64 = 220,    height: f64 = 40,    index_origin: u64 = 0,    format: Format,};pub const XyPoint = struct {    x: f64,    y: f64,    label: []const u8,};pub const XyOptions = struct {    width: f64 = 210,    height: f64 = 72,};const max_strip_dots = 512;const max_sequence_points = 512;const Domain = struct {    min: f64,    max: f64,    fn observe(self: *Domain, value: ?f64) void {        const actual = value orelse return;        if (!std.math.isFinite(actual)) return;        if (actual < self.min) self.min = actual;        if (actual > self.max) self.max = actual;    }    fn seen(self: Domain) bool {        return self.min <= self.max;    }    fn span(self: Domain) f64 {        return if (self.max > self.min) self.max - self.min else 1;    }};const empty_domain = Domain{ .min = std.math.inf(f64), .max = -std.math.inf(f64) };pub fn line(allocator: Allocator, points: []const Point, options: LineOptions) Allocator.Error![]u8 {    var out: std.ArrayList(u8) = .empty;    var domain = empty_domain;    var defined: usize = 0;    for (points) |point| {        if (point.value != null) defined += 1;        domain.observe(point.value);        domain.observe(point.low);        domain.observe(point.high);    }    try openSvg(&out, allocator, options.width, options.height, "chart-line-figure");    if (defined == 0) {        try emptyText(&out, allocator, options.width, options.height);        try out.appendSlice(allocator, "</svg>");        return try out.toOwnedSlice(allocator);    }    const pad_left: f64 = if (options.ticks) 64 else 8;    const pad_right: f64 = 8;    const pad_y: f64 = 7;    const plot = Plot{        .x0 = pad_left,        .x1 = options.width - pad_right,        .y0 = pad_y,        .y1 = options.height - pad_y,        .domain = domain,        .count = points.len,    };    if (options.ticks) try lineTicks(&out, allocator, plot, options.format);    try lineBand(&out, allocator, points, plot);    try linePath(&out, allocator, points, plot);    try lineDots(&out, allocator, points, plot, options.format);    try out.appendSlice(allocator, "</svg>");    return try out.toOwnedSlice(allocator);}pub fn strip(    allocator: Allocator,    samples: []const u64,    median: ?f64,    low: ?f64,    high: ?f64,    options: StripOptions,) Allocator.Error![]u8 {    var out: std.ArrayList(u8) = .empty;    var domain = empty_domain;    for (samples) |sample| domain.observe(@floatFromInt(sample));    domain.observe(median);    domain.observe(low);    domain.observe(high);    try openSvg(&out, allocator, options.width, options.height, "chart-strip-figure");    if (!domain.seen()) {        try emptyText(&out, allocator, options.width, options.height);        try out.appendSlice(allocator, "</svg>");        return try out.toOwnedSlice(allocator);    }    const plot = Plot{        .x0 = 8,        .x1 = options.width - 8,        .y0 = 5,        .y1 = options.height - 5,        .domain = domain,        .count = samples.len,    };    if (low != null and high != null) {        const band_x0 = plot.xValue(low.?);        const band_x1 = plot.xValue(high.?);        try appendFmt(&out, allocator, "<rect class=\"chart-band\" x=\"{d:.2}\" y=\"{d:.2}\" width=\"{d:.2}\" height=\"{d:.2}\"/>", .{            @min(band_x0, band_x1),            plot.y0,            @abs(band_x1 - band_x0),            plot.y1 - plot.y0,        });    }    if (median) |actual| {        const x = plot.xValue(actual);        try appendFmt(&out, allocator, "<line class=\"chart-median\" x1=\"{d:.2}\" y1=\"{d:.2}\" x2=\"{d:.2}\" y2=\"{d:.2}\"><title>median ", .{ x, plot.y0, x, plot.y1 });        try appendEscapedText(&out, allocator, try options.format(allocator, actual));        try out.appendSlice(allocator, "</title></line>");    }    const stride = if (samples.len > max_strip_dots) samples.len / max_strip_dots + 1 else 1;    const middle = (plot.y0 + plot.y1) / 2;    const amplitude = (plot.y1 - plot.y0) / 2 - 3;    const observation_fmt =        "<circle class=\"chart-sample\" cx=\"{d:.2}\" cy=\"{d:.2}\" r=\"2\">" ++        "<title>observation {d}: ";    var index: usize = 0;    while (index < samples.len) : (index += stride) {        const value: f64 = @floatFromInt(samples[index]);        const offsets = [_]f64{ 0, -0.5, 0.5, -1, 1 };        const jitter = offsets[index % offsets.len] * amplitude;        try appendFmt(&out, allocator, observation_fmt, .{            plot.xValue(value),            middle + jitter,            index,        });        try appendEscapedText(&out, allocator, try options.format(allocator, value));        try out.appendSlice(allocator, "</title></circle>");    }    try out.appendSlice(allocator, "</svg>");    return try out.toOwnedSlice(allocator);}pub fn sequence(    allocator: Allocator,    samples: []const u64,    median: ?f64,    low: ?f64,    high: ?f64,    options: SequenceOptions,) Allocator.Error![]u8 {    var out: std.ArrayList(u8) = .empty;    var domain = empty_domain;    for (samples) |sample| domain.observe(@floatFromInt(sample));    domain.observe(median);    domain.observe(low);    domain.observe(high);    try openSvg(&out, allocator, options.width, options.height, "chart-sequence-figure");    if (samples.len == 0) {        try emptyText(&out, allocator, options.width, options.height);        try out.appendSlice(allocator, "</svg>");        return try out.toOwnedSlice(allocator);    }    const indices = try sequenceIndices(allocator, samples);    defer allocator.free(indices);    const plot = Plot{        .x0 = 8,        .x1 = options.width - 8,        .y0 = 5,        .y1 = options.height - 5,        .domain = domain,        .count = samples.len,    };    try sequenceSummary(&out, allocator, plot, median, low, high, options.format);    try sequencePath(&out, allocator, plot, samples, indices);    try sequenceDots(&out, allocator, plot, samples, indices, options);    try out.appendSlice(allocator, "</svg>");    return try out.toOwnedSlice(allocator);}fn sequenceIndices(allocator: Allocator, samples: []const u64) Allocator.Error![]usize {    var indices: std.ArrayList(usize) = .empty;    errdefer indices.deinit(allocator);    try indices.ensureTotalCapacity(allocator, @min(samples.len, max_sequence_points));    if (samples.len <= max_sequence_points) {        for (samples, 0..) |_, index| indices.appendAssumeCapacity(index);        return try indices.toOwnedSlice(allocator);    }    indices.appendAssumeCapacity(0);    const bucket_count = (max_sequence_points - 2) / 2;    const interior = samples.len - 2;    const base_width = interior / bucket_count;    const wide_buckets = interior % bucket_count;    var start: usize = 1;    for (0..bucket_count) |bucket| {        const stop = start + base_width + @intFromBool(bucket < wide_buckets);        var min_index = start;        var max_index = start;        for (start + 1..stop) |index| {            if (samples[index] < samples[min_index]) min_index = index;            if (samples[index] > samples[max_index]) max_index = index;        }        indices.appendAssumeCapacity(@min(min_index, max_index));        if (min_index != max_index) indices.appendAssumeCapacity(@max(min_index, max_index));        start = stop;    }    indices.appendAssumeCapacity(samples.len - 1);    std.debug.assert(indices.items.len <= max_sequence_points);    return try indices.toOwnedSlice(allocator);}fn sequenceSummary(    out: *std.ArrayList(u8),    allocator: Allocator,    plot: Plot,    median: ?f64,    low: ?f64,    high: ?f64,    format: Format,) Allocator.Error!void {    if (low != null and high != null) {        const y0 = plot.yValue(@max(low.?, high.?));        const y1 = plot.yValue(@min(low.?, high.?));        try appendFmt(out, allocator, "<rect class=\"chart-band\" x=\"{d:.2}\" y=\"{d:.2}\" " ++            "width=\"{d:.2}\" height=\"{d:.2}\"/>", .{            plot.x0,            y0,            plot.x1 - plot.x0,            y1 - y0,        });    }    if (median) |value| {        const y = plot.yValue(value);        try appendFmt(out, allocator, "<line class=\"chart-median\" x1=\"{d:.2}\" y1=\"{d:.2}\" " ++            "x2=\"{d:.2}\" y2=\"{d:.2}\"><title>median ", .{            plot.x0,            y,            plot.x1,            y,        });        try appendEscapedText(out, allocator, try format(allocator, value));        try out.appendSlice(allocator, "</title></line>");    }}fn sequencePath(    out: *std.ArrayList(u8),    allocator: Allocator,    plot: Plot,    samples: []const u64,    indices: []const usize,) Allocator.Error!void {    if (indices.len < 2) return;    try out.appendSlice(allocator, "<path class=\"chart-line\" d=\"");    for (indices, 0..) |index, path_index| {        try appendFmt(out, allocator, "{s}{d:.2} {d:.2} ", .{            if (path_index == 0) "M" else "L",            plot.xIndex(index),            plot.yValue(@floatFromInt(samples[index])),        });    }    try out.appendSlice(allocator, "\"/>");}fn sequenceDots(    out: *std.ArrayList(u8),    allocator: Allocator,    plot: Plot,    samples: []const u64,    indices: []const usize,    options: SequenceOptions,) Allocator.Error!void {    const point_fmt =        "<circle class=\"chart-dot chart-sequence-sample\" cx=\"{d:.2}\" " ++        "cy=\"{d:.2}\" r=\"2\"><title>sample {d}: ";    for (indices) |index| {        const value: f64 = @floatFromInt(samples[index]);        const display_index = std.math.add(            u64,            options.index_origin,            @intCast(index),        ) catch std.math.maxInt(u64);        try appendFmt(out, allocator, point_fmt, .{            plot.xIndex(index),            plot.yValue(value),            display_index,        });        try appendEscapedText(out, allocator, try options.format(allocator, value));        try out.appendSlice(allocator, "</title></circle>");    }}pub fn xy(allocator: Allocator, points: []const XyPoint, options: XyOptions) Allocator.Error![]u8 {    var out: std.ArrayList(u8) = .empty;    try openSvg(&out, allocator, options.width, options.height, "chart-xy-figure");    if (points.len == 0) {        try emptyText(&out, allocator, options.width, options.height);        try out.appendSlice(allocator, "</svg>");        return try out.toOwnedSlice(allocator);    }    var x_domain = empty_domain;    var y_domain = empty_domain;    y_domain.observe(0);    for (points) |point| {        x_domain.observe(point.x);        y_domain.observe(point.y);    }    const plot = Plot{        .x0 = 8,        .x1 = options.width - 8,        .y0 = 7,        .y1 = options.height - 7,        .domain = y_domain,        .count = points.len,    };    const zero_y = plot.yValue(0);    try appendFmt(&out, allocator, "<line class=\"chart-grid\" x1=\"{d:.2}\" y1=\"{d:.2}\" x2=\"{d:.2}\" y2=\"{d:.2}\"/>", .{ plot.x0, zero_y, plot.x1, zero_y });    const order = try allocator.alloc(usize, points.len);    for (order, 0..) |*slot, point_index| slot.* = point_index;    std.mem.sort(usize, order, points, xyBefore);    if (points.len >= 2) {        try out.appendSlice(allocator, "<path class=\"chart-line\" d=\"");        for (order, 0..) |point_index, path_index| {            const point = points[point_index];            try appendFmt(&out, allocator, "{s}{d:.2} {d:.2} ", .{                if (path_index == 0) "M" else "L",                xyX(plot, x_domain, point.x),                plot.yValue(point.y),            });        }        try out.appendSlice(allocator, "\"/>");    }    for (order) |point_index| {        const point = points[point_index];        try appendFmt(&out, allocator, "<circle class=\"chart-dot\" cx=\"{d:.2}\" cy=\"{d:.2}\" r=\"2.5\"><title>", .{            xyX(plot, x_domain, point.x),            plot.yValue(point.y),        });        try appendEscapedText(&out, allocator, point.label);        try out.appendSlice(allocator, "</title></circle>");    }    try out.appendSlice(allocator, "</svg>");    return try out.toOwnedSlice(allocator);}fn xyX(plot: Plot, x_domain: Domain, value: f64) f64 {    if (x_domain.max == x_domain.min) return (plot.x0 + plot.x1) / 2;    const fraction = (value - x_domain.min) / x_domain.span();    return plot.x0 + fraction * (plot.x1 - plot.x0);}fn xyBefore(points: []const XyPoint, left: usize, right: usize) bool {    return points[left].x < points[right].x;}const Plot = struct {    x0: f64,    x1: f64,    y0: f64,    y1: f64,    domain: Domain,    count: usize,    fn xIndex(self: Plot, index: usize) f64 {        if (self.count <= 1) return (self.x0 + self.x1) / 2;        const fraction = @as(f64, @floatFromInt(index)) / @as(f64, @floatFromInt(self.count - 1));        return self.x0 + fraction * (self.x1 - self.x0);    }    fn xValue(self: Plot, value: f64) f64 {        if (self.domain.max == self.domain.min) return (self.x0 + self.x1) / 2;        const fraction = (value - self.domain.min) / self.domain.span();        return self.x0 + fraction * (self.x1 - self.x0);    }    fn yValue(self: Plot, value: f64) f64 {        if (self.domain.max == self.domain.min) return (self.y0 + self.y1) / 2;        const fraction = (value - self.domain.min) / self.domain.span();        return self.y1 - fraction * (self.y1 - self.y0);    }};fn openSvg(out: *std.ArrayList(u8), allocator: Allocator, width: f64, height: f64, class: []const u8) Allocator.Error!void {    try appendFmt(out, allocator, "<svg class=\"{s}\" viewBox=\"0 0 {d:.0} {d:.0}\" width=\"{d:.0}\" height=\"{d:.0}\" role=\"img\">", .{        class,        width,        height,        width,        height,    });}fn emptyText(out: *std.ArrayList(u8), allocator: Allocator, width: f64, height: f64) Allocator.Error!void {    try appendFmt(out, allocator, "<text class=\"chart-empty\" x=\"{d:.0}\" y=\"{d:.0}\" text-anchor=\"middle\">no data</text>", .{        width / 2,        height / 2 + 4,    });}fn lineTicks(out: *std.ArrayList(u8), allocator: Allocator, plot: Plot, format: Format) Allocator.Error!void {    const rows = [_]f64{ plot.domain.max, (plot.domain.max + plot.domain.min) / 2, plot.domain.min };    for (rows) |value| {        const y = plot.yValue(value);        try appendFmt(out, allocator, "<line class=\"chart-grid\" x1=\"{d:.2}\" y1=\"{d:.2}\" x2=\"{d:.2}\" y2=\"{d:.2}\"/>", .{ plot.x0, y, plot.x1, y });        try appendFmt(out, allocator, "<text class=\"chart-tick\" x=\"{d:.2}\" y=\"{d:.2}\" text-anchor=\"end\">", .{ plot.x0 - 6, y + 3 });        try appendEscapedText(out, allocator, try format(allocator, value));        try out.appendSlice(allocator, "</text>");    }}fn lineBand(out: *std.ArrayList(u8), allocator: Allocator, points: []const Point, plot: Plot) Allocator.Error!void {    var start: usize = 0;    while (start < points.len) {        while (start < points.len and !banded(points[start])) start += 1;        if (start >= points.len) return;        var stop = start;        while (stop < points.len and banded(points[stop])) stop += 1;        if (stop - start >= 2) {            try out.appendSlice(allocator, "<path class=\"chart-band\" d=\"");            var index = start;            while (index < stop) : (index += 1) {                try appendFmt(out, allocator, "{s}{d:.2} {d:.2} ", .{ if (index == start) "M" else "L", plot.xIndex(index), plot.yValue(points[index].high.?) });            }            index = stop;            while (index > start) {                index -= 1;                try appendFmt(out, allocator, "L{d:.2} {d:.2} ", .{ plot.xIndex(index), plot.yValue(points[index].low.?) });            }            try out.appendSlice(allocator, "Z\"/>");        }        start = stop;    }}fn banded(point: Point) bool {    return point.value != null and point.low != null and point.high != null;}fn linePath(out: *std.ArrayList(u8), allocator: Allocator, points: []const Point, plot: Plot) Allocator.Error!void {    var start: usize = 0;    while (start < points.len) {        while (start < points.len and points[start].value == null) start += 1;        if (start >= points.len) return;        var stop = start;        while (stop < points.len and points[stop].value != null) stop += 1;        if (stop - start >= 2) {            try out.appendSlice(allocator, "<path class=\"chart-line\" d=\"");            var index = start;            while (index < stop) : (index += 1) {                try appendFmt(out, allocator, "{s}{d:.2} {d:.2} ", .{ if (index == start) "M" else "L", plot.xIndex(index), plot.yValue(points[index].value.?) });            }            try out.appendSlice(allocator, "\"/>");        }        start = stop;    }}fn lineDots(out: *std.ArrayList(u8), allocator: Allocator, points: []const Point, plot: Plot, format: Format) Allocator.Error!void {    for (points, 0..) |point, index| {        const value = point.value orelse continue;        try appendFmt(out, allocator, "<circle class=\"chart-dot\" cx=\"{d:.2}\" cy=\"{d:.2}\" r=\"2.5\"><title>", .{            plot.xIndex(index),            plot.yValue(value),        });        try appendEscapedText(out, allocator, point.label);        try out.appendSlice(allocator, ": ");        try appendEscapedText(out, allocator, try format(allocator, value));        if (point.low != null and point.high != null) {            try out.appendSlice(allocator, " (");            try appendEscapedText(out, allocator, try format(allocator, point.low.?));            try out.appendSlice(allocator, " .. ");            try appendEscapedText(out, allocator, try format(allocator, point.high.?));            try out.appendSlice(allocator, ")");        }        try out.appendSlice(allocator, "</title></circle>");    }}fn appendFmt(out: *std.ArrayList(u8), allocator: Allocator, comptime fmt: []const u8, args: anytype) Allocator.Error!void {    const text = try std.fmt.allocPrint(allocator, fmt, args);    defer allocator.free(text);    try out.appendSlice(allocator, text);}fn appendEscapedText(out: *std.ArrayList(u8), allocator: Allocator, text: []const u8) Allocator.Error!void {    try zen.html.appendEscaped(out, allocator, text);}fn formatRaw(allocator: Allocator, value: f64) Allocator.Error![]u8 {    return std.fmt.allocPrint(allocator, "{d:.1}", .{value});}test "chart line renders band path and dots" {    var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena_state.deinit();    const allocator = arena_state.allocator();    const points = [_]Point{        .{ .label = "run a", .value = 10, .low = 9, .high = 11 },        .{ .label = "run b", .value = 20, .low = 18, .high = 22 },        .{ .label = "run c", .value = 15, .low = 14, .high = 16 },    };    const svg = try line(allocator, &points, .{ .format = formatRaw });    try std.testing.expectEqual(@as(usize, 3), std.mem.count(u8, svg, "chart-dot"));    try std.testing.expectEqual(@as(usize, 1), std.mem.count(u8, svg, "chart-band"));    try std.testing.expectEqual(@as(usize, 1), std.mem.count(u8, svg, "chart-line\""));    try std.testing.expect(std.mem.indexOf(u8, svg, "run b: 20.0 (18.0 .. 22.0)") != null);}test "chart line skips gaps and handles empty series" {    var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena_state.deinit();    const allocator = arena_state.allocator();    const gapped = [_]Point{        .{ .label = "a", .value = 5 },        .{ .label = "b", .value = null },        .{ .label = "c", .value = 6 },    };    const svg = try line(allocator, &gapped, .{ .format = formatRaw });    try std.testing.expectEqual(@as(usize, 2), std.mem.count(u8, svg, "chart-dot"));    try std.testing.expectEqual(@as(usize, 0), std.mem.count(u8, svg, "chart-line\""));    const empty = try line(allocator, &.{}, .{ .format = formatRaw });    try std.testing.expect(std.mem.indexOf(u8, empty, "no data") != null);}test "chart line single point centers a dot" {    var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena_state.deinit();    const allocator = arena_state.allocator();    const points = [_]Point{.{ .label = "only", .value = 42 }};    const svg = try line(allocator, &points, .{ .format = formatRaw, .ticks = true });    try std.testing.expectEqual(@as(usize, 1), std.mem.count(u8, svg, "chart-dot"));    try std.testing.expectEqual(@as(usize, 3), std.mem.count(u8, svg, "chart-grid"));}test "chart strip renders samples median and band" {    var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena_state.deinit();    const allocator = arena_state.allocator();    const samples = [_]u64{ 100, 120, 110, 130, 105 };    const svg = try strip(allocator, &samples, 110, 104, 126, .{ .format = formatRaw });    try std.testing.expectEqual(@as(usize, 5), std.mem.count(u8, svg, "chart-sample"));    try std.testing.expectEqual(@as(usize, 1), std.mem.count(u8, svg, "chart-median"));    try std.testing.expectEqual(@as(usize, 1), std.mem.count(u8, svg, "chart-band"));    try std.testing.expect(std.mem.indexOf(u8, svg, "observation 0: 100.0") != null);    const empty = try strip(allocator, &.{}, null, null, null, .{ .format = formatRaw });    try std.testing.expect(std.mem.indexOf(u8, empty, "no data") != null);}test "chart sequence renders acquisition order with summary context" {    var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena_state.deinit();    const allocator = arena_state.allocator();    const samples = [_]u64{ 130, 100, 120, 110 };    const svg = try sequence(        allocator,        &samples,        115,        105,        125,        .{ .format = formatRaw, .index_origin = 7 },    );    try std.testing.expectEqual(@as(usize, 4), std.mem.count(u8, svg, "chart-sequence-sample"));    try std.testing.expectEqual(@as(usize, 1), std.mem.count(u8, svg, "chart-median"));    try std.testing.expectEqual(@as(usize, 1), std.mem.count(u8, svg, "chart-band"));    try std.testing.expectEqual(@as(usize, 1), std.mem.count(u8, svg, "chart-line\""));    const first = std.mem.indexOf(u8, svg, "sample 7: 130.0").?;    const second = std.mem.indexOf(u8, svg, "sample 8: 100.0").?;    try std.testing.expect(first < second);}test "chart sequence bounds points and preserves extrema" {    var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena_state.deinit();    const allocator = arena_state.allocator();    var samples = @as([2000]u64, @splat(100));    samples[1000] = 999;    samples[1200] = 1;    const svg = try sequence(allocator, &samples, null, null, null, .{ .format = formatRaw });    const points = std.mem.count(u8, svg, "chart-sequence-sample");    try std.testing.expect(points <= max_sequence_points);    try std.testing.expect(std.mem.indexOf(u8, svg, "sample 0: 100.0") != null);    try std.testing.expect(std.mem.indexOf(u8, svg, "sample 1000: 999.0") != null);    try std.testing.expect(std.mem.indexOf(u8, svg, "sample 1200: 1.0") != null);    try std.testing.expect(std.mem.indexOf(u8, svg, "sample 1999: 100.0") != null);}test "chart xy sorts by x and anchors the zero line" {    var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena_state.deinit();    const allocator = arena_state.allocator();    const points = [_]XyPoint{        .{ .x = 20, .y = 18, .label = "+20% virtual: +18% program" },        .{ .x = 0, .y = 0, .label = "baseline" },        .{ .x = 10, .y = -4, .label = "+10% virtual: -4% program" },    };    const svg = try xy(allocator, &points, .{});    try std.testing.expectEqual(@as(usize, 3), std.mem.count(u8, svg, "chart-dot"));    try std.testing.expectEqual(@as(usize, 1), std.mem.count(u8, svg, "chart-grid"));    try std.testing.expectEqual(@as(usize, 1), std.mem.count(u8, svg, "chart-line\""));    try std.testing.expect(std.mem.indexOf(u8, svg, "d=\"M8.00") != null);    try std.testing.expect(std.mem.indexOf(u8, svg, "+20% virtual") != null);    const empty = try xy(allocator, &.{}, .{});    try std.testing.expect(std.mem.indexOf(u8, empty, "no data") != null);}test "chart strip strides oversized sample sets" {    var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena_state.deinit();    const allocator = arena_state.allocator();    var samples: [2000]u64 = undefined;    for (&samples, 0..) |*sample, index| sample.* = index;    const svg = try strip(allocator, &samples, null, null, null, .{ .format = formatRaw });    const dots = std.mem.count(u8, svg, "chart-sample");    try std.testing.expect(dots <= max_strip_dots);    try std.testing.expect(dots > 400);}

Source: src/profiling/report/root.zig:2

zig
pub const chart = @import("chart.zig");

Audit

Definitions12
Public names12
Members20
Version26.7.0
Revisiondaab053ee433