2013-02-16 9 views
31

Ho un semplice script in Python, ma per qualche motivo ricevo il seguente errore durante l'esecuzione di una grande quantità di dati:Python errori doppia per grandi insiemi di dati

*** glibc detected *** python: double free or corruption (out): 0x00002af5a00cc010 *** 

sono abituato a questi errori che vengono in C o C++, quando si cerca di liberare memoria che è già stata liberata. Tuttavia, dalla mia comprensione di Python (e in particolare del modo in cui ho scritto il codice), non capisco davvero perché questo dovrebbe accadere.

Ecco il codice:

#!/usr/bin/python -tt                                                       

import sys, commands, string 
import numpy as np 
import scipy.io as io 
from time import clock 

W = io.loadmat(sys.argv[1])['W'] 
size = W.shape[0] 
numlabels = int(sys.argv[2]) 
Q = np.zeros((size, numlabels), dtype=np.double) 
P = np.zeros((size, numlabels), dtype=np.double) 
Q += 1.0/Q.shape[1] 
nu = 0.001 
mu = 0.01 
start = clock() 
mat = -nu + mu*(W*(np.log(Q)-1)) 
end = clock() 
print >> sys.stderr, "Time taken to compute matrix: %.2f seconds"%(end-start) 

Ci si potrebbe chiedere, perché dichiarare una P e una gamma Q numpy? Lo faccio semplicemente per riflettere le condizioni effettive (dato che questo codice è semplicemente un segmento di ciò che effettivamente faccio, dove ho bisogno di una matrice P e lo dichiaro in anticipo).

Ho accesso a una macchina da 192 GB, quindi l'ho testato su una matrice sparsa di grandi dimensioni SciPy (2,2 milioni per 2,2 milioni, ma molto scarsa, non è questo il problema). La memoria principale è occupata dalle matrici Q, P e mat, in quanto sono tutte matrici da 2,2 milioni e 2000 (dimensioni = 2,2 milioni, numlabels = 2000). La memoria di picco arriva fino a 131 GB, che si adatta comodamente alla memoria. Mentre la mat matrix viene calcolata, ottengo l'errore glibc e il mio processo passa automaticamente allo stato sleep (S), senza deallocare il 131GB che ha ripreso.

Dato l'errore bizzarro (per Python) (non sto esplicitamente deallocando nulla) e il fatto che funzioni correttamente per dimensioni di matrici più piccole (circa 1,5 milioni entro il 2000), non sono sicuro di dove iniziare il debug Questo.

Come punto di partenza, ho impostato "ulimit -s unlimited" prima di eseguire, ma senza successo.

Qualsiasi aiuto o approfondimento sul comportamento di Numpy con quantità di dati molto elevate sarebbe il benvenuto.

Si noti che questo NON è un errore di memoria esaurita - Ho 196 GB, e il mio processo raggiunge circa 131 GB e rimane lì per un po 'di tempo prima di dare l'errore di seguito.

aggiornamento: 16 febbraio 2013 (13:10 PST):

Come da suggerimento, mi sono imbattuto Python con GDB. È interessante notare che, su una corsa GDB ho dimenticato di impostare il limite di dimensione dello stack a "illimitato", ed ho ottenuto il seguente risultato:

