Gå til innhold

Treg løkke for utskrift til fil


Anbefalte innlegg

Hei!

 

Jeg driver og løser differentsiallikninger på datamaskin, noe som går sinnsykt fort (problemet mitt (Poisssonlikningen i en dimensjon) kan reduseres til å radredusere en Nx(N+1)-matrise - og det tar under ett sekund selv for *STORE* N - type 10^6 - algoritmen skalerer som 6(n-1)).

 

Problemet mitt ligger i utskriften til fil - denne tar langt mer tid - det er en del data som skal ut (sist gang endte det vel på ~500 MB). Harddisklampa forteller meg med all mulig tydelighet at det er ikke IO-båndbredde som er problemet.

 

Anyway, her er den aktuelle løkka:

//Write the solution to a file - it takes time...
void file_output(char* filename, int arraylength, double* y) {
 
 //SETUP
 const int precision  = 20;
 const int fieldwidth = precision + 10;

 ofstream ofile;
 ofile.open(filename);
 ofile << setiosflags(ios::showpoint | ios::uppercase);
 
 double  h  = 1/(arraylength+1.0); //Yes, i'm making assumptions to make it go faster
 for(int i = 0; i < arraylength; i++) {
   ofile << setw(fieldwidth) << setprecision(precision) << (i+1)*h; //Ditto - i don't want to waste mem on this
   ofile << setw(fieldwidth) << setprecision(precision) << y[i] << endl;
 }

 ofile.close();
}

 

Grunnen til at jeg skriver det ut til fil, er at det skal mates til gnuplot etterpå.

 

En annen ting som tar tid, er å initialisere array'ene:

 //Initialize arrays
 cout << "Initializing arrays...\n";
 double* fn = new double[N]; //Function values
 double* an = new double[N]; //Diagonal entries
 double  h  = 1/(N+1.0);
 for(int i = 0; i < N; i++) {
   an[i] = 2;
 }
 //arrayprint(an,N); //Debug check
 for(int i = 0; i < N; i++) {
   fn[i] = h*h*function1((i+1)*h);
 }
 //arrayprint(fn,N); //Debug check

Her kaller jeg på denne funksjonen:

//Calculate the function value. Yes, i know it is poor naming.
inline double function1(double x) {
 return (3*x + x*x)*exp(x);
}

Merk at denne er inline, så en skulle tro at jeg slapp overhead ved funksjonskall inne i løkke.

 

Forøvrig:

$ time ./poissson 100000
Solving with 100000 meshpoints, saving data to outdata.dat
Initializing arrays...
Eliminating anything beneath the diagonal...
Backward-substituting...
Cleanup: Delete an[]...
Writing solution to outdata.dat...

real    0m0.793s
user    0m0.468s
sys     0m0.324s

Egentlig ikke så veldig ille :)

 

Plattform er GNU/LINUX (Fedora 7), gcc 4.1.2-12, Intel centrino duo 2.0 ghz m. 4 MB cache pr. kjerne :)

Lenke til kommentar
Videoannonse
Annonse
Anyway, her er den aktuelle løkka:

//Write the solution to a file - it takes time...
void file_output(char* filename, int arraylength, double* y) {
 
 //SETUP
 const int precision  = 20;
 const int fieldwidth = precision + 10;

 ofstream ofile;
 ofile.open(filename);
 ofile << setiosflags(ios::showpoint | ios::uppercase);
 
 double  h  = 1/(arraylength+1.0); //Yes, i'm making assumptions to make it go faster
 for(int i = 0; i < arraylength; i++) {
   ofile << setw(fieldwidth) << setprecision(precision) << (i+1)*h; //Ditto - i don't want to waste mem on this
   ofile << setw(fieldwidth) << setprecision(precision) << y[i] << endl;
 }

 ofile.close();
}

 

Testet her med algoritmen du skrev og N=1000000

 

real    0m48.556s
user    0m8.745s
sys     0m6.852s

 

Med minimale endringer av koden ovenfor:

real    0m12.748s
user    0m6.624s
sys     0m0.284s

 

setw og setprecision er *tregt*. Alternativ løsning som ikke tar hensyn til at formateringen blir *helt* lik.

 

char buf[fieldwidth*2+1];
char buf1[fieldwidth+1];
char buf2[fieldwidth+1];
const char* fmt = "%.20f";
const char* format = "%30s%30s\n";*/

for(int i = 0; i < arraylength; i++) {
 sprintf(buf1, fmt, (double) (i+1)*h);
 sprintf(buf2, fmt, (double) y[i]);
 sprintf(buf, format, buf1, buf2);
 ofile << buf;
}

 

