RFR: 6980847: (fs) Files.copy needs to be tuned [v3]

Brian Burkhalter bpb at openjdk.java.net
Thu Jun 16 01:40:03 UTC 2022


On Wed, 15 Jun 2022 17:52:13 GMT, Brian Burkhalter <bpb at openjdk.org> wrote:

>> Modify `UnixCopyFile.copyFile()` to set the transfer size to the least common multiple of the source and destination file block sizes if the block sizes are not equal. Modify `WindowsFileCopy.copy()` to set `COPY_FILE_NO_BUFFERING` in the flags passed to `CopyFileEx()` if the size of the transfer is greater than a threshold.
>
> Brian Burkhalter has updated the pull request incrementally with one additional commit since the last revision:
> 
>   6980847: Remove unnecessary catch of SecurityException and UnsupportedOperationException which are not thrown by blockSize()

Responding to [Bernd's comments](https://mail.openjdk.org/pipermail/nio-dev/2022-June/011466.html).

It has been observed before that a larger buffer can increase throughput so increasing the minimum transfer size here seems reasonable. I don’t think it would be bad to increase it to 16K. Perhaps do something like the following where `TRANSFER_SIZE` is 16384 instead of 8192

if (transferSize < TRANSFER_SIZE) {
    int factor = (int)((TRANSFER_SIZE + transferSize - 1)/transferSize);
    transferSize *= factor;
}

which will probably always compute 16384.

I think that

int advice = POSIX_FADV_SEQUENTIAL | POSIX_FADV_NOREUSE | POSIX_FADV_WILLNEED;
posix_fadvise(src, 0, 0, advice);

is a good idea.

Several mentions online state that `st_blksize` for an NFS server is the page size, but local testing shows it to be the block size of the mounted disk.

Not much benchmark work was done on this topic except on Windows which was to determine the no-buffering threshold. I went back and generated some numbers today. `patch1` is as of the third commit, `patch2` as of the fourth which I will push shortly.

==> ../master.txt <==
Benchmark      (length)   Mode  Cnt      Score      Error  Units
CopyFile.copy     10000  thrpt   10  32685.396 ± 1623.472  ops/s
CopyFile.copy    100000  thrpt   10  11660.298 ±  156.204  ops/s
CopyFile.copy   1000000  thrpt   10   1504.661 ±   15.264  ops/s
CopyFile.copy  10000000  thrpt   10    118.880 ±    5.999  ops/s

==> ../patch1.txt <==
Benchmark      (length)   Mode  Cnt      Score     Error  Units
CopyFile.copy     10000  thrpt   10  30343.618 ± 955.469  ops/s
CopyFile.copy    100000  thrpt   10  11295.039 ± 102.986  ops/s
CopyFile.copy   1000000  thrpt   10   1490.852 ±  19.018  ops/s
CopyFile.copy  10000000  thrpt   10    111.626 ±   2.392  ops/s

==> ../patch2-no-fadvise.txt <==
Benchmark      (length)   Mode  Cnt      Score     Error  Units
CopyFile.copy     10000  thrpt   10  31743.019 ± 974.794  ops/s
CopyFile.copy    100000  thrpt   10  12295.192 ± 187.331  ops/s
CopyFile.copy   1000000  thrpt   10   1656.561 ±  23.102  ops/s
CopyFile.copy  10000000  thrpt   10    122.700 ±   1.783  ops/s

==> ../patch2.txt <==
Benchmark      (length)   Mode  Cnt      Score     Error  Units
CopyFile.copy     10000  thrpt   10  31735.385 ± 374.000  ops/s
CopyFile.copy    100000  thrpt   10  12049.334 ± 112.960  ops/s
CopyFile.copy   1000000  thrpt   10   1664.070 ±  33.637  ops/s
CopyFile.copy  10000000  thrpt   10    121.623 ±   1.258  ops/s

It looks like having the minimum transfer size be 16384 is helpful; `fadvise()` does not do much here.

Please note that the transfer by read-write loop is rather an edge case: it is never used on macOS, and on Linux only if sendfile() fails. It is however the only code path on other Unix variants.

-------------

PR: https://git.openjdk.org/jdk/pull/9161


More information about the nio-dev mailing list