*** glibc detected *** /usr/bin/python: munmap_chunk(): invalid pointer: 0x00007fe7508a9010 *** 
======= Backtrace: ========= 
/lib64/libc.so.6(+0x733b6)[0x7ffff6ec23b6] 
/usr/lib64/python2.7/site-packages/numpy/core/multiarray.so(+0x4a496)[0x7ffff69fc496] 
/usr/lib64/libpython2.7.so.1.0(PyEval_EvalFrameEx+0x4e67)[0x7ffff7af48c7] 
/usr/lib64/libpython2.7.so.1.0(PyEval_EvalCodeEx+0x309)[0x7ffff7af6c49] 
/usr/lib64/libpython2.7.so.1.0(PyEval_EvalCode+0x32)[0x7ffff7b25592] 
/usr/lib64/libpython2.7.so.1.0(+0xfcc61)[0x7ffff7b33c61] 
/usr/lib64/libpython2.7.so.1.0(PyRun_FileExFlags+0x84)[0x7ffff7b34074] 
/usr/lib64/libpython2.7.so.1.0(PyRun_SimpleFileExFlags+0x189)[0x7ffff7b347c9] 
/usr/lib64/libpython2.7.so.1.0(Py_Main+0x36c)[0x7ffff7b3e1bc] 
/lib64/libc.so.6(__libc_start_main+0xfd)[0x7ffff6e6dbfd] 
/usr/bin/python[0x4006e9] 
======= Memory map: ======== 
00400000-00401000 r-xp 00000000 09:01 50336181       /usr/bin/python2.7 
00600000-00601000 r--p 00000000 09:01 50336181       /usr/bin/python2.7 
00601000-00602000 rw-p 00001000 09:01 50336181       /usr/bin/python2.7 
00602000-00e5f000 rw-p 00000000 00:00 0         [heap] 
7fdf2584c000-7ffff0a66000 rw-p 00000000 00:00 0 
7ffff0a66000-7ffff0a6b000 r-xp 00000000 09:01 50333916     /usr/lib64/python2.7/lib-dynload/mmap.so 
7ffff0a6b000-7ffff0c6a000 ---p 00005000 09:01 50333916     /usr/lib64/python2.7/lib-dynload/mmap.so 
7ffff0c6a000-7ffff0c6b000 r--p 00004000 09:01 50333916     /usr/lib64/python2.7/lib-dynload/mmap.so 
7ffff0c6b000-7ffff0c6c000 rw-p 00005000 09:01 50333916     /usr/lib64/python2.7/lib-dynload/mmap.so 
7ffff0c6c000-7ffff0c77000 r-xp 00000000 00:12 54138483     /home/avneesh/.local/lib/python2.7/site-packages/scipy/io/matlab/streams.so 
7ffff0c77000-7ffff0e76000 ---p 0000b000 00:12 54138483     /home/avneesh/.local/lib/python2.7/site-packages/scipy/io/matlab/streams.so 
7ffff0e76000-7ffff0e77000 r--p 0000a000 00:12 54138483     /home/avneesh/.local/lib/python2.7/site-packages/scipy/io/matlab/streams.so 
7ffff0e77000-7ffff0e78000 rw-p 0000b000 00:12 54138483     /home/avneesh/.local/lib/python2.7/site-packages/scipy/io/matlab/streams.so 
7ffff0e78000-7ffff0e79000 rw-p 00000000 00:00 0 
7ffff0e79000-7ffff0e9b000 r-xp 00000000 00:12 54138481     /home/avneesh/.local/lib/python2.7/site-packages/scipy/io/matlab/mio5_utils.so 
7ffff0e9b000-7ffff109a000 ---p 00022000 00:12 54138481     /home/avneesh/.local/lib/python2.7/site-packages/scipy/io/matlab/mio5_utils.so 
7ffff109a000-7ffff109b000 r--p 00021000 00:12 54138481     /home/avneesh/.local/lib/python2.7/site-packages/scipy/io/matlab/mio5_utils.so 
7ffff109b000-7ffff109f000 rw-p 00022000 00:12 54138481     /home/avneesh/.local/lib/python2.7/site-packages/scipy/io/matlab/mio5_utils.so 
7ffff109f000-7ffff10a0000 rw-p 00000000 00:00 0 
7ffff10a0000-7ffff10a5000 r-xp 00000000 09:01 50333895     /usr/lib64/python2.7/lib-dynload/zlib.so 
7ffff10a5000-7ffff12a4000 ---p 00005000 09:01 50333895     /usr/lib64/python2.7/lib-dynload/zlib.so 
7ffff12a4000-7ffff12a5000 r--p 00004000 09:01 50333895     /usr/lib64/python2.7/lib-dynload/zlib.so 
7ffff12a5000-7ffff12a7000 rw-p 00005000 09:01 50333895     /usr/lib64/python2.7/lib-dynload/zlib.so 
7ffff12a7000-7ffff12ad000 r-xp 00000000 00:12 54138491     /home/avneesh/.local/lib/python2.7/site-packages/scipy/io/matlab/mio_utils.so 
7ffff12ad000-7ffff14ac000 ---p 00006000 00:12 54138491     /home/avneesh/.local/lib/python2.7/site-packages/scipy/io/matlab/mio_utils.so 
7ffff14ac000-7ffff14ad000 r--p 00005000 00:12 54138491     /home/avneesh/.local/lib/python2.7/site-packages/scipy/io/matlab/mio_utils.so 
7ffff14ad000-7ffff14ae000 rw-p 00006000 00:12 54138491     /home/avneesh/.local/lib/python2.7/site-packages/scipy/io/matlab/mio_utils.so 
7ffff14ae000-7ffff14b5000 r-xp 00000000 00:12 54138562     /home/avneesh/.local/lib/python2.7/site-packages/scipy/sparse/sparsetools/_csgraph.so 
7ffff14b5000-7ffff16b4000 ---p 00007000 00:12 54138562     /home/avneesh/.local/lib/python2.7/site-packages/scipy/sparse/sparsetools/_csgraph.so 
7ffff16b4000-7ffff16b5000 r--p 00006000 00:12 54138562     /home/avneesh/.local/lib/python2.7/site-packages/scipy/sparse/sparsetools/_csgraph.so 
7ffff16b5000-7ffff16b6000 rw-p 00007000 00:12 54138562     /home/avneesh/.local/lib/python2.7/site-packages/scipy/sparse/sparsetools/_csgraph.so 
7ffff16b6000-7ffff17c2000 r-xp 00000000 00:12 54138558     /home/avneesh/.local/lib/python2.7/site-packages/scipy/sparse/sparsetools/_bsr.so 
7ffff17c2000-7ffff19c2000 ---p 0010c000 00:12 54138558     /home/avneesh/.local/lib/python2.7/site-packages/scipy/sparse/sparsetools/_bsr.so 
7ffff19c2000-7ffff19c3000 r--p 0010c000 00:12 54138558     /home/avneesh/.local/lib/python2.7/site-packages/scipy/sparse/sparsetools/_bsr.so 
7ffff19c3000-7ffff19c6000 rw-p 0010d000 00:12 54138558     /home/avneesh/.local/lib/python2.7/site-packages/scipy/sparse/sparsetools/_bsr.so 
7ffff19c6000-7ffff19d5000 r-xp 00000000 00:12 54138561     /home/avneesh/.local/lib/python2.7/site-packages/scipy/sparse/sparsetools/_dia.so 
7ffff19d5000-7ffff1bd4000 ---p 0000f000 00:12 54138561     /home/avneesh/.local/lib/python2.7/site-packages/scipy/sparse/sparsetools/_dia.so 
7ffff1bd4000-7ffff1bd5000 r--p 0000e000 00:12 54138561     /home/avneesh/.local/lib/python2.7/site-packages/scipy/sparse/sparsetools/_dia.so 
Program received signal SIGABRT, Aborted. 
0x00007ffff6e81ab5 in raise() from /lib64/libc.so.6 
(gdb) bt 
#0 0x00007ffff6e81ab5 in raise() from /lib64/libc.so.6 
#1 0x00007ffff6e82fb6 in abort() from /lib64/libc.so.6 
#2 0x00007ffff6ebcdd3 in __libc_message() from /lib64/libc.so.6 
#3 0x00007ffff6ec23b6 in malloc_printerr() from /lib64/libc.so.6 
#4 0x00007ffff69fc496 in ??() from /usr/lib64/python2.7/site-packages/numpy/core/multiarray.so 
#5 0x00007ffff7af48c7 in PyEval_EvalFrameEx() from /usr/lib64/libpython2.7.so.1.0 
#6 0x00007ffff7af6c49 in PyEval_EvalCodeEx() from /usr/lib64/libpython2.7.so.1.0 
#7 0x00007ffff7b25592 in PyEval_EvalCode() from /usr/lib64/libpython2.7.so.1.0 
#8 0x00007ffff7b33c61 in ??() from /usr/lib64/libpython2.7.so.1.0 
#9 0x00007ffff7b34074 in PyRun_FileExFlags() from /usr/lib64/libpython2.7.so.1.0 
#10 0x00007ffff7b347c9 in PyRun_SimpleFileExFlags() from /usr/lib64/libpython2.7.so.1.0 
#11 0x00007ffff7b3e1bc in Py_Main() from /usr/lib64/libpython2.7.so.1.0 
#12 0x00007ffff6e6dbfd in __libc_start_main() from /lib64/libc.so.6 
#13 0x00000000004006e9 in _start() 

