2012-03-14 12 views
5

Estoy escribiendo una biblioteca Java que necesita calcular hashes SHA-1. Durante una tarea común, la JVM pasa aproximadamente el 70% de su tiempo en sun.security.provider.SHA.implCompress, 10% en java.util.zip.Inflater.inflate y 2% en sun.security.provider.ByteArrayAccess.b2iBig64. (De acuerdo con el perfilador de NetBeans.)Sugerencias máximas de rendimiento SHA-1 Hash en Java

Parece que no puedo obtener las palabras clave de búsqueda de Google para obtener resultados relevantes. No estoy muy familiarizado con el algoritmo hash SHA-1. ¿Cómo puedo obtener el máximo rendimiento de SHA-1 MessageDigest? ¿Hay un cierto tamaño de porción que debería digerir, o múltiplos de ciertos tamaños que debería probar?

para responder a algunas preguntas que usted está pensando en preguntar:

  • Sí, lo estoy digiriendo al leer los archivos (MessageDigest.update), por lo que solamente se digieren bytes de una vez.
  • Los compendios de SHA-1 se utilizan como sumas de comprobación, generalmente para los archivos que deben estar zlib/inflados.
  • No, no puedo usar un hash diferente.
  • Sí, sé que zlib ya usa sumas de comprobación, pero los requisitos externos especifican el uso de hashes SHA-1 además de eso. No puedo encontrar una buena razón por la cual (+1 si puede) :-)
+2

Si es IO en su computadora local lo que necesita para hacer este trabajo, sugiero invertir en un disco SSD, ya que sospecho que realmente leer los archivos de HDD es un cuello de botella aquí. –

+0

Ya he hecho todo lo posible para optimizar la E/S. Ya he analizado varias optimizaciones de IO, y el generador de perfiles dice que IO requiere el mismo tiempo que la digestión.Estoy bastante seguro de que no puedo hacer nada mejor con IO –

+2

Java es (era) lento en comparación con C/C++, pero en algunas tareas, es un poco más rápido. Si tiene acceso a una implementación C/C++ de su algoritmo, haga una comparación. Si Java es significativamente más lenta, es probable que haya margen de mejora, pero si son casi iguales, es probable que haya pocas posibilidades de mejora. (Hice una comparación tanto con C como con D cuando tuve un montón de matemáticas para hacer, y resultó que mi versión de Java fue la más rápida). –

Respuesta

1

SHA-1 tiene un tamaño de bloque de 64 bytes, por lo que es probable que sean múltiplos de eso; de lo contrario, la implementación deberá copiar bloques parciales en búferes.

¿Está ejecutando en una computadora multi-core? Puede ejecutar la descompresión zlib y el hash SHA-1 en subprocesos separados, usando algo como java.util.concurrent.SynchronousQueue para transferir cada bloque de 64 bytes descomprimido de un hilo al otro. De esta forma, puede tener un núcleo hash un bloque mientras que otro núcleo descomprime el siguiente bloque.

(Puede probar una de las otras implementaciones BlockingQueue que tiene cierta capacidad de almacenamiento, pero no creo que ayude demasiado. La descompresión es mucho más rápida que el hash, por lo que el hilo zlib llenaría rápidamente el cola y luego tendría que esperar para poner cada bloque nuevo, al igual que con el SynchronousQueue.)

Sé que dijiste que ya has optimizado las E/S, pero ¿estás usando E/S asincrónicas? Para obtener el máximo rendimiento, no desea comprimir un bloque y , luego solicite al sistema operativo que lea el bloque siguiente, solicite al sistema operativo que lea el siguiente bloque y luego el hash que ya tiene mientras el disco está ocupado recuperando el siguiente. Sin embargo, es probable que el sistema operativo ya se haya reabreado, por lo que puede no marcar una gran diferencia.

Pero más allá de todo eso, una función de hash criptográfica es algo complejo; solo va a tomarse un tiempo para correr. Tal vez necesitas una computadora más rápida. :-)

+0

Sería bueno si hubieran usado un hash no criptográfico como suma de verificación en lugar de uno criptográfico sobre el CRC utilizado en zlib. La E/S asíncrona sería una buena idea si no tuviera como objetivo el rendimiento de mi biblioteca, en realidad no es el rendimiento de esta prueba en particular de verificar muchos archivos. Sin embargo, me hizo pensar en cómo puedo hacer que la biblioteca esté diseñando más compatible con multihilo. Creo que me sorprendió que el cálculo de las sumas de comprobación lleve más tiempo que la E/S de archivos, que los diseñadores de los programas con los que estoy trabajando acabaran de tomar una decisión extraña –

+0

Bueno, presumiblemente quieren la resistencia a la colisión adicional que una criptografía hash proporciona; de lo contrario, no existiría ningún valor agregado sobre el CRC que zlib ya tenga. – Wyzard

+0

Y el acceso secuencial a archivos no es tan lento en los discos duros modernos. Tengo algunas unidades "verdes" de 5900rpm que promedian más de 100MB/seg en todo el disco, con un pico de 150MB/seg en el borde. Comparado con un algoritmo relativamente lento como SHA-1, eso no está mal. – Wyzard

0

¿Ha intentado cambiar el procesamiento del archivo a un archivo de memoria asignada? El rendimiento para aquellos tiende a ser significativamente más rápido que el IO y el NIO normales.

+0

Los resúmenes de SHA-1 se utilizan como sumas de comprobación, generalmente para archivos que deben estar zlib/inflados. En realidad, estoy usando 'DirectByteBuffer's porque la mayoría de los archivos deben estar inflados antes de poder calcular la suma de comprobación. Al observar la pila de llamadas del generador de perfiles, el motor de resumen utiliza un método que, cuando se envía un búfer que no tiene matriz (un búfer que no es de montón), en realidad copia los contenidos del búfer directo en un nuevo montón local. conjunto de bytes primitivos. De hecho, incluso optimiza ese buffer de byte primitivo basado en el sistema operativo y el tamaño de caché de la CPU L1. Dependiendo de la JVM. –

+0

Sería bueno si el JRE del sol proporcionara un digestor que funcionara con 'MappedByteBuffers'. ¿Conoces uno que pueda distribuir con la biblioteca? Sería aún mejor si java.util.zip funciona con 'MappedByteBuffer's. Quiero decir, ¡ya funciona en la memoria nativa! Tal vez pondré un RFE ... –

1

Tal vez pueda llamar al código nativo escrito en C. Debe haber un montón de bibliotecas SHA1 súper optimizadas disponibles.

+0

Ewww ... eso suena como un montón de trabajo. Y no tengo idea de si tal vez solo necesito enviar los búferes del tamaño correcto al digestor. Eso es realmente lo que trato de descubrir. –