aboutsummaryrefslogtreecommitdiff
path: root/src/util
diff options
context:
space:
mode:
authortradke <tradke@ebee0441-1374-4afa-a3b5-247f3ba15b9a>2000-05-17 11:31:51 +0000
committertradke <tradke@ebee0441-1374-4afa-a3b5-247f3ba15b9a>2000-05-17 11:31:51 +0000
commit05519b321d7931eebd34f2246fd2ed54442481aa (patch)
tree9901a6d3e0d12d3b27514de5c580911ae7938291 /src/util
parente5af9dfe4bfd948d2301e7104548060531f9f43c (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.c533
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, &gtype);
+
+ 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);
+}