Quando ho impostato il limite di dimensione dello stack per illimitato", ottengo il seguente:

*** glibc detected *** /usr/bin/python: double free or corruption (out): 0x00002abb2732c010 *** 
^X^C 
Program received signal SIGINT, Interrupt. 
0x00002aaaab9d08fe in __lll_lock_wait_private() from /lib64/libc.so.6 
(gdb) bt 
#0 0x00002aaaab9d08fe in __lll_lock_wait_private() from /lib64/libc.so.6 
#1 0x00002aaaab969f2e in _L_lock_9927() from /lib64/libc.so.6 
#2 0x00002aaaab9682d1 in free() from /lib64/libc.so.6 
#3 0x00002aaaaaabbfe2 in _dl_scope_free() from /lib64/ld-linux-x86-64.so.2 
#4 0x00002aaaaaab70a4 in _dl_map_object_deps() from /lib64/ld-linux-x86-64.so.2 
#5 0x00002aaaaaabcaa0 in dl_open_worker() from /lib64/ld-linux-x86-64.so.2 
#6 0x00002aaaaaab85f6 in _dl_catch_error() from /lib64/ld-linux-x86-64.so.2 
#7 0x00002aaaaaabc5da in _dl_open() from /lib64/ld-linux-x86-64.so.2 
#8 0x00002aaaab9fb530 in do_dlopen() from /lib64/libc.so.6 
#9 0x00002aaaaaab85f6 in _dl_catch_error() from /lib64/ld-linux-x86-64.so.2 
#10 0x00002aaaab9fb5cf in dlerror_run() from /lib64/libc.so.6 
#11 0x00002aaaab9fb637 in __libc_dlopen_mode() from /lib64/libc.so.6 
#12 0x00002aaaab9d60c5 in init() from /lib64/libc.so.6 
#13 0x00002aaaab080933 in pthread_once() from /lib64/libpthread.so.0 
#14 0x00002aaaab9d61bc in backtrace() from /lib64/libc.so.6 
#15 0x00002aaaab95dde7 in __libc_message() from /lib64/libc.so.6 
#16 0x00002aaaab9633b6 in malloc_printerr() from /lib64/libc.so.6 
#17 0x00002aaaab9682dc in free() from /lib64/libc.so.6 
#18 0x00002aaaabef1496 in ??() from /usr/lib64/python2.7/site-packages/numpy/core/multiarray.so 
#19 0x00002aaaaad888c7 in PyEval_EvalFrameEx() from /usr/lib64/libpython2.7.so.1.0 
#20 0x00002aaaaad8ac49 in PyEval_EvalCodeEx() from /usr/lib64/libpython2.7.so.1.0 
#21 0x00002aaaaadb9592 in PyEval_EvalCode() from /usr/lib64/libpython2.7.so.1.0 
#22 0x00002aaaaadc7c61 in ??() from /usr/lib64/libpython2.7.so.1.0 
#23 0x00002aaaaadc8074 in PyRun_FileExFlags() from /usr/lib64/libpython2.7.so.1.0 
#24 0x00002aaaaadc87c9 in PyRun_SimpleFileExFlags() from /usr/lib64/libpython2.7.so.1.0 
#25 0x00002aaaaadd21bc in Py_Main() from /usr/lib64/libpython2.7.so.1.0 
#26 0x00002aaaab90ebfd in __libc_start_main() from /lib64/libc.so.6 
#27 0x00000000004006e9 in _start() 

