una semana rapido que puede peso para maximo efectivo dietas dieta dias cuanto como bajar adelgazar c performance assembly x86

c - rapido - dieta para bajar de peso en una semana



La forma más rápida de averiguar un mínimo de 3 números? (10)

En un programa que escribí, el 20% del tiempo se gasta en encontrar el mínimo de 3 números en un ciclo interno, en esta rutina:

static inline unsigned int min(unsigned int a, unsigned int b, unsigned int c) { unsigned int m = a; if (m > b) m = b; if (m > c) m = c; return m; }

Hay alguna manera de acelerar esto? Estoy bien con el código de ensamblaje también para x86 / x86_64.

Editar: En respuesta a algunos de los comentarios:
* El compilador utilizado es gcc 4.3.3
* En lo que respecta al montaje, solo soy un principiante allí. Pedí la asamblea aquí, para aprender cómo hacer esto. :)
* Tengo un Intel Kern de cuatro núcleos en ejecución, por lo que se admiten MMX / SSE, etc.
* Es difícil publicar el ciclo aquí, pero puedo decir que es una implementación muy optimizada del algoritmo de levenshtein.

Esto es lo que el compilador me está dando para la versión no en línea de min:

.globl min .type min, @function min: pushl %ebp movl %esp, %ebp movl 8(%ebp), %edx movl 12(%ebp), %eax movl 16(%ebp), %ecx cmpl %edx, %eax jbe .L2 movl %edx, %eax .L2: cmpl %ecx, %eax jbe .L3 movl %ecx, %eax .L3: popl %ebp ret .size min, .-min .ident "GCC: (Ubuntu 4.3.3-5ubuntu4) 4.3.3" .section .note.GNU-stack,"",@progbits

La versión impresa está dentro del código optimizado para -O2 (incluso mis marcadores mrk = 0xfefefefe, antes y después de la llamada a min ()) están siendo optimizados por gcc, por lo que no pude conseguirlo.

Actualización: Probé los cambios sugeridos por Nils, ephemient, sin embargo, no hay un aumento de rendimiento perceptible que obtengo al usar las versiones de ensamblaje de min (). Sin embargo, obtengo un aumento del 12.5% ​​al ​​compilar el programa con -march = i686, lo que supongo es porque todo el programa está obteniendo los beneficios de las nuevas instrucciones más rápidas que gcc está generando con esta opción. gracias por su ayuda chicos.

PD: utilicé el perfilador de ruby ​​para medir el rendimiento (mi programa C es una biblioteca compartida cargada por un programa ruby), así que podía dedicarle tiempo solo para la función C de nivel superior llamada por el programa ruby, que termina llamando a min () abajo de la pila. Por favor mira esta question .


Asegúrese de estar utilizando una configuración apropiada de -march , primero apagado. GCC se predetermina a no utilizar ninguna instrucción que no era compatible con el i386 original. ¡Permitirle usar conjuntos de instrucciones más nuevos puede hacer una GRAN diferencia a veces! En -march=core2 -O2 obtengo:

min: pushl %ebp movl %esp, %ebp movl 8(%ebp), %edx movl 12(%ebp), %ecx movl 16(%ebp), %eax cmpl %edx, %ecx leave cmovbe %ecx, %edx cmpl %eax, %edx cmovbe %edx, %eax ret

El uso de cmov aquí puede ayudarlo a evitar retrasos en la sucursal, y lo obtiene sin ningún asme en línea simplemente al pasar en -march . Cuando está integrado en una función más grande, es probable que sea incluso más eficiente, posiblemente solo cuatro operaciones de ensamblaje. Si necesita algo más rápido que esto, vea si puede hacer que las operaciones del vector SSE funcionen en el contexto de su algoritmo general.


Estas son todas buenas respuestas. A riesgo de ser acusado de no contestar la pregunta, también miraría el otro 80% del tiempo. Stackshots son mi forma favorita de encontrar un código que valga la pena optimizar, especialmente si se trata de llamadas a función que descubres que no necesitas absolutamente.


Este reemplazo directo cambia en aproximadamente 1.5% más rápido en mi AMD Phenom:

static inline unsigned int min(unsigned int a, unsigned int b, unsigned int c) { asm("cmp %1,%0/n" "cmova %1,%0/n" "cmp %2,%0/n" "cmova %2,%0/n" : "+r" (a) : "r" (b), "r" (c)); return a; }