fstream i seg selv er også treg, men optimaliseringen sålangt er kanskje god nok?

Lenke til kommentar

Takker, skal prøve så fort jeg kommer hjem fra jobb! Ante meg at de var treige ja, men ikke så treige! Kan være jeg prøver å redusere antall siffer noe, 20 siffer og double gir egentlig ikke så veldig mening (spesiellt mtp. at det bare skal plottes uansett...)

 

Kan det være seg at det lønner seg å f.eks. buffre x antall linjer, og så dumpe alle til fila *smakk*? IO-båndbredde sitter forøvrig og kjeder seg slik det er i dag...

Lenke til kommentar

Med ny utskriftsløkke:

[kyrre@sinus taskC]$ time ./poissson 10000
Solving with 10000 meshpoints, saving data to outdata.dat
Initializing arrays...
Eliminating anything beneath the diagonal...
Backward-substituting...
Cleanup: Delete an[]...
Writing solution to outdata.dat...

real    0m0.041s
user    0m0.030s
sys     0m0.010s

 

Litt bedre i allefall. Spurte foreleseren, han mente at det kanskje var cout som var synderen, og at bytte til "printf for fil" (C ikke C++) kanskje ville gjøre nytten.

 

Men: Denne filutskriften er buffret, ja? Er egentlig ikke så veldig farlig, bare irriterer meg over at jeg har funnet den mest "über-effektive"-gaus-eliminasjonen, men filutskriften trekker så grøsslig ned...

Lenke til kommentar
  • 4 uker senere...

» x=A\b;

» n=1000000;

» e=ones(n,1);

» A=spdiags([e -2*e e], -1:1,n,n);

» h=1/(n+1);

» X=[h:h:(1-h)]';

» b=1/pi^2*sin(pi*X);

» x=A\b;

 

I Matlab (antar du har 0 på randa, samt høyreside lik 1/pi^2sin(pix), trenger bare marginale endringer for å endre høyresida og sånt..)... Tok tida og med en million ukjente tok det 0.1719 (cputime), du vil gå tom for minne før du når en spesielt ufin kjørtid (du vi lagre 3n tall i dp i A, n i x og n i høyresida, så 5n tall i dp, dvs 40 MB med n=1*10^6..)

 

Dessuten har du tilgang til langt bedre plottemuligheter i matlab.. Men for all del, det er jo gunstig å lære seg å skrive i c++ også :) Senere når du evt må løse din egen ligning på en superdatamaskin må du jo kode i c for å utnytte paralelliseringen etc.

Lenke til kommentar

Viste ikke om spdiags i MATLAB. Programmet mitt ble uansett temmelig effektivt ;) Ang. plotting, så er det mye man kan gjøre med gnuplot og (skall)skripts, bare kjedelig at du (så vidt jeg vet?) må gå via disk for å kunne bruke gnuplot. Hadde jo vært überkult å kunne overføre hele arrayet til gnuplot og plotta på den måten, uten å gå via disk... Evt. kan gnuplot lese ting som ikke er i ASCII-format?

 

Akkurat dette progget er uansett ikke egnet for paralellisering da det er temmelig seriellt, hele algoritma...

Lenke til kommentar
Viste ikke om spdiags i MATLAB. Programmet mitt ble uansett temmelig effektivt ;) Ang. plotting, så er det mye man kan gjøre med gnuplot og (skall)skripts, bare kjedelig at du (så vidt jeg vet?) må gå via disk for å kunne bruke gnuplot. Hadde jo vært überkult å kunne overføre hele arrayet til gnuplot og plotta på den måten, uten å gå via disk... Evt. kan gnuplot lese ting som ikke er i ASCII-format?

 

Det er mulig at du kan bruke gnuplot_i for å laste data direkte inn i gnuplot..

Det skal være mulig å laste inn data direkte, da gnuplot-py sier den kan gjøre det...

 

Mulig du må lete litt i kildekodene for å finne hvor/hvordan det gjøres, men det kan kanskje være verdt det...

Lenke til kommentar

Opprett en konto eller logg inn for å kommentere

Du må være et medlem for å kunne skrive en kommentar

Opprett konto

Det er enkelt å melde seg inn for å starte en ny konto!

Start en konto

Logg inn

Har du allerede en konto? Logg inn her.

Logg inn nå
  • Hvem er aktive   0 medlemmer

    • Ingen innloggede medlemmer aktive
×
×
  • Opprett ny...