MLIR-AIE 1.4.5.dev
test_utils.h
Go to the documentation of this file.
1//===- test_utils.h ----------------------------000---*- C++ -*-===//
2//
3// Copyright (C) 2024 Advanced Micro Devices, Inc.
4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5//
6//===----------------------------------------------------------------------===//
7
8// This file contains common helper functions for the generic host code
9
10#ifndef _TEST_UTILS_H_
11#define _TEST_UTILS_H_
12
13#include "cxxopts.hpp"
14#include <algorithm>
15#include <cfloat>
16#include <cmath>
17#include <cstdint>
18#include <cstring>
19#include <fstream>
20#include <iomanip>
21#include <iostream>
22#include <sstream>
23#if defined(__STDCPP_BFLOAT16_T__)
24#include <stdfloat>
25#endif
26#include <string>
27#include <vector>
28
29namespace xrt {
30class device;
31class kernel;
32class xclbin;
33} // namespace xrt
34
35namespace test_utils {
36
37void check_arg_file_exists(const cxxopts::ParseResult &result,
38 std::string name);
39
40void add_default_options(cxxopts::Options &options);
41
42void parse_options(int argc, const char *argv[], cxxopts::Options &options,
43 cxxopts::ParseResult &result);
44
45std::vector<uint32_t> load_instr_sequence(std::string instr_path);
46std::vector<uint32_t> load_instr_binary(std::string instr_path);
47
48// Resolve the full name of the first kernel in `xclbin` whose name starts with
49// `name_prefix`, which is what a host's -k argument carries (the packaged name
50// is decorated, e.g. -k MLIR_AIE matches "MLIR_AIE:{...}"), so xrt::xclbin's
51// own exact-match get_kernel() does not serve. Throws with the available
52// kernel names listed if nothing matches.
53std::string get_kernel_name(const xrt::xclbin &xclbin,
54 const std::string &name_prefix, int verbosity = 0);
55
56void init_xrt_load_kernel(xrt::device &device, xrt::kernel &kernel,
57 int verbosity, std::string xclbinFileName,
58 std::string kernelNameInXclbin);
59
60static inline std::int16_t random_int16_t(int32_t range = 0x10000) {
61 return (std::int16_t)rand() % range;
62}
63
64static inline std::int32_t random_int32_t(int32_t range = 0x10000) {
65 return (std::int32_t)rand() % range;
66}
67
68// The Linux toolchain has std::bfloat16_t. MSVC does not.
69//
70// Use this host-side helper for bfloat16 XRT buffers and reference checks.
71// Device code should use the AIE bfloat16 types and APIs.
72#if defined(__STDCPP_BFLOAT16_T__)
73using bfloat16_t = std::bfloat16_t;
74
75static inline bfloat16_t bfloat16_from_float(float value) {
76 return bfloat16_t(value);
77}
78
79static inline bfloat16_t bfloat16_from_bits(std::uint16_t bits) {
80 bfloat16_t value;
81 std::memcpy(&value, &bits, sizeof(value));
82 return value;
83}
84
85static inline float bfloat16_to_float(bfloat16_t value) {
86 return static_cast<float>(value);
87}
88#else
89using bfloat16_t = std::uint16_t;
90
91static inline bfloat16_t bfloat16_from_bits(std::uint16_t bits) { return bits; }
92
93static inline float bfloat16_to_float(bfloat16_t bits) {
94 const std::uint32_t expanded_bits = static_cast<std::uint32_t>(bits) << 16;
95 float value = 0.0f;
96 std::memcpy(&value, &expanded_bits, sizeof(value));
97 return value;
98}
99
100static inline bfloat16_t bfloat16_from_float(float value) {
101 std::uint32_t bits = 0;
102 std::memcpy(&bits, &value, sizeof(bits));
103
104 // Round to nearest-even instead of truncating.
105 const std::uint32_t lsb = (bits >> 16) & 1U;
106 const std::uint32_t rounding_bias = 0x7FFFU + lsb;
107 return static_cast<bfloat16_t>((bits + rounding_bias) >> 16);
108}
109#endif
110
111static inline bfloat16_t random_bfloat16_t(bfloat16_t scale, bfloat16_t bias) {
112 const float scale_value = bfloat16_to_float(scale);
113 const float bias_value = bfloat16_to_float(bias);
114 return bfloat16_from_float((scale_value * (float)rand() / (float)(RAND_MAX)) +
115 bias_value);
116}
117
118bool nearly_equal(float a, float b, float epsilon = 128 * FLT_EPSILON,
119 float abs_th = FLT_MIN);
120
121static inline bool nearly_equal_bfloat16(bfloat16_t a, bfloat16_t b,
122 float epsilon = 128 * FLT_EPSILON,
123 float abs_th = FLT_MIN) {
124 return nearly_equal(bfloat16_to_float(a), bfloat16_to_float(b), epsilon,
125 abs_th);
126}
127
128static inline bfloat16_t bfloat16_add(bfloat16_t lhs, bfloat16_t rhs) {
129 return bfloat16_from_float(bfloat16_to_float(lhs) + bfloat16_to_float(rhs));
130}
131
132static inline bfloat16_t bfloat16_mul(bfloat16_t lhs, bfloat16_t rhs) {
133 return bfloat16_from_float(bfloat16_to_float(lhs) * bfloat16_to_float(rhs));
134}
135
136static inline bfloat16_t bfloat16_div(bfloat16_t lhs, bfloat16_t rhs) {
137 return bfloat16_from_float(bfloat16_to_float(lhs) / bfloat16_to_float(rhs));
138}
139
140static inline bfloat16_t bfloat16_tanh(bfloat16_t value) {
141 return bfloat16_from_float(std::tanh(bfloat16_to_float(value)));
142}
143
144template <typename T>
145void print_matrix(const std::vector<T> matrix, int n_cols,
146 int n_printable_rows = 10, int n_printable_cols = 10,
147 std::ostream &ostream = std::cout,
148 const char col_sep[] = " ", const char elide_sym[] = " ... ",
149 int w = -1) {
150 assert(matrix.size() % n_cols == 0);
151
152 auto maxima = std::minmax_element(matrix.begin(), matrix.end());
153 T max_val = std::max(*maxima.first, std::abs(*maxima.second));
154 size_t n_digits = log10(max_val);
155 if (w == -1) {
156 w = n_digits;
157 }
158 int n_rows = matrix.size() / n_cols;
159
160 n_printable_rows = std::min(n_rows, n_printable_rows);
161 n_printable_cols = std::min(n_cols, n_printable_cols);
162
163 const bool elide_rows = n_printable_rows < n_rows;
164 const bool elide_cols = n_printable_cols < n_cols;
165
166 if (elide_rows || elide_cols) {
167 w = std::max((int)w, (int)strlen(elide_sym));
168 }
169
170 w += 3; // for decimal point and two decimal digits
171 ostream << std::fixed << std::setprecision(2);
172
173#define print_row(what) \
174 for (int col = 0; col < n_printable_cols / 2; col++) { \
175 ostream << std::right << std::setw(w) << (what); \
176 ostream << std::setw(0) << col_sep; \
177 } \
178 if (elide_cols) { \
179 ostream << std::setw(0) << elide_sym; \
180 } \
181 for (int col = n_printable_cols / 2 + 1; col < n_printable_cols; col++) { \
182 ostream << std::right << std::setw(w) << (what); \
183 ostream << std::setw(0) << col_sep; \
184 }
185
186 for (int row = 0; row < n_printable_rows / 2; row++) {
187 print_row(matrix[row * n_rows + col]);
188 ostream << std::endl;
189 }
190 if (elide_rows) {
191 print_row(elide_sym);
192 ostream << std::endl;
193 }
194 for (int row = n_printable_rows / 2 + 1; row < n_printable_rows; row++) {
195 print_row(matrix[row * n_rows + col]);
196 ostream << std::endl;
197 }
198
199#undef print_row
200}
201
202void write_out_trace(char *traceOutPtr, size_t trace_size, std::string path);
203
204} // namespace test_utils
205
206#endif // _TEST_UTILS_H_
bool nearly_equal(float a, float b, float epsilon=128 *FLT_EPSILON, float abs_th=FLT_MIN)
void print_matrix(const std::vector< T > matrix, int n_cols, int n_printable_rows=10, int n_printable_cols=10, std::ostream &ostream=std::cout, const char col_sep[]=" ", const char elide_sym[]=" ... ", int w=-1)
Definition test_utils.h:145
std::vector< uint32_t > load_instr_binary(std::string instr_path)
void init_xrt_load_kernel(xrt::device &device, xrt::kernel &kernel, int verbosity, std::string xclbinFileName, std::string kernelNameInXclbin)
void parse_options(int argc, const char *argv[], cxxopts::Options &options, cxxopts::ParseResult &result)
std::string get_kernel_name(const xrt::xclbin &xclbin, const std::string &name_prefix, int verbosity=0)
std::uint16_t bfloat16_t
Definition test_utils.h:89
void write_out_trace(char *traceOutPtr, size_t trace_size, std::string path)
void check_arg_file_exists(const cxxopts::ParseResult &result, std::string name)
std::vector< uint32_t > load_instr_sequence(std::string instr_path)
void add_default_options(cxxopts::Options &options)
#define print_row(what)