2010-01-11 11 views
15

Inspirado por una recent question, me gustaría saber si alguien sabe cómo conseguir gcc para generar la instrucción x86-64 bts (prueba de bits y establecer) en plataformas Linux x86-64, y sin recurrir a la asamblea o inline a los intrínsecos del compilador no estándar.¿Cómo hacer que `gcc` genere la instrucción` bts` para x86-64 del estándar C?

preguntas relacionadas:

portabilidad es más importante para mí que bts, por lo que no voy a usar y asm Directiva, y si hay otra solución, prefiero no utilizar instrinsics del compilador.

EDITAR: El lenguaje C fuente no soporta operaciones atómicas, así que no estoy particularmente interesado en conseguir atómica prueba-y-set (a pesar de que esa es la razón original para la prueba-y-set de existir en primer lugar). Si quiero algo atómico, sé que no tengo ninguna posibilidad de hacerlo con la fuente C estándar: tiene que ser una función intrínseca, de biblioteca o en línea. (He implementado operaciones atómicas en compiladores que admiten varios hilos).

+0

Hmm, buena pregunta. Veo 'vtst_ *' para vector bit-test en ARM + NEON, pero nada más general ... – ephemient

+7

Si bts es realmente más rápido, envíe un informe de error. Estoy seguro de que los programadores de gcc ya conocen la existencia de bts. Después de todo, un compilador no debe mapear 1: 1. – jbcreix

+1

Mejor aún, envíe un parche para usar bts junto con testcases que puedan perfilarse para demostrar que la optimización vale la pena. –

Respuesta

0

Creo (pero no estoy seguro) que ni los estándares C++ ni los C tienen ningún mecanismo para este tipo de mecanismos de sincronización. El soporte para mecanismos de sincronización de nivel superior se encuentra en varios estados de estandarización, pero ni siquiera creo que uno de ellos le permita acceder al tipo de primitivo que está buscando.

¿Está usted programando estructuras de datos sin bloqueo donde los bloqueos son insuficientes?

Probablemente quiera seguir adelante y usar las extensiones no estándar de gcc y/o el sistema operativo o las primitivas de sincronización proporcionadas por la biblioteca. Apostaría a que hay una biblioteca que podría proporcionar el tipo de portabilidad que está buscando si le preocupa usar los intrínsecos del compilador. (Aunque en realidad, creo que la mayoría de la gente simplemente muerde la bala y usa el código específico de gcc cuando lo necesitan. No es ideal, pero los estándares no se han mantenido al día.)

+5

OP no solicita métodos de sincronización. OP pregunta si hay una forma portátil de indicarle al compilador que use 'bts' en lugar de' shl' + 'or', ya que el primero es más rápido. – ephemient

1

Uso las construcciones atómicas gcc como __sync_lock_test_and_set (http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Atomic-Builtins.html). Cambiar el indicador -march afectará directamente a lo que se genera. Lo estoy usando con i686 en este momento, pero http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/i386-and-x86_002d64-Options.html#i386-and-x86_002d64-Options muestra todas las posibilidades.

Me doy cuenta de que no es exactamente lo que estás pidiendo, pero encontré esas dos páginas web muy útiles cuando buscaba mecanismos como ese.

+0

gcc 4.2 en x86-64 '__sync_lock_test_and_set' genera un' xchg' no 'bts'. – kennytm

+1

'bts' establece un poco, mientras que el que mencioné establece una variable completa. Me conecté a la página con la esperanza de que el OP pueda encontrar algo útil allí. – laura

4

Es en la primera respuesta para el primer enlace: ¿cuánto importa en el gran esquema de cosas? La única parte cuando prueba los bits es:

  • Controladores de bajo nivel. Sin embargo, si está escribiendo uno, probablemente conozca ASM, es suficiente para el sistema y probablemente la mayoría de las demoras se encuentren en E/S
  • Prueba de indicadores. Suele ser en la inicialización (una vez solo al principio) o en algún cálculo compartido (lo que lleva mucho más tiempo).

El impacto general en el rendimiento de las aplicaciones y macrobenchmarks es probable que sea mínimo, incluso si microbenchmarks muestra una mejora.

Para Editar parte - usar bts solo no garantiza el funcionamiento atómico de la operación. Todo lo que garantiza es que será atómico en este núcleo (así es or hecho en la memoria). En unidades multiprocesador (poco comunes) o unidades multi-núcleo (muy comunes), aún debe sincronizar con otros procesadores.

como la sincronización es mucho más caro Me creer que diferencia entre:

asm("lock bts %0, %1" : "+m" (*array) : "r" (bit)); 

y

asm("lock or %0, %1" : "+m" (*array) : "r" (1 << bit)); 

es mínima. Y la segunda forma:

  • se puede establecer varios bandera a la vez
  • tener Niza forma __sync_fetch_and_or (array, 1 << bit) (trabajando en gcc y compilador Intel por lo que yo recuerdo).
+0

"cuánto importa", bueno, dependiendo del tipo de CPU, 'bts' es un 20% más rápido. Ver el informe de error 'gcc' en los comentarios a la pregunta. –

+1

@FrankH .: Lo he aclarado. 'bts' es un 20% más rápido en microbenchmark, pero si no mejora el rendimiento general, no hay ninguna razón para complicar el compilador solo para mejorar microbenchmark. Aparentemente, han encontrado uso, pero los compiladores son más frecuentemente impulsados ​​por macro y luego micro-benchmarks. –

+0

@MaciejPiechotka: Para varios tipos de software (por ejemplo, "motores lógicos proposicionales" que funcionan en grandes matrices de bits), un 20% más rápido en micro-puntos de referencia puede traducirse aproximadamente un 19% más rápido en software del mundo real. Uno de los casos para 'bts' es asignadores (por ejemplo, un bit por cada cosa que podrías asignar/libre) donde el hecho de que' bts' y 'btr' pueden ser atómicos (con un prefijo' lock') significa que puedes terminar con algoritmos sin bloque en código multihilo. También tenga en cuenta que estas instrucciones funcionan felizmente en arreglos de 2 mil millones de bits o más (en memoria) sin ningún "andamio" adicional. – Brendan

Cuestiones relacionadas