Questo mi fa credere che il problema di base sia con il numpy modulo core multiarray (riga n. 4 nella prima uscita e riga n. 18 nella seconda). Lo farò apparire come una segnalazione di bug sia in numpy che in scipy per ogni evenienza.

Qualcuno l'ha visto prima?

aggiornamento: 17 febbraio 2013 (16:45 PST)

ho trovato una macchina che ho potuto eseguire il codice su che aveva una versione più recente di SciPy (0,11) e NumPy (1.7. 0). L'esecuzione del codice verso l'alto (senza GDB) ha provocato un errore di segmentazione senza output su stdout o stderr.Esecuzione di nuovo attraverso GDB, ottengo il seguente:

Program received signal SIGSEGV, Segmentation fault. 
0x00002aaaabead970 in ??() from /lib/x86_64-linux-gnu/libc.so.6 
(gdb) bt 
#0 0x00002aaaabead970 in ??() from /lib/x86_64-linux-gnu/libc.so.6 
#1 0x00002aaaac5fcd04 in PyDataMem_FREE (ptr=<optimized out>, $K8=<optimized out>) at numpy/core/src/multiarray/multiarraymodule.c:3510 
#2 array_dealloc (self=0xc00ab7edbfc228fe) at numpy/core/src/multiarray/arrayobject.c:416 
#3 0x0000000000498eac in PyEval_EvalFrameEx() 
#4 0x000000000049f1c0 in PyEval_EvalCodeEx() 
#5 0x00000000004a9081 in PyRun_FileExFlags() 
#6 0x00000000004a9311 in PyRun_SimpleFileExFlags() 
#7 0x00000000004aa8bd in Py_Main() 
#8 0x00002aaaabe4f76d in __libc_start_main() from /lib/x86_64-linux-gnu/libc.so.6 
#9 0x000000000041b9b1 in _start() 

