diff options
author | tradke <tradke@ebee0441-1374-4afa-a3b5-247f3ba15b9a> | 2000-05-17 11:31:51 +0000 |
---|---|---|
committer | tradke <tradke@ebee0441-1374-4afa-a3b5-247f3ba15b9a> | 2000-05-17 11:31:51 +0000 |
commit | 05519b321d7931eebd34f2246fd2ed54442481aa (patch) | |
tree | 9901a6d3e0d12d3b27514de5c580911ae7938291 /src/util | |
parent | e5af9dfe4bfd948d2301e7104548060531f9f43c (diff) |
Added the recombiner for Cactus IEEEIO files.
To build it just do a
gmake <configuration>-utils UTILS=ieee_recombiner
or
gmake <configuration>-utils
if you want to build all utility programs.
The executables end up in exe/<configuration>/.
git-svn-id: http://svn.cactuscode.org/arrangements/CactusPUGHIO/IOFlexIO/trunk@126 ebee0441-1374-4afa-a3b5-247f3ba15b9a
Diffstat (limited to 'src/util')
-rw-r--r-- | src/util/ieee_recombiner.c | 533 |
1 files changed, 533 insertions, 0 deletions
diff --git a/src/util/ieee_recombiner.c b/src/util/ieee_recombiner.c new file mode 100644 index 0000000..4c12076 --- /dev/null +++ b/src/util/ieee_recombiner.c @@ -0,0 +1,533 @@ + /*@@ + @file ieee_recombiner.c + @date Sun Dec 28 12:32:28 1997 + @author Paul Walker + @desc + This file is the recombiner for chunked IEEEIO Cactus output files. + It recombines them into a single unchunked file. + @enddesc + @history + @endhistory + @@*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +/* CCTK includes */ +#include "cctk.h" + +/* FlexIO includes */ +#include "IEEEIO.h" +#include "IOProtos.h" + + +/* maximum number of dataset dimensions we can deal with */ +#define MAXDIM 3 +/* maximum length of attribute name */ +#define MAXNAMELEN 512 + +/*#define VERBOSE*/ + +int main (int argc, char **argv) +{ + IOFile *infiles, outfile; /* array of input filehandles and output fh */ + int ntype; /* datatype of dataset */ + int gtype; /* grouptype of dataset */ + Long len; /* length of attribute data */ + int attno; /* index of current attribute */ + Int nprocs; /* total number of processors */ + Int ioproc_every; /* IO performed on every n'th processor */ + Int unchunked; /* flag indicating whether file data is unchunked */ + int nioprocs; /* number of IO procs (= number of input files) */ + int nattrs; /* number of attributes to copy */ + int ioproc, dataset, attr;/* loopers for the current input file, + dataset and attribute */ + int i; /* general looper */ + char *currname; + int attrset, *currset; + Int *iters, currit; + char **name; /* array of dataset names */ + int rank, dims [MAXDIM]; /* size of current dataset */ + int gsz [MAXDIM]; /* global size of dataset */ + Int I_gsz [MAXDIM]; /* NOTE: on T3E int != Int */ + int chunk_lb [MAXDIM]; /* dito for lower bounds of chunk */ + Int I_chunk_lb [MAXDIM]; + void *data; /* pointer to data buffer */ + char **fnames; /* array of input filenames */ + int *nDatasets; /* array of "number of datasets" per input file */ + int max_filehandles; /* maximum number of open files */ + + + /* Say hello */ + printf ("\n"); + printf ("-----------------------------\n"); + printf ("Cactus IEEEIO File Recombiner\n"); + printf ("-----------------------------\n"); + printf ("\n"); + + /* Give some help if called with incorrect parameters */ + if (argc != 3) + { + printf ("Usage: recombiner <chunked_infile0> <unchunked_outfile>\n"); + printf (" eg, recombiner alp_3d.file_0.ieee alp_3d.ieee\n\n"); + return (0); + } + + /* determine filehandle limit */ + max_filehandles = sysconf (_SC_OPEN_MAX); + if (max_filehandles < 0) + { + printf ("Cannot determine filehandle limit\n"); + return (-1); + } + /* subtract stdin, stdout, stderr, and output filehandle */ + max_filehandles -= 4; + + /* open input and output file */ + infiles = (IOFile *) malloc (1 * sizeof (IOFile)); + infiles [0] = IEEEopen (argv [1], "r"); + if (! IOisValid (infiles [0])) + { + printf ("Cannot open input file '%s'\n", argv [1]); + return (-1); + } + outfile = IEEEopen (argv [2], "w"); + if (! IOisValid (outfile)) + { + printf ("Cannot open output file '%s'\n", argv [2]); + return (-1); + } + + /* OK so now read the 'GH$xxx' attributes which describe how the data + was written. + Note that these attributes are attached to the last chunked dataset + of the very first Cactus variable output. Since we don't know yet + into how many chunks a dataset is splitted we have to seek here + until we find the attributes. */ + for (dataset = 0; dataset < IOnDatasets (infiles [0]); dataset++) + { + IOseek (infiles [0], dataset); + /* find the 'GH$nprocs' attribute, + the other attributes must be in that dataset too */ + attno = IOreadAttributeInfo (infiles [0], "GH$nprocs", &ntype, &len); + if (attno >= 0) + break; + } + if (attno < 0) + { + printf ("Cannot find 'GH$nprocs' attribute !\n"); + return (-1); + } + if (IOreadAttribute (infiles [0], attno, &nprocs) < 0) + { + printf ("Cannot read 'GH$nprocs' attribute !\n"); + return (-1); + } + attno = IOreadAttributeInfo (infiles [0], "GH$ioproc_every", &ntype, &len); + if (attno < 0) + { + printf ("Cannot find 'GH$ioproc_every' attribute !\n"); + return (-1); + } + if (IOreadAttribute (infiles [0], attno, &ioproc_every) < 0) + { + printf ("Cannot read 'GH$ioproc_every' attribute !\n"); + return (-1); + } + nioprocs = nprocs / ioproc_every; + if (nprocs % ioproc_every) + nioprocs++; + + /* check if the input file(s) is already unchunked */ + /* Cactus 3.x didn't store the 'unchunked' attribute + so we can check only Cactus 4 data files */ + attno = IOreadAttributeInfo (infiles [0], "unchunked", &ntype, &len); + if (attno >= 0) + { + if (IOreadAttribute (infiles [0], attno, &unchunked) < 0) + { + printf ("Cannot read 'GH$ioproc_every' attribute !\n"); + return (-1); + } + if (unchunked) + { + printf ("IEEEIO file '%s' already contains unchunked data !\n", argv [1]); + return (0); + } + } + + printf ("Recombining IEEEIO data from %d processors, " + "output was performed by %d processors\n", nprocs, nioprocs); + + /* seek back to first dataset */ + if (dataset > 0) + IOseek (infiles [0], 0); + + /* allocate memory for arrays */ + infiles = (IOFile *) realloc (infiles, nioprocs * sizeof (IOFile)); + fnames = (char **) malloc (nioprocs * sizeof (char *)); + nDatasets = (int *) malloc (nioprocs * sizeof (int)); + + /* Now check that all chunked input files can be opened */ + /* Also collect the number of datasets here */ + if (nioprocs == 1) + { + /* not much to be done here */ + nDatasets [0] = IOnDatasets (infiles [0]); + fnames [0] = argv [1]; + } + else + { + char *tmp, fname_template [100]; + + /* close the file (it might not be the one from processor 0) */ + IOclose (infiles [0]); + + /* Get the basename of input file(s) */ + if ((tmp = strstr (argv [1], ".file_")) == NULL) + { + printf ("Cannot parse file name !\n"); + printf ("Is '%s' really a chunked Cactus IEEEIO file ?\n", argv [1]); + return (-1); + } + + /* build the filename template */ + strncpy (fname_template, argv [1], tmp - argv [1] + 6); + fname_template [tmp - argv [1] + 6] = 0; + strcat (fname_template, "%d.ieee"); + + /* now loop through all the files */ + for (ioproc = 0; ioproc < nioprocs; ioproc++) + { + /* build the input filename */ + fnames [ioproc] = (char *) malloc (strlen (fname_template) + 10); + sprintf (fnames [ioproc], fname_template, ioproc); + infiles [ioproc] = IEEEopen (fnames [ioproc], "r"); + if (! IOisValid (infiles [ioproc])) + { + printf ("Cannot open chunked IEEEIO input file '%s' !\n", + fnames [ioproc]); + return (-1); + } + + nDatasets [ioproc] = IOnDatasets (infiles [ioproc]); + + /* close file if filehandle limit would be exceeded */ + if (ioproc > max_filehandles) + IOclose (infiles [ioproc]); + } + } + + /* OK great and start going through the files. Generically these + will be multiple chunked files. So do an outer loop over + nioprocs and an inner loop over the set. This means we need + to keep the current set in an array for each file. + */ + currset = (int *) calloc (nioprocs, sizeof (int)); + iters = (Int *) malloc (nioprocs * sizeof (Int)); + name = (char **) calloc (nioprocs, sizeof (char *)); + currname = NULL; + + /* For each data set in file 0; Note this makes the (implicit but + important) assumption that you are working on a set of files which + make sense together. + */ + while (currset [0] < nDatasets [0]) + { + +#ifdef VERBOSE + printf("\n"); + printf("currset[0] = %d\n",currset[0]); + printf("infiles[0]->nDatasets() = %d\n\n", nDatasets [0]); +#endif + + /* Outer loop over each IO proc */ + for (ioproc = 0 ; ioproc < nioprocs ; ioproc++) + { +#ifdef VERBOSE + printf("ioproc = %d\n\n",ioproc); +#endif + + /* Re-open the file if it was closed before */ + if (ioproc > max_filehandles) + { + infiles [ioproc] = IEEEopen (fnames [ioproc], "r"); + if (! IOisValid (infiles [ioproc])) + { + printf ("Cannot reopen input file '%s'\n", fnames [ioproc]); + return (-1); + } + } + + /* keep the set where ioproc 0 will copy the attributes from later on */ + if (ioproc == 0) + attrset = currset [ioproc]; + + /* Seek to the top dataset and find out the group type */ + IOseek (infiles [ioproc], currset [ioproc]); + attno = IOreadAttributeInfo (infiles [ioproc], "grouptype", &ntype, &len); + if (attno < 0) + { + printf ("Cannot find 'grouptype' attribute in input file '%s' !\n", + fnames [ioproc]); + printf ("Is this really a Cactus file ?\n"); + return (-1); + } + IOreadAttribute (infiles [ioproc], attno, >ype); + + if (gtype == GROUP_SCALAR) + iters [ioproc] = 0; + else + { + /* Find out the iteration number */ + attno = IOreadAttributeInfo (infiles [ioproc], "chunk_dataset", &ntype, + &len); + if (attno < 0) + { + printf ("Cannot find 'chunk_dataset' attribute " + "in input file '%s' !\n", fnames [ioproc]); + printf ("Is this really a chunked Cactus IEEEIO file ?\n"); + return (-1); + } + IOreadAttribute (infiles [ioproc], attno, &iters [ioproc]); + } + currit = iters [ioproc]; + + /* Find out the name of the dataset */ + attno = IOreadAttributeInfo (infiles [ioproc], "name", &ntype, &len); +#ifdef VERBOSE + printf("Reading attribute\n"); + printf("name: attno = %d\n", attno); +#endif + if (attno < 0) + { + printf ("Cannot find name of dataset in input file '%s' !\n", + fnames [ioproc]); + printf ("Is this really a Cactus IEEEIO file ?\n"); + return (-1); + } + if (name [ioproc]) + free (name [ioproc]); + if (currname) + free (currname); + name [ioproc] = (char *) malloc ((len+1) * sizeof (char)); + IOreadAttribute (infiles [ioproc], attno, name [ioproc]); + currname = strdup (name [ioproc]); +#ifdef VERBOSE + printf ("name = %s\n", name [ioproc]); +#endif + + /* If ioproc == 0, we are at the top, so reserve our chunk */ + if (ioproc == 0) + { + /* Now get the global size and reserve the chunk */ + attno = IOreadAttributeInfo (infiles [0], "global_size", &ntype, &len); + if (attno < 0) + { + printf ("Cannot find global size attribute !\n"); + return (-1); + } + if (ntype != INT32 || len != 3) + { + printf ("Inconsistent global size attribute !\n"); + return (-1); + } + IOreadAttribute (infiles [ioproc], attno, I_gsz); + printf ("Global size: %d %d %d\n", I_gsz [0], I_gsz [1], I_gsz [2]); + printf (" Beginning data copy\n"); + + /* Find out what kind of data we are dealing with */ + IOreadInfo (infiles [ioproc], &ntype, &rank, dims, MAXDIM); + + if (gtype != GROUP_SCALAR) + { + /* copy Int to int */ + for (i = 0; i < rank; i++) + gsz [i] = I_gsz [i]; + /* So now the writer can reserve a chunk */ + IOreserveChunk (outfile, ntype, rank, gsz); + } + } + + /* Inner loop over each chunk of a single dataset + (same iteration, same name) */ + while (currit == iters [ioproc] && ! strcmp (currname, name [ioproc])) + { + printf (" - file %d set %d iteration %d name %s\n", + ioproc, currset [ioproc], currit, currname); + + /* Read the data */ + IOseek (infiles [ioproc], currset [ioproc]); + IOreadInfo (infiles [ioproc], &ntype, &rank, dims, MAXDIM); + + data = malloc (IOnBytes (ntype, rank, dims)); + IOread (infiles [ioproc], data); + + if (gtype == GROUP_SCALAR) + { + /* write SCALAR only once ! */ + if (ioproc == 0) + IOwrite (outfile, ntype, rank, dims, data); + } + else + { + /* Get the LB */ + attno = IOreadAttributeInfo (infiles [ioproc], "chunk_origin", &ntype, + &len); + if (attno < 0) + { + printf ("Cannot find chunk_origin !\n"); + return (-1); + } + if (ntype != INT32 || len != 3) + { + printf ("Inconsistent chunk_origin attribute !\n"); + return (-1); + } + IOreadAttribute (infiles [ioproc], attno, I_chunk_lb); + printf (" - dims : %d %d %d LB : %d %d %d\n", + dims [0], dims [1], dims [2], + I_chunk_lb [0], I_chunk_lb [1], I_chunk_lb [2]); + + /* copy from int to Int */ + for (i = 0; i < rank; i++) + chunk_lb [i] = I_chunk_lb [i]; + + /* Write the data */ + IOwriteChunk (outfile, dims, chunk_lb, data); + } + + /* free data buffer */ + free (data); + + /* Now advance and see if the next set has our iteration number */ + currset [ioproc] ++; + if (currset [ioproc] >= nDatasets [ioproc]) + currit = iters [ioproc] - 1; + else if (gtype == GROUP_SCALAR) + currit = iters [ioproc] - 1; + else + { + IOseek (infiles [ioproc], currset [ioproc]); + /* Get the iteration */ + attno = IOreadAttributeInfo (infiles [ioproc], "chunk_dataset", + &ntype, &len); + if (attno < 0) + { + printf ("Cannot read iteration number of chunked dataset %d in " + "input file '%s'\n", currset [ioproc], fnames [ioproc]); + return (-1); + } + IOreadAttribute (infiles [ioproc], attno, &iters [ioproc]); + + /* Get the name */ + attno = IOreadAttributeInfo (infiles [ioproc], "name", &ntype, &len); +#ifdef VERBOSE + printf("Reading attribute ...\n"); + printf("name: attno = %d\n",attno); +#endif + /* Cheap fix for now */ + if (attno >= 0) + { + free (name [ioproc]); + name [ioproc] = (char *) malloc ((len+1) * sizeof (char)); + IOreadAttribute (infiles [ioproc], attno, name [ioproc]); +#ifdef VERBOSE + printf ("name = %s\n\n", name [ioproc]); +#endif + } + } +#ifdef VERBOSE + printf ("\n"); +#endif + } /* end of inner loop over all chunks of a single dataset */ + + /* close file if filehandle limit would be exceeded */ + if (ioproc > max_filehandles) + IOclose (infiles [ioproc]); + + } /* end of outer loop over all nioprocs files */ + + /* Now copy all attributes */ + /* Re-open the file if it was closed before */ + if (max_filehandles < 0) + { + infiles [0] = IEEEopen (fnames [0], "r"); + if (! IOisValid (infiles [0])) + { + printf ("Cannot reopen input file '%s'\n", fnames [0]); + return (-1); + } + } + + /* NOTE: Cactus 4.x stores the common attributes in the first chunked + dataset so we have to seek back there. */ + printf (" Copying attributes of sets %d to %d\n", attrset, currset [0]); + IOseek (infiles [0], attrset); + + do + { + /* Read the dataset info */ + IOreadInfo (infiles [0], &ntype, &rank, dims, MAXDIM); + + nattrs = IOnAttributes (infiles [0]); + for (attr = 0; attr < nattrs; attr++) + { + char name [MAXNAMELEN]; + Int attrBuffer [256]; /* should be big enough for all attributes */ + Long nelems; + int attrElems; + + IOreadIndexedAttributeInfo (infiles [0], attr, name, &ntype, &nelems, + MAXNAMELEN); + attrElems = nelems; + printf ("Reading attribute : %s\n", name); +#ifdef VERBOSE + printf ("Reading attribute : %s\n", name); +#endif + if (IOnBytes (ntype, 1, &attrElems) > sizeof (attrBuffer)) + { + printf ("buffer overflow reading attribute contents !\n"); + return (-1); + } + IOreadAttribute (infiles [0], attr, attrBuffer); + + /* reset 'GH$nprocs', 'GH$ioproc_every', and 'unchunked' attributes + in the unchunked file */ + if (! strcmp (name, "GH$nprocs")) + attrBuffer [0] = 1; + if (! strcmp (name, "GH$ioproc_every")) + attrBuffer [0] = nprocs; + if (! strcmp (name, "unchunked")) + attrBuffer [0] = 1; + IOwriteAttribute (outfile, name, ntype, nelems, attrBuffer); + } + + attrset++; + + } while (attrset < currset [0]); + + /* close file if filehandle limit would be exceeded */ + if (max_filehandles < 0) + IOclose (infiles [0]); + + } /* end of loop over all datasets in infile [0] */ + + /* close all open files */ + for (ioproc = 0; ioproc < nioprocs; ioproc++) + { + if (ioproc <= max_filehandles) + IOclose (infiles [ioproc]); + free (infiles [ioproc]); + } + IOclose (outfile); + + /* clean up */ + free (currset); + free (currname); + + free (nDatasets); + free (infiles); +} |