Arquitectura de un ordenador

De MateWiki
Saltar a: navegación, buscar

El término arquitectura de ordenador hace referencia a cómo están organizados los elementos de un ordenador. En la actualidad, prácticamente todos los ordenadores siguen el mismo modelo básico de arquitectura[1], pero en el pasado se experimentaron con muchos modelos diferentes de ordenador, cada uno con sus ventajas e inconvenientes[2]. Conocer cómo funciona la arquitectura de un ordenador es importante para programar y para optimizar métodos numéricos (como ocurre por ejemplo con la factorización de Doolittle).

1 Componentes de un ordenador

El hardware del ordenador está dividido en diferentes componentes que trabajan de manera coordinada:

  • El procesador; en inglés, Central Processing Unit (CPU)
  • La memoria RAM, donde se almacenan de manera temporal los datos y programas en ejecución
  • El disco duro, donde se almacenan de manera permanente ficheros y programas
  • Otros dispositivos de entrada y salida (pantalla, teclado, altavaoces, webcam, micrófono, etc).

1.1 Procesador

El procesador dispone de un juego de instrucciones básicas, que son todas las operaciones que puede realizar el ordenador. Por ejemplo, la suma de dos números se realiza en el procesador. Las operaciones de las que dispone el procesador suelen ser operaciones lógicas de bajo nivel, que combinadas dan lugar a operaciones más complejas. Por ejemplo, la suma se realiza combinando varias operaciones AND lógicas. La información también se representa en el ordenador usando un sistema numérico binario, y las operaciones suelen trabajar sobre cada uno de los dígitos (bits) de la representación numérica binaria de la información. Cuando se habla de arquitecturas de 32 bits significa que los números que maneja el procesador pueden tener hasta 32 dígitos binarios. También, que cada posición de la memoria RAM puede almacenar un número de 32 bits. En la actualidad, los ordenadores más modernos incorporan arquitecturas de 64 bits, aunque en ocasiones tienen instalados sistemas operativos de 32 bits por motivos de compatibilidad (un sistema operativo de 32 bits puede funcionar en una arquitectura de 64 bits, pero un sistema operativo de 64 bits es imposible que funcione sobre una arquitectura de 32 bits).

La representación binaria acabó imponiéndose sobre otros sistemas de representación numérica (por ejemplo, el decimal al que estamos acostumbrados) por las técnicas con las que se construyen los ordenadores, usando dispositivos electrónicos. El dispositivo más sencillo del que consta un procesador es el transistor[3], que puede representar fácilmente dos estados diferentes (correspondientes a los dos posibles valorses, 0 y 1, que toma un bit). El procesador también consta de una pequeña memoria (registros) donde se guardan los elementos que intervienen en una operación y los resultados de las operaciones. Estos valores se escriben y leen en la memoria RAM del ordenador. La comunicación tiene lugar a través del denominado bus[4].

1.2 Memoria RAM

La memoria RAM es el dispositivo donde se guarda la información mientras el ordenador está funcionando. Contiene tanto los programas que se están ejecutando, como los datos que manejan esos programas. La memoria tiene varias posiciones donde se puede guardar información codificada en números binarios. Por ejemplo, una arquitectura de 64 bits puede guardar en cada posición números en binario con hasta 64 dígitos. Estas posiciones se conocen como direcciones de memoria. El procesador puede recuperar valores de direcciones de memoria específicas, y escribir también en otras posiciones de memoria. La cantidad de posiciones de memoria disponibles es el tamaño de la memoria RAM. Por tanto, una mayor memoria implica que se pueden tener más programas en ejecución, y que manejen más información. Ésta es la causa de que ampliar la memoria RAM de un ordenador incremente de manera notable la experiencia de usuario, al poder ejecutar más programas de manera simultánea.

El acrónimo RAM proviene de Random Access Memory, en español Memoria de Accesso Aleatorio. En Informática, el término acceso aleatorio hace referencia a que se puede acceder a posiciones de memoria concretas de manera directa, si se conoce su posición. Antiguamente, las memorias eran de accesso secuencial, y para acceder a una posición había que recorrer todas las posiciones anteriores. Por el contrario, las memorias de acceso aleatorio pueden saltar directamente a una localización de memoria sin necesidad de recorrer todas las posiciones anteriores.