ho capito questo non è così utile come NumPy compilato con simboli di debug, cercherò di fare quello e inviare l'output in seguito.

+4

Interessante - Anche se potrebbe essere meglio archiviare una segnalazione di bug con 'scipy'. Forse la compilazione di '-g' e l'esecuzione in' gdb' sarebbero utili ... Almeno allora potresti vedere dove si trovava il codice quando si è verificato l'errore ... – mgilson

+0

quale sistema operativo stai usando? (e quali sono questi dati?) – tacaswell

+3

Che versione Python/numpy stai usando? Vedo alcune segnalazioni di bug su questo, ma sono vecchie e suggeriscono che il problema è stato risolto. – BrenBarn

risposta

5

Dopo discussioni sullo stesso problema nella pagina Numpy Github (https://github.com/numpy/numpy/issues/2995) è stato portato alla mia attenzione che Numpy/Scipy non supporta un numero così grande di non zeri nella matrice sparsa risultante.

Fondamentalmente, W è una matrice sparsa e Q (o np.log(Q)-1) è una matrice densa. Quando si moltiplica una matrice densa con una sparsa, il prodotto risultante sarà anche rappresentato in una matrice sparsa (il che ha molto senso). Tuttavia, poiché non ho zero righe nella mia matrice W, il prodotto risultante W*(np.log(Q)-1) avrà nnz > 2^31 (2,2 milioni moltiplicato per 2000) e questo supera il numero massimo di elementi in una matrice sparsa nelle versioni correnti di Scipy.

A questo punto, non sono sicuro di come altro farlo funzionare, escludendo una reimplementazione in un'altra lingua. Forse può ancora essere fatto in Python, ma potrebbe essere meglio scrivere semplicemente un'implementazione C++ ed Eigen.

Un ringraziamento speciale a pv. per dare una mano su questo per individuare il problema esatto e grazie a tutti gli altri per il brainstorming!

+0

Mi sembra che se è ragionevole per te avere una matrice densa grande come 'W * (np.log (Q) -1)', potrebbe anche essere _anche ragionevole per te avere una matrice densa grande come 'W'. Nel qual caso, c'è una risposta facile: 'W.todense() * (np.log (Q) -1)'. – abarnert

+0

No, non direi che è vero. '' 'W * (np.log (Q) -1)' '' è '' '2.2 milioni x 2000''' e' '' W.todense() '' 'è' 2.2 milioni x 2.2 milioni' ''. – Avneesh

1

Fondamentalmente, W è una matrice sparsa, e Q (o np.log(Q)-1) è una matrice densa. Quando si moltiplica una matrice densa con una sparsa, il prodotto risultante sarà anche rappresentato in una matrice sparsa (il che ha molto senso).

Sono probabilmente manca qualcosa di davvero evidente qui, e finirà per sembrare un idiota, ma ...

Se Q è una matrice densa, e si sta sperando di salvare il risultato come una fitta matrice, probabilmente hai abbastanza da contenere lo W come una matrice densa. Il che significa:

W.todense()*(np.log(Q)-1) 

Osservando i dettagli, come si è calcolato nei commenti, ciò richiederebbe 35,8 GB di memoria temporanea. Dato che hai 131 GB di dati e questo "si adatta comodamente alla memoria", sembra quantomeno plausibile che l'utilizzo temporaneo di un altro 35,8 GB sia ragionevole.

Se è non ragionevole, è sempre possibile scomporre la moltiplicazione della matrice da soli. Ovviamente farlo riga per riga o colonna per colonna renderebbe l'intero processo molto più lento (forse non tanto quanto spingere il processo oltre il bordo in swapping, ma ancora forse troppo lento per essere accettabile). Tuttavia, eseguirlo, ad es., Un chunk di 1 GB di file alla volta non dovrebbe essere un problema. Ciò significherebbe memoria temporanea dell'ordine di pochi GB e probabilmente solo un piccolo rallentamento. Certo, è un codice più complicato e brutto, ma non in modo ingestibile.

+0

Non penso che quello che hai detto funzioni. '' 'W''' è una matrice' '' N * N''', dove '' 'N''' è 2,2 milioni, non una matrice' '' N * M''' e '' 'Q '' 'è una matrice' '' N * M''', dove '' 'M = 2000'''. Convertire la matrice sparse, che al momento ha 42.666.354 non zeri (e quindi memoria totale = '' '(42666354 * 8)/(2^20) = ~ 326MB'''), in una matrice densa significherebbe' '' (2,2 milioni * 2,2 milioni * 8)/(2^30) ~ 35,8 GB'''. Ciò aumenta significativamente la memoria. – Avneesh

+0

Inoltre, il piano originale era di ridimensionare a '' 'N = 7,2 milioni''', il che renderebbe la soluzione' '' W.todense() '' 'meno fattibile. – Avneesh

+0

@Avneesh: Mi rendo conto che significa più memoria, ma la mia ipotesi era che se 131GB "si adatta comodamente alla memoria", allora altri 35,8 GB di spazio temporaneo (per la durata di questa moltiplicazione) potrebbero essere accettabili. Certo che potrebbe non essere accettabile, ma sembrava almeno provarci. – abarnert

Problemi correlati