size_t airDioWrite(int fd, const void *_ptr, size_t size) { size_t rit, totalrit; int align, min, max, flags; size_t remain, part; char *ptr; if (!( _ptr && (airNoDio_okay == airDioTest(fd, _ptr, size)) )) { return 0; } flags = fcntl(fd, F_GETFL); fcntl(fd, F_SETFL, flags | FDIRECT); airDioInfo(&align, &min, &max, fd); remain = size; totalrit = 0; ptr = (char*)_ptr; do { part = AIR_MIN(remain, max); rit = write(fd, ptr, part); totalrit += rit; if (rit != part) { break; } ptr += rit; remain -= rit; } while (remain); fcntl(fd, F_SETFL, flags); return totalrit; }
size_t airDioRead(int fd, void *_ptr, size_t size) { size_t red, totalred; int align, min, max, flags; size_t remain, part; char *ptr; if (!( _ptr && airNoDio_okay == airDioTest(fd, _ptr, size) )) { return 0; } flags = fcntl(fd, F_GETFL); fcntl(fd, F_SETFL, flags | FDIRECT); airDioInfo(&align, &min, &max, fd); remain = size; totalred = 0; ptr = (char*)_ptr; do { part = AIR_MIN(remain, max); red = read(fd, ptr, part); totalred += red; if (red != part) { break; } ptr += red; remain -= red; } while (remain); fcntl(fd, F_SETFL, flags); return totalred; }
static int _nrrdEncodingRaw_read(FILE *file, void *data, size_t elementNum, Nrrd *nrrd, NrrdIoState *nio) { static const char me[]="_nrrdEncodingRaw_read"; size_t ret, bsize; int fd, dio, car; long savePos; char *data_c; size_t elementSize, maxChunkSize, remainderValue, chunkSize; size_t retTmp; char stmp[3][AIR_STRLEN_SMALL]; bsize = nrrdElementSize(nrrd)*elementNum; if (nio->format->usesDIO) { fd = fileno(file); dio = airDioTest(fd, data, bsize); } else { fd = -1; dio = airNoDio_format; } if (airNoDio_okay == dio) { if (2 <= nrrdStateVerboseIO) { fprintf(stderr, "with direct I/O ... "); } ret = airDioRead(fd, data, bsize); if (ret != bsize) { biffAddf(NRRD, "%s: airDioRead got read only %s of %sbytes " "(%g%% of expected)", me, airSprintSize_t(stmp[0], ret), airSprintSize_t(stmp[1], bsize), 100.0*AIR_CAST(double, ret)/AIR_CAST(double, bsize)); return 1; } } else {
int _nrrdEncodingRaw_write(FILE *file, const void *data, size_t elementNum, const Nrrd *nrrd, NrrdIoState *nio) { char me[]="_nrrdEncodingRaw_write", err[BIFF_STRLEN]; int fd, dio; size_t ret, bsize; bsize = nrrdElementSize(nrrd)*elementNum; if (nio->format->usesDIO) { fd = fileno(file); dio = airDioTest(fd, data, bsize); } else { fd = -1; dio = airNoDio_format; } if (airNoDio_okay == dio) { if (2 <= nrrdStateVerboseIO) { fprintf(stderr, "with direct I/O ... "); } ret = airDioWrite(fd, data, bsize); if (ret != bsize) { sprintf(err, "%s: airDioWrite wrote only " _AIR_SIZE_T_CNV " of " _AIR_SIZE_T_CNV " bytes " "(%g%% of expected)", me, ret, bsize, 100.0*ret/bsize); biffAdd(NRRD, err); return 1; } } else { if (2 <= nrrdStateVerboseIO) { if (AIR_DIO && nio->format->usesDIO) { fprintf(stderr, "with fread(), not DIO: %s ...", airNoDioErr(dio)); } } ret = fwrite(data, nrrdElementSize(nrrd), elementNum, file); if (ret != elementNum) { sprintf(err, "%s: fwrite wrote read only " _AIR_SIZE_T_CNV " " _AIR_SIZE_T_CNV "-sized things, not " _AIR_SIZE_T_CNV " (%g%% of expected)", me, ret, nrrdElementSize(nrrd), elementNum, 100.0*ret/elementNum); biffAdd(NRRD, err); return 1; } fflush(file); /* if (ferror(file)) { sprintf(err, "%s: ferror returned non-zero", me); biffAdd(NRRD, err); return 1; } */ } return 0; }
int _nrrdEncodingRaw_read(FILE *file, void *data, size_t elementNum, Nrrd *nrrd, NrrdIoState *nio) { static const char me[]="_nrrdEncodingRaw_read"; size_t ret, bsize; int fd, dio, car; long savePos; char *data_c; size_t elementSize, maxChunkSize, remainder, chunkSize; size_t retTmp; bsize = nrrdElementSize(nrrd)*elementNum; if (nio->format->usesDIO) { fd = fileno(file); dio = airDioTest(fd, data, bsize); } else { fd = -1; dio = airNoDio_format; } if (airNoDio_okay == dio) { if (2 <= nrrdStateVerboseIO) { fprintf(stderr, "with direct I/O ... "); } ret = airDioRead(fd, data, bsize); if (ret != bsize) { biffAddf(NRRD, "%s: airDioRead got read only " _AIR_SIZE_T_CNV " of " _AIR_SIZE_T_CNV " bytes " "(%g%% of expected)", me, ret, bsize, 100.0*ret/bsize); return 1; } } else { if (2 <= nrrdStateVerboseIO) { if (AIR_DIO && nio->format->usesDIO) { fprintf(stderr, "with fread(), not DIO: %s ...", airNoDioErr(dio)); } } /* HEY: There's a bug in fread/fwrite in gcc 4.2.1 (with SnowLeopard). When it reads/writes a >=2GB data array, it pretends to succeed (i.e. the return value is the right number) but it hasn't actually read/written the data. The work-around is to loop over the data, reading/writing 1GB (or smaller) chunks. */ ret = 0; data_c = (char *)data; elementSize = nrrdElementSize(nrrd); maxChunkSize = 1024 * 1024 * 1024 / elementSize; while(ret < elementNum) { remainder = elementNum-ret; if (remainder < maxChunkSize) { chunkSize = remainder; } else { chunkSize = maxChunkSize; } retTmp = fread(&(data_c[ret*elementSize]), elementSize, chunkSize, file); ret += retTmp; if (retTmp != chunkSize) { biffAddf(NRRD, "%s: fread got read only " _AIR_SIZE_T_CNV " " _AIR_SIZE_T_CNV "-sized things, not " _AIR_SIZE_T_CNV " (%g%% of expected)", me, ret, nrrdElementSize(nrrd), elementNum, 100.0*ret/elementNum); return 1; } } /* HEY: Here's the old version of the above code. ret = fread(data, nrrdElementSize(nrrd), elementNum, file); if (ret != elementNum) { biffAddf(NRRD, "%s: fread got read only " _AIR_SIZE_T_CNV " " _AIR_SIZE_T_CNV "-sized things, not " _AIR_SIZE_T_CNV " (%g%% of expected)", me, ret, nrrdElementSize(nrrd), elementNum, 100.0*ret/elementNum); return 1; } */ car = fgetc(file); if (1 <= nrrdStateVerboseIO && EOF != car) { fprintf(stderr, "%s: WARNING: finished reading raw data, " "but file not at EOF\n", me); ungetc(car, file); } if (2 <= nrrdStateVerboseIO && nio->byteSkip && stdin != file) { savePos = ftell(file); if (!fseek(file, 0, SEEK_END)) { fprintf(stderr, "(%s: used %g%% of file for nrrd data)\n", me, 100.0*bsize/(ftell(file) + 1)); fseek(file, savePos, SEEK_SET); } } } return 0; }
int _nrrdEncodingRaw_write(FILE *file, const void *data, size_t elementNum, const Nrrd *nrrd, NrrdIoState *nio) { static const char me[]="_nrrdEncodingRaw_write"; int fd, dio; size_t ret, bsize; char *data_c; size_t elementSize, maxChunkSize, remainder, chunkSize; size_t retTmp; bsize = nrrdElementSize(nrrd)*elementNum; if (nio->format->usesDIO) { fd = fileno(file); dio = airDioTest(fd, data, bsize); } else { fd = -1; dio = airNoDio_format; } if (airNoDio_okay == dio) { if (2 <= nrrdStateVerboseIO) { fprintf(stderr, "with direct I/O ... "); } ret = airDioWrite(fd, data, bsize); if (ret != bsize) { biffAddf(NRRD, "%s: airDioWrite wrote only " _AIR_SIZE_T_CNV " of " _AIR_SIZE_T_CNV " bytes " "(%g%% of expected)", me, ret, bsize, 100.0*ret/bsize); return 1; } } else { if (2 <= nrrdStateVerboseIO) { if (AIR_DIO && nio->format->usesDIO) { fprintf(stderr, "with fread(), not DIO: %s ...", airNoDioErr(dio)); } } /* HEY: There's a bug in fread/fwrite in gcc 4.2.1 (with SnowLeopard). When it reads/writes a >=2GB data array, it pretends to succeed (i.e. the return value is the right number) but it hasn't actually read/written the data. The work-around is to loop over the data, reading/writing 1GB (or smaller) chunks. */ ret = 0; data_c = (char *)data; elementSize = nrrdElementSize(nrrd); maxChunkSize = 1024 * 1024 * 1024 / elementSize; while(ret < elementNum) { remainder = elementNum-ret; if (remainder < maxChunkSize) { chunkSize = remainder; } else { chunkSize = maxChunkSize; } retTmp = fwrite(&(data_c[ret*elementSize]), elementSize, chunkSize, file); ret += retTmp; if (retTmp != chunkSize) { biffAddf(NRRD, "%s: fwrite wrote only " _AIR_SIZE_T_CNV " " _AIR_SIZE_T_CNV "-sized things, not " _AIR_SIZE_T_CNV " (%g%% of expected)", me, ret, nrrdElementSize(nrrd), elementNum, 100.0*ret/elementNum); return 1; } } /* HEY: Here's the old version of the above code. ret = fwrite(data, nrrdElementSize(nrrd), elementNum, file); if (ret != elementNum) { biffAddf(NRRD, "%s: fwrite wrote only " _AIR_SIZE_T_CNV " " _AIR_SIZE_T_CNV "-sized things, not " _AIR_SIZE_T_CNV " (%g%% of expected)", me, ret, nrrdElementSize(nrrd), elementNum, 100.0*ret/elementNum); return 1; } */ fflush(file); /* if (ferror(file)) { biffAddf(NRRD, "%s: ferror returned non-zero", me); return 1; } */ } return 0; }
int _nrrdEncodingRaw_read(FILE *file, void *data, size_t elementNum, Nrrd *nrrd, NrrdIoState *nio) { char me[]="_nrrdEncodingRaw_read", err[BIFF_STRLEN]; size_t ret, bsize; int fd, dio, car; long savePos; bsize = nrrdElementSize(nrrd)*elementNum; if (nio->format->usesDIO) { fd = fileno(file); dio = airDioTest(fd, data, bsize); } else { fd = -1; dio = airNoDio_format; } if (airNoDio_okay == dio) { if (2 <= nrrdStateVerboseIO) { fprintf(stderr, "with direct I/O ... "); } ret = airDioRead(fd, data, bsize); if (ret != bsize) { sprintf(err, "%s: airDioRead got read only " _AIR_SIZE_T_CNV " of " _AIR_SIZE_T_CNV " bytes " "(%g%% of expected)", me, ret, bsize, 100.0*ret/bsize); biffAdd(NRRD, err); return 1; } } else { if (2 <= nrrdStateVerboseIO) { if (AIR_DIO && nio->format->usesDIO) { fprintf(stderr, "with fread(), not DIO: %s ...", airNoDioErr(dio)); } } ret = fread(data, nrrdElementSize(nrrd), elementNum, file); if (ret != elementNum) { sprintf(err, "%s: fread got read only " _AIR_SIZE_T_CNV " " _AIR_SIZE_T_CNV "-sized things, not " _AIR_SIZE_T_CNV " (%g%% of expected)", me, ret, nrrdElementSize(nrrd), elementNum, 100.0*ret/elementNum); biffAdd(NRRD, err); return 1; } car = fgetc(file); if (1 <= nrrdStateVerboseIO && EOF != car) { fprintf(stderr, "%s: WARNING: finished reading raw data, " "but file not at EOF\n", me); ungetc(car, file); } if (2 <= nrrdStateVerboseIO && nio->byteSkip && stdin != file) { savePos = ftell(file); if (!fseek(file, 0, SEEK_END)) { fprintf(stderr, "(%s: used %g%% of file for nrrd data)\n", me, 100.0*bsize/(ftell(file) + 1)); fseek(file, savePos, SEEK_SET); } } } return 0; }
int main(int argc, char *argv[]) { #if TEEM_DIO == 0 AIR_UNUSED(argc); fprintf(stderr, "%s: no direct-io testing for you\n", argv[0]); return 1; #else char *me, *fname, *multS, *data; FILE *file; double time0, time1, time2; int fd, align, mult, min, max, ret; size_t size; airArray *mop; me = argv[0]; if (3 != argc) { /* 0 1 2 (3) */ fprintf(stderr, "usage: %s <filename> <mult>\n", me); return 1; } fname = argv[1]; multS = argv[2]; if (1 != sscanf(multS, "%d", &mult)) { fprintf(stderr, "%s: couln't parse mult %s as int\n", me, multS); return 1; } mop = airMopNew(); if (!(file = fopen(fname, "w"))) { fprintf(stderr, "%s: couldn't open %s for writing\n", me, fname); airMopError(mop); return 1; } airMopAdd(mop, file, (airMopper)airFclose, airMopAlways); fd = fileno(file); if (-1 == fd) { fprintf(stderr, "%s: couldn't get underlying descriptor\n", me); airMopError(mop); return 1; } fprintf(stderr, "%s: fd(%s) = %d\n", me, fname, fd); ret = airDioTest(fd, NULL, 0); if (airNoDio_okay != ret) { fprintf(stderr, "%s: no good: \"%s\"\n", me, airNoDioErr(ret)); airMopError(mop); return 1; } airDioInfo(&align, &min, &max, fd); fprintf(stderr, "%s: --> align=%d, min=%d, max=%d\n", me, align, min, max); size = (size_t)max*mult; data = airDioMalloc(size, fd); if (!data) { fprintf(stderr, "%s: airDioMalloc(" _AIR_SIZE_T_CNV ") failed\n", me, size); airMopError(mop); return 1; } airMopAdd(mop, data, airFree, airMopAlways); fprintf(stderr, "\ndata size = %g MB\n", (double)size/(1024*1024)); /* -------------------------------------------------------------- */ fprintf(stderr, "(1) non-aligned memory, regular write:\n"); time0 = airTime(); if (size-1 != write(fd, data+1, size-1)) { fprintf(stderr, "%s: write failed\n", me); airMopError(mop); return 1; } time1 = airTime(); fsync(fd); time2 = airTime(); fprintf(stderr, " time = %g + %g = %g (%g MB/sec)\n", time1 - time0, time2 - time1, time2 - time0, (size/(1024*1024)) / (time2 - time0)); airMopSub(mop, file, (airMopper)airFclose); fclose(file); /* -------------------------------------------------------------- */ /* -------------------------------------------------------------- */ fprintf(stderr, "(2) aligned memory, regular write:\n"); file = fopen(fname, "w"); airMopAdd(mop, file, (airMopper)airFclose, airMopAlways); fd = fileno(file); time0 = airTime(); if (size != write(fd, data, size)) { fprintf(stderr, "%s: write failed\n", me); airMopError(mop); return 1; } time1 = airTime(); fsync(fd); time2 = airTime(); fprintf(stderr, " time = %g + %g = %g (%g MB/sec)\n", time1 - time0, time2 - time1, time2 - time0, (size/(1024*1024)) / (time2 - time0)); airMopSub(mop, file, (airMopper)airFclose); fclose(file); /* -------------------------------------------------------------- */ /* -------------------------------------------------------------- */ fprintf(stderr, "(3) aligned memory, air's direct IO:\n"); file = fopen(fname, "w"); airMopAdd(mop, file, (airMopper)airFclose, airMopAlways); fd = fileno(file); time0 = airTime(); if (size != airDioWrite(fd, data, size)) { fprintf(stderr, "%s: write failed\n", me); airMopError(mop); return 1; } time1 = airTime(); fsync(fd); time2 = airTime(); fprintf(stderr, " time = %g + %g = %g (%g MB/sec)\n", time1 - time0, time2 - time1, time2 - time0, (size/(1024*1024)) / (time2 - time0)); airMopSub(mop, file, (airMopper)airFclose); fclose(file); /* -------------------------------------------------------------- */ /* -------------------------------------------------------------- */ fprintf(stderr, "(4) aligned memory, direct IO by hand:\n"); { /* "input": fname, size, data */ int flags; struct dioattr dio; char *ptr; size_t remain, totalrit, rit, part; file = fopen(fname, "w"); if (-1 == (fd = fileno(file))) { fprintf(stderr, "%s: couldn't get underlying descriptor\n", me); airMopError(mop); return 1; } airMopAdd(mop, file, (airMopper)airFclose, airMopAlways); flags = fcntl(fd, F_GETFL); if (-1 == fcntl(fd, F_SETFL, flags | FDIRECT)) { fprintf(stderr, "%s: couldn't turn on direct IO\n", me); airMopError(mop); return 1; } if (0 != fcntl(fd, F_DIOINFO, &dio)) { fprintf(stderr, "%s: couldn't learn direct IO specifics", me); airMopError(mop); return 1; } remain = size; totalrit = 0; ptr = data; time0 = airTime(); do { part = remain > dio.d_maxiosz ? dio.d_maxiosz : remain; rit = write(fd, ptr, part); if (rit != part) { fprintf(stderr, "%s: write failed\n", me); airMopError(mop); return 1; } totalrit += rit; ptr += rit; remain -= rit; } while (remain); time1 = airTime(); fsync(fd); time2 = airTime(); fprintf(stderr, " time = %g + %g = %g (%g MB/sec)\n", time1 - time0, time2 - time1, time2 - time0, (size/(1024*1024)) / (time2 - time0)); airMopSub(mop, file, (airMopper)airFclose); fclose(file); } /* -------------------------------------------------------------- */ airMopError(mop); exit(0); #endif }