Am un script Matab care foloseste bucata de cod de pe net care foloseste un third-party
mexeig.c, care la randul sau foloseste functia
dsyevd() din Lapack. Sub Windows, mai demult nu mai stiu cum, compilasem
.c -ul in mex si mergea foarte bine.Din pacate, intreg script-ul dura vreo doua zile pe 3 threaduri ale PC-ului de la birou.
Azi, ca sa nu imi ocup din nou comp-ul pentru 2 zile, mi-am zis sa copii codul pe serverul sub Linux si sa-l rulez acolo pe 6 threaudri (tip: startworkers 6, si apoi matlabpool serverplus).
Cand colo, pac eroare ca nu stie
mexeig(). Dupa ca ma gandesc putin, imi dau seama ca nu compilasem
mexeig.c sub noua arhitectura. Bine, bag repede un
mex mexeig.c. Pac, nu gaseste dsyevd la link-editare, undefined reference. Bine din nou, bag reloaded un
mex mexeig.c -llapack. Pac,
skipping incompatible library vreo 4 lapack-uri si in continuare undefined reference. Si in plus, la deruta, si un warning ca folosesc gcc 3.4.6 in timp ce minimul testat de ei este 4.0.0.
Eu ma gandesc, bineinteles, ca e problema cu gcc-ul. Injur in gand administratorul care tine o versiune antica si acceptata de CentOS 4.8, cu un gcc antediluvian, si ma gandesc sa-mi instalez o varianta locala de gcc 4.x. Pierd vreo 40 de minute pe net, documentatie, cauta repository CentOS 5.x, trag un rpm cu gcc-4.1.2, ii zic de la obraz un
rpm -i --test gcc..., bineintelesc ca nu are dependecies necesare. Mama lui de administrator, imi zic in gand. Dead end, timp pierdut.
Apoi, ca din intamplare, bag un
gcc4. De fapt nu din intamplare, vazusem prin
lib un folder cu niste librarii gcc 4.1.2. Ce sa vezi,
gcc4 merge. E instalat si gcc 4.1.2, dar sub numele de
gcc4, nu
gcc. Bine, zic, acum cum dracu' il fac sa-l vada si matlab-ul, ca in
mex -setup imi apare doar gcc-ul vechi. Iar documentatie, aflu ca exista un
mexopts.sh care defineste comenzile si optiunile folosite de Matlab la compilare, intru, replace
gcc cu
gcc4, dau victorios un
mex mexeig.c -llapack, la fel. Skipping incompatible library, undefined reference. Mama naibii. Macar warning--ul se dusese, deci folosea versiune noua de gcc. Toate astea au durat inca vreo juma de ora.
Exasperat, dau un View (F3) din Midnight Commander pe
liblapack.so.3.0.3, sa vad, ce dracu' nu gaseste dsyevd, te pomeni ca nu e definita in librarie, sau mai stiu io ce. Si-mi sare in ochi un
i386. Nu realizez pe moment, dar dupa vreo 5-10 minute subconstientul ma trage de maneca:
i386 ?!? Pe 64 biti?
Mama ei de porcarie, exista un folder
lib64 in
usr, dar acolo n-are lapack. Asta e, imi zic, CentOS-ul asta are numai versiunea perfect inutila
i386, de ce naiba n-are si pe 64 de biti? Iar fugi pe net, cauta un repository, trag un rpm cu liblapack x86_64, dezarhiveaza intr-un folder local,
mex -llapack -L/home/... mexeig.c. L-am prins, zic. Cand colo, stupoare. Undefined reference. Nu mai da
skipping incompatible library, deci libraria e buna, de ce naiba nu merge?
Ma uit cu F3 in librarie, caut
dsyevd, exista, dar vad si multe _ si imi aduc aminte ca e o chestie cu astea. Intru in
mexeig.c si inlocuiesc apelul lui
dsyevd cu
dsyevd_ (imi aduc aminte ca am mai facut asta odata, probabil cand am compilat pe Windows). In sfarsit, merge!
In total, am irosit vreo ora si jumatate, plus un sfert de ora postul asta.
Lectii din treaba asta:
1.
Skipping incompatible library se refera la arhitectura pe care a fost compilata libraria (i386, x86_64 etc). nu la versiunea gcc sau mai stiu eu ce.
2. Poti sa adaugi un _ la numele functiei cand nu merge sa link-editezi cu librarii din astea publice si n-ai idee de ce.
3.
gcc mai poate avea si numele
gcc4Update. Ehei, dragii mosului, eu inca nu testasem daca
mexeig-ul compilat chiar merge. Adica m-am oprit la compilarea si link-area cu succes. Mai departe, cand dau sa rulez, sare cu o eroare run-time cum ca nu gaseste liblapack-ul. Noroc ca vazusem in help-ul lui
mex ca, daca compilez cu o librarie dintr-un folder oarecare, tre sa modific si path-urile ca Matlab-ul chiar sa gaseasca libraria respectiva la run-time. Asa ca le-am adaugat frumusel intr-un script fix inainte de a starta matlab-ul (matlab-ul fiind pornit din script, e child process si mosteneste environmentul acestuia):
#!/bin/bash
LD_LIBRARY_PATH=:/home/...$LD_LIBRARY_PATH
export LD_LIBRARY_PATH
cd "CS/Ale mele"
matlab
Au trebuit cea modificari fata de ce zicea help-ul Matlabului, adica am pus ":" inainte de calea mea, si nu intre (pentru ca LD_L... default continea un ":" la inceput), si a trebuit si "$", desigur.
Si inca nu m-a lasat. Cica nu gaseste nici libraria
blas. Asa ca ia-o si pe asta de pe net si dezarhiveaz-o in acelasi
usr local. Intr-un final, merge.
Update 2 Merge pe dracu! Da, merge daca rulez pe un singur thread. Daca insa incep un
matlabpool si rulez codul in
parfor, s-a dus. Iarasi nu gaseste liblapack-ul. Problema este ca, in acest caz, codul este executat de catre workers, care nu mostenesc environmentul de la Matlab-ul mare, pentru ca ei sunt creati independent, cu daemon-ul
mdce. Asa ca ce-am facut: in primul rand, am adaugat noua LD_LIBRARY_PATH atat in bashrc cat si in bash_profile, si le-am scos din script-ul meu. Sa fie mereu definit mereu si peste tot, ce naiba. Apoi am dat un
source, cica, apoi am si repornit
vncserver ca sa ma loghez inca o data (nu stiu daca chiar a fost un logout pe bune) ca sa fiu sigur ca s-au citit fisierele din nou. Apoi am reastartat daemon-ul
mdce. Asta era chestia esentiala. Acum
mdce a re-pornit dintr-un terminal, care mostenise environment-ul bun de la bashrc, deci si
mdce il mosteneste, si apoi toti workerii creati de
mdce. Se pare ca, intr-un sfarsit, merge (a treia oara)!
Labels: lucru, matlab