Un problema habitual al usar un ordenador es que la memoria RAM no sea suficiente para ejecutar todos los programas. En los sistemas operativos primitivos, cuando esto ocurría el ordenador dejaba de funcionar (en términos coloquiales, se colgaba), ya que en la memoria RAM está toda la información que el ordenador necesita para seguir funcionando. Desde hace muchos años, los sistemas operativos intentan remediar esta situación con un proceso denominado swapping. Cuando el ordenador se queda sin memoria suficiente para mantener en memoria todos los programas en ejecución y la información que manejan, vuelva al disco duro algo del contenido de la memoria RAM, para hacer espacio para la información que necesite para seguir funcionando en ese momento. Si necesita alguna de la información que se ha eliminado de la memoria, la vuelve a recuperar del disco. Para esto, necesita hacer hueco y volcar otros contenidos en el disco duro. Este trasiego de información entre el disco y la memoria es muy lento, ya que el disco duro suele ser mucho más lento que la memoria RAM.

El software que es encarga de, entre otras tareas, la comunicación entre la memoria y el procesador es el sistema operativo, por medio del kernel, el núcleo del sistema operativo[5]. Por ejemplo, cuando escribimos el siguiente código en Octave UPM, el intérprete se encarga de comunicarse con el sistema operativo, que escribe el valor de la variable en una posición determinada. El programador no tiene que preocuparse por la posición concreta donde se escribe el número, ni sobre cómo se escribe. Al volver a usar esa variable en otra parte del programa, el kernel se encargará de recuperar la información de la posición donde se escribió, y devolver a nuestro programa el valor en forma de número:

n = 42; % El número 42 se guarda en alguna posición de memoria

Del mismo modo, en el siguiente código, las líneas 1 y 2 se encargan de comunicarse con el kernel para escribir los valores de las variables en alguna posición de la memoria, que no es necesario conocer, ya que gracias al intérprete nosotros siempre accedemos a esas variables a través de sus nombres. En la tercera línea, se recuperan los valores de las variables, y a través del bus, se comunican al procesador, que las guarda en sus registros. A continuación se le indica también al procesador qué operación tiene que realizar (en este caso, multiplicación). El resultado se guarda en otro registro del procesador, y vuelve por el bus a la memoria. El kernel lee esa posición de memoria, y le pasa el valor devuelto al intérprete, que lo guarda en la variable c:

1 a = 6;
2 b = 7;
3 c = a*b;

1.3 Disco duro

El disco duro es un dispositivo donde se guardan de manera permanente datos y programas. A diferencia de la memoria RAM, si apagamos el ordenador la información contenida en el disco duro se mantiene. Existen diferentes tecnologías para discos duros. La tecnología más habitual es la de discos magnéticos, que se leen con un cabezal similar al de un tocadiscos. Más recientemente, se comercializan también discos de estado sólido, que son totalmente electrónicos. Estos discos duros no llevan partes mecánicas, por lo que son mucho más rápidos que los discos duros magnéticos. Sin embargo, también fallan con más facilidad, y duran menos ciclos de escritura y lectura.

Para poder escribir y leer en el disco duro, que es un dispositivo físico, el sistema operativo usa un programa denominado sistema de ficheros, que expone el disco duro a los programas como si fuera una estructura ramificada (un árbol, en términos informáticos) de directorios y ficheros[6]. El sistema de ficheros se encarga de decidir en qué partes del disco duro se escribe un fichero, y en general, de organizar y distribuir la información físicamente en el dispositivo.

El disco duro no es un componente con demasiada influencia en la programación de ordenadores. El sistema de ficheros siempre expondrá el disco duro a nuestros programas de la misma manera. No podemos optimizar nuestros programas de ninguna manera, más allá de minimizar las posibles escrituras y lecturas en el disco duro, que es siempre uno de los elementos más lentos del ordenador.

1.4 Otros dispositivos

Cuando el usuario se comunica con los programas que se ejecutan en el ordenador, siempre lo hace a través de algún dispositivo de entrada o de salida. Escribimos texto usando el teclado, lo leemos en la pantalla, lanzamos programas apuntando con el ratón, hablamos a través de un micrófono, escuchamos sonidos a través de altavoces, etc.

