Solución del problema
El error de GCC 88809 está cerrado, corregido para GCC10, que afecta a GCC9 y versiones anteriores.
GCC10 y versiones posteriores ya no deberían expandirse strlen
en línea con basura lenta como repnz scasb
cuando se compila glibc. (Consulte ¿Por qué este código usa strlen en gran medida 6,5 veces más lento con las optimizaciones de GCC habilitadas? para obtener detalles sobre cómo strlen
se compila en las versiones de GCC afectadas. La versión que muestra usando repnz scasb
parece el -O1
peor de los casos).
snprintf
todavía no es rápido en general (mucha sobrecarga analizando la cadena de formato y pasando varargs a través de funciones de contenedor). Pero con esa corrección de errores, con suerte debería escalar de manera similar a cadenas grandes como strcpy
, o al menos como strlen
+ memcpy
que hace dos pasadas sobre los datos. Entonces, con grandes entradas que conducen a pasar la mayor parte de su tiempo en strlen y/o memcpy, al menos lo hará de manera eficiente. Probablemente con el tiempo dividido equitativamente entre strlen y memcpy, si internamente usa memcpy en lugar de un bucle escrito a mano. En lugar del 99 % en strlen como lo encontró con perf record
, a menos que solo contara los resultados de muestra en esta función, no en las llamadas a memcpy.
Sus casos de prueba de referencia con cadenas medianas a grandes como 1000 y 10k bytes seguirán dedicando la mayor parte de su tiempo a eso, no analizando las cadenas de formato y la sobrecarga de la función varargs / wrapper, pero para tamaños pequeños esa sobrecarga dominará frente strncpy
a eso simplemente va directamente en copiar, encontrando la longitud a lo largo del camino.
Como se señaló en los comentarios, su strncat
bucle es un antipatrón. Construir una cadena grande de esa manera vuelve a escanear la parte ya copiada cada vez, dando O(N * M)
tiempo de ejecución para concatenar N cadenas de longitud M.
O en su caso, una vez que completa el destino, entonces solo cuesta O (tamaño de dst) tiempo por llamada básicamente memchr para un cero de terminación.
Para evitar esto, use strlen
y memcpy
usted mismo para realizar un seguimiento del punto al que agregar. O si puede usar las funciones POSIX-2008, use stpcpy
que devuelve el final de la copia, el lugar donde desea comenzar a copiar la siguiente. Desafortunadamente, esto no brinda una manera fácil de realizar comprobaciones de límites.
stpcpy
debería ser tan rápido como strcpy
en glibc, supongo que usando el mismo asm escrito a mano. Ha sido parte de glibc desde 1992.
Consulte también el valor de retorno de strcpy() sobre el diseño de API deficiente de las funciones de cadena ISO C que se remontan a una fecha muy temprana. (Separado del strncpy
diseño que hace que apeste para evitar desbordamientos de búfer, sin forzar que el destino termine en cero).
No hay comentarios.:
Publicar un comentario