Primeros Pasos con OpenCL: Usando el ODROID-XU4

OpenCL on ODROIDs

Aunque he testeado OpenGL ES con herramientas como glmark2-es2 y es2gears, así como también demos de WebGL en Chromium, no he llegado a probar OpenCL, ya que no estoy muy familiarizado con él, excepto que se usa con GPGPU (GPU de propósito general) para acelerar tareas como el procesamiento de imagen/audio. Esta es una buena excusa para aprender un poco más, probarlo en la placa y escribir una breve guía para poner en marcha OpenGL sobre hardware con la GPU Arm Mali. La finalidad de este tutorial es mostrar cómo ejecutar una muestra de OpenCL y la utilidad OpenCL, no entraré en los pormenores del código de OpenCL. Si quieres más información sobre la codificación OpenCL en Arm, un buen lugar por donde empezar sería verificar el código fuente de las muestras proporcionadas.

Arm Compute Library y muestras de OpenCL Como no sabía por dónde empezar, Hardkernel me redirigió a un hilo del foro donde se muestra cómo usar la Arm Compute Library para probar OpenCL en la placa. La publicación tiene fecha de enero de 2018 y está basado en la Compute Library 17.12, pero puedes consultar la última versión y documentación en https://arm-software.github.io/ComputeLibrary/latest/. Cuando escribí este artículo, la última versión era la 18.03, así que la recuperé y traté de compilarla tal y como se indica:

$ wget https://github.com/ARM-software/ComputeLibrary/archive/v18.03.tar.gz
$ tar xvf v18.03.tar.gz
$ cd ComputeLibrary-18.03/
$ sudo apt install scons
$ scons Werror=1 -j8 debug=0 neon=1 opencl=1 embed_kernels=1 os=linux arch=armv7a build=native
Sin embargo, falló con:
$ g++: internal compiler error: Killed (program cc1plus)
Al analizar el registro log del kernel con dmesg, estaba claro que el problema estaba en que la placa se había quedado sin memoria: "Out of memory: Kill process 4984 (cc1plus) Out of memory: Kill process 4984 (cc1plus)“. Así que tuve que configurar un archivo de intercambio swap (1GB):
$ sudo dd if=/dev/zero of=/swapfile bs=1024 count=1M
$ sudo chown root.root /swapfile
$ sudo chmod 0600 /swapfile
$ sudo mkswap /swapfile
$ sudo swapon /swapfile
El archivo swap nos proporciona más memoria:
free -m
total used free shared buff/cache available
Mem: 1994 336 520 34 1137 1568
Swap: 1023 0 1023
Volví a iniciar la compilación con NEON y OpenCL activado:
$ scons Werror=1 -j8 debug=0 neon=1 opencl=1 embed_kernels=1 os=linux arch=armv7a build=native
Esta vez se completó:
scons: done building targets.

Actualizar

La configuración de ZRAM en lugar de swap suele ser mejor solución en caso de que te quedes sin memoria, tal y como se describe https://www.cnx-software.com/2018/05/14/running-out-of-ram-in-ubuntu-enable-zram/. Podemos copiar las librerías a /usr/lib, que nos proporciona un montón de muestras para probar:

$ sudo cp build/*.so /usr/lib/
$ ls examples/
SConscript graph_mobilenet_qasymm8.cpp
cl_convolution.cpp graph_resnet50.cpp
cl_events.cpp graph_squeezenet.cpp
cl_sgemm.cpp graph_squeezenet_v1_1.cpp
gc_absdiff.cpp graph_vgg16.cpp
gc_dc.cpp graph_vgg19.cpp
graph_alexnet.cpp neon_cartoon_effect.cpp
graph_googlenet.cpp neon_cnn.cpp
graph_inception_v3.cpp neon_convolution.cpp
graph_inception_v4.cpp neon_copy_objects.cpp
graph_lenet.cpp neon_scale.cpp
graph_mobilenet.cpp neoncl_scale_median_gaussian.cpp
Ten en cuenta que algunas solo son NEON, no usan OpenCL, el prefijo explica el tipo de muestra:

  • cl_*.cpp –> OpenCL examples
  • gc_*.cpp –> GLES compute shaders examples
  • graph_*.cpp –> Graph examples
  • neoncl_*.cpp –> NEON / OpenCL interoperability examples
  • neon_*.cpp –> NEON examples

Todas las muestras han sido compiladas y se pueden encontrar en el directorio build/examples. Yo ejecuté cl_convolution después de generar una imagen ppm Raw usando Gimp:

$ time ./cl_convolution ~/ODROID-XU4Q-Large.ppm
$ ./cl_convolution

Test passed

real 0m5.814s
user 0m4.893s
sys 0m0.758s
Procesó la foto (5184 x 3456) en menos de 6 segundos. Si analizamos la imagen resultante, podemos ver el resultado con una escala de grises desde la complejidad de OpenCL, tal y como se muestra en la Figura 1.

Figura 01 - Imagen original (izquierda) vs Después de la Convolución OpenCL (derecha)

He repetido una operación similar con convert que no ha sido compilado con soporte OpenCL, sólo usa software:

$ time convert ODROID-XU4Q-Large.ppm -colorspace Gray ODROID-XU4Q-Large-Grayscale.ppm

real 0m10.475s
user 0m0.724s
sys 0m2.957s
Le llevo algo más de 10 segundos, casi el doble del tiempo utilizado por la demo de OpenCL. Sin embargo, los archivos de imagen PPM ocupan más de 50 MB, de modo que parte del tiempo se usa para leer y guardar el archivo desde la memoria flash eMMC. Repetir las pruebas proporcionaron rendimientos similar (~ 6s vs ~ 11s), de modo que eran insignificantes. El resultado del comando "convert version" que muestra OpenCL no forma parte de las características habilitadas en ImageMagick:
$ convert -version
Version: ImageMagick 6.9.7-4 Q16 arm 20170114 http://www.imagemagick.org
Copyright: © 1999-2017 ImageMagick Studio LLC
License: http://www.imagemagick.org/script/license.php
Features: Cipher DPC Modules OpenMP
Delegates (built-in): bzlib djvu fftw fontconfig freetype jbig jng jpeg lcms lqr ltdl lzma openexr pangocairo png tiff wmf x xml zlib
Era divertido, así que probé otra muestra:
$ time ./cl_events ~/ODROID-XU4Q-Large.ppm
$ ./cl_events

Test passed

real 0m3.068s
user 0m2.527s
sys 0m0.369s
¿Qué hizo? Cuando abrí el archivo, tenía el mismo aspecto que la primera muestra (imagen en escala de grises), pero en realidad la imagen estaba escalada (50% de ancho, 50% de alto):
$ file ~/ODROID-XU4Q-Large.ppm_out.ppm
/home/odroid/ODROID-XU4Q-Large.ppm_out.ppm: Netpbm image data, size = 2592 x 1728, rawbits, pixmap
La última muestra cl_sgemm manipula las matrices. El objetivo principal de los tres OpenCL (muestras cl_xxx_ ) es mostrar cómo usar OpenCL Convolution, Events y SGEMM (Single-precision GEneral Matrix Multiply) utilizando Compute Library. También puedes jugar con otras muestras para NEON y OpenGL ES. La comunidad de ARM publicó un post en el blog explicando cómo ejecutar neon_cartoon_effect en Raspberry Pi y explicando el código fuente en detalle. En realidad, no necesitas una placa RPi para esto, ya que cualquier placa ARM con un procesador que soporte NEON debería funcionar.

Utilidad clinfo

clinfo es una utilidad que muestra información sobre los dispositivos y plataformas OpenCL en el sistema, https://github.com/Oblomov/clinfo, que se instala fácilmente:

$ sudo apt install clinfo
Sin embargo, ejecutar el programa no devuelve ninguna información útil:
$ clinfo
Number of platforms 0
Esto no es lo que esperaba. Afortunadamente, la configuración de clinfo está explicada en el artículo de ODROID Magazine https://magazine.odroid.com/article/clinfo-compiling-the-essential-opencl-gpu-tuning-utility-for-the-odroid-xu4/, así que vamos a intentarlo. Necesitamos usar el driver framebuffer de Mali, luego configuramos el archivo ICD del proveedor:
$ sudo apt install mali-fbdev
$ sudo mkdir -p /etc/OpenCL/vendors
$ sudo sh -c 'echo "/usr/lib/arm-linux-gnueabihf/mali-egl/libOpenCL.so" > /etc/OpenCL/vendors/armocl.icd'
Ahora podemos ejecutar clinfo:
$ clinfo
Number of platforms 1
Platform Name ARM Platform
Platform Vendor ARM
Platform Version OpenCL 1.2 v1.r12p0-04rel0.03af15950392f3702b248717f4938b82
Platform Profile FULL_PROFILE
Platform Extensions cl_khr_global_int32_base_atomics cl_khr_global_int32_extended_atomics cl_khr_local_int32_base_atomics cl_khr_local_int32_extended_atomics cl_khr_byte_addressable_store cl_khr_3d_image_writes cl_khr_fp64 cl_khr_int64_base_atomics cl_khr_int64_extended_atomics cl_khr_fp16 cl_khr_gl_sharing cl_khr_icd cl_khr_egl_event cl_khr_egl_image cl_arm_core_id cl_arm_printf cl_arm_thread_limit_hint cl_arm_non_uniform_work_group_size cl_arm_import_memory
Platform Extensions function suffix ARM

Platform Name ARM Platform
Number of devices 2
Device Name Mali-T628
Device Vendor ARM
Device Vendor ID 0x6200010
Device Version OpenCL 1.2 v1.r12p0-04rel0.03af15950392f3702b248717f4938b82
Driver Version 1.2
Device OpenCL C Version OpenCL C 1.2 v1.r12p0-04rel0.03af15950392f3702b248717f4938b82
Device Type GPU
Device Profile FULL_PROFILE
Device Available Yes
Compiler Available Yes
Linker Available Yes
Max compute units 4
Max clock frequency 600MHz
Device Partition (core)
Max number of sub-devices 0
Supported partition types None
Max work item dimensions 3
Max work item sizes 256x256x256
Max work group size 256
Preferred work group size multiple 4
Preferred / native vector sizes
char 16 / 16
short 8 / 8
int 4 / 4
long 2 / 2
half 8 / 8 (cl_khr_fp16)
float 4 / 4
double 2 / 2 (cl_khr_fp64)
Half-precision Floating-point support (cl_khr_fp16)
Denormals Yes
Infinity and NANs Yes
Round to nearest Yes
Round to zero Yes
Round to infinity Yes
IEEE754-2008 fused multiply-add Yes
Support is emulated in software No
Single-precision Floating-point support (core)
Denormals Yes
Infinity and NANs Yes
Round to nearest Yes
Round to zero Yes
Round to infinity Yes
IEEE754-2008 fused multiply-add Yes
Support is emulated in software No
Correctly-rounded divide and sqrt operations No
Double-precision Floating-point support (cl_khr_fp64)
Denormals Yes
Infinity and NANs Yes
Round to nearest Yes
Round to zero Yes
Round to infinity Yes
IEEE754-2008 fused multiply-add Yes
Support is emulated in software No
Address bits 64, Little-Endian
Global memory size 2090397696 (1.947GiB)
Error Correction support No
Max memory allocation 522599424 (498.4MiB)
Unified memory for Host and Device Yes
Minimum alignment for any data type 128 bytes
Alignment of base address 1024 bits (128 bytes)
Global Memory cache type Read/Write
Global Memory cache size 131072 (128KiB)
Global Memory cache line size 64 bytes
Image support Yes
Max number of samplers per kernel 16
Max size for 1D images from buffer 65536 pixels
Max 1D or 2D image array size 2048 images
Max 2D image size 65536x65536 pixels
Max 3D image size 65536x65536x65536 pixels
Max number of read image args 128
Max number of write image args 8
Local memory type Global
Local memory size 32768 (32KiB)
Max number of constant args 8
Max constant buffer size 65536 (64KiB)
Max size of kernel argument 1024
Queue properties
Out-of-order execution Yes
Profiling Yes
Prefer user sync for interop No
Profiling timer resolution 1000ns
Execution capabilities
Run OpenCL kernels Yes
Run native kernels No
printf() buffer size 1048576 (1024KiB)
Built-in kernels
Device Extensions cl_khr_global_int32_base_atomics cl_khr_global_int32_extended_atomics cl_khr_local_int32_base_atomics cl_khr_local_int32_extended_atomics cl_khr_byte_addressable_store cl_khr_3d_image_writes cl_khr_fp64 cl_khr_int64_base_atomics cl_khr_int64_extended_atomics cl_khr_fp16 cl_khr_gl_sharing cl_khr_icd cl_khr_egl_event cl_khr_egl_image cl_arm_core_id cl_arm_printf cl_arm_thread_limit_hint cl_arm_non_uniform_work_group_size cl_arm_import_memory

Device Name Mali-T628
Device Vendor ARM
Device Vendor ID 0x6200010
Device Version OpenCL 1.2 v1.r12p0-04rel0.03af15950392f3702b248717f4938b82
Driver Version 1.2
Device OpenCL C Version OpenCL C 1.2 v1.r12p0-04rel0.03af15950392f3702b248717f4938b82
Device Type GPU
Device Profile FULL_PROFILE
Device Available Yes
Compiler Available Yes
Linker Available Yes
Max compute units 2
Max clock frequency 600MHz
Device Partition (core)
Max number of sub-devices 0
Supported partition types None
Max work item dimensions 3
Max work item sizes 256x256x256
Max work group size 256
Preferred work group size multiple 4
Preferred / native vector sizes
char 16 / 16
short 8 / 8
int 4 / 4
long 2 / 2
half 8 / 8 (cl_khr_fp16)
float 4 / 4
double 2 / 2 (cl_khr_fp64)
Half-precision Floating-point support (cl_khr_fp16)
Denormals Yes
Infinity and NANs Yes
Round to nearest Yes
Round to zero Yes
Round to infinity Yes
IEEE754-2008 fused multiply-add Yes
Support is emulated in software No
Single-precision Floating-point support (core)
Denormals Yes
Infinity and NANs Yes
Round to nearest Yes
Round to zero Yes
Round to infinity Yes
IEEE754-2008 fused multiply-add Yes
Support is emulated in software No
Correctly-rounded divide and sqrt operations No
Double-precision Floating-point support (cl_khr_fp64)
Denormals Yes
Infinity and NANs Yes
Round to nearest Yes
Round to zero Yes
Round to infinity Yes
IEEE754-2008 fused multiply-add Yes
Support is emulated in software No
Address bits 64, Little-Endian
Global memory size 2090397696 (1.947GiB)
Error Correction support No
Max memory allocation 522599424 (498.4MiB)
Unified memory for Host and Device Yes
Minimum alignment for any data type 128 bytes
Alignment of base address 1024 bits (128 bytes)
Global Memory cache type Read/Write
Global Memory cache size 131072 (128KiB)
Global Memory cache line size 64 bytes
Image support Yes
Max number of samplers per kernel 16
Max size for 1D images from buffer 65536 pixels
Max 1D or 2D image array size 2048 images
Max 2D image size 65536x65536 pixels
Max 3D image size 65536x65536x65536 pixels
Max number of read image args 128
Max number of write image args 8
Local memory type Global
Local memory size 32768 (32KiB)
Max number of constant args 8
Max constant buffer size 65536 (64KiB)
Max size of kernel argument 1024
Queue properties
Out-of-order execution Yes
Profiling Yes
Prefer user sync for interop No
Profiling timer resolution 1000ns
Execution capabilities
Run OpenCL kernels Yes
Run native kernels No
printf() buffer size 1048576 (1024KiB)
Built-in kernels
Device Extensions cl_khr_global_int32_base_atomics cl_khr_global_int32_extended_atomics cl_khr_local_int32_base_atomics cl_khr_local_int32_extended_atomics cl_khr_byte_addressable_store cl_khr_3d_image_writes cl_khr_fp64 cl_khr_int64_base_atomics cl_khr_int64_extended_atomics cl_khr_fp16 cl_khr_gl_sharing cl_khr_icd cl_khr_egl_event cl_khr_egl_image cl_arm_core_id cl_arm_printf cl_arm_thread_limit_hint cl_arm_non_uniform_work_group_size cl_arm_import_memory

NULL platform behavior
clGetPlatformInfo(NULL, CL_PLATFORM_NAME, ...) ARM Platform
clGetDeviceIDs(NULL, CL_DEVICE_TYPE_ALL, ...) Success [ARM]
clCreateContext(NULL, ...) [default] Success [ARM]
clCreateContextFromType(NULL, CL_DEVICE_TYPE_DEFAULT) Success (1)
Platform Name ARM Platform
Device Name Mali-T628
clCreateContextFromType(NULL, CL_DEVICE_TYPE_CPU) No devices found in platform
clCreateContextFromType(NULL, CL_DEVICE_TYPE_GPU) Success (2)
Platform Name ARM Platform
Device Name Mali-T628
Device Name Mali-T628
clCreateContextFromType(NULL, CL_DEVICE_TYPE_ACCELERATOR) No devices found in platform
clCreateContextFromType(NULL, CL_DEVICE_TYPE_CUSTOM) No devices found in platform
clCreateContextFromType(NULL, CL_DEVICE_TYPE_ALL) Success (2)
Platform Name ARM Platform
Device Name Mali-T628
Device Name Mali-T628

ICD loader properties
ICD loader Name OpenCL ICD Loader
ICD loader Vendor OCL Icd free software
ICD loader Version 2.2.11
ICD loader Profile OpenCL 2.1
Es mucha información y muestra una plataforma con dos dispositivos OpenCL (ambos Mali-T628) compatibles con OpenCL 1.2.

Esto es todo en esta pequeña guía de inicio. Si realmente quieres hacer algo con OpenCL, es hora de leer la documentación de Arm Compute Library y recurrir a otros recursos en la web.

Referencias

Este artículo procede de www.cnx-software.com. Para ver el artículo original o leer noticias similares, visita https://www.cnx-software.com/2018/05/13/how-to-get-started-with-opencl-on-odroid-xu4-board-with-arm-mali-t628mp6-gpu/.

Be the first to comment

Leave a Reply