Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
MICROPROCESADORES
DOCENTE
CUSCO - PERÚ
2018
Pag. 1
1. Caratula
2. Índice
3. Presentación
4. Introducción
5. Marco conceptual
5.1. Arquitectura del procesador
5.2. Arquitectura del FPU/AVX/GPU
5.2.1. Organización del FPU/AVX/GPU
5.2.2. Modelo de programación del FPU/AVX/GPU
5.3. Fundamentos del método numérico seleccionado
5.4. Aplicaciones del método numérico seleccionado
6. Implementación secuencial del método numérico seleccionado
6.1. Pseudocódigo del método numérico seleccionado
6.2. Implementación en lenguaje ensamblador o C
7. Implementación del método numérico seleccionado en FPU/AVX/GPU
7.1. Pseudocódigo del método numérico seleccionado
7.2. Implementación en lenguaje ensamblador o C
8. Métricas de evaluación de las implementaciones
8.1. Diseño de experimentos
8.2. Experimentación
8.3. Comparación y evaluación de resultados
9. Conclusiones
10. Referencias
11. Anexos:
11.1. CD conteniendo:
11.1.1. Código fuente de los programas implementados
11.1.2. Informe en formato docx y pdf.
Pag. 2
PRESENTACIÓN
El presente trabajo se centra en el estudio de la inversión de matrices con el método de Gauss Jordan y
la programación de este en el GPU (Unidad de procesamiento gráfico). En este sentido, es relevante
destacar dos cuestiones. Por un lado, la importancia de dicho método en el estudio de nuevas y más
optimas tecnologías y por otro lado, la programación paralela y las virtudes de esta.
Se inicia el proyecto, a modo de introducción general, un breve recorrido histórico sobre el método de
Gauss Jordan para la inversión de matrices y las diferentes arquitecturas del procesador, así como los
modelos de programación. Seguidamente se muestra la implementación de este método, para el GPU y
el análisis de tiempo de demora tanto en GPU como CPU.
Pag. 3
INTRODUCCIÓN
La inversión de matrices es un paso esencial en una amplia gama de problemas numéricos desde la
resolución de ecuaciones lineales, estructuralmente se analiza utilizando el método de elementos finitos,
representación 3D, filtrado digital, filtrado de imágenes y procesamiento de imágenes y constituye un
componente indispensable en casi todos los paquetes de software matemáticos / estadísticos. Algunos
de los algoritmos disponibles comunes para calcular la inversa de una matriz son Strassen, Strassen-
Newton, eliminación gaussiana, Gauss-Jordan, Calderero y Winograd, LUP Decom-posición,
Descomposición de Cholesky, descomposición QR, factorización RRQR, Métodos Monte Carlo para
inversa, etc.
Hasta finales de 1960 se creía que para la inversión de matrices se requería un número cúbico de
operaciones, el algoritmo más rápido conocido era el método de eliminación de Gauss, o más bien Gauss
Jordan método que se ejecuta en O (n3), tiempo donde n es el tamaño de la matriz. En 1969, Strassen
excito la comunidad de investigación, dando el primer algoritmo de tiempo sub cúbico para la
multiplicación de matrices, que se ejecuta en O (n2,808). Esto también reduce la complejidad de tiempo,
w, de la inversión de matrices usando Strassen siendo de O (n2,808). Este descubrimiento provocó una
larga línea de investigación que reduce gradualmente la complejidad del tiempo w con los años. En 1978,
Pan presento un método que demostró w <2,796 y el siguiente año, Biniet al. introdujo la noción de
rango frontera y obtuvo w <2,78. Schönhage esta noción generalizada en 1981, lo que demuestra w
<2,548. En el mismo documento, combinando su trabajo con las ideas por Pan, También mostró w
<2,522.
Al año siguiente, Romaní encontró que w <2,517. El primer resultado de romper 2,5 era por Calderero y
Winograd que obtuvo w <2,496. En 1988, Strassen presentó su método láser que era un nuevo enfoque
para la multiplicación de la matriz, y por lo tanto la disminución de la cota a w <2,479. Dos años más
tarde, Calderero y Winograd combinó la técnica de Strassen con una nueva forma de análisis basado en
grandes conjuntos evitando progresiones aritméticas y obteniendo el famoso límite de w <2.376 que ha
permanecido sin cambios durante más de 22 años (un trabajo no publicado muy reciente afirma haber
reducido el límite a w <2,3727). Mientras que la mayor actividad se centra en tratar de reducir el
exponente w, tanto Calderero y Winograd y Cohnet presentaron conjeturas que afirman podría implicar
w = 2, pero nunca menos que eso.
Los recientes desarrollos en arquitectura paralela y su uso en la computación han traído sobre la
perspectiva de los sistemas masivamente paralelos capaces de reducir los tiempos de funcionamiento
de los códigos por debajo del límite de w = 2. La cantidad de aumento de rendimiento, por supuesto,
depende en gran medida del alcance de paralelización que el algoritmo de pro-Vides.
Uno de los métodos más antiguos para inversión de la matriz. Es sencillo y robusto y es particularmente
adecuado para la paralelización masiva a diferencia de muchos de los métodos más avanzados. Sin
embargo, la literatura disponible, ya sea en el ámbito de la paralelización del algoritmo de Gauss Jordan
o su optimización aparecen en lugar insuficiente. Este trabajo implementa el algoritmo de Gauss-Jordan
para inversión de la matriz en un CUDA (Compute Unified Device Architecture), con plataforma base
GPU y estudia las métricas de rendimiento del algoritmo.
Pag. 4
5. Marco conceptual
Usa una arquitectura Kaby Lake de 64 bits, Kaby Lake es el nombre clave de Intel para el sucesor de
la microarquitectura Skylake,1 siendo la séptima generación. Se anunció el 30 de agosto de 2016.
Al igual que Skylake, Kaby Lake tiene una medida de 14 nanómetros. Se empezó a distribuir procesadores Kaby
Lake a fabricantes y OEM’s en el segundo trimestre de 2016.34 en 2017, se presentó la actualización del mismo
bajo el nombre de Kaby Lake Refresh, como anticipo del lanzamiento de Coffee Lake.
Construido en un proceso mejorado de 14 nm (14FF+), Kaby Lake presenta velocidades de reloj más rápidas,
cambios en la velocidad del reloj, y frecuencias Turbo más rápidas. Más allá de esto poco de la arquitectura ha
cambiado desde Skylake.5 Skylake y Kaby Lake tienen el mismo IPC (rendimiento por MHz).2 Kaby Lake añade
soporte nativo para USB 3.1 Generación 2 (10 Gbit/s)6
Kaby Lake también presenta una arquitectura de gráficos nueva para mejorar rendimiento en gráficos 3D y
reproducción de video en 4K .27 Añade soporte nativo para HDCP 2.2.
Pag. 5
5.2. Arquitectura del GPU
La organización del GPU está basada en hilos y jerarquía de memoria de la GPU en CUDA, donde puede
observarse la memoria global, constante, compartida y local. También hay que agregar que CUDA posee un
conjunto de instrucciones que permiten la sincronización entre programas y ejecuciones de los hilos. Además, los
hilos dentro de los bloques son agrupados en conjuntos de 32 hilos, llamados warps, los cuales ejecutarán la
misma instrucción al mismo tiempo. Esto quiere decir, que todos los hilos de un warp están sincronizados, lo que
permite ciertas optimizaciones a la hora de la programación. Sin embargo, se deben evitar divergencias, ya que
disminuyen el desempeño de la aplicación. La divergencia se origina cuando dos hilos ejecutan dos conjuntos de
instrucciones diferentes; debido, por ejemplo, a la ejecución de un condicional. Cuando ocurren divergencia entre
hilos de un mismo warp, algunos hilos deben esperar a que el resto de los hilos del mismo warp ejecuten su
conjunto de instrucciones para luego ser ejecutados, disminuyendo el paralelismo.
La NVIDIA GeForce GTX 950M es una tarjeta de vídeo de gama media-alta, compatible con DirectX 11 para
portátiles. Se basa en la arquitectura Maxwell de Nvidia (chip GM107) y es producida en 28 nm. La GTX 950M
presenta 640 unidades shader con frecuencia de 1097 - 914 MHz (Boost) así como memoria GDDR5 (128 bit, 5000
MHz efectivos, 80 GB/s).
Arquitectura, comparada con Kepler, la Maxwell ha sido optimizada en diversos detalles para aumentar la
eficiencia del poder. Smaller Streaming Multiprocessors (SMM) con 128 ALUs (Kepler: 192) y un programador
optimizado proporciona mejor utilización de los shaders. GM107 tiene 5 SMMs y, por tanto, 640 núcleos shader,
40 TMUs y 16 ROPs (interfaz de 128-bits).
Pag. 6
Fig. 3 GPU Nvidia 950m architecture, Fuente: [3]
Debido a las diferencias fundamentales entre las arquitecturas de la GPU y la CPU, no cualquier
problema se puede beneficiar de una implementación en la GPU. En concreto, el acceso a memoria
plantea las mayores dificultades. Las CPU están diseñadas para el acceso aleatorio a memoria. Esto
favorece la creación de estructuras de datos complejas, con punteros a posiciones arbitrarias en
memoria. En cambio, en una GPU, el acceso a memoria está mucho más restringido. Por ejemplo, en un
procesador de vértices (la parte de una GPU diseñada para transformar vértice en aplicaciones 3D), se
favorece el modelo scatter, en el que el programa lee en una posición predeterminada de la memoria,
pero escribe en una o varias posiciones arbitrarias. En cambio, un procesador de píxeles, o fragmentos,
favorece el modelo gather, pudiendo el programa leer de varias posiciones arbitrarias, pero escribir en
sólo una posición predeterminada.
La tarea del diseñador de algoritmos GPGPU consiste principalmente en adaptar los accesos a memoria
y las estructuras de datos a las características de la GPU. Generalmente, la forma de almacenar datos es
en un buffer 2D, en lugar de lo que normalmente sería una textura. El acceso a esas estructuras de datos
es el equivalente a una lectura o escritura de una posición en la textura. Puesto que generalmente no se
Pag. 7
puede leer y escribir en la misma textura, si esta operación es imprescindible para el desarrollo del
algoritmo, éste se debe dividir en varias pasadas.
Pese a que cualquier algoritmo que sea implementable en una CPU lo es también en una GPU, esas
implementaciones no serán igual de eficientes en las dos arquitecturas. En concreto, los algoritmos con
un alto grado de paralelismo, sin necesidad de estructuras de datos complejas y con una alta intensidad
aritmética son los que mayores beneficios obtienen de su implementación en la GPU.
A.A-1=A-1.A=Id
Se trata de plantearla como una ecuación matricial donde el objetivo es encontrar A-1. Para ello
seguiremos los siguientes pasos:
1. Partimos de la matriz A.
Observamos dos matrices separadas por la barra vertical. La de la izquierda es la matriz A de la que
queremos calcular su matriz inversa. La de la derecha es la matriz identidad.
Pag. 8
Fig. 6 Matriz Identidad, Fuente: [4]
El movimiento de un brazo robótico. Este ejemplo se basa en sistemas lineales se ha estudiado los
aspectos importantes de la robótica en el mundo real y las aplicaciones de sistemas mecánicos. La
estructura del brazo robótico y las ecuaciones que modelan su movimiento para que pueda controlarse
para realizar las operaciones deseadas estuvieron basadas en la inversión de matrices. Tiene estructuras
comunes en mecánica de sistemas. El PA de punta es el efector final, que denota el final de un brazo
robótico y está diseñado para interactuar con el exterior ambiente. Cada articulación puede ser
accionada por un motor, y debido al diseño de la conexión, está limitada a 2 dimensiones movimiento
plano El mecanismo tiene 3 grados de libertad: dos de ellos son rotativos y uno es lineal. Estos
parámetros son inicializado como θ1 = 30◦ , θ2 = 30◦ y l = 0.7m.
Pag. 9
Fig. 8 Brazo robótico, Fuente: [6]
La robótica y la mecatrónica no son las únicas aplicaciones de la inversión de matrices con el método de
Gauss Jordan, ya que a estas aplicaciones se suma una amplia gama de utilidades en la ingeniería como
son en la ingeniería civil en el análisis de estructuras, proyectos de desarrollo sistematizado, etc.
Otro ámbito importante es en el de la programación ya que constituyen una parte esencial de los
lenguajes de programación.
Pag. 10
la mitad izquierda de la matriz, el primero de los cuales es convertir el elemento aii en 1 mediante la
transformación:
Si aii es cero, cualquier fila que no sea cero se agrega a la i-ésima fila antes de aplicar la ecuación anterior.
El segundo paso es reducir todos los demás elementos de la columna j-ésima a cero mediante la siguiente
transformación de cada fila, excepto la j-ésima:
Pag. 11
6.1 Pseudocódigo de la implementación secuencial del método utilizado
Leer augmentedmatrix
Inicializar dimensión como tamaño de la matriz
Function gauss_jordan()
float temporary, r
for j = 0 hasta dimensión hacer
temp <- j
Pag. 12
6.2 Implementación en lenguaje C
Para la implementación de la matriz inversa en C se utilizaron las siguientes funciones además de la
función Gauss-Jordan explicada anteriormente.
void matrix_read()
int main()
La implementación del código a continuación recoge una matriz de una dimensión de 1000 la que será
convertida en nuestra matriz augmentedmatrix y será procesada por el algoritmo utilizado (Gauss-Jordan).
• Cabeceras de código:
Fig. 12 Modulo para escribir la matriz de salida del código implementado. Fuente: Propia
Pag. 13
Fig. 13 Modulo para recuperar la matriz de ejemplo del código implementado. Fuente: Propia
Pag. 14
Fig. 14 Modulo para utilizar Gauss-Jordan del código implementado. Fuente: Propia
Pag. 15
7. Implementación de la matriz inversa en GPU
7.1 Pseudocódigo de la implementación en CUDA del método utilizado
Fig. 16 Pseudo código explicando el algoritmo Gauss-Jordan para la inversión de matrices adaptado
para computación en GPU. Fuente: [5]
7.2 Implementación en lenguaje C
Host función:
void savetofile(double *A, string s, int n, int h) Efecto: Guarda la matriz que necesitamos a un txt file.
Device función:
Pag. 16
Effect: the realization of parallel matrix inverse using Gaussian Jordan Elimination.
La implementación del código a continuación recoge una matriz de una dimensión de 1000 la que será
convertida en nuestra matriz augmentedmatrix y será procesada por el algoritmo utilizado (Gauss-Jordan).
• Cabeceras de código:
Fig. 18 Modulo para escribir la matriz de salida del código implementado. Fuente: Propia
Pag. 17
Fig. 19 Modulo para recuperar la matriz de ejemplo del código implementado. Fuente: Propia
Pag. 18
Fig. 21 Método de Gauss-Jordan en CUDA, Fuente: Propia
Pag. 19
Fig. 21 Modulo principal del código implementado. Fuente: Propia
Pag. 20
hilos distribuidos que se ejecutan en paralelo, es decir, 32 SM x 48 Warps residentes por SM x 32 Hilos
por urdimbre hilos activos, pero solo 32 SM x 32 Threads por warp corriendo en paralelo, cualquier
número por encima de ese dará lugar a apilamiento de warps esperando sus turnos. Por lo tanto, hasta
n = √1024 = 32, el algoritmo tendrá una complejidad temporal de O (n); la complejidad comienza a
aumentar para n> 221 y se vuelve cuadrática en n = 1024. Si se usa un clúster de GPU paralelas y se
ejecuta el programa usando todas las GPU, entonces esta capacidad de hardware se puede aumentar
aún más.
Los programas se corrieron en la distribución de LINUX Ubuntu versión 18.08 LST.
8.2. Experimentación
El algoritmo se programó usando CUDA C y se probó contra varios tamaños de los siguientes tipos de
matrices: matriz de identidad, matriz dispersa, matriz de banda (con k = n / 2), matriz aleatoria y matriz
hueca. Para este documento, la GPU utilizada fue Nvidia GForce GTX 950m (640 núcleos), Maxwell SMM
con 128 ALU puede ofrecer el 90% del rendimiento de un Kepler SMX con 192 ALU. GM107 presenta 5
SMM y, por lo tanto, 640 núcleos de sombreado, 40 TMU y 16 ROP (interfaz de 128 bits). La CPU utilizada
con fines de comparación es el procesador Intel Core i7 7700hq @ 3 GHz cada uno, capaz de ejecutar 8
hilos en paralelo.
Compilación de programas en secuencial y paralelo.
CPU:
GPU:
Pag. 21
Fig. 22 Comparación del algoritmo en una matriz de n=50, Fuente: [5]
Ahora si se hace una comparación del algoritmo en CPU y GPU de matrices aleatorias generadas, se
tendría el siguiente esquema:
Pag. 22
Fig. 23 benshmarking del algoritmo en CPU y GPU, Fuente: Propia
9. Conclusiones
La capacidad de invertir matrices grandes de forma precisa y rápida determina la efectividad de una
amplia gama de algoritmos y productos computacionales. La computación GPU es ideal para tareas
paralelas masivas ya que la creación de subprocesos y los gastos generales de transferencia de memoria
son insignificantes. Hemos rediseñado el algoritmo de Gauss Jordan para la inversión de matriz en la
plataforma CUDA basada en GPU, lo probamos en cinco tipos diferentes de matrices (identidad, dispersa,
en bandas, aleatoria y hueca) de varios tamaños, y hemos demostrado que la complejidad temporal de
la inversión de matriz como n si hay suficientes recursos computacionales disponibles. La escala lineal
continuará usando una red de GPU. También demostramos que la paralelización basada en GPU para
inversión de matriz es órdenes de magnitud más rápida que la paralelización basada en CPU. Incluso una
pequeña matriz de tamaño 10 x 10 mejoró usando el algoritmo paralelo CUDA Gauss Jordan.
10. Referencias
[1] Intel Core 7th generation architecture (20 de Julio de 2018). Recuperado de
https://www.intel.com/content/www/us/en/products/processors/core/i7processors.html
[2] GPU architecture (13 de agosto 2011). Recuperado de http://fisica.cab.cnea.gov.ar/gpgpu
[3] Nvidia GeForce GTX 950m architecture (20 de julio 2018). Recuperado de
https://www.geforce.com/hardware/notebook-gpus/geforce-gtx-950m/specifications
[4] Mahmoud Shirazi, M. K. y Farshad K. (2015). Gauss-Jordan Matrix Inversion Speed-Up using GPUs
whit the Consideration of Power Consumption. INFOCOMP 20,25. ISBN: 978-1-61208-416-9
[5] Grish S., A. A. y Baidurya B. (2013). A fast-parallel Gauss Jordan algorithm for matrix iversion using
CUDA. COMPUTERS & STRUCTURES. DOI:10.1016
[6] Zhang y Jeffery U. (2018). A Generalized Matrix Inverse whit Applications to Robotic Systems.
University of Misuri. DOI:18.0177
Pag. 23