Cosa sta causando questi arresti anomali dopo la compilazione incrociata?


8

Sto cercando di compilare in modo incrociato una libreria di grandi dimensioni (TensorFlow) usando gcc su Ubuntu. Ho installato la toolchain g ++ - arm-linux-gnueabihf e sono riuscito a costruire il mio binario. Il processo che sto usando per compilare è documentato qui: https://github.com/petewarden4prs/tensorflow/tree/master/tensorflow/contrib/makefile#raspberry-pi

Inizialmente ho riscontrato un errore in cui pthreading era disabilitato ("Abilita il multithreading per utilizzare std :: thread: operazione non consentita") quando ho provato a eseguire l'eseguibile risultante sul mio Pi 3. Ho ricompilato con -pthread abilitato come opzione di compilazione e ora il programma si blocca apparentemente in modo casuale con errori di segmentazione. Eseguendolo in gdb, sembrano spesso legati al fatto che free () venga chiamato con puntatori errati e che le pile di chiamate sembrano corrotte, quindi presumo che stia accadendo qualche disallineamento di memoria.

Qualcuno ha suggerimenti su cose che posso provare a rintracciare cosa non va qui?

Ecco alcuni dettagli in più dal mio Pi:

pi@raspberrypi ~ $ uname -a
Linux raspberrypi 4.1.19-v7+ #858 SMP Tue Mar 15 15:56:00 GMT 2016 armv7l GNU/Linux
pi@raspberrypi ~ $ file benchmark 
benchmark: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=0x5043384f5d0003f8074b07dfdd38cdc20315143f, not stripped

Ecco un esempio di una sessione tipica in gdb:

[New Thread 0x76cf5450 (LWP 6011)]
*** glibc detected *** /home/pi/benchmark: free(): invalid pointer: 0x018e2e89 ***

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x76cf5450 (LWP 6011)]
0x76f98e40 in std::string::c_str() const () from /usr/lib/arm-linux-gnueabihf/libstdc++.so.6
(gdb) thread apply all bt

Thread 2 (Thread 0x76cf5450 (LWP 6011)):
#0  0x76f98e40 in std::string::c_str() const () from /usr/lib/arm-linux-gnueabihf/libstdc++.so.6
#1  0x00bad996 in tensorflow::thread::ThreadPool::Impl::WorkerLoop() ()
#2  0x00bad5de in tensorflow::thread::ThreadPool::Impl::Impl(tensorflow::Env*, tensorflow::ThreadOptions const&, std::string const&, int)::{lambda()#1}::operator()() const ()
#3  0x00badec2 in std::_Function_handler<void (), tensorflow::thread::ThreadPool::Impl::Impl(tensorflow::Env*, tensorflow::ThreadOptions const&, std::string const&, int)::{lambda()#1}>::_M_invoke(std::_Any_data const&) ()
#4  0x0029aaf4 in std::function<void ()>::operator()() const ()
#5  0x00b53e1e in _ZNSt12_Bind_simpleIFSt8functionIFvvEEvEE9_M_invokeIJEEEvSt12_Index_tupleIJXspT_EEE ()
#6  0x00b53d90 in std::_Bind_simple<std::function<void ()> ()>::operator()() ()
#7  0x00b53d4a in std::thread::_Impl<std::_Bind_simple<std::function<void ()> ()> >::_M_run() ()
#8  0x76f91848 in ?? () from /usr/lib/arm-linux-gnueabihf/libstdc++.so.6
#9  0x76f91848 in ?? () from /usr/lib/arm-linux-gnueabihf/libstdc++.so.6
Backtrace stopped: previous frame identical to this frame (corrupt stack?)

Thread 1 (Thread 0x76ff6000 (LWP 6010)):
#0  0x76dfc61c in ?? () from /lib/arm-linux-gnueabihf/libc.so.6
#1  0x76fff048 in ?? () from /lib/ld-linux-armhf.so.3
Cannot access memory at address 0x158
#2  0x76fff048 in ?? () from /lib/ld-linux-armhf.so.3
Cannot access memory at address 0x158
Backtrace stopped: previous frame identical to this frame (corrupt stack?)

1
Il tuo codice è 32 bit o 64? Anch'io ho un progetto che voglio far funzionare ma ho un dump simile "Impossibile accedere alla memoria ....." Lo abbiamo rintracciato in incompatibilità con l'ambiente a 32 bit.
Dan V,

2
Proprio come un aggiornamento, ho finito per abbandonare la compilazione incrociata, poiché sembra meno utilizzato della compilazione nativa ed è stato più difficile eseguire il debug di problemi come questo.
Pete Warden,

Risposte:


3

Il modo più semplice per una compilazione incrociata compatibile binaria è installare la toolchain utilizzata dagli sviluppatori Raspbian. Esso può essere trovato qui . È essenziale utilizzare questa toolchain se si desidera compilare il kernel e i driver, poiché gli oggetti del kernel richiedono una perfetta compatibilità ABI, ma avere una perfetta compatibilità non danneggerà se si stanno costruendo anche i binari dello spazio utente.

Secondo la documentazione , questa toolchain è compatibile con l'attuale Ubuntu, sia a 32-bit che a 64-bit.


3

Stavo ottenendo pure virtual method calledun'eccezione durante la compilazione incrociata. @ La risposta di JeremyBarnes non ha funzionato del tutto per me. Invece ho usato:

-U__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 -U__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 -U__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8

Spiegazione :

Come sottolineato da @JeremyBarnes, per garantire la compatibilità ABI dell'applicazione con lo stdc ++ installato, entrambi devono essere compilati con gli stessi SYNCflag.

Su Raspbian:

$ g++ -dM -E - < /dev/null | grep SYNC
#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1

Senza la correzione attiva dockcross/linux-armv6e dockcross/linux-armv7:

$ g++ -dM -E - < /dev/null | grep SYNC
#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 1
#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 1
#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1
#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 1

Con la correzione attiva dockcross/linux-armv6e dockcross/linux-armv7:

$ g++ -U__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 -U__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2  -E - < /dev/null | grep SYNC
#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1

2

FWIW, questo può essere risolto aggiungendo -D__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 -D__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 -D__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8ai flag del compilatore.

Perché? In /usr/include/c++/4.{8,9}/bits/concurrency.h, la politica di blocco predefinita dipende da questi definiti:

#if (definito (__ GCC_HAVE_SYNC_COMPARE_AND_SWAP_2) \
     && definito (__ GCC_HAVE_SYNC_COMPARE_AND_SWAP_4))

L'ABI di un puntatore condiviso dipende da come sono definiti questi flag, poiché eredita da una classe di base che utilizza un argomento modello predefinito per la politica di blocco. Quindi, cambiando questi flag cambia il layout (perché cambia il layout della classe base) degli oggetti std :: shared_ptr <...> nella libreria C ++ standard.

Nel compilatore fornito con il Pi, con cui è stato creato Raspbian, sono impostati come segue:

g ++ -dM -E - </ dev / null | grep SYNC
#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1

Questo è ragionevole per il Pi 1, ma è un vero peccato per il Pi 3 che può tranquillamente usare puntatori atomici condivisi.

Su Ubuntu, sono impostati in questo modo:

arm-linux-gnueabihf-g ++ -dM -E - </ dev / null | grep SYNC
#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 1
#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 1
#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1
#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 1

I flag della riga di comando sopra li resettano come sono di default sul Pi.

Ne vale la pena la compilazione incrociata; Tensorflow è già lento a costruire su un server robusto; deve impiegare un tempo incredibilmente lungo per costruire sul Pi!

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.