-
Notifications
You must be signed in to change notification settings - Fork 3.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add initial support for Intel FPGA SDK for OpenCL (AOCL) #1474
Changes from 9 commits
8a5ffdb
8b0eef8
120979c
ca137cb
f2257d0
edd0437
8c22538
aca96a5
5016f73
ed47e4a
d51f19e
2c18ee0
fd3d4fa
5b578e2
66a46ea
fb80366
0030c81
65ad10d
d3ab18a
3a49eee
93d8d9f
b174098
68569d9
d4d435f
9d45ead
8ff0272
f7317b0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
AOCL Backend Example | ||
==================== | ||
|
||
TVM supports Intel FPGA SDK for OpenCL also known as AOCL. Here is a tutorial for how to use TVM with AOCL. | ||
|
||
***Note***: This feature is still experimental. We cannot use AOCL to deploy an end to end neural networks for now. In addition, we can only use AOCL's emulation mode for now. | ||
|
||
We use a python scripts for this tutorial. | ||
|
||
- emu-aocl-fpga.py | ||
```# -*- coding: utf-8 -*- | ||
import tvm | ||
import numpy as np | ||
|
||
tgt_host = 'llvm' | ||
tgt = 'opencl' | ||
|
||
# Define a computation. | ||
n = tvm.var('n') | ||
a = tvm.placeholder((n,), name='a') | ||
b = tvm.placeholder((n,), name='b') | ||
c = tvm.compute(a.shape, lambda i: a[i] + b[i], name='c') | ||
|
||
# Make a schedule. | ||
s = tvm.create_schedule(c.op) | ||
px, x = s[c].split(c.op.axis[0], nparts=1) | ||
s[c].bind(px, tvm.thread_axis("pipeline")) | ||
|
||
# Make a executable code. | ||
fadd = tvm.build(s, [a, b, c], tgt, target_host=tgt_host, name='myadd') | ||
|
||
# Run. | ||
ctx = tvm.context(tgt, 0) | ||
n = 1024 | ||
a = tvm.nd.array(np.random.uniform(size=n).astype(a.dtype), ctx) | ||
b = tvm.nd.array(np.random.uniform(size=n).astype(b.dtype), ctx) | ||
c = tvm.nd.array(np.zeros(n, dtype=c.dtype), ctx) | ||
fadd(a, b, c)``` | ||
|
||
Setup | ||
----- | ||
|
||
- Install AOCL 17.1 on Ubuntu 16.04.4 LTS. | ||
- Install FPGA device driver. | ||
- Make ICD file. | ||
- Make FCD file. | ||
- Setup TVM with AOCL and OpenCL enabled. | ||
|
||
Emulation | ||
--------- | ||
|
||
- Set environment variable. | ||
```export CL_CONTEXT_EMULATOR_DEVICE_INTELFPGA=1``` | ||
|
||
- Run software emulation | ||
```python emu-aocl-fpga.py``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -143,7 +143,11 @@ class OpenCLWorkspace : public DeviceAPI { | |
void Init(const std::string& type_key, const std::string& device_type, | ||
const std::string& platform_name = ""); | ||
virtual void Init() { | ||
#ifndef AOCL_BOARD_NAME | ||
Init("opencl", "gpu"); | ||
#else | ||
Init("opencl", "accelerator"); | ||
#endif | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Implement AOCLWorkspace as a subclass of OpenCLWorkspace so that it can coexist with other OpenCL platforms. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Introduced AOCLWorkspace. |
||
} | ||
// Check whether the context is OpenCL or not. | ||
virtual bool IsOpenCLDevice(TVMContext ctx) { | ||
|
@@ -284,6 +288,10 @@ class OpenCLModuleNode : public ModuleNode { | |
std::unordered_map<std::string, KTRefEntry> kid_map_; | ||
// kernels build so far. | ||
std::vector<cl_kernel> kernels_; | ||
|
||
#ifdef AOCL_BOARD_NAME | ||
void OfflineCompile(cl::OpenCLWorkspace* w, cl::OpenCLThreadEntry* t); | ||
#endif | ||
}; | ||
|
||
} // namespace runtime | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -208,7 +208,11 @@ std::vector<cl_device_id> GetDeviceIDs( | |
cl_device_type dtype = CL_DEVICE_TYPE_ALL; | ||
if (device_type == "cpu") dtype = CL_DEVICE_TYPE_CPU; | ||
if (device_type == "gpu") dtype = CL_DEVICE_TYPE_GPU; | ||
#ifndef AOCL_BOARD_NAME | ||
if (device_type == "accelerator") dtype = CL_DEVICE_TYPE_ACCELERATOR; | ||
#else | ||
if (device_type == "accelerator") dtype = CL_DEVICE_TYPE_DEFAULT; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do you want to use CL_DEVICE_TYPE_DEFAULT here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Deleted this code and now works with device_type == "accelerator". |
||
#endif | ||
cl_uint ret_size; | ||
cl_int code = clGetDeviceIDs(pid, dtype, 0, nullptr, &ret_size); | ||
std::vector<cl_device_id> ret; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,8 @@ | |
#include <tvm/runtime/registry.h> | ||
#include <vector> | ||
#include <string> | ||
#include <iostream> | ||
#include <fstream> | ||
#include <unordered_map> | ||
#include "./opencl_common.h" | ||
#include "./opencl_module.h" | ||
|
@@ -185,11 +187,15 @@ cl_kernel OpenCLModuleNode::InstallKernel(cl::OpenCLWorkspace* w, | |
// create program | ||
if (fmt_ == "cl") { | ||
if (program_ == nullptr) { | ||
#ifndef AOCL_BOARD_NAME | ||
const char* s = data_.c_str(); | ||
size_t len = data_.length(); | ||
cl_int err; | ||
program_ = clCreateProgramWithSource(w->context, 1, &s, &len, &err); | ||
OPENCL_CHECK_ERROR(err); | ||
#else | ||
OfflineCompile(w, t); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should be moved to codegen since compiling OpenCL codes for FPGAs takes very long time. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Offline compilation was moved to codegen. See also BuildAOCL(). |
||
#endif | ||
} | ||
} else if (fmt_ == "xclbin" || fmt_ == "awsxclbin") { | ||
const unsigned char* s = (const unsigned char *)data_.c_str(); | ||
|
@@ -227,6 +233,54 @@ cl_kernel OpenCLModuleNode::InstallKernel(cl::OpenCLWorkspace* w, | |
return kernel; | ||
} | ||
|
||
#ifdef AOCL_BOARD_NAME | ||
void OpenCLModuleNode::OfflineCompile(cl::OpenCLWorkspace* w, | ||
cl::OpenCLThreadEntry* t) { | ||
// Write a .cl file. | ||
std::ofstream ofs("aocltmp.cl"); | ||
if (!ofs) { | ||
LOG(FATAL) << "Can't create OpenCL temporary file."; | ||
} | ||
ofs << data_.c_str(); | ||
if (!ofs) { | ||
LOG(FATAL) << "Can't write to OpenCL temporary file."; | ||
} | ||
ofs.close(); | ||
|
||
// Compile the .cl file. | ||
std::string cmd = "aoc aocltmp.cl -march=emulator -board="; | ||
cmd += AOCL_BOARD_NAME; | ||
if (system(cmd.c_str()) != 0) { | ||
LOG(FATAL) << "OpenCL offline compilation error."; | ||
} | ||
|
||
// Read .aocx file | ||
std::ifstream ifs("aocltmp.aocx", std::ios::in | std::ios::binary); | ||
if (!ifs) { | ||
LOG(FATAL) << "Can't open aocltmp.aocx file."; | ||
} | ||
ifs.seekg(0, std::fstream::end); | ||
const size_t len = ifs.tellg(); | ||
char *buf = new char[len]; | ||
ifs.clear(); | ||
ifs.seekg(0, std::fstream::beg); | ||
ifs.read(buf, len); | ||
if (!ifs) { | ||
LOG(FATAL) << "Can't read aocltmp.aocx file."; | ||
} | ||
|
||
// Create program from aocx. | ||
cl_int err; | ||
int device_id = t->context.device_id; | ||
cl_device_id dev = w->devices[device_id]; | ||
const unsigned char* s = (const unsigned char *)buf; | ||
program_ = clCreateProgramWithBinary(w->context, 1, &dev, &len, &s, NULL, &err); | ||
OPENCL_CHECK_ERROR(err); | ||
|
||
delete[] buf; | ||
} | ||
#endif | ||
|
||
Module OpenCLModuleCreate( | ||
std::string data, | ||
std::string fmt, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the board name should be passed with target options (e.g.
tvm.context("opencl -device=[board name]")
).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed to use target name option like tgt="aocl -device=de5net_a7".