Desde el punto de vista del programador, no es necesario preocuparse por cómo funcionan estos dispositivos. El kernel del sistema operativo dispone de funciones que nos permiten escribir en los dispositivos de salida (por ejemplo, reproducir un sonido supone escribir en el dispositivo de salida de sonido) o leer desde los dispositivos de entrada. Normalmente, estas funciones del kernel del sistema operativo están trasladadas al lenguaje de programación que usamos. Por ejemplo, el siguiente código de Octave UPM lee información del teclado. El intérprete de Octave UPM llama a la función correspondiente del kernel, que se comunica con el teclado, y recoge las pulsaciones de las teclas. Todo este proceso es completamente transparente para el programador. El efecto neto es que el programador obtiene un determinado valor en una variable:

n = input('Dame un numero: ');

Del mismo modo, al ejecutar el siguiente código, el intérprete de Octave UPM llama a la función correspondiente del kernel, que se encarga de interactuar con la pantalla y escribir el texto Hola mundo en la pantalla:

disp('¡Hola mundo!');

2 Arquitectura de los ordenadores modernos

Arquitectura de von Neumann

El esquema que hemos descrito en la sección anterior puede representarse por la imagen de la derecha. Es el modelo de arquitectura de von Neumann[1], donde la memoria y el procesador se comunican por medio de un bus. Esta arquitectura tiene una gran influencia en el rendimiento de nuestros programas, sobre todo en la implementación de métodos numéricos. Normalmente, a la hora de implementar un método numérico, la cantidad de operaciones que se realizan era el factor principal que determinaba el tiempo de ejecución de nuestro programa. Si un programa tiene que realizar más operaciones que otro, era más lento. Este concepto se conoce como complejidad algorítmica: a grandes rasgos, un programa más complejo es el que realiza más operaciones, y un programa más complejo se ejecuta más lentamente.

Sin embargo, en los últimos años, según predecía la ley de Moore[7], se ha incrementado espectacularmente la capacidad de los procesadores. La cantidad de operaciones por segundo que puede realizar un procesador se conoce como frecuencia. A finales de los años 90 del siglo pasado, un procesador doméstico podía tener una frecuencia de 400 ó 500 MHz en el mejor de los casos. Eso implica que era capaz de hacer entre 400 y 500 millones de operaciones por segundo. En la actualidad, es fácil encontrar procesadores domésticos de 3 GHz, es decir, que son capaces de hacer 3000 millones de operaciones por segundo. Además, los ordenadores modernos suelen incorporar más de un procesador, trabajando todos los procesadores a la vez.

En estos procesadores modernos, que trabajan de manera tan rápida, en muchas ocasiones el procesador no recibe los datos que necesita al mismo ritmo que es capaz de realizar las operaciones. Es decir, tradicionalmente el cuello de botella que determinaba el tiempo de ejecución de un programa era el procesador. Sin embargo, en los ordenadores modernos la transferencia de información entre la memoria y el procesador es la clave. Esto ha forzado la investigación de memorias RAM y buses cada vez más rápidos, pero se ha llegado a unos límites donde no es posible suministrar los datos a un procesador al mismo ritmo que el procesador es capaz de operar con ellos.

Arquitectura de von Neumann con jerarquía de memorias (caché y memoria principal, aliviando el cuello de botella)

Para solucionar este inconveniente, las arquitecturas modernas se desvían del modelo de von Neumann, y presentan más de una memoria. Estas memorias están organizadas jerárquicamente. Hay una memoria más cercana al procesador, mucho más rápida que la memoria principal, y con un bus más ancho, que es capaz de transportar más datos que el bus normal. Esta nueva memoria recibe el nombre de caché. En Informática, el concepto de caché es muy habitual y puede encontrarse en diferentes sitios. Hace referencia a un almacén temporal, que contiene datos que se van a reutilizar con frecuencia. Por ejemplo, los navegadores web suelen guardar las fotos y las imágenes en una caché, para que cuando volvamos a una página web no sea necesario descargar de nuevo esas imágenes. En el caso de un procesador, la memoria caché guarda todos los datos que se han utilizado recientemente en cualquier operación, y también los resultados de esa operación. Como la caché es pequeña, suele estar siempre llena. Cuando el procesador necesita guardar un dato nuevo en la caché, los datos más antiguos se descartan.

