9 #include "connections/weight_conversions.hpp" 10 #include "structures/Buffer.hpp" 11 #include "utils/BufferUtilsMPI.hpp" 12 #include "utils/PVLog.hpp" 13 #include "utils/conversions.h" 27 PV_Stream *PV_fopen(
const char *path,
const char *mode,
bool verifyWrites) {
29 ErrorLog().printf(
"PV_fopen: mode argument must be a string (path was \"%s\").\n", path);
33 char *realPath = strdup(expandLeadingTilde(path).c_str());
36 if (mode[0] ==
'r' || mode[0] ==
'a') {
38 int statstatus = stat(realPath, &statbuf);
39 if (statstatus == 0) {
40 filelength = (long)statbuf.st_size;
45 else if (errno != ENOENT) {
47 "PV_fopen: unable to stat \"%s\" with mode \"%s\": %s\n",
58 fp = fopen(realPath, mode);
63 "fopen failure for \"%s\" on attempt %d: %s\n", realPath, fopencounts, strerror(errno));
64 if (fopencounts < MAX_FILESYSTEMCALL_TRIES) {
73 "PV_fopen: exceeded MAX_FILESYSTEMCALL_TRIES = %d attempting to open \"%s\"\n",
74 MAX_FILESYSTEMCALL_TRIES,
78 if (fopencounts > 0) {
79 WarnLog().printf(
"fopen succeeded for \"%s\" on attempt %d\n", realPath, fopencounts + 1);
82 if (streampointer != NULL) {
83 streampointer->name = strdup(realPath);
84 streampointer->mode = strdup(mode);
85 streampointer->fp = fp;
86 streampointer->filepos = filepos;
87 streampointer->filelength = filelength;
88 streampointer->isfile = 1;
89 streampointer->verifyWrites = verifyWrites;
92 ErrorLog().printf(
"PV_fopen failure for \"%s\": %s\n", realPath, strerror(errno));
100 int PV_stat(
const char *path,
struct stat *buf) {
106 char *realPath = strdup(expandLeadingTilde(path).c_str());
109 while (retval != 0) {
111 retval = stat(realPath, buf);
116 "stat() failure for \"%s\" on attempt %d: %s\n", path, attempt, strerror(errno));
117 if (attempt < MAX_FILESYSTEMCALL_TRIES) {
126 "PV_stat exceeded MAX_FILESYSTEMCALL_TRIES = %d for \"%s\"\n",
127 MAX_FILESYSTEMCALL_TRIES,
134 long int PV_ftell_primitive(
PV_Stream *pvstream) {
138 while (filepos < 0) {
140 filepos = ftell(pvstream->fp);
145 "ftell failure for \"%s\" on attempt %d: %s\n",
149 if (ftellcounts < MAX_FILESYSTEMCALL_TRIES) {
158 "PV_ftell failure for \"%s\": MAX_FILESYSTEMCALL_TRIES = %d exceeded\n",
160 MAX_FILESYSTEMCALL_TRIES);
162 else if (ftellcounts > 0) {
164 "PV_ftell succeeded for \"%s\" on attempt %d", pvstream->name, ftellcounts + 1);
169 long int getPV_StreamFilepos(
PV_Stream *pvstream) {
return pvstream->filepos; }
174 long int filepos = PV_ftell_primitive(pvstream);
175 if (pvstream->filepos != filepos) {
177 "ftell for \"%s\" returned %ld instead of the expected %ld\n",
185 int PV_fseek(
PV_Stream *pvstream,
long offset,
int whence) {
187 int fseekstatus = -1;
188 while (fseekstatus != 0) {
190 fseekstatus = fseek(pvstream->fp, offset, whence);
191 if (fseekstatus == 0)
195 "fseek failure for \"%s\" on attempt %d: %s\n",
199 if (fseekcounts < MAX_FILESYSTEMCALL_TRIES) {
206 if (fseekstatus != 0) {
208 "PV_fseek failure for \"%s\": MAX_FILESYSTEMCALL_TRIES = %d exceeded\n",
210 MAX_FILESYSTEMCALL_TRIES);
212 else if (fseekcounts > 0) {
214 "PV_fseek succeeded for \"%s\" on attempt %d\n", pvstream->name, fseekcounts + 1);
216 if (pvstream->mode[0] !=
'a') {
218 case SEEK_SET: pvstream->filepos = offset;
break;
219 case SEEK_CUR: pvstream->filepos += offset;
break;
220 case SEEK_END: pvstream->filepos = pvstream->filelength + offset;
break;
221 default: assert(0);
break;
258 PV_fwrite(
const void *RESTRICT ptr,
size_t size,
size_t nitems,
PV_Stream *RESTRICT pvstream) {
259 assert(ferror(pvstream->fp) == 0);
260 int fwritecounts = 0;
261 size_t writesize = nitems * size;
262 size_t charswritten = (size_t)0;
263 const char *RESTRICT curptr = (
const char *RESTRICT)ptr;
264 long int fpos = pvstream->filepos;
267 "PV_fwrite error: unable to determine file position of \"%s\". Fatal error\n",
270 long int ftellresult = ftell(pvstream->fp);
271 if (pvstream->isfile && fpos != ftellresult) {
273 "PV_fwrite error for \"%s\": fpos = %ld but ftell() returned %ld\n",
279 bool hasfailed =
false;
280 for (
int fwritecounts = 1; fwritecounts <= MAX_FILESYSTEMCALL_TRIES; fwritecounts++) {
281 charswritten = fwrite(ptr, 1UL, writesize, pvstream->fp);
282 if (charswritten == writesize) {
284 clearerr(pvstream->fp);
286 "fwrite succeeded for \"%s\" on attempt %d.\n", pvstream->name, fwritecounts);
292 WarnLog(fwriteFailure);
293 fwriteFailure.printf(
294 "fwrite failure for \"%s\" on attempt %d. Return value %zu instead of %zu. ",
299 if (ferror(pvstream->fp)) {
300 fwriteFailure.printf(
" Error: %s\n", strerror(errno));
302 if (fwritecounts < MAX_FILESYSTEMCALL_TRIES) {
303 fwriteFailure.printf(
"Retrying.\n");
305 int fseekstatus = fseek(pvstream->fp, fpos, SEEK_SET);
306 if (fseekstatus != 0) {
308 "PV_fwrite error: Unable to reset file position of \"%s\". Fatal error: %s\n",
312 long int ftellreturn = ftell(pvstream->fp);
313 if (fpos != ftellreturn) {
315 "PV_fwrite error: attempted to reset file position of \"%s\" to %ld, but " 316 "ftell() returned %ld. Fatal error.\n",
323 ErrorLog().printf(
"MAX_FILESYSTEMCALL_TRIES exceeded.\n");
328 if (pvstream->verifyWrites && pvstream->isfile) {
329 fflush(pvstream->fp);
330 int status = PV_SUCCESS;
331 PV_Stream *readStream = PV_fopen(pvstream->name,
"r",
false );
332 if (readStream == NULL) {
334 "PV_fwrite verification: unable to open \"%s\" for reading: %s\n",
339 if (status == PV_SUCCESS) {
340 if (fseek(readStream->fp, pvstream->filepos, SEEK_SET) != 0) {
342 "PV_fwrite verification: unable to verify \"%s\" write of %zu chars from " 343 "position %ld: %s\n",
351 char *read_buffer = NULL;
352 if (status == PV_SUCCESS) {
353 read_buffer = (
char *)malloc(writesize);
354 if (read_buffer == NULL) {
356 "PV_fwrite verification: unable to create readback buffer of size %zu to verify " 363 if (status == PV_SUCCESS) {
364 for (
size_t n = 0; n < writesize; n++) {
365 read_buffer[n] = ~((
char *)ptr)[n];
368 if (status == PV_SUCCESS) {
369 size_t numread = fread(read_buffer, (
size_t)1, writesize, readStream->fp);
370 if (numread != writesize) {
372 "PV_fwrite verification: unable to read into readback buffer for \"%s\": fread " 373 "returned %zu instead of %zu\n",
380 if (status == PV_SUCCESS) {
381 status = memcmp(ptr, read_buffer, writesize) == 0 ? PV_SUCCESS : PV_FAILURE;
382 if (status != PV_SUCCESS) {
384 for (
size_t n = 0; n < writesize; n++) {
385 badcount += (((
char *)ptr)[n] != read_buffer[n]);
388 "PV_fwrite verification: readback of %zu bytes from \"%s\" starting at position " 389 "%zu failed: %zu bytes disagree.\n",
398 PV_fclose(readStream);
401 if (status != PV_SUCCESS) {
402 fseek(pvstream->fp, pvstream->filepos, SEEK_SET);
406 pvstream->filepos += writesize;
410 size_t PV_fread(
void *RESTRICT ptr,
size_t size,
size_t nitems,
PV_Stream *RESTRICT pvstream) {
412 size_t readsize = nitems * size;
413 size_t stilltoread = readsize;
414 char *RESTRICT curptr = (
char *RESTRICT)ptr;
415 long int fpos = pvstream->filepos;
416 clearerr(pvstream->fp);
419 "PV_fread error: unable to determine file position of \"%s\". Fatal error\n",
422 while (stilltoread != 0UL) {
423 size_t charsread_thispass = fread(curptr, 1UL, stilltoread, pvstream->fp);
424 stilltoread -= charsread_thispass;
425 pvstream->filepos += charsread_thispass;
426 if (stilltoread == 0UL) {
427 if (freadcounts > 0) {
429 "fread succeeded for \"%s\" on attempt %d.\n", pvstream->name, freadcounts + 1);
434 if (feof(pvstream->fp)) {
436 "fread failure for \"%s\": end of file reached with %lu characters still " 443 curptr += charsread_thispass;
445 if (freadcounts < MAX_FILESYSTEMCALL_TRIES) {
447 "fread failure for \"%s\" on attempt %d. %lu bytes read; %lu bytes still to read " 457 "PV_fread failure for \"%s\": MAX_FILESYSTEMCALL_TRIES = %d exceeded, and %lu bytes " 460 MAX_FILESYSTEMCALL_TRIES,
461 readsize - stilltoread,
466 return (readsize - stilltoread) / size;
470 int status = PV_SUCCESS;
472 if (pvstream->fp && pvstream->isfile) {
473 status = fclose(pvstream->fp);
476 ErrorLog().printf(
"fclose failure for \"%s\": %s", pvstream->name, strerror(errno));
479 free(pvstream->name);
480 free(pvstream->mode);
487 int checkDirExists(MPIBlock
const *mpiBlock,
const char *dirname,
struct stat *pathstat) {
495 int rank = mpiBlock->getRank();
501 char *expandedDirName = strdup(expandLeadingTilde(dirname).c_str());
502 status = stat(dirname, pathstat);
503 free(expandedDirName);
504 return status ? errno : 0;
507 static inline int makeDirectory(
char const *dir) {
508 mode_t dirmode = S_IRWXU | S_IRWXG | S_IRWXO;
511 char *workingDir = strdup(dir);
512 FatalIf(workingDir ==
nullptr,
"makeDirectory: unable to duplicate path \"%s\".", dir);
514 int len = strlen(workingDir);
515 if (workingDir[len - 1] ==
'/')
516 workingDir[len - 1] =
'\0';
518 for (
char *p = workingDir + 1; *p; p++)
521 status |= mkdir(workingDir, dirmode);
522 if (status != 0 && errno != EEXIST) {
527 status |= mkdir(workingDir, dirmode);
528 if (errno == EEXIST) {
534 void ensureDirExists(MPIBlock
const *mpiBlock,
char const *dirname) {
537 int rank = mpiBlock->getRank();
538 struct stat pathstat;
539 int resultcode = checkDirExists(mpiBlock, dirname, &pathstat);
541 if (resultcode == 0) {
543 rank == 0 && !(pathstat.st_mode & S_IFDIR),
544 "Path \"%s\" exists but is not a directory\n",
547 else if (resultcode == ENOENT ) {
549 InfoLog().printf(
"Directory \"%s\" does not exist; attempting to create\n", dirname);
552 int const numAttempts = 5;
553 for (
int attemptNum = 0; attemptNum < numAttempts; attemptNum++) {
554 int mkdirstatus = makeDirectory(dirname);
555 if (mkdirstatus != 0) {
556 if (attemptNum == numAttempts - 1) {
558 "Directory \"%s\" could not be created: %s; Exiting\n",
563 getOutputStream().flush();
565 "Directory \"%s\" could not be created: %s; Retrying %d out of %d\n",
582 "Error checking status of directory \"%s\": %s\n", dirname, strerror(resultcode));
609 int pv_text_write_patch(
610 PrintStream *outStream,
619 const int nx = (int)patch->nx;
620 const int ny = (
int)patch->ny;
622 assert(outStream != NULL);
624 for (f = 0; f < nf; f++) {
625 for (j = 0; j < ny; j++) {
626 for (i = 0; i < nx; i++) {
627 outStream->printf(
"%7.5f ", (
double)data[i * sx + j * sy + f * sf]);
629 outStream->printf(
"\n");
631 outStream->printf(
"\n");