diff --git a/src/p1st/btrfs_send_chunks.py b/src/p1st/btrfs_send_chunks.py index e8039bd..5b4b441 100644 --- a/src/p1st/btrfs_send_chunks.py +++ b/src/p1st/btrfs_send_chunks.py @@ -56,10 +56,10 @@ def parse_args(): ) parser.add_argument('--chunk-size', - help='Size in bytes; defaults to 64 MB.', + help='Size in bytes; defaults to 128 MB.', dest='chunk_size', type=int, - default=64 * 1024 * 1024, + default=128 * 1024 * 1024, ) parser.add_argument('child', diff --git a/src/p1st/data_units.py b/src/p1st/data_units.py new file mode 100644 index 0000000..26d2721 --- /dev/null +++ b/src/p1st/data_units.py @@ -0,0 +1,50 @@ +from enum import Enum + + +def test(): + for num_bytes in [0, 1, 128, 512, 1024, 4096, 75 * 1000, 750 * 1000, 850 * 1000, 1111 * 1000]: + print(f'{num_bytes} bytes = {DataUnitConverter.to_unit_auto_str(num_bytes)}') + + +class DataUnitConverter: + class DataUnit(Enum): + B = 'B' + KB = 'KB' + MB = 'MB' + GB = 'GB' + TB = 'TB' + + # Units sorted from small to large. + _unit_dict: dict[DataUnit, int] = { + DataUnit.B: 1, + DataUnit.KB: 1024, + DataUnit.MB: 1024 * 1024, + DataUnit.GB: 1024 * 1024 * 1024, + DataUnit.TB: 1024 * 1024 * 1024 * 1024, + } + + @classmethod + def to_bytes(cls, num: int, unit: DataUnit) -> int: + return num * cls._unit_dict[unit] + + @classmethod + def to_unit(cls, num_bytes: int, unit: DataUnit = DataUnit.GB) -> float: + return round(num_bytes / cls._unit_dict[unit], 3) + + @classmethod + def to_unit_auto(cls, num_bytes: int) -> (float, DataUnit): + for unit, factor in cls._unit_dict.items(): + converted = cls.to_unit(num_bytes, unit) + if converted <= 999: + return converted, unit + + return num_bytes, cls.DataUnit.B + + @classmethod + def to_unit_auto_str(cls, num_bytes: int) -> str: + value, unit = cls.to_unit_auto(num_bytes) + return f'{value} {unit.value}' + + +if __name__ == '__main__': + test() diff --git a/src/p1st/exec_print_transfer.py b/src/p1st/exec_print_transfer.py index a0ab967..6bd76a4 100644 --- a/src/p1st/exec_print_transfer.py +++ b/src/p1st/exec_print_transfer.py @@ -1,5 +1,7 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- +import datetime +import time from pathlib import Path import sys import threading @@ -7,18 +9,20 @@ import subprocess from typing import AnyStr, IO, Callable from p1st.common import _get_chunk_file +from p1st.data_units import DataUnitConverter def _rotate_chunk(chunk_file: Path, chunk_number: int, eof: bool, chunk_transfer_fun: Callable, chunk_transfer_args: tuple): - print(f'Transferring chunk {chunk_file}') + print(f'Transferring chunk') chunk_transfer_fun(chunk_file, chunk_number, eof, *chunk_transfer_args) - print(f'Removing chunk {chunk_file}') + print(f'Removing chunk') chunk_file.unlink(missing_ok=False) def _save_chunk(chunk: bytes, chunk_file: Path): print(f'Saving chunk {chunk_file}') + # Fails if file does already exist. with open(chunk_file, 'xb') as f: f.write(chunk) @@ -44,6 +48,8 @@ def _save_output_rotating_chunks(out_pipe: IO[AnyStr], chunk_transfer_args: tuple, get_chunk_file: Callable[[Path, int], Path], ): + start_time = time.time() + ct: int = 1 remaining_bytes = chunk_size chunk: bytes = b'' @@ -60,6 +66,11 @@ def _save_output_rotating_chunks(out_pipe: IO[AnyStr], _save_chunk(chunk, chunk_file) _rotate_chunk(chunk_file, ct, True, chunk_transfer_fun, chunk_transfer_args) + current_time = time.time() + elapsed_time = current_time - start_time + print(f'Elapsed time: {datetime.timedelta(seconds=elapsed_time)}\n' + f'Transferred: {DataUnitConverter.to_unit_auto_str(ct * chunk_size)}') + break chunk += b @@ -72,6 +83,14 @@ def _save_output_rotating_chunks(out_pipe: IO[AnyStr], _save_chunk(chunk, chunk_file) _rotate_chunk(chunk_file, ct, False, chunk_transfer_fun, chunk_transfer_args) + current_time = time.time() + elapsed_time = current_time - start_time + transferred_bytes = ct * chunk_size + bytes_per_second = transferred_bytes / elapsed_time + print(f'Elapsed time: {datetime.timedelta(seconds=elapsed_time)}\n' + f'Transferred: {DataUnitConverter.to_unit_auto_str(transferred_bytes)}\n' + f'Speed: {DataUnitConverter.to_unit_auto_str(bytes_per_second)}/s') + chunk = b'' remaining_bytes = chunk_size ct += 1