# Mapping a Guided Image Filter on the HARP Reconfigurable Architecture Using OpenCL
## 4 Benchmarking OpenCL Performance on HARP
### OpenCL Cache  
Cache behavior is typically subdivided into two different types: spatial locality and temporal locality. When using spatial locality, data elements are loaded that are located close together in memory. In temporal locality, on the other hand, data is loaded several times within a small time duration. The OpenCL kernel used to test the FIU cache is displayed in Listing 1.  
```
1__kernelvoid
2__attribute__((task))
3 cache_read(
4__globalvolatileulong8*restrictsrc,dst,
5 unsignedintlines)
6{
7 ulong8 output=(ulong8)(0);
8 for(unsignedinti=0;i<ITERATIONS;i++){
9 unsignedintindex=illines;
10 output+=src[index];
11}
12*dst=output;
13}
```  
Listing 1: Kernel code used to test the cache effectiveness of OpenCL.  
The for-loop iterates for a fixed number of iterations, indicated by the constant ITERATIONS. The number of iterations is determined at compile time, and is chosen sufficiently high such that overhead effects become insignificant. The array src is indexed by the variable index = i$lines,  
Figure 4: Bandwidth for various buffer sizes and data widths.  
running over lines cache lines in a round robin fashion. If lines is, for instance, equal to 4, the first four variables will be repeatedly accessed. This leads to following access pattern: 0, 1, 2, 3, 0, 1, 2, 3,... By using this modulo-operation, temporal locality is enforced, and cache performance can be evaluated. The input parameter lines determines the degree of temporal locality. The pointers src and dst are marked volatile. This keyword indicates that the data to which a pointer points may change over time. Therefore, every time the variable is read, a memory request should be sent. If the volatile keyword is not used, on the other hand, the loaded data is buffered in the OpenCL kernel. In this case, the OpenCL compiler adds a software implemented cache to the FPGA bitstream through which all memory requests pass [14]. When using a hardware-implemented QPI cache, it is, therefore, important to mark src and dst as volatile, such that no software cache prevents the FIU cache to be read. The software cache, however, can be used as a comparison to the FIU cache. Therefore, the kernel cache read was also implemented without using the volatile keyword.  
The kernel was developed for both the ulong8 and ulong16 data type. It was synthesized to an.aocx file, which resulted in a clock frequency of 240.6 MHz. The variable lines was varied from 1 to 2048. This resulted in repeated reads of a memory region with size 64 B to 128 KiB for the ulong8 variable, and 128 B to 256 KiB for the ulong16 variable. As the kernels are fully pipelined, every clock cycle a variable is read. Because of the frequency of 240.6 MHz, clock cycle time of 4.16 ns, the requested bandwidth is 15.4 GB/s for the ulong8 vector data type and 30.8 GB/s for the ulong16 vector data type. In Figure 5, the obtained average bandwidths for both kernels are displayed with and without using the volatile keyword.  
As can be seen in Figure 5, the OpenCL-implemented cache is able to fulfill the requested bandwidths of 30.8 GB/s. From the graph the size of the OpenCL generated cache core can be derived from the point where the bandwidth drops. When reading ulong8-variables, the OpenCL cache has a size of 64 KiB; when reading ulong16- variables, the cache is 128 KiB large. When the memory region is larger than the cache size, the bandwidth decreases and converges to an asymptotic bandwidth of 9.3 GB/s.