MLIR-AIE
test_utils.cpp
Go to the documentation of this file.
1//===- test_utils.cpp ----------------------------000---*- C++ -*-===//
2//
3// This file is licensed under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7// Copyright (C) 2024, Advanced Micro Devices, Inc.
8//
9//===----------------------------------------------------------------------===//
10
11// This file contains common helper functions for the generic host code
12
13#include "test_utils.h"
14#include <cassert>
15#include <filesystem>
16
17// --------------------------------------------------------------------------
18// Command Line Argument Handling
19// --------------------------------------------------------------------------
20
22 std::string name) {
23 if (!result.count(name)) {
24 throw std::runtime_error("Missing required argument: " + name);
25 }
26 std::string path = result[name].as<std::string>();
27 if (!std::filesystem::exists(path)) {
28 throw std::runtime_error("File does not exist: " + path);
29 }
30}
31
33 options.add_options()("help,h", "produce help message")(
34 "xclbin,x", "the input xclbin path", cxxopts::value<std::string>())(
35 "kernel,k", "the kernel name in the XCLBIN (for instance PP_PRE_FD)",
36 cxxopts::value<std::string>())("verbosity,v",
37 "the verbosity of the output",
38 cxxopts::value<int>()->default_value("0"))(
39 "instr,i",
40 "path of file containing userspace instructions sent to the NPU",
41 cxxopts::value<std::string>())(
42 "verify", "whether to verify the AIE computed output",
43 cxxopts::value<bool>()->default_value("true"))(
44 "iters", "number of iterations",
45 cxxopts::value<int>()->default_value("1"))(
46 "warmup", "number of warmup iterations",
47 cxxopts::value<int>()->default_value("0"))(
48 "trace_sz,t", "trace size", cxxopts::value<int>()->default_value("0"))(
49 "trace_file", "where to store trace output",
50 cxxopts::value<std::string>()->default_value("trace.txt"));
51}
52
53void test_utils::parse_options(int argc, const char *argv[],
54 cxxopts::Options &options,
56 try {
57 vm = options.parse(argc, argv);
58
59 if (vm.count("help")) {
60 std::cout << options.help() << "\n";
61 std::exit(1);
62 }
63 } catch (const cxxopts::exceptions::parsing &e) {
64 std::cerr << e.what() << "\n\n";
65 std::cerr << "Usage:\n" << options.help() << "\n";
66 std::exit(1);
67 }
68
69 try {
70 check_arg_file_exists(vm, "xclbin");
71 check_arg_file_exists(vm, "instr");
72 } catch (const std::exception &ex) {
73 std::cerr << ex.what() << "\n\n";
74 }
75}
76
77// --------------------------------------------------------------------------
78// AIE Specifics
79// --------------------------------------------------------------------------
80
81std::vector<uint32_t> test_utils::load_instr_sequence(std::string instr_path) {
82 std::ifstream instr_file(instr_path);
83 std::string line;
84 std::vector<uint32_t> instr_v;
85 while (std::getline(instr_file, line)) {
86 std::istringstream iss(line);
87 uint32_t a;
88 if (!(iss >> std::hex >> a)) {
89 throw std::runtime_error("Unable to parse instruction file\n");
90 }
91 instr_v.push_back(a);
92 }
93 return instr_v;
94}
95
96std::vector<uint32_t> test_utils::load_instr_binary(std::string instr_path) {
97 // Open file in binary mode
98 std::ifstream instr_file(instr_path, std::ios::binary);
99 if (!instr_file.is_open()) {
100 throw std::runtime_error("Unable to open instruction file\n");
101 }
102
103 // Get the size of the file
104 instr_file.seekg(0, std::ios::end);
105 std::streamsize size = instr_file.tellg();
106 instr_file.seekg(0, std::ios::beg);
107
108 // Check that the file size is a multiple of 4 bytes (size of uint32_t)
109 if (size % 4 != 0) {
110 throw std::runtime_error("File size is not a multiple of 4 bytes\n");
111 }
112
113 // Allocate vector and read the binary data
114 std::vector<uint32_t> instr_v(size / 4);
115 if (!instr_file.read(reinterpret_cast<char *>(instr_v.data()), size)) {
116 throw std::runtime_error("Failed to read instruction file\n");
117 }
118 return instr_v;
119}
120
121// --------------------------------------------------------------------------
122// XRT
123// --------------------------------------------------------------------------
124void test_utils::init_xrt_load_kernel(xrt::device &device, xrt::kernel &kernel,
125 int verbosity, std::string xclbinFileName,
126 std::string kernelNameInXclbin) {
127 // Get a device handle
128 unsigned int device_index = 0;
129 device = xrt::device(device_index);
130
131 // Load the xclbin
132 if (verbosity >= 1)
133 std::cout << "Loading xclbin: " << xclbinFileName << "\n";
134 auto xclbin = xrt::xclbin(xclbinFileName);
135
136 if (verbosity >= 1)
137 std::cout << "Kernel opcode: " << kernelNameInXclbin << "\n";
138
139 // Get the kernel from the xclbin
140 auto xkernels = xclbin.get_kernels();
141 auto xkernel =
142 *std::find_if(xkernels.begin(), xkernels.end(),
143 [kernelNameInXclbin, verbosity](xrt::xclbin::kernel &k) {
144 auto name = k.get_name();
145 if (verbosity >= 1) {
146 std::cout << "Name: " << name << std::endl;
147 }
148 return name.rfind(kernelNameInXclbin, 0) == 0;
149 });
150 auto kernelName = xkernel.get_name();
151 // Register xclbin
152 if (verbosity >= 1)
153 std::cout << "Registering xclbin: " << xclbinFileName << "\n";
154
155 device.register_xclbin(xclbin);
156
157 // Get a hardware context
158 if (verbosity >= 1)
159 std::cout << "Getting hardware context.\n";
160 xrt::hw_context context(device, xclbin.get_uuid());
161
162 // Get a kernel handle
163 if (verbosity >= 1)
164 std::cout << "Getting handle to kernel:" << kernelName << "\n";
165 kernel = xrt::kernel(context, kernelName);
166
167 return;
168}
169
170// --------------------------------------------------------------------------
171// Matrix / Float / Math
172// --------------------------------------------------------------------------
173
174// nearly_equal function adapted from Stack Overflow, License CC BY-SA 4.0
175// Original author: P-Gn
176// Source: https://stackoverflow.com/a/32334103
177bool test_utils::nearly_equal(float a, float b, float epsilon, float abs_th)
178// those defaults are arbitrary and could be removed
179{
180 assert(std::numeric_limits<float>::epsilon() <= epsilon);
181 assert(epsilon < 1.f);
182
183 if (a == b)
184 return true;
185
186 auto diff = std::abs(a - b);
187 auto norm =
188 std::min((std::abs(a) + std::abs(b)), std::numeric_limits<float>::max());
189 // or even faster: std::min(std::abs(a + b),
190 // std::numeric_limits<float>::max()); keeping this commented out until I
191 // update figures below
192 return diff < std::max(abs_th, epsilon * norm);
193}
194
195// --------------------------------------------------------------------------
196// Tracing
197// --------------------------------------------------------------------------
198void test_utils::write_out_trace(char *traceOutPtr, size_t trace_size,
199 std::string path) {
200 std::ofstream fout(path);
201 uint32_t *traceOut = (uint32_t *)traceOutPtr;
202 for (int i = 0; i < trace_size / sizeof(traceOut[0]); i++) {
203 fout << std::setfill('0') << std::setw(8) << std::hex << (int)traceOut[i];
204 fout << std::endl;
205 }
206}
std::string help(const std::vector< std::string > &groups={}, bool print_usage=true) const
Definition cxxopts.hpp:2120
ParseResult parse(int argc, const char *const *argv)
Definition cxxopts.hpp:1835
OptionAdder add_options(std::string group="")
Definition cxxopts.hpp:1707
std::size_t count(const std::string &o) const
Definition cxxopts.hpp:1302
CXXOPTS_NODISCARD const char * what() const noexcept override
Definition cxxopts.hpp:338
bool nearly_equal(float a, float b, float epsilon=128 *FLT_EPSILON, float abs_th=FLT_MIN)
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)
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)