Los resultados pueden variar; algunos procesadores x86 no manejan muy bien CMOV.



Mi opinión sobre una implementación de ensamblador x86, sintaxis GCC. Debe ser trivial para traducir a otra sintaxis de ensamblador en línea:

int inline least (int a, int b, int c) { int result; __asm__ ("mov %1, %0/n/t" "cmp %0, %2/n/t" "cmovle %2, %0/n/t" "cmp %0, %3/n/t" "cmovle %3, %0/n/t" : "=r"(result) : "r"(a), "r"(b), "r"(c) ); return result; }

Nueva versión mejorada:

int inline least (int a, int b, int c) { __asm__ ( "cmp %0, %1/n/t" "cmovle %1, %0/n/t" "cmp %0, %2/n/t" "cmovle %2, %0/n/t" : "+r"(a) : "%r"(b), "r"(c) ); return a; }

NOTA: Puede o no ser más rápido que el código C.

Esto depende de muchos factores. Por lo general, cmov gana si las ramas no son predecibles (en algunas arquitecturas x86). El ensamblador en línea OTOH siempre es un problema para el optimizador, por lo que la penalización de optimización para el código circundante puede superar todas las ganancias.

Por cierto, Sudhanshu, sería interesante escuchar cómo funciona este código con sus datos de prueba.


Podría intentar algo como esto para ahorrar en declaraciones y comparaciones innecesarias:

static inline unsigned int min(unsigned int a, unsigned int b, unsigned int c) { if (a < b) { if (a < c) return a; else return c; } if (b < c) return b; else return c; }


Primero, mira el desmontaje. Eso te dirá mucho. Por ejemplo, tal como está escrito, hay 2 sentencias if (lo que significa que hay 2 posibles errores de predicción de bifurcaciones), pero mi suposición es que un compilador de C moderno decente tendrá alguna optimización inteligente que pueda hacerlo sin ramificarse. Me gustaría saberlo.

En segundo lugar, si su libc tiene funciones min / max incorporadas especiales, úselos. GNU libc tiene fmin / fmax para coma flotante, por ejemplo, y afirman que "en algunos procesadores estas funciones pueden usar instrucciones especiales de máquina para realizar estas operaciones más rápido que el código C equivalente". Tal vez hay algo similar para uints.

Finalmente, si haces esto en un grupo de números en paralelo, probablemente haya instrucciones vectoriales para hacer esto, lo que podría proporcionar una aceleración significativa. Pero incluso he visto que el código no vectorial es más rápido cuando se usan unidades de vectores. Algo así como "cargue una uint en un registro de vectores, llame a la función de min de vectores, obtenga resultados" parece tonto, pero en realidad podría ser más rápido.


Sí, post ensamblaje, pero mi optimización ingenua es:

static inline unsigned int min(unsigned int a, unsigned int b, unsigned int c) { unsigned int m = a; if (m > b) m = b; if (m > c) return c; return m; }


Si solo está haciendo una comparación, es posible que desee desenrollar el ciclo manualmente.

Primero, vea si puede hacer que el compilador desenrolle el ciclo, y si no puede, hágalo usted mismo. Esto al menos reducirá la sobrecarga del control de bucle ...


Suponiendo que su compilador no está listo para el almuerzo, esto debería compilar hasta dos comparaciones y dos movimientos condicionales. No es posible hacer mucho mejor que eso.

Si publica el ensamblado que su compilador está realmente generando, podemos ver si hay algo innecesario que lo esté ralentizando.

Lo primero que hay que verificar es que la rutina se está en línea. El compilador no está obligado a hacerlo, y si está generando una llamada de función, será muy costoso para una operación tan simple.

Si la llamada realmente se está introduciendo, el desenrollado del bucle puede ser beneficioso, como dijo DigitalRoss, o la vectorización puede ser posible.

Editar: si quiere vectorizar el código y está usando un procesador x86 reciente, querrá usar la instrucción pminud SSE4.1 (intrínseca: _mm_min_epu32 ), que toma dos vectores de cuatro entradas sin signo cada uno, y produce un vector de cuatro entradas sin firmar. Cada elemento del resultado es el mínimo de los elementos correspondientes en las dos entradas.

También observo que su compilador usó ramas en lugar de movimientos condicionales; Probablemente deberías probar una versión que usa movimientos condicionales primero y ver si eso te permite acelerar antes de ir a las carreras en una implementación de vector.