lib/choir/src/profiling/versus/core/workload.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

  1 const std = @import("std");
  2 
  3 pub const Kind = enum {
  4     saxpy,
  5     dot,
  6     sum,
  7     matmul,
  8     polybench_gemm,
  9     stencil3,
 10     clampsum,
 11 
 12     pub fn symbol(self: Kind) [:0]const u8 {
 13         return switch (self) {
 14             .saxpy => "kernel_saxpy",
 15             .dot => "kernel_dot",
 16             .sum => "kernel_sum",
 17             .matmul => "kernel_matmul",
 18             .polybench_gemm => "kernel_gemm",
 19             .stencil3 => "kernel_stencil3",
 20             .clampsum => "kernel_clampsum",
 21         };
 22     }
 23 
 24     pub fn source(self: Kind) []const u8 {
 25         return switch (self) {
 26             .saxpy => @embedFile("../corpus/saxpy.c"),
 27             .dot => @embedFile("../corpus/dot.c"),
 28             .sum => @embedFile("../corpus/sum.c"),
 29             .matmul => @embedFile("../corpus/matmul.c"),
 30             .polybench_gemm => @embedFile("../corpus/polybench_gemm.c"),
 31             .stencil3 => @embedFile("../corpus/stencil3.c"),
 32             .clampsum => @embedFile("../corpus/clampsum.c"),
 33         };
 34     }
 35 };
 36 
 37 pub const Workload = struct {
 38     name: []const u8,
 39     kind: Kind,
 40     n: u64,
 41 
 42     pub fn elements(self: Workload) u64 {
 43         return switch (self.kind) {
 44             .matmul, .polybench_gemm => self.n * self.n,
 45             else => self.n,
 46         };
 47     }
 48 
 49     pub fn flops(self: Workload) u64 {
 50         return switch (self.kind) {
 51             .saxpy => 2 * self.n,
 52             .dot => 2 * self.n,
 53             .matmul => 2 * self.n * self.n * self.n,
 54             .polybench_gemm => 3 * self.n * self.n * self.n + self.n * self.n,
 55             .stencil3 => 5 * self.n,
 56             .sum, .clampsum => 0,
 57         };
 58     }
 59 
 60     pub fn movedBytes(self: Workload) u64 {
 61         return switch (self.kind) {
 62             .saxpy => 12 * self.n,
 63             .dot => 16 * self.n,
 64             .sum => 8 * self.n,
 65             .matmul => 24 * self.n * self.n,
 66             .polybench_gemm => 32 * self.n * self.n,
 67             .stencil3 => 16 * self.n,
 68             .clampsum => 8 * self.n,
 69         };
 70     }
 71 };
 72 
 73 pub const battery = [_]Workload{
 74     .{ .name = "saxpy_f32_1m", .kind = .saxpy, .n = 1 << 20 },
 75     .{ .name = "dot_f64_1m", .kind = .dot, .n = 1 << 20 },
 76     .{ .name = "sum_i64_1m", .kind = .sum, .n = 1 << 20 },
 77     .{ .name = "matmul_f64_192", .kind = .matmul, .n = 192 },
 78     .{ .name = "polybench_gemm_f64_128", .kind = .polybench_gemm, .n = 128 },
 79     .{ .name = "stencil3_f64_1m", .kind = .stencil3, .n = 1 << 20 },
 80     .{ .name = "clampsum_i64_1m", .kind = .clampsum, .n = 1 << 20 },
 81 };
 82 
 83 pub fn byName(name: []const u8) ?Workload {
 84     for (battery) |workload| {
 85         if (std.mem.eql(u8, workload.name, name)) return workload;
 86     }
 87     return null;
 88 }
 89 
 90 pub const clamp_lo: i64 = -500;
 91 pub const clamp_hi: i64 = 500;
 92 pub const gemm_alpha: f64 = 1.5;
 93 pub const gemm_beta: f64 = 1.2;
 94 
 95 fn splitmix(index: u64) u64 {
 96     var z = index +% 0x9e3779b97f4a7c15;
 97     z = (z ^ (z >> 30)) *% 0xbf58476d1ce4e5b9;
 98     z = (z ^ (z >> 27)) *% 0x94d049bb133111eb;
 99     return z ^ (z >> 31);
100 }
101 
102 pub fn fillUnit(comptime T: type, values: []T, offset: u64) void {
103     for (values, 0..) |*value, index| {
104         const bits = splitmix(offset + index);
105         const unit = @as(T, @floatFromInt(bits >> 11)) / @as(T, @floatFromInt(@as(u64, 1) << 53));
106         value.* = unit - 0.5;
107     }
108 }
109 
110 pub fn fillInt(values: []i64, offset: u64) void {
111     for (values, 0..) |*value, index| {
112         const bits = splitmix(offset + index);
113         value.* = @as(i64, @intCast(bits % 2001)) - 1000;
114     }
115 }
116 
117 test "battery names resolve" {
118     for (battery) |workload| {
119         try std.testing.expectEqual(workload.kind, byName(workload.name).?.kind);
120     }
121     try std.testing.expect(byName("bogus") == null);
122 }
123 
124 test "fills are deterministic" {
125     var a: [8]f64 = undefined;
126     var b: [8]f64 = undefined;
127     fillUnit(f64, a[0..], 7);
128     fillUnit(f64, b[0..], 7);
129     for (a, b) |left, right| try std.testing.expectEqual(left, right);
130     for (a) |value| try std.testing.expect(value >= -0.5 and value < 0.5);
131 
132     var xs: [8]i64 = undefined;
133     fillInt(xs[0..], 3);
134     for (xs) |value| try std.testing.expect(value >= -1000 and value <= 1000);
135 }