Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

181
Views
Memcpy más rápido asumiendo la legibilidad y escritura de bytes más allá de los búferes de origen y destino

Supongamos que queremos copiar n bytes de datos de void* src a void* dst . Es bien sabido que la implementación de la biblioteca estándar de memcpy está muy optimizada para usar instrucciones vectorizadas dependientes de la plataforma y varios otros trucos para realizar la copia lo más rápido posible.

Ahora suponga que se pueden leer p bytes de datos después de src + n y se pueden escribir p bytes de datos después de dst + n . Además, suponga que está bien si se escribe basura arbitraria en [dst + n, dst + n + p) .

Claramente, estas suposiciones amplían el rango de nuestras posibles acciones, lo que posiblemente conduzca a un memcpy aún más rápido. Por ejemplo, podemos copiar una parte de menos de 16 bytes finales en una pequeña cantidad de instrucciones de 128 bits no alineadas (cargar + almacenar). Tal vez haya otros trucos permitidos por tales suposiciones adicionales.

 01234 ..... n src: abcdabcdabcdabcdabcdabcGARBAGEGA vv dst: ______(actl dst)________(wrtbl)_ | block1 || block2 |

Tenga en cuenta que las suposiciones son bastante prácticas en los casos en que necesita agregar una secuencia de cadenas dentro del búfer asignado con capacidad suficiente para contener p + bytes de tamaño total de cadena. Por ejemplo, la siguiente rutina puede ocurrir en algún lugar interno de la base de datos:

Se le proporciona un char* dictionary de cadena binaria y una matriz de enteros int* offsets que es una secuencia monótona de compensaciones en el diccionario; estas dos variables representan un diccionario de cadenas obtenidas de un disco. También tiene una matriz de enteros int* indices indica un orden en el que las cadenas de diccionario deben escribirse en un búfer de salida char* buffer .

Usando la técnica descrita anteriormente, puede escribir con seguridad cada nueva cadena sin preocuparse por la basura a la derecha de ella, ya que será anulada por la siguiente cadena que se agregará.

Las preguntas son:

  1. ¿Existen implementaciones de código abierto de dicha técnica? Lograr una implementación óptima claramente requeriría dedicar mucho tiempo a la optimización (dependiendo de la plataforma), por lo que escribir dicho código sin considerar las implementaciones existentes no parece una buena idea.
  2. ¿Por qué la legibilidad de 15 bytes más allá de una asignación no es una característica de los asignadores modernos? Si un asignador de memoria pudiera simplemente asignar una página de memoria unificada más en cada mmap que hace internamente, proporcionaría la legibilidad deseada efectivamente sin costo alguno sin necesidad de cambiar el código del programa.

Comentario final: esta idea no es nueva; por ejemplo, aparece en el código fuente de ClickHouse. Aún así, han implementado su propia matriz POD con plantilla personalizada para manejar tales asignaciones.

over 4 years ago · Santiago Trujillo
2 answers
Answer question

0

Ahora suponga que se pueden leer p bytes de datos después de src + n y se pueden escribir p bytes de datos después de dst + n . Además, suponga que está bien si se escribe basura arbitraria en [dst + n, dst + n + p) .

Estas suposiciones son poco prácticas en la mayoría de los casos:

  • Si se sabe que el sistema operativo de destino asigna bloques con un tamaño múltiplo de algún valor de alineación, como 16, 4K o incluso 8K, el compilador y la biblioteca pueden suponer que se pueden leer bytes de datos adicionales al final de un bloque no alineado. Entonces, para su propósito, parece que podría guardar algunas pruebas en la última lectura del fragmento.

  • Por el contrario, una función de biblioteca no debe hacer las otras dos suposiciones, por lo que una implementación genérica de memcpy no hará esto, incluso si restaura los contenidos anteriores del área más allá de dst + n , ya que esto sería potencialmente incorrecto en un subproceso múltiple. proceso.

  • El programador podría intentar redondear n por unos pocos bytes en un intento de reducir algunos ciclos, pero es muy complicado y propenso a errores.

  • En la mayoría de los casos, hay muy poco que ganar con este enfoque. memcpy ya está optimizado en línea para muchos tamaños constantes y la diferencia sería infinitesimal para tamaños grandes.

Sin embargo, si sabe que el tamaño real de los datos está en el rango [1 .. 16] , y se pueden leer/escribir 16 bytes de manera inofensiva, puede optimizar la llamada especificando un tamaño máximo constante: memcpy(dst, src, 16) . Puede ajustar otros casos similares, verificar el código generado y medir el rendimiento real, que podría ser sustancialmente mejor que memcpy(dst, src, n) con n variable pero que se sabe que está en el rango esperado.

over 4 years ago · Santiago Trujillo Report

0

Si implementa memchr o memcmp vectorizados, donde solo lee, puede alinear los vectores con los límites naturales y, para el primer/último vector incompleto, enmascare los rellenos. Al procesar en fragmentos alineados naturalmente, nunca accederá a la página siguiente en la misma lectura, por lo que la lectura de datos no asignados debería ser segura, aunque el espacio adicional no esté asignado.

Aparentemente, es la única forma de vectorizar memchr , ya que esta función debe estar preparada para funcionar cuando el parámetro de count es mayor que el rango real, si el resultado se encuentra antes del final real. preferencia cp:

Esta función se comporta como si leyera los caracteres secuencialmente y se detiene tan pronto como se encuentra un carácter coincidente: si la matriz a la que apunta ptr es más pequeña que count, pero la coincidencia se encuentra dentro de la matriz, el comportamiento está bien definido


Para las escrituras, no creo que sea posible realizar ninguna optimización, a menos que las instrucciones de vectorización admitan escrituras enmascaradas.

Suponga que tiene una matriz separada por usuario en algún índice arbitrario, y subprocesos separados memcpy los diferentes datos en las partes. Si memcpy escribiera fuera de rango, habría una carrera de datos.

over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!