Progresul algoritmic târziu (partea 2)

Până la vestea cu CUDA și până la paralelizarea sortării în OMP, mai încercasem să vitezuiesc codul numeric cu OMP asta, dar nu reușisem decât la NUMSIMPL pentru căutarea în sus (înmulțirea numerelor din GIG sau LIT cu factori primi nedivizori).

Luat de val cu reușita sortării, am încercat să paralelizez și... scrierea de numere în fișiere, dar a trebuit să dau înapoi, realizând că este o strategie greșită - apar mici zone de numere neordonate crescător, plus că NU poți să faci de 8 ori mai rapidă rata de scriere pe un hard disk SATA-III, este limită de fabricație).

Am reîncercat, în plus, să paralelizez codul de vânătoare numerică pe la MODIFSUM, profitând de descoperirea noilor instrucțiuni OMP de tipul „#pragma omp parallel num_threads(SF)”, unde a se citi SF numărul dorit - 10, 12, 16 - de thread-uri puse la bătaie, „#pragma omp single” cu sau fără nowait și urmat de „#pragma omp task”, dar tot nu a fost bine și a trebuit să fiu dezamăgit iar.

Altă idee de remodelare a codului-sursă, care mi-a venit în 6 aprilie, a fost pentru RECONST, programul care reia, cu o anume acuratețe, execuția vânătorii numerice dintr-un punct de întrerupere: l-am făcut să fie cu număr variabil de parametri și cu purtare diferită în funcție de cât de lungă îi este „coama” de comandă.

Astfel, la „/reconst a”, ca și până acum, doar afișează pe ecran o situație a fișierelor cu extensia .NUM2 (presupuse a fi în rulare sau cele mai recent aflate în derularea vânătorii), cu gradul în care au urcat căutările corespunzătoare în fișierele .LIT sau .GIG pe baza numerelor cărora se caută noutăți. Rularea asta se poate da oricând se vrea văzut statusul lucrului.

La „/reconst a b”, a se vedea parametrul următor, după afișarea situației fișierelor în cauză, toate .NUM2-urile sunt redenumite în .NUM1 (bune să fie luate la sortare), apoi programele din care ele au venit sunt reluate, pe baza datelor de urcuș și a unor parametri aflați în alte fișiere asociate, cu extensia .NUMC. Rularea asta este bună după o repornire de sistem, sau oricum când programele vânătorești au fost deja oprite și se vrea reluare. Iar urcușul numeric este de preferat să se fi manifestat peste tot măcar cu coeficientul „2” (adică dacă am început de la numerele de 131 de cifre cu prima cifră 1, reluarea să fie cel puțin de la 131 cu cifra 2, să nu se ia chiar de la capăt).

Noutatea din 6 aprilie este „/reconst a b c”, o sofisticare a „a b”-ului care este menită să întrerupă toate programele cu numere (HMODIFSUM, NUMSIMPL, MODPRIME) unde se depistează urcuș numeric (a se vedea referirea la coeficientul 2 de mai sus), excluzându-le pe celelalte (care excludere NU se face mai sus) și pe cele întrerupte reluându-le, dar cu fișiere noi de rezultate, cele vechi fiind redenumite din NUM2 în NUM1 și puse în pregătire pentru culegerea de rezultate din ele.
Și descoperirea programelor implicate se face pornind de la clauza „pidof”, care dă pe rând ID-urile de proces pentru cele trei denumiri de mai sus. Acolo unde sunt mai multe programe omonime în memorie, pe ecran rezultă un șir de numere, care este luat în C prin clauza popen cu fișier; din șirul citit, cu sscanf(), se pot lua numerele de proces unul câte unul și pune în vector; mai departe, pentru fiecare astfel de ID de proces, se ajunge la NUM2-ul deschis.

