Visible to Intel only — GUID: GUID-D47D2015-D0EB-4925-87C6-E2BF3BDEAA74
Visible to Intel only — GUID: GUID-D47D2015-D0EB-4925-87C6-E2BF3BDEAA74
Using the Timers
The standard C++ chrono library can be used for tracking times with varying degrees of precision in SYCL. The following example shows how to use the chrono timer class to time kernel execution from the host side.
#include <CL/sycl.hpp>
#include <iostream>
using sycl;
// Array type and data size for this example.
constexpr size_t array_size = (1 << 16);
typedef std::array<int, array_size> IntArray;
double VectorAdd(queue &q, const IntArray &a, const IntArray &b, IntArray &sum) {
range<1> num_items{a.size()};
buffer a_buf(a);
buffer b_buf(b);
buffer sum_buf(sum.data(), num_items);
auto t1 = std::chrono::steady_clock::now(); // Start timing
q.submit([&](handler &h) {
// Input accessors
auto a_acc = a_buf.get_access<access::mode::read>(h);
auto b_acc = b_buf.get_access<access::mode::read>(h);
// Output accessor
auto sum_acc = sum_buf.get_access<access::mode::write>(h);
h.parallel_for(num_items, [=](id<1> i) { sum_acc[i] = a_acc[i] + b_acc[i]; });
}).wait();
auto t2 = std::chrono::steady_clock::now(); // Stop timing
return(std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1).count());
}
void InitializeArray(IntArray &a) {
for (size_t i = 0; i < a.size(); i++) a[i] = i;
}
int main() {
default_selector d_selector;
IntArray a, b, sum;
InitializeArray(a);
InitializeArray(b);
queue q(d_selector);
std::cout << "Running on device: "
<< q.get_device().get_info<info::device::name>() << "\n";
std::cout << "Vector size: " << a.size() << "\n";
double t = VectorAdd(q, a, b, sum);
std::cout << "Vector add successfully completed on device in " << t << " microseconds\n";
return 0;
}
Note that this timing is purely from the host side. The actual execution of the kernel on the device may start much later, after the submission of the kernel by the host. SYCL provides a profiling capability that let you keep track of the time it took to execute kernels.
#include <CL/sycl.hpp>
#include <array>
#include <iostream>
using namespace sycl;
// Array type and data size for this example.
constexpr size_t array_size = (1 << 16);
typedef std::array<int, array_size> IntArray;
double VectorAdd(queue &q, const IntArray &a, const IntArray &b, IntArray &sum) {
range<1> num_items{a.size()};
buffer a_buf(a);
buffer b_buf(b);
buffer sum_buf(sum.data(), num_items);
event e = q.submit([&](handler &h) {
// Input accessors
auto a_acc = a_buf.get_access<access::mode::read>(h);
auto b_acc = b_buf.get_access<access::mode::read>(h);
// Output accessor
auto sum_acc = sum_buf.get_access<access::mode::write>(h);
h.parallel_for(num_items, [=](id<1> i) { sum_acc[i] = a_acc[i] + b_acc[i]; });
});
q.wait();
return(e.template get_profiling_info<info::event_profiling::command_end>() -
e.template get_profiling_info<info::event_profiling::command_start>());
}
void InitializeArray(IntArray &a) {
for (size_t i = 0; i < a.size(); i++) a[i] = i;
}
int main() {
default_selector d_selector;
IntArray a, b, sum;
InitializeArray(a);
InitializeArray(b);
queue q(d_selector, property::queue::enable_profiling{});
std::cout << "Running on device: "
<< q.get_device().get_info<info::device::name>() << "\n";
std::cout << "Vector size: " << a.size() << "\n";
double t = VectorAdd(q, a, b, sum);
std::cout << "Vector add successfully completed on device in " << t << " nanoseconds\n";
return 0;
}
When these examples are run, it is quite possible that the time reported by chrono is much larger than the time reported by the SYCL profiling class. This is because the SYCL profiling does not include any data transfer times between the host and the offload device.