En muchas operaciones, el procesador reutiliza continuamente resultados de operaciones anteriores. Esto ocurre sobre todo en las aplicaciones de escritorio, que pintan ventanas. En estas aplicaciones, la caché acelera la ejecución de los programas, ya que no es necesario que muchos de los datos viajen a través del bus entre la memoria y el procesador. Estos datos están en la caché y el procesador los puede reutilizar mucho más rápidamente, porque el bus que conecta con la caché es más rápido y ancho.

Esta característica de la caché puede usarse para optimizar métodos numéricos. Si tradicionalmente la cantidad de operaciones había sido el factor principal para comparar la velocidad de ejecución de un método numérico, cuando el cuello de botella es el bus y existe una memoria caché, el orden en el que se realizan las operaciones es más importante que la cantidad de operaciones. Si un método numérico es capaz de forzar al procesador a reutilizar continuamente los resultados de las operaciones que acaba de realizar, los datos que necesita estarán siempre disponibles en la caché, y el tiempo de ejecución será menor. Esto es lo que ocurre por ejemplo con la factorización de Doolittle, comparada con el método de Gauss para resolver sistemas lineales. Aunque la cantidad de operaciones es muy similar tanto con Doolittle como con Gauss, el método de Doolittle se ejecuta de manera más rápida en ordenadores modernos que disponen de una memoria caché.

En algunas ocasiones, puede haber más de un nivel de caché. Es bastante habitual encontrar ordenadores con dos niveles de caché, de manera que existe una jerarquía con tres niveles de memoria, donde cada nivel es más lento que el anterior:

  1. Caché de nivel 1
  2. Caché de nivel 2
  3. Memoria principal

2.1 ¿Por qué no se fabrica la memoria principal con las mismas características que la caché?

En realidad, la memoria caché y la memoria principal pueden ser exactamente de los mismos materiales. El problema de comunicación entre la memoria y el procesador se debe a que son componentes aislados dentro de la placa base del ordenador. Ambos están conectados a la placa, y están físicamente a algunos centímetros de distancia. Aunque el tiempo que tardan las señales eléctricas en llegar desde uno a otro es muy pequeño, con la velocidad de ejecución de los procesadores actuales, ese tiempo de comunicación, denominado latencia, puede ser del orden del que tarda el procesador en realizar una operación. Para solucionar este problema de comunicación, la memoria caché es mucho más pequeña y se monta mucho más cercana al procesador, en ocasiones incluso forma parte del mismo procesador.

Otro factor que tradicionalmente ha justificado que exista una memoria caché es que el precio de las memorias de alta velocidad es mucho más caro que el de la memoria RAM convencional. Incluyendo una pequeña memoria caché puede lograrse un notable aumento de rendimiento con un pequeño incremento del precio, y se puede aprovechar la memoria RAM convencional más lenta y barata.

En la actualidad, prácticamente todos los ordenadores que se pueden adquirir en el mercado incorporan uno o dos niveles de caché, por lo que es recomendable tener en cuenta sus propiedades a la hora de implementar algoritmos y métodos numéricos. Por ejemplo, en el caso de Octave UPM y MATLAB, las matrices se guardan siempre en la memoria en orden de columnas. Es decir, en la memoria, los elementos de una misma columna están contiguos, mientras que los de una misma fila están separados. Un algoritmo que intente aprovechar la caché reutilizando información continuamente, debería recorrer la matriz en orden de columnas, para obtener siempre los elementos de la matriz de posiciones contiguas en la memoria. Si la recorriera en orden de filas, el procesador tendría que estar continuamente pidiendo posiciones distantes a la memoria, lo que haría sensiblemente más lenta la ejecución.

3 Referencias

  1. 1,0 1,1 Arquitectura de von Neumann (Wikipedia ES)
  2. Comparison of CPU architectures (Wikipedia EN)
  3. Transistor (Wikipedia ES)
  4. Bus (Wikipedia ES)
  5. Kernel (Wikipedia ES)
  6. Sistema de ficheros (Wikipedia ES)
  7. Ley de Moore (Wikipedia ES)