mirror of
https://github.com/HDFGroup/hdf5.git
synced 2024-11-27 02:10:55 +08:00
2521c4084c
Anti-feature Description: Revert changes to H5G_stat_t struct, to make it compatible with the 1.6.x branch again. The information that was added to the H5G_stat_t struct will be reported through other API routines. Platforms tested: FreeBSD 4.11 (sleipnir) w/C++ Linux 2.4/64 (mir) w/C++ & Fortran Solaris 2.9 (shanti)
1100 lines
31 KiB
C
1100 lines
31 KiB
C
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
* Copyright by the Board of Trustees of the University of Illinois. *
|
|
* All rights reserved. *
|
|
* *
|
|
* This file is part of HDF5. The full HDF5 copyright notice, including *
|
|
* terms governing use, modification, and redistribution, is contained in *
|
|
* the files COPYING and Copyright.html. COPYING can be found at the root *
|
|
* of the source code distribution tree; Copyright.html can be found at the *
|
|
* root level of an installed copy of the electronic HDF5 document set and *
|
|
* is linked from the top-level documents page. It can also be found at *
|
|
* http://hdf.ncsa.uiuc.edu/HDF5/doc/Copyright.html. If you do not have *
|
|
* access to either file, you may request a copy from hdfhelp@ncsa.uiuc.edu. *
|
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
|
|
#include <stdlib.h>
|
|
#include "h5diff.h"
|
|
#include "H5private.h"
|
|
#include "ph5diff.h"
|
|
|
|
/*
|
|
* Debug printf macros. The prefix allows output filtering by test scripts.
|
|
*/
|
|
#ifdef H5DIFF_DEBUG
|
|
#define h5diffdebug(x) fprintf(stderr, "h5diff debug: " x)
|
|
#define h5diffdebug2(x1, x2) fprintf(stderr, "h5diff debug: " x1, x2)
|
|
#define h5diffdebug3(x1, x2, x3) fprintf(stderr, "h5diff debug: " x1, x2, x3)
|
|
#define h5diffdebug4(x1, x2, x3, x4) fprintf(stderr, "h5diff debug: " x1, x2, x3, x4)
|
|
#define h5diffdebug5(x1, x2, x3, x4, x5) fprintf(stderr, "h5diff debug: " x1, x2, x3, x4, x5)
|
|
#else
|
|
#define h5diffdebug(x)
|
|
#define h5diffdebug2(x1, x2)
|
|
#define h5diffdebug3(x1, x2, x3)
|
|
#define h5diffdebug4(x1, x2, x3, x4)
|
|
#define h5diffdebug5(x1, x2, x3, x4, x5)
|
|
#endif
|
|
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: print_objname
|
|
*
|
|
* Purpose: print object name only when:
|
|
* 1) verbose mode
|
|
* 2) when diff was found (normal mode)
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
int
|
|
print_objname (diff_opt_t * options, hsize_t nfound)
|
|
{
|
|
return ((options->m_verbose || nfound) && !options->m_quiet) ? 1 : 0;
|
|
}
|
|
|
|
#ifdef H5_HAVE_PARALLEL
|
|
/*-------------------------------------------------------------------------
|
|
* Function: phdiff_dismiss_workers
|
|
*
|
|
* Purpose: tell all workers to end.
|
|
*
|
|
* Return: none
|
|
*
|
|
* Programmer: Albert Cheng
|
|
*
|
|
* Date: Feb 6, 2005
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
void phdiff_dismiss_workers(void)
|
|
{
|
|
int i;
|
|
for(i=1; i<g_nTasks; i++)
|
|
MPI_Send(NULL, 0, MPI_BYTE, i, MPI_TAG_END, MPI_COMM_WORLD);
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: print_manager_output
|
|
*
|
|
* Purpose: special function that prints any output accumulated by the
|
|
* manager task.
|
|
*
|
|
* Return: none
|
|
*
|
|
* Programmer: Leon Arber
|
|
*
|
|
* Date: Feb 7, 2005
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
void print_manager_output(void)
|
|
{
|
|
/* If there was something we buffered, let's print it now */
|
|
if( (outBuffOffset>0) && g_Parallel)
|
|
{
|
|
printf("%s", outBuff);
|
|
|
|
if(overflow_file)
|
|
{
|
|
int tmp;
|
|
|
|
rewind(overflow_file);
|
|
while((tmp = getc(overflow_file)) >= 0)
|
|
putchar(tmp);
|
|
|
|
fclose(overflow_file);
|
|
overflow_file = NULL;
|
|
}
|
|
|
|
fflush(stdout);
|
|
memset(outBuff, 0, OUTBUFF_SIZE);
|
|
outBuffOffset = 0;
|
|
}
|
|
else if( (outBuffOffset>0) && !g_Parallel)
|
|
{
|
|
fprintf(stderr, "h5diff error: outBuffOffset>0, but we're not in parallel!\n");
|
|
}
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: print_incoming_data
|
|
*
|
|
* Purpose: special function that prints any output that has been sent to the manager
|
|
* and is currently sitting in the incoming message queue
|
|
*
|
|
* Return: none
|
|
*
|
|
* Programmer: Leon Arber
|
|
*
|
|
* Date: March 7, 2005
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
static void print_incoming_data(void)
|
|
{
|
|
char data[PRINT_DATA_MAX_SIZE+1];
|
|
int incomingMessage;
|
|
MPI_Status Status;
|
|
|
|
do
|
|
{
|
|
MPI_Iprobe(MPI_ANY_SOURCE, MPI_TAG_PRINT_DATA, MPI_COMM_WORLD, &incomingMessage, &Status);
|
|
if(incomingMessage)
|
|
{
|
|
memset(data, 0, PRINT_DATA_MAX_SIZE+1);
|
|
MPI_Recv(data, PRINT_DATA_MAX_SIZE, MPI_CHAR, Status.MPI_SOURCE, MPI_TAG_PRINT_DATA, MPI_COMM_WORLD, &Status);
|
|
|
|
printf("%s", data);
|
|
}
|
|
} while(incomingMessage);
|
|
}
|
|
#endif
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: h5diff
|
|
*
|
|
* Purpose: public function, can be called in an application program.
|
|
* return differences between 2 HDF5 files
|
|
*
|
|
* Return: Number of differences found.
|
|
*
|
|
* Programmer: Pedro Vicente, pvn@ncsa.uiuc.edu
|
|
*
|
|
* Date: October 22, 2003
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
hsize_t h5diff(const char *fname1,
|
|
const char *fname2,
|
|
const char *objname1,
|
|
const char *objname2,
|
|
diff_opt_t *options)
|
|
{
|
|
int nobjects1, nobjects2;
|
|
trav_info_t *info1 = NULL;
|
|
trav_info_t *info2 = NULL;
|
|
hid_t file1_id=(-1), file2_id=(-1);
|
|
char filenames[2][1024];
|
|
hsize_t nfound = 0;
|
|
|
|
memset(filenames, 0, 1024*2);
|
|
|
|
if (options->m_quiet &&
|
|
(options->m_verbose || options->m_report))
|
|
{
|
|
printf("Error: -q (quiet mode) cannot be added to verbose or report modes\n");
|
|
options->err_stat=1;
|
|
return 0;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* open the files first; if they are not valid, no point in continuing
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
/* disable error reporting */
|
|
H5E_BEGIN_TRY
|
|
{
|
|
/* Open the files */
|
|
if ((file1_id = H5Fopen (fname1, H5F_ACC_RDONLY, H5P_DEFAULT)) < 0)
|
|
{
|
|
printf ("h5diff: <%s>: unable to open file\n", fname1);
|
|
options->err_stat = 1;
|
|
|
|
#ifdef H5_HAVE_PARALLEL
|
|
if(g_Parallel)
|
|
{
|
|
/* Let tasks know that they won't be needed */
|
|
phdiff_dismiss_workers();
|
|
}
|
|
#endif
|
|
|
|
goto out;
|
|
}
|
|
if ((file2_id = H5Fopen (fname2, H5F_ACC_RDONLY, H5P_DEFAULT)) < 0)
|
|
{
|
|
printf ("h5diff: <%s>: unable to open file\n", fname2);
|
|
options->err_stat = 1;
|
|
|
|
#ifdef H5_HAVE_PARALLEL
|
|
if(g_Parallel)
|
|
{
|
|
/* Let tasks know that they won't be needed */
|
|
phdiff_dismiss_workers();
|
|
}
|
|
#endif
|
|
|
|
goto out;
|
|
}
|
|
/* enable error reporting */
|
|
}
|
|
H5E_END_TRY;
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* get the number of objects in the files
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
nobjects1 = h5trav_getinfo (file1_id, NULL, 0);
|
|
nobjects2 = h5trav_getinfo (file2_id, NULL, 0);
|
|
|
|
if (nobjects1 < 0 || nobjects2 < 0)
|
|
{
|
|
printf ("Error: Could not get get file contents\n");
|
|
options->err_stat = 1;
|
|
#ifdef H5_HAVE_PARALLEL
|
|
if(g_Parallel)
|
|
{
|
|
/* Let tasks know that they won't be needed */
|
|
phdiff_dismiss_workers();
|
|
}
|
|
#endif
|
|
goto out;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* get the list of objects in the files
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
info1 = (trav_info_t *) malloc (nobjects1 * sizeof (trav_info_t));
|
|
info2 = (trav_info_t *) malloc (nobjects2 * sizeof (trav_info_t));
|
|
if (info1 == NULL || info2 == NULL)
|
|
{
|
|
printf ("Error: Not enough memory for object list\n");
|
|
options->err_stat = 1;
|
|
if (info1) h5trav_freeinfo (info1, nobjects1);
|
|
if (info2) h5trav_freeinfo (info2, nobjects1);
|
|
#ifdef H5_HAVE_PARALLEL
|
|
if(g_Parallel)
|
|
{
|
|
/* Let tasks know that they won't be needed */
|
|
phdiff_dismiss_workers();
|
|
}
|
|
#endif
|
|
goto out;
|
|
}
|
|
|
|
h5trav_getinfo (file1_id, info1, 0);
|
|
h5trav_getinfo (file2_id, info2, 0);
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* object name was supplied
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
if (objname1)
|
|
{
|
|
|
|
#ifdef H5_HAVE_PARALLEL
|
|
if(g_Parallel)
|
|
{
|
|
/* Let tasks know that they won't be needed */
|
|
phdiff_dismiss_workers();
|
|
}
|
|
#endif
|
|
assert (objname2);
|
|
options->cmn_objs = 1; /* eliminate warning */
|
|
nfound = diff_compare (file1_id, fname1, objname1, nobjects1, info1,
|
|
file2_id, fname2, objname2, nobjects2, info2,
|
|
options);
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* compare all
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
else
|
|
{
|
|
|
|
#ifdef H5_HAVE_PARALLEL
|
|
if(g_Parallel)
|
|
{
|
|
int i;
|
|
|
|
if( (strlen(fname1) > 1024) || (strlen(fname2) > 1024))
|
|
{
|
|
fprintf(stderr, "The parallel diff only supports path names up to 1024 characters\n");
|
|
MPI_Abort(MPI_COMM_WORLD, 0);
|
|
}
|
|
|
|
strcpy(filenames[0], fname1);
|
|
strcpy(filenames[1], fname2);
|
|
|
|
/* Alert the worker tasks that there's going to be work. */
|
|
|
|
for(i=1; i<g_nTasks; i++)
|
|
MPI_Send(filenames, 1024*2, MPI_CHAR, i, MPI_TAG_PARALLEL, MPI_COMM_WORLD);
|
|
}
|
|
#endif
|
|
nfound = diff_match (file1_id, nobjects1, info1,
|
|
file2_id, nobjects2, info2, options);
|
|
}
|
|
|
|
h5trav_freeinfo (info1, nobjects1);
|
|
h5trav_freeinfo (info2, nobjects2);
|
|
|
|
out:
|
|
/* close */
|
|
H5E_BEGIN_TRY
|
|
{
|
|
H5Fclose (file1_id);
|
|
H5Fclose (file2_id);
|
|
}
|
|
H5E_END_TRY;
|
|
|
|
return nfound;
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: diff_match
|
|
*
|
|
* Purpose: Find common objects; the algorithm used for this search is the
|
|
* cosequential match algorithm and is described in
|
|
* Folk, Michael; Zoellick, Bill. (1992). File Structures. Addison-Wesley.
|
|
*
|
|
* Return: Number of differences found
|
|
*
|
|
* Programmer: Pedro Vicente, pvn@ncsa.uiuc.edu
|
|
*
|
|
* Date: May 9, 2003
|
|
*
|
|
* Modifications: Jan 2005 Leon Arber, larber@uiuc.edu
|
|
* Added support for parallel diffing
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
hsize_t diff_match (hid_t file1_id,
|
|
int nobjects1,
|
|
trav_info_t * info1,
|
|
hid_t file2_id,
|
|
int nobjects2,
|
|
trav_info_t * info2,
|
|
diff_opt_t * options)
|
|
{
|
|
int more_names_exist = (nobjects1 > 0 && nobjects2 > 0) ? 1 : 0;
|
|
trav_table_t *table = NULL;
|
|
int cmp;
|
|
int curr1 = 0;
|
|
int curr2 = 0;
|
|
unsigned infile[2];
|
|
char c1, c2;
|
|
hsize_t nfound = 0;
|
|
int i;
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* build the list
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
trav_table_init (&table);
|
|
|
|
while (more_names_exist)
|
|
{
|
|
/* criteria is string compare */
|
|
cmp = strcmp (info1[curr1].name, info2[curr2].name);
|
|
if (cmp == 0)
|
|
{
|
|
infile[0] = 1;
|
|
infile[1] = 1;
|
|
trav_table_addflags (infile, info1[curr1].name, info1[curr1].type,
|
|
table);
|
|
|
|
curr1++;
|
|
curr2++;
|
|
}
|
|
else if (cmp < 0)
|
|
{
|
|
infile[0] = 1;
|
|
infile[1] = 0;
|
|
trav_table_addflags (infile, info1[curr1].name, info1[curr1].type,
|
|
table);
|
|
curr1++;
|
|
}
|
|
else
|
|
{
|
|
infile[0] = 0;
|
|
infile[1] = 1;
|
|
trav_table_addflags (infile, info2[curr2].name, info2[curr2].type,
|
|
table);
|
|
curr2++;
|
|
}
|
|
|
|
more_names_exist = (curr1 < nobjects1 && curr2 < nobjects2) ? 1 : 0;
|
|
|
|
|
|
} /* end while */
|
|
|
|
/* list1 did not end */
|
|
if (curr1 < nobjects1)
|
|
{
|
|
while (curr1 < nobjects1)
|
|
{
|
|
infile[0] = 1;
|
|
infile[1] = 0;
|
|
trav_table_addflags (infile, info1[curr1].name, info1[curr1].type,
|
|
table);
|
|
curr1++;
|
|
}
|
|
}
|
|
|
|
/* list2 did not end */
|
|
if (curr2 < nobjects2)
|
|
{
|
|
while (curr2 < nobjects2)
|
|
{
|
|
infile[0] = 0;
|
|
infile[1] = 1;
|
|
trav_table_addflags (infile, info2[curr2].name, info2[curr2].type,
|
|
table);
|
|
curr2++;
|
|
}
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* print the list
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
if (options->m_verbose)
|
|
{
|
|
printf ("\n");
|
|
printf ("file1 file2\n");
|
|
printf ("---------------------------------------\n");
|
|
for (i = 0; i < table->nobjs; i++)
|
|
{
|
|
c1 = (table->objs[i].flags[0]) ? 'x' : ' ';
|
|
c2 = (table->objs[i].flags[1]) ? 'x' : ' ';
|
|
printf ("%5c %6c %-15s\n", c1, c2, table->objs[i].name);
|
|
}
|
|
printf ("\n");
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* do the diff for common objects
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
{
|
|
#ifdef H5_HAVE_PARALLEL
|
|
char* workerTasks = malloc((g_nTasks-1) * sizeof(char));
|
|
int n;
|
|
int busyTasks=0;
|
|
struct diffs_found nFoundbyWorker;
|
|
struct diff_args args;
|
|
int havePrintToken = 1;
|
|
MPI_Status Status;
|
|
|
|
/*set all tasks as free */
|
|
memset(workerTasks, 1, g_nTasks-1);
|
|
#endif
|
|
|
|
for (i = 0; i < table->nobjs; i++)
|
|
{
|
|
if (table->objs[i].flags[0] && table->objs[i].flags[1])
|
|
{
|
|
#ifdef H5_HAVE_PARALLEL
|
|
int workerFound = 0;
|
|
#endif /* H5_HAVE_PARALLEL */
|
|
options->cmn_objs = 1;
|
|
if(!g_Parallel)
|
|
{
|
|
nfound += diff (file1_id,
|
|
table->objs[i].name,
|
|
file2_id,
|
|
table->objs[i].name, options, table->objs[i].type);
|
|
}
|
|
#ifdef H5_HAVE_PARALLEL
|
|
else
|
|
{
|
|
h5diffdebug("beginning of big else block\n");
|
|
/* We're in parallel mode */
|
|
/* Since the data type of diff value is hsize_t which can
|
|
* be arbitary large such that there is no MPI type that
|
|
* matches it, the value is passed between processes as
|
|
* an array of bytes in order to be portable. But this
|
|
* may not work in non-homogeneous MPI environments.
|
|
*/
|
|
|
|
/*Set up args to pass to worker task. */
|
|
if(strlen(table->objs[i].name) > 255)
|
|
{
|
|
printf("The parallel diff only supports object names up to 255 characters\n");
|
|
MPI_Abort(MPI_COMM_WORLD, 0);
|
|
}
|
|
|
|
strcpy(args.name, table->objs[i].name);
|
|
args.options = *options;
|
|
args.type= table->objs[i].type;
|
|
|
|
h5diffdebug2("busyTasks=%d\n", busyTasks);
|
|
/* if there are any outstanding print requests, let's handle one. */
|
|
if(busyTasks > 0)
|
|
{
|
|
int incomingMessage;
|
|
/* check if any tasks freed up, and didn't need to print. */
|
|
MPI_Iprobe(MPI_ANY_SOURCE, MPI_TAG_DONE, MPI_COMM_WORLD, &incomingMessage, &Status);
|
|
|
|
/* first block*/
|
|
if(incomingMessage)
|
|
{
|
|
workerTasks[Status.MPI_SOURCE-1] = 1;
|
|
MPI_Recv(&nFoundbyWorker, sizeof(nFoundbyWorker), MPI_BYTE, Status.MPI_SOURCE, MPI_TAG_DONE, MPI_COMM_WORLD, &Status);
|
|
nfound += nFoundbyWorker.nfound;
|
|
options->not_cmp = options->not_cmp | nFoundbyWorker.not_cmp;
|
|
busyTasks--;
|
|
}
|
|
|
|
/* check to see if the print token was returned. */
|
|
if(!havePrintToken)
|
|
{
|
|
/* If we don't have the token, someone is probably sending us output */
|
|
print_incoming_data();
|
|
|
|
/* check incoming queue for token */
|
|
MPI_Iprobe(MPI_ANY_SOURCE, MPI_TAG_TOK_RETURN, MPI_COMM_WORLD, &incomingMessage, &Status);
|
|
|
|
/* incoming token implies free task. */
|
|
if(incomingMessage)
|
|
{
|
|
workerTasks[Status.MPI_SOURCE-1] = 1;
|
|
MPI_Recv(&nFoundbyWorker, sizeof(nFoundbyWorker), MPI_BYTE, Status.MPI_SOURCE, MPI_TAG_TOK_RETURN, MPI_COMM_WORLD, &Status);
|
|
nfound += nFoundbyWorker.nfound;
|
|
options->not_cmp = options->not_cmp | nFoundbyWorker.not_cmp;
|
|
busyTasks--;
|
|
havePrintToken = 1;
|
|
}
|
|
}
|
|
|
|
/* check to see if anyone needs the print token. */
|
|
if(havePrintToken)
|
|
{
|
|
/* check incoming queue for print token requests */
|
|
MPI_Iprobe(MPI_ANY_SOURCE, MPI_TAG_TOK_REQUEST, MPI_COMM_WORLD, &incomingMessage, &Status);
|
|
if(incomingMessage)
|
|
{
|
|
MPI_Recv(NULL, 0, MPI_BYTE, Status.MPI_SOURCE, MPI_TAG_TOK_REQUEST, MPI_COMM_WORLD, &Status);
|
|
MPI_Send(NULL, 0, MPI_BYTE, Status.MPI_SOURCE, MPI_TAG_PRINT_TOK, MPI_COMM_WORLD);
|
|
havePrintToken = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* check array of tasks to see which ones are free.
|
|
* Manager task never does work, so freeTasks[0] is really
|
|
* worker task 0. */
|
|
|
|
for(n=1; (n<g_nTasks) && !workerFound; n++)
|
|
{
|
|
if(workerTasks[n-1])
|
|
{
|
|
/* send file id's and names to first free worker */
|
|
MPI_Send(&args, sizeof(struct diff_args), MPI_BYTE, n, MPI_TAG_ARGS, MPI_COMM_WORLD);
|
|
|
|
/* increment counter for total number of prints. */
|
|
busyTasks++;
|
|
|
|
/* mark worker as busy */
|
|
workerTasks[n-1] = 0;
|
|
workerFound = 1;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
h5diffdebug2("workerfound is %d \n", workerFound);
|
|
if(!workerFound)
|
|
{
|
|
/* if they were all busy, we've got to wait for one free up before we can move on.
|
|
* if we don't have the token, some task is currently printing so we'll wait for that task to return it. */
|
|
|
|
if(!havePrintToken)
|
|
{
|
|
while(!havePrintToken) {
|
|
int incomingMessage;
|
|
print_incoming_data();
|
|
MPI_Iprobe(MPI_ANY_SOURCE, MPI_TAG_TOK_RETURN, MPI_COMM_WORLD, &incomingMessage, &Status);
|
|
if(incomingMessage)
|
|
{
|
|
MPI_Recv(&nFoundbyWorker, sizeof(nFoundbyWorker), MPI_BYTE, MPI_ANY_SOURCE, MPI_TAG_TOK_RETURN, MPI_COMM_WORLD, &Status);
|
|
havePrintToken = 1;
|
|
nfound += nFoundbyWorker.nfound;
|
|
options->not_cmp = options->not_cmp | nFoundbyWorker.not_cmp;
|
|
/* send this task the work unit. */
|
|
MPI_Send(&args, sizeof(struct diff_args), MPI_BYTE, Status.MPI_SOURCE, MPI_TAG_ARGS, MPI_COMM_WORLD);
|
|
}
|
|
}
|
|
}
|
|
/* if we do have the token, check for task to free up, or wait for a task to request it */
|
|
else
|
|
{
|
|
/* But first print all the data in our incoming queue */
|
|
print_incoming_data();
|
|
MPI_Probe(MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &Status);
|
|
if(Status.MPI_TAG == MPI_TAG_DONE)
|
|
{
|
|
MPI_Recv(&nFoundbyWorker, sizeof(nFoundbyWorker), MPI_BYTE, Status.MPI_SOURCE, MPI_TAG_DONE, MPI_COMM_WORLD, &Status);
|
|
nfound += nFoundbyWorker.nfound;
|
|
options->not_cmp = options->not_cmp | nFoundbyWorker.not_cmp;
|
|
MPI_Send(&args, sizeof(struct diff_args), MPI_BYTE, Status.MPI_SOURCE, MPI_TAG_ARGS, MPI_COMM_WORLD);
|
|
}
|
|
else if(Status.MPI_TAG == MPI_TAG_TOK_REQUEST)
|
|
{
|
|
int incomingMessage;
|
|
MPI_Recv(NULL, 0, MPI_BYTE, Status.MPI_SOURCE, MPI_TAG_TOK_REQUEST, MPI_COMM_WORLD, &Status);
|
|
MPI_Send(NULL, 0, MPI_BYTE, Status.MPI_SOURCE, MPI_TAG_PRINT_TOK, MPI_COMM_WORLD);
|
|
|
|
do
|
|
{
|
|
MPI_Iprobe(MPI_ANY_SOURCE, MPI_TAG_TOK_RETURN, MPI_COMM_WORLD, &incomingMessage, &Status);
|
|
|
|
print_incoming_data();
|
|
}
|
|
while(!incomingMessage);
|
|
|
|
|
|
MPI_Recv(&nFoundbyWorker, sizeof(nFoundbyWorker), MPI_BYTE, Status.MPI_SOURCE, MPI_TAG_TOK_RETURN, MPI_COMM_WORLD, &Status);
|
|
nfound += nFoundbyWorker.nfound;
|
|
options->not_cmp = options->not_cmp | nFoundbyWorker.not_cmp;
|
|
MPI_Send(&args, sizeof(struct diff_args), MPI_BYTE, Status.MPI_SOURCE, MPI_TAG_ARGS, MPI_COMM_WORLD);
|
|
}
|
|
else
|
|
{
|
|
printf("ERROR: Invalid tag (%d) received \n", Status.MPI_TAG);
|
|
MPI_Abort(MPI_COMM_WORLD, 0);
|
|
MPI_Finalize();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif /* H5_HAVE_PARALLEL */
|
|
}
|
|
}
|
|
h5diffdebug("done with for loop\n");
|
|
|
|
#ifdef H5_HAVE_PARALLEL
|
|
if(g_Parallel)
|
|
{
|
|
while(busyTasks > 0) /* make sure all tasks are done */
|
|
{
|
|
MPI_Probe(MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &Status);
|
|
if(Status.MPI_TAG == MPI_TAG_DONE)
|
|
{
|
|
MPI_Recv(&nFoundbyWorker, sizeof(nFoundbyWorker), MPI_BYTE, Status.MPI_SOURCE, MPI_TAG_DONE, MPI_COMM_WORLD, &Status);
|
|
nfound += nFoundbyWorker.nfound;
|
|
options->not_cmp = options->not_cmp | nFoundbyWorker.not_cmp;
|
|
busyTasks--;
|
|
}
|
|
else if(Status.MPI_TAG == MPI_TAG_TOK_RETURN)
|
|
{
|
|
MPI_Recv(&nFoundbyWorker, sizeof(nFoundbyWorker), MPI_BYTE, Status.MPI_SOURCE, MPI_TAG_DONE, MPI_COMM_WORLD, &Status);
|
|
nfound += nFoundbyWorker.nfound;
|
|
options->not_cmp = options->not_cmp | nFoundbyWorker.not_cmp;
|
|
busyTasks--;
|
|
havePrintToken = 1;
|
|
}
|
|
else if(Status.MPI_TAG == MPI_TAG_TOK_REQUEST)
|
|
{
|
|
MPI_Recv(NULL, 0, MPI_BYTE, Status.MPI_SOURCE, MPI_TAG_TOK_REQUEST, MPI_COMM_WORLD, &Status);
|
|
if(havePrintToken)
|
|
{
|
|
int incomingMessage;
|
|
MPI_Send(NULL, 0, MPI_BYTE, Status.MPI_SOURCE, MPI_TAG_PRINT_TOK, MPI_COMM_WORLD);
|
|
do
|
|
{
|
|
MPI_Iprobe(MPI_ANY_SOURCE, MPI_TAG_TOK_RETURN, MPI_COMM_WORLD, &incomingMessage, &Status);
|
|
|
|
print_incoming_data();
|
|
}
|
|
while(!incomingMessage);
|
|
MPI_Recv(&nFoundbyWorker, sizeof(nFoundbyWorker), MPI_BYTE, Status.MPI_SOURCE, MPI_TAG_TOK_RETURN, MPI_COMM_WORLD, &Status);
|
|
nfound += nFoundbyWorker.nfound;
|
|
options->not_cmp = options->not_cmp | nFoundbyWorker.not_cmp;
|
|
busyTasks--;
|
|
}
|
|
else /* someone else must have it...wait for them to return it, then give it to the task that just asked for it. */
|
|
{
|
|
int source = Status.MPI_SOURCE;
|
|
int incomingMessage;
|
|
do
|
|
{
|
|
MPI_Iprobe(MPI_ANY_SOURCE, MPI_TAG_TOK_RETURN, MPI_COMM_WORLD, &incomingMessage, &Status);
|
|
|
|
print_incoming_data();
|
|
}
|
|
while(!incomingMessage);
|
|
|
|
|
|
MPI_Recv(&nFoundbyWorker, sizeof(nFoundbyWorker), MPI_BYTE, MPI_ANY_SOURCE, MPI_TAG_TOK_RETURN, MPI_COMM_WORLD, &Status);
|
|
nfound += nFoundbyWorker.nfound;
|
|
options->not_cmp = options->not_cmp | nFoundbyWorker.not_cmp;
|
|
busyTasks--;
|
|
MPI_Send(NULL, 0, MPI_BYTE, source, MPI_TAG_PRINT_TOK, MPI_COMM_WORLD);
|
|
}
|
|
}
|
|
else if(Status.MPI_TAG == MPI_TAG_TOK_RETURN)
|
|
{
|
|
MPI_Recv(&nFoundbyWorker, sizeof(nFoundbyWorker), MPI_BYTE, Status.MPI_SOURCE, MPI_TAG_TOK_RETURN, MPI_COMM_WORLD, &Status);
|
|
nfound += nFoundbyWorker.nfound;
|
|
options->not_cmp = options->not_cmp | nFoundbyWorker.not_cmp;
|
|
busyTasks--;
|
|
havePrintToken = 1;
|
|
}
|
|
else if(Status.MPI_TAG == MPI_TAG_PRINT_DATA)
|
|
{
|
|
char data[PRINT_DATA_MAX_SIZE+1];
|
|
memset(data, 0, PRINT_DATA_MAX_SIZE+1);
|
|
|
|
MPI_Recv(data, PRINT_DATA_MAX_SIZE, MPI_CHAR, Status.MPI_SOURCE, MPI_TAG_PRINT_DATA, MPI_COMM_WORLD, &Status);
|
|
|
|
printf("%s", data);
|
|
}
|
|
else
|
|
{
|
|
printf("ph5diff-manager: ERROR!! Invalid tag (%d) received \n", Status.MPI_TAG);
|
|
MPI_Abort(MPI_COMM_WORLD, 0);
|
|
}
|
|
}
|
|
|
|
for(i=1; i<g_nTasks; i++)
|
|
MPI_Send(NULL, 0, MPI_BYTE, i, MPI_TAG_END, MPI_COMM_WORLD);
|
|
|
|
/* Print any final data waiting in our queue */
|
|
print_incoming_data();
|
|
|
|
}
|
|
h5diffdebug("done with if block\n");
|
|
|
|
free(workerTasks);
|
|
#endif /* H5_HAVE_PARALLEL */
|
|
}
|
|
|
|
/* free table */
|
|
trav_table_free (table);
|
|
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* do the diff for the root.
|
|
* this is a special case, we get an ID for the root group and call diff()
|
|
* with this ID; it compares only the root group attributes
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
/* the manager can do this. */
|
|
nfound += diff (file1_id, "/", file2_id, "/", options, H5G_GROUP);
|
|
|
|
return nfound;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: diff_compare
|
|
*
|
|
* Purpose: get objects from list, and check for the same type
|
|
*
|
|
* Return: Number of differences found
|
|
*
|
|
* Programmer: Pedro Vicente, pvn@ncsa.uiuc.edu
|
|
*
|
|
* Date: May 9, 2003
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
hsize_t diff_compare (hid_t file1_id,
|
|
const char *file1_name,
|
|
const char *obj1_name,
|
|
int nobjects1,
|
|
trav_info_t * info1,
|
|
hid_t file2_id,
|
|
const char *file2_name,
|
|
const char *obj2_name,
|
|
int nobjects2,
|
|
trav_info_t * info2,
|
|
diff_opt_t * options)
|
|
{
|
|
int f1 = 0, f2 = 0;
|
|
hsize_t nfound = 0;
|
|
|
|
int i = h5trav_getindex (obj1_name, nobjects1, info1);
|
|
int j = h5trav_getindex (obj2_name, nobjects2, info2);
|
|
|
|
if (i == -1)
|
|
{
|
|
parallel_print ("Object <%s> could not be found in <%s>\n", obj1_name,
|
|
file1_name);
|
|
f1 = 1;
|
|
}
|
|
if (j == -1)
|
|
{
|
|
parallel_print ("Object <%s> could not be found in <%s>\n", obj2_name,
|
|
file2_name);
|
|
f2 = 1;
|
|
}
|
|
if (f1 || f2)
|
|
{
|
|
options->err_stat = 1;
|
|
return 0;
|
|
}
|
|
|
|
/* use the name with "/" first, as obtained by iterator function */
|
|
obj1_name = info1[i].name;
|
|
obj2_name = info2[j].name;
|
|
|
|
/* objects are not the same type */
|
|
if (info1[i].type != info2[j].type)
|
|
{
|
|
if (options->m_verbose)
|
|
parallel_print
|
|
("Comparison not possible: <%s> is of type %s and <%s> is of type %s\n",
|
|
obj1_name, get_type (info1[i].type), obj2_name,
|
|
get_type (info2[j].type));
|
|
options->not_cmp=1;
|
|
return 0;
|
|
}
|
|
|
|
nfound =
|
|
diff (file1_id, obj1_name, file2_id, obj2_name, options, info1[i].type);
|
|
|
|
return nfound;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: diff
|
|
*
|
|
* Purpose: switch between types and choose the diff function
|
|
* TYPE is either
|
|
* H5G_GROUP Object is a group
|
|
* H5G_DATASET Object is a dataset
|
|
* H5G_TYPE Object is a named data type
|
|
* H5G_LINK Object is a symbolic link
|
|
*
|
|
* Return: Number of differences found
|
|
*
|
|
* Programmer: Pedro Vicente, pvn@ncsa.uiuc.edu
|
|
*
|
|
* Date: May 9, 2003
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
hsize_t diff (hid_t file1_id,
|
|
const char *path1,
|
|
hid_t file2_id,
|
|
const char *path2,
|
|
diff_opt_t * options,
|
|
H5G_obj_t type)
|
|
{
|
|
hid_t type1_id=(-1);
|
|
hid_t type2_id=(-1);
|
|
hid_t grp1_id=(-1);
|
|
hid_t grp2_id=(-1);
|
|
int ret;
|
|
H5G_stat_t sb1;
|
|
H5G_stat_t sb2;
|
|
hsize_t nfound = 0;
|
|
|
|
switch (type)
|
|
{
|
|
/*-------------------------------------------------------------------------
|
|
* H5G_DATASET
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
case H5G_DATASET:
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* verbose, always print name
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
if (options->m_verbose)
|
|
{
|
|
if (print_objname (options, (hsize_t)1))
|
|
parallel_print("Dataset: <%s> and <%s>\n", path1, path2);
|
|
nfound = diff_dataset (file1_id, file2_id, path1, path2, options);
|
|
/* always print the number of differences found */
|
|
print_found(nfound);
|
|
}
|
|
/*-------------------------------------------------------------------------
|
|
* non verbose, check first if we have differences
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
else
|
|
{
|
|
if (options->m_quiet == 0)
|
|
{
|
|
/* shut up temporarily */
|
|
options->m_quiet = 1;
|
|
nfound = diff_dataset (file1_id, file2_id, path1, path2, options);
|
|
/* print again */
|
|
options->m_quiet = 0;
|
|
if (nfound)
|
|
{
|
|
if (print_objname (options, nfound))
|
|
parallel_print("Dataset: <%s> and <%s>\n", path1, path2);
|
|
nfound = diff_dataset (file1_id, file2_id, path1, path2, options);
|
|
/* print the number of differences found only when found
|
|
this is valid for the default mode and report mode */
|
|
print_found(nfound);
|
|
} /*if nfound */
|
|
} /*if quiet */
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* quiet mode, just count differences
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
else
|
|
{
|
|
nfound = diff_dataset (file1_id, file2_id, path1, path2, options);
|
|
}
|
|
} /*else verbose */
|
|
|
|
break;
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* H5G_TYPE
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
case H5G_TYPE:
|
|
if ((type1_id = H5Topen (file1_id, path1)) < 0)
|
|
goto out;
|
|
if ((type2_id = H5Topen (file2_id, path2)) < 0)
|
|
goto out;
|
|
|
|
if ((ret = H5Tequal (type1_id, type2_id)) < 0)
|
|
goto out;
|
|
|
|
/* if H5Tequal is > 0 then the datatypes refer to the same datatype */
|
|
nfound = (ret > 0) ? 0 : 1;
|
|
|
|
if (print_objname (options, nfound))
|
|
parallel_print("Datatype: <%s> and <%s>\n", path1, path2);
|
|
|
|
/* always print the number of differences found in verbose mode */
|
|
if (options->m_verbose)
|
|
print_found(nfound);
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* compare attributes
|
|
* the if condition refers to cases when the dataset is a referenced object
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
if (path1)
|
|
diff_attr (type1_id, type2_id, path1, path2, options);
|
|
|
|
if (H5Tclose (type1_id) < 0)
|
|
goto out;
|
|
if (H5Tclose (type2_id) < 0)
|
|
goto out;
|
|
|
|
break;
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* H5G_GROUP
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
case H5G_GROUP:
|
|
if ((grp1_id = H5Gopen (file1_id, path1)) < 0)
|
|
goto out;
|
|
if ((grp2_id = H5Gopen (file2_id, path2)) < 0)
|
|
goto out;
|
|
|
|
ret = HDstrcmp (path1, path2);
|
|
|
|
/* if "path1" != "path2" then the groups are "different" */
|
|
nfound = (ret != 0) ? 1 : 0;
|
|
|
|
if (print_objname (options, nfound))
|
|
parallel_print("Group: <%s> and <%s>\n", path1, path2);
|
|
|
|
/* always print the number of differences found in verbose mode */
|
|
if (options->m_verbose)
|
|
print_found(nfound);
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* compare attributes
|
|
* the if condition refers to cases when the dataset is a referenced object
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
if (path1)
|
|
diff_attr (grp1_id, grp2_id, path1, path2, options);
|
|
|
|
if (H5Gclose (grp1_id) < 0)
|
|
goto out;
|
|
if (H5Gclose (grp2_id) < 0)
|
|
goto out;
|
|
|
|
break;
|
|
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* H5G_LINK
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
case H5G_LINK:
|
|
{
|
|
char *buf1 = NULL;
|
|
char *buf2 = NULL;
|
|
|
|
if (H5Gget_objinfo (file1_id, path1, FALSE, &sb1) < 0)
|
|
goto out;
|
|
if (H5Gget_objinfo (file1_id, path1, FALSE, &sb2) < 0)
|
|
goto out;
|
|
|
|
buf1 = HDmalloc (sb1.linklen);
|
|
buf2 = HDmalloc (sb2.linklen);
|
|
|
|
if (H5Gget_linkval (file1_id, path1, sb1.linklen, buf1) < 0)
|
|
goto out;
|
|
if (H5Gget_linkval (file2_id, path2, sb1.linklen, buf2) < 0)
|
|
goto out;
|
|
|
|
ret = HDstrcmp (buf1, buf2);
|
|
|
|
/* if "buf1" != "buf2" then the links are "different" */
|
|
nfound = (ret != 0) ? 1 : 0;
|
|
|
|
if (print_objname (options, nfound))
|
|
parallel_print("Soft Link: <%s> and <%s>\n", path1, path2);
|
|
|
|
/* always print the number of differences found in verbose mode */
|
|
if (options->m_verbose)
|
|
print_found(nfound);
|
|
|
|
HDfree (buf1);
|
|
HDfree (buf2);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
nfound = 0;
|
|
if (options->m_verbose)
|
|
{
|
|
parallel_print("Comparison not supported: <%s> and <%s> are of type %s\n",
|
|
path1, path2, get_type (type));
|
|
options->not_cmp=1;
|
|
}
|
|
|
|
break;
|
|
} /* switch */
|
|
|
|
|
|
out:
|
|
|
|
/* close */
|
|
/* disable error reporting */
|
|
H5E_BEGIN_TRY
|
|
{
|
|
H5Tclose (type1_id);
|
|
H5Tclose (type2_id);
|
|
H5Gclose (grp1_id);
|
|
H5Tclose (grp2_id);
|
|
/* enable error reporting */
|
|
}
|
|
H5E_END_TRY;
|
|
return nfound;
|
|
}
|
|
|
|
|