Cum se ajunge în Linux de la ID-ul unui program până la un anumit fișier deschis de acel program, fișierul în care el scrie?
În folderul /proc, fiecare proces activ și depistabil în System Monitor și prin comanda pidof trebuie să aibă un folder al cărui nume este chiar numărul cu pricina (Process ID sau PID). De pildă, dacă un HMODIFSUM are PID-ul 5593, trebuie să existe un dosar (folder) /proc/5593 pe disc.

Mai departe, în 5593 trebuie să fie folderul fd (de la file descriptor, pesemne), de unde, mai departe, trebuie să ajungem la fișierele pe care programul rulător le are deschise. Pentru .NUM2-uri, am depistat până acum că se folosește sau subfolderul 4, sau subfolderul 5 din acest fd, și în C trebuie să scriem „readlink” de /proc/5593/fd/4, de pildă, ca apoi, tot cu comanda popen, să luăm din fișier rezultatul scris pe ecran - numele fișierului.

Astfel, dacă HMODIFSUM-ul cu PID 5593 își scrie mendrele în /run/media/root/T12/PROMBISBALD.NUM2, trebuie scrisă în C comanda readlink de /proc/5593/fd/5, ca fișier string apoi, presupunând un fișier FP, trebuie să deschidem FP-ul prin comanda popen aplicată acelui string cu readlink - astfel, se execută respectiva comandă de sistem (este o alternativă mai dezvoltată pentru system()) și se preia ce rezultat s-a afișat pe ecran.

Se citește în alt string ce scrie în FP (unde trebuie să fie PROMBISBALD-ul); se poate ca în folderul 5 să NU fie numele căutat, ori poate chiar 5 să nu existe și 4 să fie ultimul folder din fd, caz în care eventualul fișier scris trebuie căutat în 4 și de verificat că string-ul cititor din FP nu este gol și apoi, cu altă clauză de C, anume „strstr”, se verifică dacă, nefiind gol stringul, are „.NUM2” prin el.

Dacă nu, atunci se caută la fel și în 4 și se verifică până la extensie (măcar în 4 trebuie să fie).

O dată găsit și NUM2-ul procesului, se ucide programul cu clauza system() de kill() de PID, se schimbă extensia NUM2-ului în NUM1, se execută și comanda de reluare a HMODIFSUM-ului (sau cum se mai numește programul) din zona de mărime numerică din depozit unde a fost întrerupt, apoi, dacă mai este în față cel puțin un astfel de program de executat, se așteaptă o vreme (60 de secunde, de pildă) cu clauza sleep() de câte secunde de pauză sunt, ca la următoarea primenire de program numeric fișierul de rezultate deschis să nu apuce să fie același cu al programului curent.

Fiecare program căutător trebuie să scrie într-un singur fișier. Fără îmbârligări numerice.

Și sunt destule situații în care trebuie să treacă secunde de la declanșarea programului până ce fișierul NUM2 să fie populat cu primele numere, ceea ce îl face de nescris pentru alte programe.

Și astfel, cu „a b c” se face o împrospătare generală a vânătorilor de numere, cu excluderea fișierelor care au urcat prea puțin (sau dacă depozitul este prost sortat, pot să apară așa-zise minusuri de urcuș), și se poate să fie mai repede disponibile fișiere numerice cu rezultate noi (fără să se aștepte până la sfârșitul unui întreg rând de căutare).
Este așa-numitul reconst nerăbdător.

Bonus: acum, la ambele variante de reconst cu coadă lungă (a b și a b c), la sfârșit se pornesc, tot cu o clauză de system(), cele două procese care fac, respectiv, segmentarea fișierelor prea mari pentru memoria calculatorului (CIRCENTE sau, pentru segmente mai mici, poate fi CIRCENTE0) și ordonarea NUM1-urilor (PARONTE).
Ca să nu le mai dau eu manual. Așadar, cu reconst, se aerisește traseul numeric și se și pornește la prelucrarea rezultatelor parțiale. Și sortarea rapidizată.

Comentarii

Postări populare