src/Utility/DiscField.cpp

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 /***************************************************************************
00003  *
00004  * The IPPL Framework
00005  * 
00006  * This program was prepared by PSI. 
00007  * All rights in the program are reserved by PSI.
00008  * Neither PSI nor the author(s)
00009  * makes any warranty, express or implied, or assumes any liability or
00010  * responsibility for the use of this software
00011  *
00012  * Visit http://www.acl.lanl.gov/POOMS for more details
00013  *
00014  ***************************************************************************/
00015 
00016 // -*- C++ -*-
00017 /***************************************************************************
00018  *
00019  * The IPPL Framework
00020  * 
00021  *
00022  * Visit http://people.web.psi.ch/adelmann/ for more details
00023  *
00024  ***************************************************************************/
00025 
00026 // include files
00027 #include "Utility/DiscField.h"
00028 #include "Utility/DiscConfig.h"
00029 #include "Utility/DiscMeta.h"
00030 #include "Field/BrickIterator.h"
00031 #include "Message/Tags.h"
00032 #include "Profile/Profiler.h"
00033 #include "Utility/PAssert.h"
00034 #include "Utility/IpplStats.h"
00035 #include <string.h>
00036 #include <errno.h>
00037 
00038 
00040 // Constructor: make a DiscField for writing
00041 // fname = name of file (without extensions)
00042 // config = name of configuration file
00043 // numFields = number of Fields in the file (for writing)
00044 // typestr = string describing the 'type' of the Field to be written (this
00045 //           is ignored if the Field is being read).  The string should be
00046 //           the same as the statement used to declare the Field object
00047 //           e.g., for a field of the form Field<double,2> the string
00048 //           should be "Field<double,2>".  The string should be such that
00049 //           if read later into a variable F, you can use the string in
00050 //           a source code line as  'F A' to create an instance of the
00051 //           same type of data as is stored in the file.
00052 template <unsigned Dim>
00053 DiscField<Dim>::DiscField(const char* base, const char* config,
00054                           unsigned int numFields, const char* typestr) {
00055   TAU_TYPE_STRING(taustr, CT(*this) +  
00056                   " void (char *, char *, unsigned int, char *)" );
00057   TAU_PROFILE("DiscField::DiscField()", taustr, 
00058               TAU_UTILITY | TAU_FIELD | TAU_IO);
00059   initialize(base, config, typestr, numFields);
00060 }
00061 
00062 
00064 // Constructor: same as above, but without a config file specified.  The
00065 // default config file entry that will be used is "*  .", which means, for
00066 // each SMP machine, assume the directory to put data files in is "."
00067 template <unsigned Dim>
00068 DiscField<Dim>::DiscField(const char* base, unsigned int numFields,
00069                           const char* typestr) {
00070   TAU_TYPE_STRING(taustr,CT(*this) +  " void (char *, unsigned int, char *)" );
00071   TAU_PROFILE("DiscField::DiscField()", taustr, 
00072               TAU_UTILITY | TAU_FIELD | TAU_IO);
00073   initialize(base, 0, typestr, numFields);
00074 }
00075 
00076 
00078 // Constructor: make a DiscField for reading only.
00079 // fname = name of file (without extensions
00080 // config = name of configuration file
00081 template <unsigned Dim>
00082 DiscField<Dim>::DiscField(const char* base, const char* config) {
00083   TAU_TYPE_STRING(taustr, CT(*this) +  " void (char *, char *)" );
00084   TAU_PROFILE("DiscField::DiscField()", taustr, 
00085               TAU_UTILITY | TAU_FIELD | TAU_IO);
00086   initialize(base, config, 0, 0);
00087 }
00088 
00089 
00091 // Constructor: same as above, but without a config file specified.  The
00092 // default config file entry that will be used is "*  .", which means, for
00093 // each SMP machine, assume the directory to put data files in is "."
00094 template <unsigned Dim>
00095 DiscField<Dim>::DiscField(const char* base) {
00096   TAU_TYPE_STRING(taustr, CT(*this) +  " void (char * )" );
00097   TAU_PROFILE("DiscField::DiscField()", taustr, 
00098               TAU_UTILITY | TAU_FIELD | TAU_IO);
00099   initialize(base, 0, 0, 0);
00100 }
00101 
00102 
00104 // perform initialization based on the constuctor arguments
00105 template <unsigned Dim>
00106 void DiscField<Dim>::initialize(const char *base, const char *config,
00107                                 const char *typestr, unsigned int numFields) {
00108   TAU_TYPE_STRING(taustr, CT(*this) +  
00109                   " void (char *, char *, char *, unsigned int )" );
00110   TAU_PROFILE("DiscField::initialize()", taustr, 
00111               TAU_UTILITY | TAU_FIELD | TAU_IO);
00112 
00113   // save string data
00114   BaseFile = base;
00115   DiscType = "";
00116   if (typestr != 0)
00117     TypeString = typestr;
00118   else
00119     TypeString = "unknown";
00120 
00121   // initialize member data
00122   DataDimension = Dim;
00123   CurrentOffset = 0;
00124   NumRecords = 0;
00125   NumWritten = 0;
00126   NumVnodes = 0;
00127   VnodeTally = 0;
00128 
00129 #ifdef IPPL_DIRECTIO
00130   openedDirectIO = false;
00131 #endif
00132 
00133   // save the number of fields, which indicates if this object is being
00134   // opened for reading or writing
00135   NumFields = numFields;
00136   WritingFile = (NumFields > 0);
00137   if (WritingFile)
00138     NeedStartRecord = 1;
00139   else
00140     NeedStartRecord = -1;
00141 
00142   // initialize valid field flags
00143   for (unsigned int i=0; i < NumFields; ++i)
00144     ValidField.push_back(false);
00145 
00146   // parse the configuration file to find our SMP's, file directories, etc.
00147   ConfigOK = parse_config(config, WritingFile);
00148 
00149   // figure out the number of fields, number of records, size, and
00150   // typestring from the .meta file, and store it here.  This is only done
00151   // if we're reading the file
00152   if (ConfigOK && !WritingFile)
00153     ConfigOK = read_meta();
00154 }
00155 
00156 
00158 // Destructor
00159 template <unsigned Dim>
00160 DiscField<Dim>::~DiscField() {
00161   TAU_TYPE_STRING(taustr, CT(*this) +  " void ()" );
00162   TAU_PROFILE("DiscField::~DiscField()", taustr, 
00163     TAU_UTILITY | TAU_FIELD | TAU_IO);
00164 
00165   // delete per-record vnode information
00166   if (NumVnodes != 0)
00167     delete [] NumVnodes;
00168   if (VnodeTally != 0)
00169     delete [] VnodeTally;
00170 
00171   // delete the configuration file info
00172   if (Config != 0)
00173     delete Config;
00174 }
00175 
00176 
00178 // Obtain all the information about the file, including the number
00179 // of records, fields, and number of vnodes stored in each record.
00180 template <unsigned Dim>
00181 void DiscField<Dim>::query(int& numRecords, int& numFields,
00182                            vector<int>& size) const {
00183   TAU_TYPE_STRING(taustr, CT(*this) +  " void (int, int, vector<int> )" );
00184   TAU_PROFILE("DiscField::query()", taustr, 
00185               TAU_UTILITY | TAU_FIELD | TAU_IO);
00186   numRecords = NumRecords;
00187   numFields = NumFields;
00188   if (numFiles() > 0 && myBox0() == Ippl::myNode()) {
00189     size = NumVnodes[0];
00190     for (int i=1; i < numFiles(); ++i) {
00191       for (int j=0; j < NumVnodes[i].size(); ++j)
00192         size[j] += NumVnodes[i][j];
00193     }
00194   }
00195 }
00196 
00197 
00199 // open a file in the given mode.  If an error occurs, print a message
00200 // and return 0.
00201 template <unsigned Dim>
00202 FILE* DiscField<Dim>::open_df_file(const string& fnm, const string& mode) {
00203   TAU_TYPE_STRING(taustr, CT(*this) +  " FILE * (string, string)" );
00204   TAU_PROFILE("DiscField::open_df_file()", taustr, 
00205               TAU_UTILITY | TAU_FIELD | TAU_IO);
00206   FILE *f = fopen(fnm.c_str(), mode.c_str());
00207   if (f == 0) {
00208     ERRORMSG("DiscField: Could not open file '" << fnm.c_str());
00209     ERRORMSG("' for mode '" << mode.c_str() << "' on node ");
00210     ERRORMSG(Ippl::myNode() << "." << endl);
00211     Ippl::abort("Exiting due to DiscField error.");
00212   }
00213   return f;
00214 }
00215 
00216 
00218 // open a file in the given mode.  If an error occurs, print a message
00219 // and return 0.  This version is used for data files.
00220 template <unsigned Dim>
00221 int DiscField<Dim>::open_df_file_fd(const string& fnm, const string& suf,
00222                                     int origflags) {
00223 
00224   // Form a string with the total filename
00225   string fnamebuf("");
00226   if (fnm.length() > 0)
00227     fnamebuf += fnm;
00228   if (suf.length() > 0)
00229     fnamebuf += suf;
00230 
00231   // Form the open flags
00232   int flags = origflags;
00233 #ifdef IPPL_DIRECTIO
00234   openedDirectIO = false;
00235   if (IpplInfo::useDirectIO) {
00236     flags |= O_DIRECT;
00237     openedDirectIO = true;
00238   }
00239 #endif
00240 
00241   // Try to open the file
00242   int f = ::open(fnamebuf.c_str(), flags, 0644);
00243   if (f < 0) {
00244     // If we tried with direct-io but failed, see if we can dothis without dio
00245 #ifdef IPPL_DIRECTIO
00246     f = ::open(fnamebuf.c_str(), origflags, 0644);
00247     openedDirectIO = (f >= 0);
00248 #endif
00249 
00250     // If that still did not work, we're screwed
00251     if (f < 0) {
00252       ERRORMSG("DiscField: Could not open file '" << fnamebuf.c_str());
00253       ERRORMSG("' on node " << Ippl::myNode() << ", f = " << f << "."<<endl);
00254       return (-1);
00255     }
00256   }
00257 
00258   // Get direct-io info, if necessary
00259 
00260 #ifdef IPPL_DIRECTIO
00261   if (openedDirectIO) {
00262     if (::fcntl(f, F_DIOINFO, &dioinfo) != 0) {
00263       ERRORMSG("DiscField: Could not get dio info for '"<< fnamebuf.c_str());
00264       ERRORMSG("' using direct io on node ");
00265       ERRORMSG(Ippl::myNode() << "." << endl);
00266       close(f);
00267       return (-1);
00268     }
00269 
00270     DFDBG(string dbgmsgname("DF:open_df_file_fd"));
00271     DFDBG(Inform dbgmsg(dbgmsgname.c_str(), INFORM_ALL_NODES));
00272     DFDBG(dbgmsg << "Opened file '" << fnamebuf.c_str() << "' with direct-io");
00273     DFDBG(dbgmsg << ", dioinfo = (miniosz="<<dioinfo.d_miniosz<<", maxiosz=");
00274     DFDBG(dbgmsg << dioinfo.d_maxiosz << ", mem=" << dioinfo.d_mem << ")");
00275     DFDBG(dbgmsg << endl);
00276   }
00277 #endif
00278 
00279   return f;
00280 }
00281 
00282 
00284 // same as above, but also specifying a file suffix
00285 template <unsigned Dim>
00286 FILE* DiscField<Dim>::open_df_file(const string& fnm, const string& suf,
00287                                    const string& mode) {
00288   TAU_TYPE_STRING(taustr, CT(*this) +  
00289                   " FILE * (string, string, string)" );
00290   TAU_PROFILE("DiscField::open_df_file()", taustr, 
00291               TAU_UTILITY | TAU_FIELD | TAU_IO);
00292 
00293   string fnamebuf("");
00294   if (fnm.length() > 0)
00295     fnamebuf += fnm;
00296   if (suf.length() > 0)
00297     fnamebuf += suf;
00298 
00299   /*
00300   char fnamebuf[1024];
00301   fnamebuf[0] = '\0';
00302   if (fnm.length() > 0)
00303     strcat(fnamebuf, fnm.c_str());
00304   if (suf.length() > 0)
00305     strcat(fnamebuf, suf.c_str());
00306   FILE *f = fopen(fnamebuf, mode.c_str());
00307   */
00308 
00309   FILE *f = fopen(fnamebuf.c_str(), mode.c_str());
00310 
00311   if (f == 0) {
00312     ERRORMSG("DiscField: Could not open file '" << fnamebuf);
00313     ERRORMSG("' for mode '" << mode.c_str() << "' on node ");
00314     ERRORMSG(Ippl::myNode() << "." << endl);
00315     Ippl::abort("Exiting due to DiscField error.");
00316   }
00317   return f;
00318 }
00319 
00320 
00322 // create the data files used to store Field data.  Return success.
00323 template <unsigned Dim>
00324 bool DiscField<Dim>::create_files() {
00325   TAU_TYPE_STRING(taustr, CT(*this) +  " bool ()" );
00326   TAU_PROFILE("DiscField::create_files()", taustr, 
00327               TAU_UTILITY | TAU_FIELD | TAU_IO);
00328 
00329   FILE *f;
00330   string om("w");
00331   string suff[4];
00332   suff[0] = ".meta";
00333   suff[1] = ".layout";
00334   suff[2] = ".offset";
00335   suff[3] = ".data";
00336 
00337   unsigned int nfiles = 3;
00338 
00339   // create the non-data files
00340   for (unsigned int i=0; i < nfiles; ++i) {
00341     string fname(Config->getFilename(0) + suff[i]);
00342     if ((f = open_df_file(fname, om)) == 0) {
00343       ERRORMSG("DiscField: Could not create file '" << fname.c_str());
00344       ERRORMSG("'." << endl);
00345       Ippl::abort("Exiting due to DiscField error.");
00346     }
00347     fclose(f);
00348   }
00349 
00350   // create the data file
00351   int fd = open_df_file_fd(Config->getFilename(0), suff[3],
00352                            O_RDWR|O_CREAT|O_TRUNC);
00353   if (fd < 0) {
00354     string fname(Config->getFilename(0) + suff[3]);
00355     ERRORMSG("DiscField: Could not create data file '"<<fname.c_str());
00356     ERRORMSG("'. errno = " << errno << endl);
00357     Ippl::abort("Exiting due to DiscField error.");
00358   } else {
00359     close(fd);
00360   }
00361 
00362   return true;
00363 }
00364 
00365 
00367 // Since the layout can be different every time write
00368 // is called, the globalID container needs to be recalculated.  The total
00369 // domain of the Field should not change, though, just the layout.  Return
00370 // success.
00371 template <unsigned Dim>
00372 bool DiscField<Dim>::make_globalID(FieldLayout<Dim>& layout) {
00373   TAU_TYPE_STRING(taustr, CT(*this) +  " bool (" + CT(layout) + " )" );
00374   TAU_PROFILE("DiscField::make_globalID()", taustr, 
00375               TAU_UTILITY | TAU_FIELD | TAU_IO);
00376 
00377   // check layout to make sure it's valid
00378   if (Size.size() != 0 && !(Size == layout.getDomain()))
00379     return false;
00380   else
00381     Size = layout.getDomain();
00382 
00383   // get rid of the existing mapping
00384   globalID.erase(globalID.begin(), globalID.end());
00385 
00386   // for each local vnode, get the NDIndex it has and store it along with
00387   // the node that owns it.
00388   typedef typename GlobalIDList_t::value_type vtype;
00389   typename FieldLayout<Dim>::iterator_iv local;
00390   for (local = layout.begin_iv() ; local != layout.end_iv(); ++local) {
00391     // get the domain, and the node and SMP that holds that domain
00392     NDIndex<Dim>& domain = (NDIndex<Dim>&) (*local).second.get()->getDomain();
00393     int node = (*local).second.get()->getNode();
00394     int nodesmp = Config->getNodeSMPIndex(node);
00395 
00396     // find out of any of our SMP's contain that node
00397     bool foundsmp = (nodesmp == mySMP());
00398     int checksmp = 0;
00399     while (!foundsmp && checksmp < Config->getNumOtherSMP()) {
00400       foundsmp = (nodesmp == Config->getOtherSMP(checksmp));
00401       checksmp++;
00402     }
00403 
00404     // if we are responsible for this vnode, save it
00405     if (foundsmp) {
00406       // WARNMSG(" ==> Found vnode " << domain << " on this SMP, from node ");
00407       // WARNMSG(node << endl);
00408       globalID.insert(vtype(domain, node));
00409     }
00410   }
00411 
00412   // for each remote vnode, get the NDIndex it has and store it along with
00413   // the node that owns it.
00414   typename FieldLayout<Dim>::iterator_dv remote;
00415   for (remote = layout.begin_rdv() ; remote != layout.end_rdv(); ++remote) {
00416     // get the domain, and the node and SMP that holds that domain
00417     NDIndex<Dim>& domain = (NDIndex<Dim>&) (*remote).first;
00418     int node = (*remote).second->getNode();
00419     int nodesmp = Config->getNodeSMPIndex(node);
00420 
00421     // find out of any of our SMP's contain that node
00422     bool foundsmp = (nodesmp == mySMP());
00423     int checksmp = 0;
00424     while (!foundsmp && checksmp < Config->getNumOtherSMP()) {
00425       foundsmp = (nodesmp == Config->getOtherSMP(checksmp));
00426       checksmp++;
00427     }
00428 
00429     // if we are responsible for this vnode, save it
00430     if (foundsmp) {
00431       // WARNMSG(" ==> Found vnode " << domain << " on this SMP, from node ");
00432       // WARNMSG(node << endl);
00433       globalID.insert(vtype(domain, node));
00434     }
00435   }
00436 
00437   return true;
00438 }
00439 
00440 
00442 // read in from configuration file - an ascii file of token pairs.
00443 // This is mostly handled by the DiscConfig class.  Return success.
00444 template <unsigned Dim>
00445 bool DiscField<Dim>::parse_config(const char *fname, bool writing) {
00446   TAU_TYPE_STRING(taustr, CT(*this) +  " bool (char *, bool)" );
00447   TAU_PROFILE("DiscField::parse_config()", taustr, 
00448               TAU_UTILITY | TAU_FIELD | TAU_IO);
00449 
00450   // create a DiscConfig instance, which will parse the file on some of
00451   // the nodes and distribute the information to all the other nodes.
00452   Config = new DiscConfig(fname, BaseFile.c_str(), writing);
00453 
00454   // need to set up a few things if the config file checked out OK
00455   if (Config->ok()) {
00456     // create vnode information storage for Box0 nodes
00457     if (numFiles() > 0 && myBox0() == Ippl::myNode()) {
00458       NumVnodes  = new vector<int>[numFiles()];
00459       VnodeTally = new vector<int>[numFiles()];
00460     }
00461 
00462     // if we need to, create the files
00463     if (writing && Ippl::myNode() == myBox0() && NumFields > 0) {
00464       if (!create_files())
00465         return false;
00466     }
00467 
00468     // indicate how many filesets we're reading or writing
00469     if (writing) {
00470       ADDIPPLSTAT(incDiscFilesetWrites,numFiles());
00471     } else {
00472       ADDIPPLSTAT(incDiscFilesetReads,numFiles());
00473     }
00474   } else {
00475     ERRORMSG("DiscField: A problem occurred reading the config file '");
00476     ERRORMSG(fname << "'." << endl);
00477     Ippl::abort("Exiting due to DiscField error.");
00478   }
00479 
00480   return Config->ok();
00481 }
00482 
00483 
00485 // print out debugging information for this DiscField
00486 template <unsigned Dim>
00487 void DiscField<Dim>::printDebug() { printDebug(cout); }
00488 
00489 template <unsigned Dim>
00490 void DiscField<Dim>::printDebug(ostream& outmsg) {
00491   TAU_TYPE_STRING(taustr, CT(*this) +  " void (ostream )" );
00492   TAU_PROFILE("DiscField::printDebug()", taustr, 
00493               TAU_UTILITY | TAU_FIELD | TAU_IO);
00494 
00495   Inform msg("DiscField", outmsg, INFORM_ALL_NODES);
00496 
00497   msg << "BaseFile = " << BaseFile << endl;
00498   msg << "Field Type = " << TypeString << endl;
00499   msg << "NumRecords = " << NumRecords << endl;
00500   msg << "NumFields = " << NumFields << endl;
00501 
00502   msg << "Configuration file information:" << endl;
00503   Config->printDebug(msg);
00504 
00505   msg << endl;
00506 }
00507 
00508 
00510 // write out a new .meta file.  The .meta file contains the following
00511 // information, on each line:
00512 //   String with type of data stored here, supplied by user
00513 //   Dimension
00514 //   For each dimension:
00515 //     Total domain of the Fields, as   first  last  stride
00516 //   Number of Fields
00517 //   Number of Records
00518 //   Number of SMPs
00519 //   Vnodes/SMP for each record, on one line
00520 //   Vnodes/SMP tally for each record, on one line
00521 // return success of operation.
00522 template <unsigned Dim>
00523 bool DiscField<Dim>::write_meta() {
00524   TAU_TYPE_STRING(taustr, CT(*this) +  " bool ()" );
00525   TAU_PROFILE("DiscField::write_meta()", taustr, 
00526               TAU_UTILITY | TAU_FIELD | TAU_IO);
00527 
00528   unsigned int r, d;
00529 
00530   // no need to write anything if we have no files for this SMP
00531   if (numFiles() == 0)
00532     return true;
00533 
00534   // open the meta data file
00535   FILE *outputMeta = open_df_file(Config->getFilename(0),".meta",string("w"));
00536   if (outputMeta == 0)
00537     return false;
00538 
00539   // write the initial header info
00540   fprintf(outputMeta, "Type =           %s\n", TypeString.c_str());
00541   fprintf(outputMeta, "Dim =            %d\n", Dim);
00542   for (d=0; d < Dim; ++d)
00543     fprintf(outputMeta, "Domain =         %d %d %d\n",
00544             Size[d].first(), Size[d].last(), Size[d].stride());
00545   fprintf(outputMeta, "Fields =         %d\n", NumFields);
00546   fprintf(outputMeta, "Records =        %d\n", NumRecords);
00547   fprintf(outputMeta, "SMPs =           %d\n", fileSMPs());
00548 
00549   // write information for each record.  When writing, we will only
00550   // write one file set per box, so we use '0' for the fileset number.
00551   fprintf(outputMeta, "VnodesInRecord = ");
00552   for (r=0; r < NumRecords; ++r)
00553     fprintf(outputMeta, " %d", NumVnodes[0][r]);
00554   fprintf(outputMeta, "\n");
00555 
00556   fprintf(outputMeta, "VnodeTally=    ");
00557   for (r=0; r < NumRecords; ++r)
00558     fprintf(outputMeta, " %d", VnodeTally[0][r]);
00559   fprintf(outputMeta, "\n");
00560 
00561   // close data file and return
00562   fclose(outputMeta);
00563   return true;
00564 }
00565 
00566 
00568 // read in data from .meta file, and replace current storage values.
00569 // The format for a .meta file is described in the write_meta routine.
00570 // return success of operation.
00571 template <unsigned Dim>
00572 bool DiscField<Dim>::read_meta() {
00573   TAU_TYPE_STRING(taustr, CT(*this) +  " bool ()" );
00574   TAU_PROFILE("DiscField::read_meta()", taustr, 
00575               TAU_UTILITY | TAU_FIELD | TAU_IO);
00576   unsigned int r;
00577   bool iserror = false;
00578   int tag = Ippl::Comm->next_tag(DF_READ_META_TAG, DF_TAG_CYCLE);
00579 
00580   DFDBG(string dbgmsgname("DF:read_meta:"));
00581   DFDBG(dbgmsgname += Config->getConfigFile());
00582   DFDBG(Inform dbgmsg(dbgmsgname.c_str(), INFORM_ALL_NODES));
00583   DFDBG(dbgmsg << "Starting to read meta info: mySMP=" << mySMP());
00584   DFDBG(dbgmsg << ", mybox0=" << myBox0() << ", numfiles=" << numFiles());
00585   DFDBG(dbgmsg << endl);
00586 
00587   // on Box0 nodes, read in the meta data ... on others, wait for
00588   // Box0 nodes to send info to them
00589   if (Ippl::myNode() == myBox0()) {
00590     // loop over all the files on this Box0 node
00591     for (int sf=0; sf < numFiles(); ++sf) {
00592       // open and parse the meta data file
00593       string filename = Config->getFilename(sf) + ".meta";
00594       DiscMeta outputMeta(filename.c_str());
00595       if (outputMeta.size() == 0) {
00596         ERRORMSG("DiscField: The meta file '" << filename << "' is empty ");
00597         ERRORMSG("or does not exist." << endl);
00598         Ippl::abort("Exiting due to DiscField error.");
00599         return false;
00600       }
00601 
00602       // initialize data before reading .meta file
00603       unsigned int dimread = 0;
00604       TypeString = "unknown";
00605       DataDimension = Dim;
00606       NumFields = 0;
00607       NumRecords = 0;
00608       NumVnodes[sf].erase(NumVnodes[sf].begin(), NumVnodes[sf].end());
00609       VnodeTally[sf].erase(VnodeTally[sf].begin(), VnodeTally[sf].end());
00610 
00611       // keep reading until we have all data
00612       DiscMeta::iterator metaline, metaend = outputMeta.end();
00613       for (metaline = outputMeta.begin(); metaline != metaend; ++metaline) {
00614         // get number of tokens and list of tokens in the line
00615         int linesread  = (*metaline).first;
00616         int numtokens  = (*metaline).second.first;
00617         string *tokens = (*metaline).second.second;
00618 
00619         // action is based on first keyword
00620         if (tokens[0] == "Type") {
00621           if (numtokens > 1)
00622             TypeString = tokens[1];
00623         }
00624         else if (tokens[0] == "Dim" && numtokens == 2) {
00625           DataDimension = atoi(tokens[1].c_str());
00626           if (DataDimension < 1) {
00627             ERRORMSG("DiscField: The meta file '" << filename << "' ");
00628             ERRORMSG("contains a value for dimension < 1, '");
00629             ERRORMSG(tokens[1] << "'." << endl);
00630             Ippl::abort("Exiting due to DiscField error.");
00631             iserror = true;
00632           }
00633         }
00634         else if (tokens[0] == "Fields" && numtokens == 2) {
00635           NumFields = atoi(tokens[1].c_str());
00636           if (NumFields < 1) {
00637             ERRORMSG("DiscField: The meta file '" << filename << "' ");
00638             ERRORMSG("contains a value for Fields < 1, '");
00639             ERRORMSG(tokens[1] << "'." << endl);
00640             Ippl::abort("Exiting due to DiscField error.");
00641             iserror = true;
00642           }
00643         }
00644         else if (tokens[0] == "Records" && numtokens == 2) {
00645           NumRecords = atoi(tokens[1].c_str());
00646         }
00647         else if (tokens[0] == "SMPs" && numtokens == 2) {
00648           int checkfileSMPs = atoi(tokens[1].c_str());
00649           if (fileSMPs() != checkfileSMPs) {
00650             ERRORMSG("DiscField: The meta file '" << filename << "' ");
00651             ERRORMSG("contains a value for the number of filesets that\n");
00652             ERRORMSG("does not match the number of filesets in the config\n");
00653             ERRORMSG("file: metafile filesets = " << tokens[1] << ", ");
00654             ERRORMSG("config filesets = " << fileSMPs() << "." << endl);
00655             Ippl::abort("Exiting due to DiscField error.");
00656             iserror = true;
00657           }
00658         }
00659         else if (tokens[0] == "Domain" && numtokens == 4) {
00660           if (dimread < Dim) {
00661             Size[dimread] = Index(atoi(tokens[1].c_str()),
00662                                   atoi(tokens[2].c_str()),
00663                                   atoi(tokens[3].c_str()));
00664           }
00665           dimread++;
00666         }
00667         else if (tokens[0] == "VnodesInRecord") {
00668           for (r=1; r < numtokens; ++r)
00669             NumVnodes[sf].push_back(atoi(tokens[r].c_str()));
00670         }
00671         else if (tokens[0] == "VnodeTally") {
00672           for (r=1; r < numtokens; ++r)
00673             VnodeTally[sf].push_back(atoi(tokens[r].c_str()));
00674         }
00675         else {
00676           // error in line
00677           ERRORMSG("DiscField: Format error on line " << linesread);
00678           ERRORMSG(" in meta file '" << filename << "'." << endl);
00679           Ippl::abort("Exiting due to DiscField error.");
00680           iserror = true;
00681         }
00682 
00683         DFDBG(dbgmsg << "On box0: finished line with tokens[0]='"<<tokens[0]);
00684         DFDBG(dbgmsg << "' ... iserror = " << iserror << endl);
00685 
00686         if (iserror)
00687           break;
00688       }
00689 
00690       // do a little sanity checking
00691       if (DataDimension != dimread) {
00692         ERRORMSG("DiscField: Dim != # Domain lines in meta file '");
00693         ERRORMSG(filename << "'. (" << DataDimension << " != " << dimread);
00694         ERRORMSG(")" << endl);
00695         Ippl::abort("Exiting due to DiscField error.");
00696         iserror = true;
00697       }
00698       if (NumRecords != NumVnodes[sf].size()) {
00699         ERRORMSG("DiscField: Records != VnodesInRecord items in meta file '");
00700         ERRORMSG(filename << "'. (" << NumRecords << " != ");
00701         ERRORMSG(NumVnodes[sf].size() << ")" << endl);
00702         Ippl::abort("Exiting due to DiscField error.");
00703         iserror = true;
00704       }
00705       if (NumRecords != VnodeTally[sf].size()) {
00706         ERRORMSG("DiscField: Records != VnodeTally items in meta file '");
00707         ERRORMSG(filename << "'. (" << NumRecords << " != ");
00708         ERRORMSG(VnodeTally[sf].size() << ")" << endl);
00709         Ippl::abort("Exiting due to DiscField error.");
00710         iserror = true;
00711       }
00712 
00713       // stop processing meta files is there was an error
00714       if (iserror)
00715         break;
00716     }
00717 
00718     DFDBG(dbgmsg << "Summary of meta info:" << endl);
00719     DFDBG(dbgmsg << "  iserror = " << iserror << endl);
00720     DFDBG(dbgmsg << "  DataDimension = " << DataDimension << endl);
00721     DFDBG(dbgmsg << "  NumFields = " << NumFields << endl);
00722     DFDBG(dbgmsg << "  NumRecords = " << NumRecords << endl);
00723     DFDBG(dbgmsg << "  Size = " << Size << endl);
00724     DFDBG(dbgmsg << "  TypeString = " << TypeString << endl);
00725 
00726     // now send meta info to all nodes which expect it
00727     int numinform = Config->getNumOtherSMP();
00728     DFDBG(dbgmsg << "Preparing messages to send to other nodes ..." << endl);
00729     DFDBG(dbgmsg << "  Must send data to my SMP nodes, and to ");
00730     DFDBG(dbgmsg << numinform << " other SMP's." << endl);
00731     for (int s=0; s <= numinform; ++s) {
00732       int smp = mySMP();
00733       if (s != numinform)
00734         smp = Config->getOtherSMP(s);
00735       DFDBG(dbgmsg << "  Preparing messages for SMP " << smp << " with ");
00736       DFDBG(dbgmsg << Config->getNumSMPNodes(smp) << " nodes." << endl);
00737       for (int n=0; n < Config->getNumSMPNodes(smp); ++n) {
00738         int node = Config->getSMPNode(smp, n);
00739         if (node != Ippl::myNode()) {
00740           // create a message with meta info
00741           Message *msg = new Message;
00742           int errint = iserror;
00743           msg->put(errint);
00744           msg->put(DataDimension);
00745           msg->put(NumFields);
00746           msg->put(NumRecords);
00747           ::putMessage(*msg, Size);
00748           ::putMessage(*msg, TypeString);
00749 
00750           // send the message to the intended node
00751           DFDBG(dbgmsg << "  Sending meta info to node " << node);
00752           DFDBG(dbgmsg << " with tag " << tag << ", on SMP " << smp << endl);
00753           Ippl::Comm->send(msg, node, tag);
00754         } else {
00755           DFDBG(dbgmsg << "  Skipping send to node " << node);
00756           DFDBG(dbgmsg << " since it is my node." << endl);
00757         }
00758       }
00759     }
00760 
00761   } else {
00762     // all other nodes (which are not Box0 nodes) should get a message
00763     // telling them the meta info
00764     int node = myBox0();
00765     DFDBG(dbgmsg << "Waiting for meta info from node " << node);
00766     DFDBG(dbgmsg << " with tag " << tag << endl);
00767     Message *msg = Ippl::Comm->receive_block(node, tag);
00768     PAssert(msg != 0);
00769 
00770     // get info out of message
00771     DFDBG(dbgmsg << "Summary of received meta info:" << endl);
00772     int errint;
00773     msg->get(errint);
00774     iserror = (errint != 0);
00775     DFDBG(dbgmsg << "  iserror = " << iserror << endl);
00776     msg->get(DataDimension);
00777     DFDBG(dbgmsg << "  DataDimension = " << DataDimension << endl);
00778     msg->get(NumFields);
00779     DFDBG(dbgmsg << "  NumFields = " << NumFields << endl);
00780     msg->get(NumRecords);
00781     DFDBG(dbgmsg << "  NumRecords = " << NumRecords << endl);
00782     ::getMessage(*msg, Size);
00783     DFDBG(dbgmsg << "  Size = " << Size << endl);
00784     ::getMessage(*msg, TypeString);
00785     DFDBG(dbgmsg << "  TypeString = " << TypeString << endl);
00786 
00787     // we're done with this message
00788     delete msg;
00789   }
00790 
00791   return (!iserror);
00792 }
00793 
00794 
00796 // Read the data for a single NDIndex from the given file.  Return success.
00797 template <unsigned Dim>
00798 bool DiscField<Dim>::read_NDIndex(FILE *f, NDIndex<Dim> &ndi) {
00799   // an array of ints used to read the data
00800   int ndidata[6*Dim];
00801 
00802   // OK, this is a mess, for the reasons described in write_NDIndex.  This
00803   // reads in 6 ints for each dimension, of which three are used for
00804   // the first, stride, and length parameters.  These are put in to the given
00805   // NDIndex.
00806 
00807   // first read the data into the int array
00808   if (fread(ndidata, sizeof(int), 6*Dim, f) != 6*Dim) {
00809     ERRORMSG("DiscField: Error reading NDIndex line from data file." << endl);
00810     Ippl::abort("Exiting due to DiscField error.");
00811     return false;
00812   }
00813 
00814   // now copy data int the NDIndex
00815   int *dptr = ndidata + 1;
00816   for (int d=0; d < Dim; ++d) {
00817     int first = *dptr;
00818     int stride = *(dptr + 1);
00819     int length = *(dptr + 2);
00820     ndi[d] = Index(first, first + (length - 1)*stride, stride);
00821     dptr += 6;
00822   }
00823 
00824   return true;
00825 }
00826 
00827 
00829 // Write the data for a single NDIndex to the given file.  Return success.
00830 template <unsigned Dim>
00831 bool DiscField<Dim>::write_NDIndex(FILE *f, const NDIndex<Dim> &ndi) {
00832   // OK, this is a mess ... originally, data was just written
00833   // out from an NDIndex directly, which is just an array of Index objs.
00834   // However, the contents of an Index are compiler-specific, since some
00835   // compilers use the empty-base-class optimization, some put in an
00836   // extra int in a base class, etc.  So, this has been switched from
00837   // writing out the NDIndex data using
00838   //   fwrite(&((*id).first), sizeof(NDIndex<Dim>), 1, outputLayout)
00839   // to
00840   //   fwrite(ndidata, sizeof(int), 6*Dim, outputLayout)
00841   // since the original, most-used version of DiscField did so with
00842   // a compiler that constructed an Index object with this data:
00843   //   int = 0    (empty-base-class storage)
00844   //   int = first
00845   //   int = stride
00846   //   int = length
00847   //   int = base
00848   //   int = id
00849   // With some compilers, the initial int = 0 is not included, since it
00850   // is not necessary.  But for backwards compatibility, we'll use this
00851   // format of 6 ints, with the first, fifth, and sixth set to zero
00852 
00853   // first copy the data into the int array
00854   int ndidata[6*Dim];
00855   int *dptr = ndidata;
00856   for (int d=0; d < Dim; ++d) {
00857     *dptr++ = 0;
00858     *dptr++ = ndi[d].first();
00859     *dptr++ = ndi[d].stride();
00860     *dptr++ = ndi[d].length();
00861     *dptr++ = 0;
00862     *dptr++ = 0;
00863   }
00864 
00865   // now write the data, and report whether the result is OK
00866   return (fwrite(ndidata, sizeof(int), 6*Dim, f) == 6*Dim);
00867 }
00868 
00869 
00871 // update the .layout file, which contains information on the layout
00872 // of the Fields for each record.  This file contains a set of NDIndex
00873 // objects for each record.  The format, for each record, is:
00874 //   Number of vnodes on this SMP box
00875 //   For each vnode on this SMP box:
00876 //     Vnode object, containing   NDIndex(first  last  stride)
00877 // return success of update
00878 template <unsigned Dim>
00879 bool DiscField<Dim>::write_layout() {
00880   TAU_TYPE_STRING(taustr, CT(*this) +  " bool ()" );
00881   TAU_PROFILE("DiscField::write_layout()", taustr, 
00882               TAU_UTILITY | TAU_FIELD | TAU_IO);
00883 
00884   // no need to write anything if we have no files for this SMP
00885   if (numFiles() == 0)
00886     return true;
00887 
00888   // open the layout data file
00889   FILE *outputLayout = open_df_file(Config->getFilename(0), ".layout",
00890                                     string("a"));
00891 
00892   // write out the number of vnodes in this record for this file set
00893   int numvnodes = globalID.size();
00894   if (fwrite(&numvnodes, sizeof(int), 1, outputLayout) != 1) {
00895     ERRORMSG("Error writing .layout file in DiscField::write_layout." << endl);
00896     Ippl::abort("Exiting due to DiscField error.");
00897     fclose(outputLayout);
00898     return false;
00899   }
00900 
00901   // write out the current vnode sizes from the provided FieldLayout
00902   typename GlobalIDList_t::iterator id, idend = globalID.end();
00903   for (id = globalID.begin(); id != idend; ++id) {
00904     if (!write_NDIndex(outputLayout, (*id).first)) {
00905       ERRORMSG("Error writing record " << NumRecords-1 << " to .layout file.");
00906       Ippl::abort("Exiting due to DiscField error.");
00907       fclose(outputLayout);
00908       return false;
00909     }
00910   }
00911 
00912   // close the file, we're done
00913   fclose(outputLayout);
00914   return true;
00915 }
00916 
00917 
00919 // Read layout info for one file set in the given record.
00920 template <unsigned Dim>
00921 int DiscField<Dim>::read_layout(int record, int sf) {
00922   TAU_TYPE_STRING(taustr, CT(*this) +  " int (int, int, int &)" );
00923   TAU_PROFILE("DiscField::read_layout()", taustr,
00924               TAU_UTILITY | TAU_FIELD | TAU_IO);
00925 
00926   DFDBG(string dbgmsgname("DF:read_layout:"));
00927   DFDBG(dbgmsgname += Config->getConfigFile());
00928   DFDBG(Inform dbgmsg(dbgmsgname.c_str(), INFORM_ALL_NODES));
00929   DFDBG(dbgmsg << "Starting to read layout info for record " << record);
00930   DFDBG(dbgmsg << ", file " << sf << ": mySMP=" << mySMP() << ", mybox0=");
00931   DFDBG(dbgmsg << myBox0() << ", numfiles=" << numFiles() << endl);
00932 
00933   // open the layout data file
00934   string filename = Config->getFilename(sf) + ".layout";
00935   FILE *outputLayout = open_df_file(Config->getFilename(sf),
00936                                     ".layout", string("r"));
00937   if (outputLayout == 0)
00938     return (-1);
00939 
00940   DFDBG(dbgmsg << "On box0: sf=" << sf << ", opened file '");
00941   DFDBG(dbgmsg << filename << "' ..." << endl);
00942 
00943   // seek to the proper location
00944   Offset_t seekpos = record*sizeof(int) +
00945     VnodeTally[sf][record]*6*Dim*sizeof(int);
00946   DFDBG(dbgmsg << "  Seeking to position ");
00947   DFDBG(dbgmsg << static_cast<long>(seekpos) << endl);
00948 
00949   if (fseek(outputLayout, seekpos, SEEK_SET) != 0) {
00950     ERRORMSG("Error seeking to position " << static_cast<long>(seekpos));
00951     ERRORMSG(" in file '" << filename << "' for DiscField::read_layout.");
00952     ERRORMSG(endl);
00953     Ippl::abort("Exiting due to DiscField error.");
00954     fclose(outputLayout);
00955     return (-1);
00956   }
00957 
00958   // read the number of vnodes stored here
00959   int numvnodes = 0;
00960   if (fread(&numvnodes, sizeof(int), 1, outputLayout) != 1) {
00961     ERRORMSG("Error reading file '" << filename);
00962     ERRORMSG("' in DiscField::read_layout.");
00963     ERRORMSG(endl);
00964     Ippl::abort("Exiting due to DiscField error.");
00965     fclose(outputLayout);
00966     return (-1);
00967   }
00968 
00969   // we used to have to read the vnode domains, but now it is
00970   // not necessary, we get that from the offset file.  layout files
00971   // will continue to store correct data for backwards compatibility,
00972   // but we don't need it for reading any more.  So, just return.
00973 
00974   fclose(outputLayout);
00975   return numvnodes;
00976 }
00977 
00978 
00980 // Compute how many elements we should expect to store into the local
00981 // node for the given FieldLayout.  Just loop through the local vnodes
00982 // and accumulate the sizes of the owned domains.  This is modified
00983 // by the second "read domain" argument, which might be a subset of
00984 // the total domain.
00985 template <unsigned Dim>
00986 int DiscField<Dim>::compute_expected(const FieldLayout<Dim> &f,
00987                                      const NDIndex<Dim> &readDomain) {
00988   int expected = 0;
00989 
00990   DFDBG(string dbgmsgname("DF:compute_expected"));
00991   DFDBG(Inform dbgmsg(dbgmsgname.c_str(), INFORM_ALL_NODES));
00992   DFDBG(dbgmsg << "Computing expected size for node " << Ippl::myNode());
00993   DFDBG(dbgmsg <<endl);
00994 
00995   typename FieldLayout<Dim>::const_iterator_iv local = f.begin_iv();
00996   for (; local != f.end_iv(); ++local) {
00997     // Compute the size of the domain of this vnode, and add it to the
00998     // amount we expect for this node.
00999     NDIndex<Dim>& domain = (NDIndex<Dim>&)(*local).second.get()->getDomain();
01000     if (domain.touches(readDomain)) {
01001       NDIndex<Dim> newdomain = domain.intersect(readDomain);
01002       DFDBG(dbgmsg << "Intersection of " << domain << " and " << readDomain);
01003       DFDBG(dbgmsg << " = " << newdomain << endl);
01004       // expected += domain.size();
01005       expected += newdomain.size();
01006     } else {
01007       DFDBG(dbgmsg << "No intersection of " << domain << " and ");
01008       DFDBG(dbgmsg << readDomain << endl);
01009     }
01010 
01011     DFDBG(dbgmsg << "  Size for local domain " << domain << " = ");
01012     DFDBG(dbgmsg << domain.size() << ", readDomain = " << readDomain);
01013     DFDBG(dbgmsg << ", new expected for node " << Ippl::myNode() << " ");
01014     DFDBG(dbgmsg << expected << endl);
01015   }
01016 
01017   return expected;
01018 }
01019 
01020 
01022 // Compute the size of a domain, zero-based, that has a total
01023 // size <= chunkelems and has evenly chunked slices.
01024 template <unsigned Dim>
01025 NDIndex<Dim> DiscField<Dim>::chunk_domain(const NDIndex<Dim> &currblock,
01026                                           int chunkelems,
01027                                           int &msdim,
01028                                           bool iscompressed)
01029 {
01030   TAU_TYPE_STRING(taustr, CT(*this) +  " NDIndex (NDIndex, int, int &, bool)");
01031   TAU_PROFILE("DiscField::chunk_domain()", taustr, 
01032               TAU_UTILITY | TAU_FIELD | TAU_IO);
01033 
01034   // Initialize result to the total block sizes
01035   NDIndex<Dim> sliceblock;
01036   for (int i=0; i < Dim; ++i)
01037     sliceblock[i] = Index(currblock[i].length());
01038 
01039   // If this is compressed, or we are not chunking, just use the whole block
01040   int currsize = currblock.size();
01041   if (chunkelems < 1 || iscompressed)
01042     chunkelems = currsize;
01043 
01044   // Find out actual size for each dimension, generally smaller than the
01045   // total size
01046   for (int d=(Dim-1); d >= 0; --d) {
01047     // Size of this domain slice
01048     int axislen = currblock[d].length();
01049     currsize /= axislen;
01050 
01051     // Compute the number of lower-dim slices
01052     int numslices = chunkelems / currsize;
01053     if (numslices > axislen)
01054       numslices = axislen;
01055 
01056     // If there are some slices, just use those and we're done
01057     if (numslices > 0) {
01058       sliceblock[d] = Index(numslices);
01059       msdim = d;
01060       break;
01061     } else {
01062       // No slices here, so change the length of this dimension to 1
01063       sliceblock[d] = Index(1);
01064     }
01065   }
01066 
01067   // Return the newly computed block size; msdim is set to the maximum
01068   // dimension of the chunk block
01069   return sliceblock;
01070 }
01071 
01072 
01073 /***************************************************************************
01074  * $RCSfile: DiscField.cpp,v $   $Author: adelmann $
01075  * $Revision: 1.1.1.1 $   $Date: 2003/01/23 07:40:33 $
01076  * IPPL_VERSION_ID: $Id: DiscField.cpp,v 1.1.1.1 2003/01/23 07:40:33 adelmann Exp $ 
01077  ***************************************************************************/

Generated on Mon Jan 16 13:23:57 2006 for IPPL by  doxygen 1.4.6