sandbox/Antoonvh/dump2.h
These altarnatives to dump()
are based on the existing dump()
functionality and the existing helper functions are re-used.
#include "output.h"
dump2("name")
lets each thread write its onw file name-
x. with x the pid()
with quite possibly some leading zeros (for upto 100000 cores). Such that,
cat name-* > name
can be used to concatenate the files for e.g. restore()
and bview
.
trace
void dump2 (struct Dump p)
{
FILE * fp;
char * file = p.file;
if (file == NULL) {
fprintf (ferr, "dump(): must specify a file name when using MPI\n");
exit(1);
}
char * name = NULL;
if (file) {
char pd[97];
sprintf(pd, "-%05d", pid());
name = (char *) malloc (strlen(file) + 99);
strcpy (name, file);
strcat (name, pd);
if ((fp = fopen (name, "w")) == NULL) {
perror (name);
exit (1);
}
}
assert (fp);
scalar * dlist = dump_list (p.list ? p.list : all);
scalar size[];
scalar * list = list_concat ({size}, dlist); free (dlist);
struct DumpHeader header = { t, list_len(list), iter, depth(), npe(),
dump_version };
#if MULTIGRID_MPI
for (int i = 0; i < dimension; i++)
(&header.n.x)[i] = mpi_dims[i];
MPI_Barrier (MPI_COMM_WORLD);
#endif
if (pid() == 0)
dump_header (fp, &header, list);
subtree_size (size, false);
foreach_cell() {
unsigned flags = is_leaf(cell) ? leaf : 0;
if (is_local(cell)) {
if (fwrite (&flags, sizeof(unsigned), 1, fp) < 1) {
perror ("dump(): error while writing flags");
exit (1);
}
for (scalar s in list)
if (fwrite (&s[], sizeof(double), 1, fp) < 1) {
perror ("dump(): error while writing scalars");
exit (1);
}
}
if (is_leaf(cell))
continue;
}
free (list);
if (file) {
fclose (fp);
free (name);
}
}
dump3()
shoud work well
trace
void dump3 (struct Dump p)
{
FILE * fh = p.fp;
char def[] = "dump", * file = p.file ? p.file : p.fp ? NULL : def;
#if _MPI
if (fh != NULL || file == NULL) {
fprintf (ferr, "dump(): must specify a file name when using MPI\n");
exit(1);
}
#endif
char * name = NULL;
if (file) {
name = (char *) malloc (strlen(file) + 2);
strcpy (name, file);
if (p.buffered)
strcat (name, "~");
if ((fh = fopen (name, "w")) == NULL) {
perror (name);
exit (1);
}
}
if (fh == NULL) {
perror (name);
exit (1);
}
scalar * dlist = dump_list (p.list ? p.list : all);
scalar size[];
scalar * list = list_concat ({size}, dlist); free (dlist);
struct DumpHeader header = {t, list_len(list), iter, depth(), npe(),
dump_version};
#if MULTIGRID_MPI
for (int i = 0; i < dimension; i++)
(&header.n.x)[i] = mpi_dims[i];
MPI_Barrier (MPI_COMM_WORLD);
#endif
if (pid() == 0)
dump_header (fh, &header, list);
For parallel writing, each thread starts with an offset.
#if _MPI
long offset = 0;
int cell_size = sizeof(unsigned) + header.len*sizeof(double);
int sizeofheader = sizeof(header) + 4*sizeof(double);
for (scalar s in list)
sizeofheader += sizeof(unsigned) + sizeof(char)*strlen(s.name);
scalar index = {-1};
index = new scalar;
z_indexing (index, false);
foreach_cell() {
if (is_local(cell)) {
if (offset == (long)0)
offset = sizeofheader + index[]*cell_size;
break;
}
}
delete ({index});
fseek (fh, offset, SEEK_SET);
#endif
To help encode the tree-grid structure, the size of each subtree is computed and dumped for each cell.
subtree_size (size, false);
foreach_cell() {
if (is_local(cell)) {
unsigned flags = is_leaf(cell) ? leaf : 0;
fwrite (&flags, 1, sizeof(unsigned), fh);
for (scalar s in list)
fwrite (&s[], 1, sizeof(double), fh);
}
if (is_leaf(cell))
continue;
}
free (list);
if (file) {
fclose (fh);
if (p.buffered && pid() == 0)
rename (name, file);
free (name);
}
}
dump4()
employs functions for output defined by the MPI library.
So-called ‘hints’ may be passed by modifying MPI_INFO
for optimal parallel output performance.
#if _MPI
MPI_Info MPI_INFO;
static void MPI_dump_header (MPI_File fp, struct DumpHeader * header, scalar * list) {
MPI_Status status;
MPI_File_write (fp, header, sizeof(struct DumpHeader), MPI_BYTE , &status);
for (scalar s in list) {
unsigned len = strlen (s.name);
MPI_File_write (fp, &len, 1, MPI_UNSIGNED, &status);
MPI_File_write (fp, s.name, len, MPI_CHAR, &status);
}
double o[4] = {X0, Y0, Z0, L0};
MPI_File_write (fp, o, 4, MPI_DOUBLE, &status);
}
trace
void MPI_dump (struct Dump p) {
if (p.fp) {
fprintf (ferr, "You should provide a file name instead of a pointer\n");
exit (1);
}
MPI_File fh;
char * file = p.file;
if (file == NULL) {
fprintf (ferr, "dump(): must specify a file name when using MPI_dump\n");
exit(1);
}
char name[strlen(file) + 2];
strcpy (name, file);
if (MPI_INFO == NULL)
MPI_File_open (MPI_COMM_WORLD, name,
MPI_MODE_WRONLY | MPI_MODE_CREATE,
MPI_INFO_NULL, &fh);
else
MPI_File_open (MPI_COMM_WORLD, name,
MPI_MODE_WRONLY | MPI_MODE_CREATE,
MPI_INFO, &fh);
scalar * dlist = dump_list (p.list ? p.list : all);
scalar size[];
scalar * list = list_concat ({size}, dlist);
free (dlist);
struct DumpHeader header = {t, list_len(list), iter, depth(),
npe(), dump_version };
#if MULTIGRID_MPI
for (int i = 0; i < dimension; i++)
(&header.n.x)[i] = mpi_dims[i];
MPI_Barrier (MPI_COMM_WORLD);
#endif
if (pid() == 0)
MPI_dump_header (fh, &header, list);
scalar index = {-1};
index = new scalar;
z_indexing (index, false);
int cell_size = sizeof(unsigned) + header.len*sizeof(double);
int sizeofheader = sizeof(header) + 4*sizeof(double);
for (scalar s in list)
sizeofheader += sizeof(unsigned) + sizeof(char)*strlen(s.name);
subtree_size (size, false);
long offset = 0;
foreach_cell() { //We find the index of the first local cell
if (is_local(cell)) {
if (offset == (long)0)
offset = sizeofheader + index[]*cell_size;
break;
}
}
MPI_File_seek (fh, offset , MPI_SEEK_SET);
MPI_Status status;
foreach_cell() {
if (is_local(cell)) {
unsigned flags = is_leaf(cell) ? leaf : 0;
MPI_File_write(fh, &flags,1,MPI_UNSIGNED, &status);
for (scalar s in list)
MPI_File_write(fh, &s[],1,MPI_DOUBLE, &status);
}
if (is_leaf(cell))
continue;
}
delete ({index});
free (list);
MPI_File_close (&fh);
}
#endif