A veces es útil simular algo con un pequeño programa en C que utiliza una gran cantidad de memoria estática. Me di cuenta después de cambiar a Fedora 15 el programa tomó un largo tiempo a compilación . Estamos hablando de 30 s contra 0.1 s. Aún más extraño fue que ld (el enlazador ) estaba maximizando la CPU y lentamente comenzó a comer toda la memoria disponible. Después de un poco de manipulación, logré para encontrar una correlación entre este nuevo problema y el tamaño de mi archivo swap . He aquí un programa de ejemplo para los propósitos de esta discusión:¿Rendimiento del enlazador relacionado con el espacio de intercambio?
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#define M 1000000
#define GIANT_SIZE (200*M)
size_t g_arr[GIANT_SIZE];
int main(int argc, char **argv){
int i;
for(i = 0; i<10; i++){
printf("This should be zero: %d\n",g_arr[i]);
}
exit(1);
}
Este programa cuenta con una red gigante que tiene un tamaño declarado de alrededor 200 * 8 MB = 1,6 GB de memoria estática. La elaboración de este programa toma un cantidad excesiva de tiempo:
[[email protected]]$ time gcc HugeTest.c
real 0m12.954s
user 0m6.995s
sys 0m3.890s
[[email protected]]$
13s Para una línea de programa 13 ~ C !? Eso no está bien. El número de clave es el tamaño del espacio de memoria estática. Tan pronto como es más grande que el espacio de intercambio total , comienza a compilarse rápidamente nuevamente. Por ejemplo, yo tengo 5.3GB de espacio de intercambio, por lo que cambiar a GIANT_SIZE (1000 * M) da el siguiente tiempo:
[[email protected]]$ time gcc HugeTest.c
real 0m0.087s
user 0m0.026s
sys 0m0.027s
Ah, eso es más como! Para convencerme aún más a mí mismo (y a usted mismo, si está intentando esto en casa) de que el espacio de intercambio era efectivamente el número mágico, traté de cambiar el espacio de intercambio disponible por uno realmente masivo 19GB y tratando de compilar el (1000 * M) versión de nuevo:
[[email protected]]$ ls -ali /extraswap
5986 -rw-r--r-- 1 root root 14680064000 Jul 26 15:01 /extraswap
[[email protected]]$ sudo swapon /extraswap
[[email protected]]$ time gcc HugeTest.c
real 4m28.089s
user 0m0.016s
sys 0m0.010s
¡Ni siquiera se completó después de 4.5 minutos!
Claramente, el enlazador está haciendo algo mal aquí, pero no sé cómo para evitar esto, además de reescribir el programa o perder el tiempo con el espacio de intercambio. Me encantaría saber si hay una solución, o si tengo tropecé con algún error arcano.
Por cierto, todos los programas compilan y se ejecutan correctamente, independientemente de todo el negocio de intercambio.
Como referencia, he aquí algo de información posiblemente relevante:
[]$ ulimit -a
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 27027
max locked memory (kbytes, -l) 64
max memory size (kbytes, -m) unlimited
open files (-n) 1024
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 8192
cpu time (seconds, -t) unlimited
max user processes (-u) 1024
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
[]$ uname -r
2.6.40.6-0.fc15.x86_64
[]$ ld --version
GNU ld version 2.21.51.0.6-6.fc15 20110118
Copyright 2011 Free Software Foundation, Inc.
This program is free software; you may redistribute it under the terms of
the GNU General Public License version 3 or (at your option) a later version.
This program has absolutely no warranty.
[]$ gcc --version
gcc (GCC) 4.6.1 20110908 (Red Hat 4.6.1-9)
Copyright (C) 2011 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
[]$ cat /proc/meminfo
MemTotal: 3478272 kB
MemFree: 1749388 kB
Buffers: 16680 kB
Cached: 212028 kB
SwapCached: 368056 kB
Active: 489688 kB
Inactive: 942820 kB
Active(anon): 401340 kB
Inactive(anon): 803436 kB
Active(file): 88348 kB
Inactive(file): 139384 kB
Unevictable: 32 kB
Mlocked: 32 kB
SwapTotal: 19906552 kB
SwapFree: 17505120 kB
Dirty: 172 kB
Writeback: 0 kB
AnonPages: 914972 kB
Mapped: 60916 kB
Shmem: 1008 kB
Slab: 55248 kB
SReclaimable: 26720 kB
SUnreclaim: 28528 kB
KernelStack: 3608 kB
PageTables: 63344 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 21645688 kB
Committed_AS: 11208980 kB
VmallocTotal: 34359738367 kB
VmallocUsed: 139336 kB
VmallocChunk: 34359520516 kB
HardwareCorrupted: 0 kB
AnonHugePages: 151552 kB
HugePages_Total: 0
HugePages_Free: 0
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 2048 kB
DirectMap4k: 730752 kB
DirectMap2M: 2807808 kB
TL; DR: Cuando el (grande) de memoria estática de programa en C es ligeramente menor que el espacio de intercambio disponible, el enlazador necesita siempre para enlace el programa. Sin embargo, es bastante rápido cuando el espacio estático es ligeramente más grande que el espacio de intercambio disponible. ¿¡Que pasa con eso!?
Duplica esta pregunta: http://stackoverflow.com/questions/4978664/long-compilation-time-for-program-with-static-allocation –
@praetoriandroid Excelente hallazgo, lo siento, no lo vi más temprano. La respuesta en esa pregunta explica muy bien por qué esto probablemente está sucediendo, pero señalaré algo más que mi pregunta implica: ¿por qué el enlazador puede ser tan rápido para algo ligeramente más grande que el espacio de intercambio disponible? – Rooke
@Rooke: parece probable que cuando no hay suficiente espacio de intercambio disponible, la asignación de todo el objeto falla y el enlazador recurre a un método diferente que realmente se ejecuta más rápido (debido a que no se sumerge en el intercambio en absoluto). – caf