Estou tentando carregar algumas tabelas de registros FITS gigantescas usando memmap=True
e estou recebendo error: [Errno 12] Cannot allocate memory
.
Um exemplo de sessão:
filename = '/home/sdfits/AGBT12B_221_01/AGBT12B_221_01.raw.acs.fits'
import astropy.io.fits as fits
filefits = fits.open(filename,memmap=True)
data = filefits[2].data[:50]
O erro está nesta linha:
/users/aginsbur/anaconda/lib/python2.7/site-packages/numpy/core/memmap.py(253)__new__()
--> 253 mm = mmap.mmap(fid.fileno(), bytes, access=acc, offset=start)
ipdb> bytes
23718381056L
ipdb> bytes/1024**2
22619L
ipdb> start
413921280
ipdb> acc
3
Eu realmente não sei o que está acontecendo, mas suspeito que o memmap está decidindo indevidamente a quantidade de dados a ser lida. Alguma dica sobre como depurar ainda mais? É realmente um problema do FITS ou um problema entorpecido?
Detalhes:
In [15]: numpy.__version__
Out[15]: '1.7.1'
In [16]: astropy.__version__
Out[16]: '0.2.4'
In [18]: sys.maxint
Out[18]: 9223372036854775807
Qual sistema operacional?
O que ulimit -v
retorna?
OS é uma espécie de linux; não sei de cara ou o
comando mais fácil de descobrir.
Além disso, estava usando a instalação do anaconda de python / astropy / numpy, mas atualizado
astropia via pip.
$ ulimit -v
ilimitado
Na terça-feira, 27 de agosto de 2013 às 16h02, Erik Bray [email protected] escreveu:
Qual sistema operacional?
O que ulimit -v retorna?
-
Responda a este e-mail diretamente ou visualize-o em Gi tHubhttps: //github.com/astropy/astropy/issues/1380#issuecomment -23374814
.
Adão
O que cat /proc/meminfo
mostra?
$ cat /proc/meminfo
MemTotal: 1903396 kB
MemFree: 203864 kB
Buffers: 215320 kB
Cached: 884708 kB
SwapCached: 2268 kB
Active: 492052 kB
Inactive: 954324 kB
Active(anon): 165684 kB
Inactive(anon): 181096 kB
Active(file): 326368 kB
Inactive(file): 773228 kB
Unevictable: 0 kB
Mlocked: 0 kB
SwapTotal: 1048568 kB
SwapFree: 1031460 kB
Dirty: 24 kB
Writeback: 0 kB
AnonPages: 344352 kB
Mapped: 65676 kB
Shmem: 432 kB
Slab: 191348 kB
SReclaimable: 151148 kB
SUnreclaim: 40200 kB
KernelStack: 2312 kB
PageTables: 22940 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 2000264 kB
Committed_AS: 847268 kB
VmallocTotal: 34359738367 kB
VmallocUsed: 286128 kB
VmallocChunk: 34359439336 kB
HardwareCorrupted: 0 kB
AnonHugePages: 12288 kB
HugePages_Total: 0
HugePages_Free: 0
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 2048 kB
DirectMap4k: 8188 kB
DirectMap2M: 2070528 kB
... isso parece uma pequena quantidade de memória; 2 GB? Hrmph.
@keflavich - você ainda está vendo esse problema?
Esqueci-me totalmente disso. MemTotal
é apenas a memória física total disponível. Esses 2 GB não são muito, com certeza, mas esse não deveria ser o problema. Você tem cerca de 32 TB para VmallocTotal
que é o que deve importar aqui - em princípio, o mmap deve ser capaz de usar a maior parte disso. Portanto, há algo estranho acontecendo aqui.
Ah! Acho que vejo o problema aqui. Por padrão, o PyFITS usa MAP_PRIVATE
ao abrir um arquivo no modo somente leitura para que os usuários ainda possam modificar a matriz de dados no local como fariam se o arquivo inteiro fosse mapeado na memória principal.
O problema é que, em princípio, o arquivo inteiro pode ser sobrescrito, então o mmap precisa ser capaz de alocar memória suficiente com antecedência, caso isso ocorra. É por isso que isso está acontecendo aqui. PyFITS / Astropy definitivamente deve capturar esse cenário e fornecer um erro mais útil.
Atualmente, existem duas maneiras de contornar isso: Você pode abrir o arquivo com mode='denywrite
. Eu adicionei isso há um tempo especificamente para este caso, mas raramente é usado. Isso abre o mmap com MAP_SHARED | PROT_READ
- isso significa que as páginas são somente leitura (qualquer tentativa de modificar o array resultará em uma exceção). Mas se tudo que você precisa é ler os dados, isso funciona bem e não requer a alocação de nenhum espaço de swap, eu não acho.
Outra possibilidade é abrir com mode='update'
. Então, quaisquer alterações no array podem ser sincronizadas diretamente de volta para o arquivo, o que é bom se você quiser, mas obviamente não tanto se não quiser.
Olhando a página do manual, parece que também há um sinalizador, pelo menos no Linux, chamado MAP_NORESERVE
que o impedirá de pré-alocar espaço para cópia na gravação. Portanto, se você não _precisa_ gravar nenhuma alteração em todo o array, isso também pode funcionar. Mas teríamos que ser capazes de capturar o SIGSEGV resultante se você acabar ficando sem espaço de troca.
Consegui reproduzir isso diretamente - na verdade, ambas as soluções alternativas que ofereci ( mode='denywrite'
e mode='update'
funcionam. Ainda tentarei ver o que posso fazer sobre MAP_NORESERVE
e de outra forma capturar esse erro e fornecer uma mensagem de erro melhor.
Aborrecimento: numpy.memmap
não permite ajustes nos sinalizadores que são passados para a chamada mmap
. Embora olhando para ele, não é muito mais do que uma leve subclasse de ndarray
que lida com o trabalho de criar um mmap com os sinalizadores corretos e, em seguida, chamar ndarray.__new__
com o mmap como seu buffer. Ele também adiciona um método flush
.
Deve ser fácil simplesmente evitar o uso de numpy.memmap
e lidar com o mmap nós mesmos. Mas isso ainda é mais do que eu quero fazer agora. Portanto, em vez disso, resolverei esse problema identificando o erro e sugerindo uma das soluções alternativas existentes.
Observe que com # 7597 não usamos mais np.memmap
, então deve ser mais fácil usar outros sinalizadores se isso for útil.
Isso agora pode ser fechado, pois uma solução alternativa foi mesclada em https://github.com/astropy/astropy/pull/7926. MAP_NORESERVE
não está disponível no Python, portanto, essa não é uma solução, infelizmente.