Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

183
Visualizações
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 Respostas
Responde à pergunta

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 Relatório

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 Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda