Instrucciones por ciclo
# Instrucciones por ciclo

Las instrucciones por ciclo o IPC (en inglés instructions per cycle) indica la cantidad de instrucciones que un procesador ejecuta en un ciclo de reloj. En otras palabras, es un indicador más de rendimiento de un microprocesador. Otros factores de rendimiento son la frecuencia de reloj del microprocesador y la cantidad de instrucciones del programa. Por tanto tenemos que el rendimiento final de un microprocesador depende de tres factores: microarquitectura (IPC), tecnología (frecuencia de reloj) y compilador (instrucciones).

# Instrucciones por ciclo
## Descripción

Las instrucciones de un procesador se suelen ejecutar dividas en varias etapas o fases. Cuando se tienen varias instrucciones en ejecución, una en cada etapa, en condiciones ideales se da el resultado aparente de obtener una instrucción por ciclo de reloj (IPC = 1), puesto que cuando una instrucción acaba su última fase, la instrucción siguiente entra en su última fase de manera que al siguiente ciclo acaba también, como si se tratara de la cadena de montaje de un coche.
El IPC normalmente trata de un valor medio, ya que la cantidad de instrucciones ejecutadas en un ciclo de reloj en la mayoría de microarquitectura de procesadores varía en función del programa ejecutado en el procesador. Sumas de números enteros, por ejemplo, pueden ejecutarse más rápidamente que sumas con números reales.
Existen programas que realizan pruebas de rendimiento que, debido a la naturaleza del IPC y su valor en función del programa ejecutado, es importante seleccionar los adecuados para tener una buena indicación del IPC de un procesador. Con ellos el IPC medio es más significativo y aproxima mejor el rendimiento en los entornos habituales de producción previstos. Por ello las pruebas deben ser representativas de los programas que se van a ejecutar habitualmente con la microarquitectura del procesador medido. Por ejemplo, al diseñar un procesador multinúcleo los programas para medir su rendimiento no pueden consistir únicamente en programas con un solo hilo de ejecución.
A la hora de medir el rendimiento de un procesador se calcula el tiempo que tarda en ejecutar un programa. Este tiempo se obtiene con base en la fórmula siguiente:
$T=N\cdot {\frac {1}{IPC}}\cdot f$
Si reordenamos las variables:
$IPC=N\cdot {\frac {1}{T}}\cdot f$
Donde N es el número de instrucciones —en código ensamblador compatible con el procesador— del programa (y sus algoritmos) y f es la frecuencia del procesador. IPC es el recíproco del CPI o ciclos por instrucción (CPI = ${\frac {1}{IPC}}$), usado también en la bibliografía especializada.
La N o número de instrucciones es un valor que depende del compilador empleado, puesto que el código fuente de los lenguajes de niveles superiores al del código máquina es transformado en éste mediante un compilador. En el caso de no usar un compilador, el valor de N dependerá de la pericia que tenga el programador en usar las instrucciones que ofrece la microarquitectura del procesador. Esto hace difícil la comparación directa entre dos modelos de procesador distintos, puesto que sin tener el código fuente disponible no es posible disponer de un programa en código máquina imparcial. El código fuente puede ser el escrito por un humano, ya sea en ensamblador o en un lenguaje de mayor nivel, o una representación intermedia (bytecode) como la usada por LLVM o Vulkan (SPIR-V).
Además, aún disponiendo del código fuente del programa, el compilador puede ser también parcial, como ya ocurriera antiguamente con el compilador de Intel. El compilador de Intel generaba binarios con unas instrucciones y planificación de las mismas que resultaban en un pobre rendimiento usando los procesadores de AMD y VIA Technologies para el mismo algoritmo. Por tanto también es recomendable disponer del código fuente del compilador para poder comprobar que genera el mejor código posible para cada una de las microarquitecturas de las que obtener medidas de rendimiento. Entiéndase como mejor código posible la generación de un código máquina con instrucciones siguiendo una secuencia que no haga perder ciclos al procesador inútilmente cuando con otro orden de ejecución u otras instrucciones ofrecidas por su microarquitectura desperdiciaría menos ciclos, obteniendo un IPC más elevado.
Diseñar una microarquitectura para obtener un IPC elevado no es sencillo, y si los programas a ejecutar (incluidas las pruebas de rendimiento) no disponen de código fuente y/o han sido programados para unas determinadas características de microarquitectura, las opciones de los arquitectos de computadores pueden verse seriamente limitadas. Éstos han de diseñar una microarquitectura para código máquina pensado para microarquitecturas de otros fabricantes. A su vez disminuye la innovación, puesto que todos los diseños de procesador tienden al mismo esquema con mínimas variaciones. Esto favorece al diseño del fabricante con mayor cuota de mercado, que siempre contará con la ventaja competitiva de ser el estándar de facto para el que todos los programadores crean y prueban sus programas.
Los desarrolladores de software tienen por tanto influencia en el IPC de una microarquitectura, puesto que el compilador que usen y el código que escriban puede favorecer a unos procesadores sobre otros. Bibliotecas de funciones y de tiempo de ejecución sirven para abstraerse de dichos detalles del hardware obteniendo un programa más neutral, relegando a dichas bibliotecas la optimización para cada una de las arquitecturas en las que se vaya a ejecutar el programa. Los compiladores incluyen bibliotecas de este tipo como pueden ser las funciones intrínsecas, OpenMP, OpenACC, OpenCL y CUDA. A su vez, con estas bibliotecas se crean abstracciones optimizadas para cada variante de arquitectura, para distintas generaciones de GPUs y CPUs. Bibliotecas de álgebra como GSL, CuBLAS , clFFT y clBLAS,
ATLAS , LAPACK y MAGMA
son algunos ejemplos de abstracciones con optimizaciones por microarquitectura que utilizan las bibliotecas que incluyen los compiladores. En el campo de los videojuegos la abstracción se correspondería con el motor gráfico, que a su vez utiliza bibliotecas como OpenGL, Vulkan o Direct3D distribuidas con el controlador de dispositivo del dispositivo gráfico, el cual incluye el compilador para generar el binario compatible con la GPU a partir del código shader del programador. La biblioteca de tiempo de ejecución Java distribuida con Android (Dalvik o ART, según la versión de Android) abstrae las características del hardware y también del sistema operativo del dispositivo sobre el que se ejecuta la aplicación, lo que permite ejecutar las aplicaciones no sólo en dispositivos diferentes sino también en sistemas operativos diferentes.