2012-07-29 11 views
12

Actualmente estoy tratando de implementar varios algoritmos en un compilador Just In Time (JIT). Muchos de los algoritmos operan en bitmaps, más comúnmente conocidos como bitsets.¿Qué implementación de conjunto de bits debería usar para obtener el máximo rendimiento?

En C++ hay varias formas de implementar un conjunto de bits. Como verdadero desarrollador de C++, preferiría usar algo de STL. El aspecto más importante es el rendimiento. No necesariamente necesito un conjunto de bits dinámicamente redimensionable.

Según lo veo, hay tres opciones posibles.

I. Una opción sería usar std::vector<bool>, que ha sido optimizado para el espacio. Esto también indicaría que los datos no tienen que estar contiguos en la memoria. Supongo que esto podría disminuir el rendimiento. Por otro lado, tener un bit por cada valor de bool podría mejorar la velocidad, ya que es muy compatible con la caché.

II. Otra opción sería usar un std::vector<char> en su lugar. Garantiza que los datos estén contiguos en la memoria y que sea más fácil acceder a elementos individuales. Sin embargo, se siente extraño utilizar esta opción, ya que no está destinado a ser un conjunto de bits.

III. La tercera opción sería usar el std::bitset real. El hecho de que no sea redimensionable dinámicamente no importa.

¿Cuál debo elegir para obtener el máximo rendimiento?

+4

Benchmark! [Relacionado.] (Http://www.youtube.com/watch?v=wg4trPZFUwc) –

+3

También hay [Boost.Dynamic Bitset] (http://www.boost.org/doc/libs/1_50_0/libs/ dynamic_bitset/dynamic_bitset.html) a considerar. Pero en serio, realmente no hay forma de decir qué rendimiento tiene el mejor rendimiento sin conocer el patrón de uso. Por ejemplo: si su colección es pequeña y se accede a menudo, el vector 'podría proporcionarle un acceso más rápido que los conjuntos de bits, debido a que no tiene que hacer cambios de bits/enmascaramiento. Sin embargo, cuando se acceda a menos/más grande, la mayor cantidad de errores de caché debido a la mayor huella de memoria podría matar ese beneficio. – Grizzly

+0

A riesgo de señalar algo posiblemente obvio: std :: bitset está asignado en la pila y, por lo tanto, es bastante limitado en tamaño máximo en la mayoría de los casos. Sin embargo, no sé nada sobre la cantidad de datos que necesita almacenar. – identity

Respuesta

6

La mejor manera es simplemente compararlo, porque cada situación es diferente.

No utilizaría std::vector<bool>. Lo intenté una vez y la actuación fue horrible. Podría mejorar el rendimiento de mi aplicación simplemente usando std::vector<char>.

Realmente no comparé std::bitset con std::vector<char>, pero si el espacio no es un problema en su caso, yo iría por std::vector<char>. Utiliza 8 veces más espacio que un conjunto de bits, pero como no tiene que hacer operaciones de bits para obtener o establecer los datos, debería ser más rápido.

Por supuesto, si necesita almacenar muchos datos en el conjunto de bits/vector, entonces podría ser beneficioso utilizar el conjunto de bits, porque eso cabría en la memoria caché del procesador.

La manera más fácil es usar un typedef y ocultar la implementación. Tanto el conjunto de bits y el vector apoyan al operador [], por lo que debería ser fácil cambiar una implementación por la otra.

+0

El 'operador []' es lo suficientemente similar sí, pero los constructores no lo son. –

+0

@MooingDuck: cierto. Utilizo typedef para simplificar la migración de un tipo a otro, pero no para hacerlo sin esfuerzo. También uso typedef's para colecciones, así que puedo ocultar la implementación real (list, vector, deque, ...), que reduce los cambios reales del código con un 90% si alguna vez cambio el tipo de contenedor. – Patrick

2

Usted también puede estar interesado en este documento (un poco anticuado): http://www.cs.up.ac.za/cs/vpieterse/pub/PieterseEtAl_SAICSIT2010.pdf

+0

En pocas palabras, aquí está la conclusión del documento: "Hemos demostrado que' boost :: dynamic_bitset' es considerablemente más eficiente que la mayoría de las otras implementaciones en términos de velocidad de ejecución, mientras que la implementación usando 'std :: vector 'superó a las otras implementaciones en términos de eficiencia de la memoria." – davidhigh

3

Me respondió una pregunta similar hace poco en este foro. Recomiendo mi BITSCAN library. Acabo de lanzar la versión 1.0. BITSCAN está específicamente diseñado para operaciones de escaneo rápido de bits.

clase A BitBoard se ajusta un número de diferentes implementaciones para operaciones típicas tales como BSF, BSR o popcount para las palabras de 64 bits (también conocido como bitboards). Las clases BitBoardN, BBIntrin y BBSentinel amplían el escaneo de bits a cadenas de bits. Una cadena de bits en BITSCAN es una matriz de tablas de bits. La clase de contenedor base para una cadena de bits es BitBoardN. BBIntrin amplía BitBoardN utilizando los intrínsecos del compilador de Windows sobre 64 bitboards.BBIntrin se hace portátil a POSIX utilizando las funciones equivalentes de asm apropiadas.

He utilizado BITSCAN para implementar una cantidad de solucionadores eficientes para problemas combinatorios NP en el dominio del gráfico. Normalmente, la matriz de adyacencia del gráfico, así como los conjuntos de vértices, se codifican como cadenas de bits y los cálculos típicos se realizan usando máscaras de bits. El código para objetos de gráfico bitencoded simples está disponible en GRAPH. Ejemplos de cómo usar BITSCAN y GRAPH también están disponibles.

Una comparación entre BITSCAN y las implementaciones típicas en STL (BitSet) y BOOST (dynamic_bitset) se pueden encontrar aquí: http://blog.biicode.com/bitscan-efficiency-at-glance/

Cuestiones relacionadas