para - programacion en ensamblador
¿Cuántas instrucciones asm por instrucción C? (8)
Me doy cuenta de que esta pregunta es imposible de responder en forma absoluta, pero solo estoy después de las cifras del estadio:
Dado un programa C de tamaño razonable (miles de líneas de código), en promedio, cuántas instrucciones ASM se generarían. En otras palabras, ¿qué es una relación de instrucción C-ASM realista? Siéntase libre de hacer suposiciones, como ''con las arquitecturas x86 actuales''.
Traté de Google sobre esto, pero no pude encontrar nada.
Adición : al notar cuánta confusión trajo esta pregunta, siento la necesidad de una explicación: lo que quería saber por esta respuesta, es saber, en términos prácticos, qué significa "3GHz". Soy plenamente consciente de que el rendimiento por Herz varía enormemente según la arquitectura, el hardware, las memorias caché, la velocidad del bus y la posición de la luna.
No busco una respuesta precisa y científica, sino más bien una respuesta empírica que podría ponerse en escalas insondables.
Esta no es una respuesta trivial al lugar (como me di cuenta), y este fue mi mejor esfuerzo al respecto. Sé que la cantidad de líneas resultantes de ASM por línea de C varía según lo que esté haciendo. i++
no está en el mismo vecindario que sqrt(23.1)
- Lo sé. Además, no importa qué ASM obtenga de la C, la ASM se interpreta en varios conjuntos de microcódigos dentro del procesador, lo cual, de nuevo, depende de si está ejecutando AMD, Intel u otra cosa, y sus respectivas generaciones. Soy consciente de esto también.
Las respuestas que he obtenido hasta el momento son lo que he estado buscando: un proyecto con promedios lo suficientemente grandes en aproximadamente 2 líneas de ASM x86 por 1 línea de ANSI-C. Los procesadores de hoy en día promediarían alrededor de un comando de ASM por ciclo de reloj, una vez que se llenen las tuberías y se les dé una muestra lo suficientemente grande.
¡Eso varía tremendamente! No le creería a nadie si trataban de ofrecer una conversión aproximada.
Declaraciones como i++;
se puede traducir a un solo INC AX
.
Las declaraciones para llamadas a funciones que contienen muchos parámetros pueden ser docenas de instrucciones, ya que la pila está configurada para la llamada.
A continuación, agregue allí la optimización del compilador que ensamblará su código de una manera diferente a como lo escribió, eliminando así las instrucciones.
Además, algunas instrucciones funcionan mejor en los límites de las palabras de la máquina, por lo que los NOP
se salpicarán a lo largo de su código.
No creo que pueda concluir nada útil sobre el rendimiento de las aplicaciones reales de lo que está tratando de hacer aquí. A menos que "no sea preciso" significa "dentro de varios órdenes de magnitud".
Estás demasiado generalizado, y estás descartando el almacenamiento en caché, etc., como si fuera secundario, mientras que puede ser totalmente dominante.
Si su aplicación es lo suficientemente grande como para haber tendido una tendencia a un promedio de instrucciones por ubicación, entonces también será lo suficientemente grande como para tener E / S o al menos importantes problemas de acceso a la RAM para tener en cuenta.
No estoy seguro de lo que quiere decir con "C-instrucción", tal vez declaración o línea? Por supuesto, esto variará mucho debido a una serie de factores, pero después de ver algunos programas de muestra propios, muchos de ellos están cerca de la marca de 2-1 (2 instrucciones de ensamblaje por LOC), no sé qué significa o cómo podría ser útil.
Puede resolver esto usted mismo para cualquier combinación particular de programa e implementación pidiendo al compilador que genere solo el ensamblado ( gcc -S
por ejemplo) o usando un desensamblador en un ejecutable ya compilado (pero necesitaría el código fuente para compararlo) de todos modos).
Editar
Solo para ampliar esto en base a su aclaración de lo que está tratando de lograr (comprender cuántas líneas de código puede ejecutar un procesador moderno en un segundo):
Si bien un procesador moderno puede funcionar a 3 mil millones de ciclos por segundo, eso no significa que pueda ejecutar 3 mil millones de instrucciones por segundo. Aquí hay algunas cosas a considerar:
- Muchas instrucciones tardan varios ciclos en ejecutarse (las operaciones de división o coma flotante pueden llevar docenas de ciclos para ejecutarse).
- La mayoría de los programas pasan la mayor parte de su tiempo esperando cosas como accesos a memoria, acceso a disco, etc.
- Muchos otros factores, incluida la sobrecarga del sistema operativo (programación, llamadas al sistema, etc.) también son factores limitantes.
Pero en general sí, los procesadores son increíblemente rápidos y pueden lograr cosas increíbles en un corto período de tiempo.
No estoy seguro de que realmente haya una respuesta útil para esto. Seguramente tendrá que elegir la arquitectura (como sugirió).
Qué haría: tomar un programa C de tamaño razonable. Dale a gcc la opción "-S" y mírate. Generará el código fuente del ensamblador y usted mismo podrá calcular la proporción para ese programa.
No hay respuesta posible. declaraciones como int a;
podría requerir cero líneas de asm. while declaraciones como a = call_is_inlined();
podría requerir más de 20 líneas de asm.
Puede verse compilando el programa de CA y luego comenzando objdump -Sd ./a.out
. Mostrará el código ASM y C entremezclado, para que pueda ver cuántas líneas ASM se generan para una línea C. Ejemplo:
test.c
int get_int(int c);
int main(void) {
int a = 1, b = 2;
return getCode(a) + b;
}
$ gcc -c -g test.c
$ objdump -Sd ./test.o
00000000 <main>:
int get_int(int c);
int main(void) { /* here, the prologue creates the frame for main */
0: 8d 4c 24 04 lea 0x4(%esp),%ecx
4: 83 e4 f0 and $0xfffffff0,%esp
7: ff 71 fc pushl -0x4(%ecx)
a: 55 push %ebp
b: 89 e5 mov %esp,%ebp
d: 51 push %ecx
e: 83 ec 14 sub $0x14,%esp
int a = 1, b = 2; /* setting up space for locals */
11: c7 45 f4 01 00 00 00 movl $0x1,-0xc(%ebp)
18: c7 45 f8 02 00 00 00 movl $0x2,-0x8(%ebp)
return getCode(a) + b;
1f: 8b 45 f4 mov -0xc(%ebp),%eax
22: 89 04 24 mov %eax,(%esp)
25: e8 fc ff ff ff call 26 <main+0x26>
2a: 03 45 f8 add -0x8(%ebp),%eax
} /* the epilogue runs, returning to the previous frame */
2d: 83 c4 14 add $0x14,%esp
30: 59 pop %ecx
31: 5d pop %ebp
32: 8d 61 fc lea -0x4(%ecx),%esp
35: c3 ret
RISC o CISC? ¿Qué es una instrucción en C, de todos modos?
Lo cual es repetir los puntos anteriores de los que realmente no tienes idea hasta que te vuelvas muy específico sobre el tipo de código con el que estás trabajando.
Puede intentar revisar la literatura académica sobre la optimización de ensamblaje y la interferencia cruzada de hardware / software que ha sucedido en los últimos 30-40 años. Ahí es donde encontrarás algún tipo de datos reales sobre lo que te interesa. (Aunque te advierto, podrías terminar viendo datos C-> PDP en lugar de datos C-> IA-32).
Según su entorno, puede usar la opción de estudio visual: / FAs
más aquí
Usted escribió en uno de los comentarios que quiere saber qué significa 3GHz.
Incluso la frecuencia de la CPU no importa. Las PC-CPU modernas intercalan y programan las instrucciones en gran medida, captan y captan previamente, almacenan en caché la memoria y las instrucciones, y con frecuencia esa caché se invalida y se arroja al contenedor. La mejor interpretación de la potencia de procesamiento se puede obtener mediante la ejecución de puntos de referencia del rendimiento en el mundo real.