''' Copyright (c) 2024 Beijing Volcano Engine Technology Ltd. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ''' import argparse import os import time from functools import lru_cache import numpy as np import torch import veturboio def human_read_to_byte(size): factors = { 'B': 1, 'KB': 1024, 'MB': 1048576, 'GB': 1073741824, 'TB': 1099511627776, 'PB': 1125899906842624, 'EB': 1152921504606846976, 'ZB': 1180591620717411303424, 'YB': 1208925819614629174706176, } if size[-2:] in factors: return factors[size[-2:]] * int(size[:-2]) elif size[-1:] in factors: return int(size[:-1]) else: return int(size) def parse_args(): parser = argparse.ArgumentParser( description='benchmark veturboio, notice to clear page cache manually when benchmarking for existing file' ) parser.add_argument( '--begin', default='1048576', dest='begin', help='specify the minimum file size to benchmark in bytes or in format like xxKB/MB/GB', ) parser.add_argument( '--end', default='1048576', dest='end', help='specify the maximum file size to benchmark in bytes or in format like xxKB/MB/GB', ) parser.add_argument('--base_dir', dest='base_dir', help='specify the the base dir of files to be benchmarked') parser.add_argument('--fs_name', default='local_fs', help='file system name that would be displayed in the result') parser.add_argument('--gen_data', default=False, action=argparse.BooleanOptionalAction, dest='gen_data') parser.add_argument( '--map_location', default='cpu', dest='map_location', help='map location of tensor to be loaded' ) parser.add_argument('--use_pinmem', default=False, action=argparse.BooleanOptionalAction, dest='use_pinmem') parser.add_argument( '--load_mode', default='veturboio', dest='load_mode', help='load modes specified, seperated by comma' ) args = parser.parse_args() return args def print_header(load_modes): mode_list = list(map(lambda mode: f"{mode}{' load_time(s)' + ' ':<25}", load_modes)) print(f"{'fs_name' + ' ':<10} {'tensor_size' + ' ':<15}", ' '.join(mode_list)) def print_load_time(fs_name, tensor_size, load_times): load_times = list(map(lambda load_time: f"{load_time}{' ':<30}", load_times)) print(f"{fs_name:<10} {str(tensor_size):<15}", ' '.join(load_times)) def main(): args = parse_args() load_modes = args.load_mode.split(',') # warmup GPU otherwise the first case would be slow device = torch.device(args.map_location) if device.type == "cuda": file_path = os.path.join(args.base_dir if args.base_dir else "", 'warmup.safetensors') tensors = {"weight": torch.randn(10)} veturboio.save_file(tensors, file_path) veturboio.load(file_path, map_location=args.map_location, use_pinmem=args.use_pinmem) print_header(load_modes) tensor_size = human_read_to_byte(args.begin) end_size = human_read_to_byte(args.end) while tensor_size <= end_size: if args.gen_data: numel = tensor_size // np.dtype(float).itemsize * 2 tensors = {"weight": torch.randn(numel)} load_times = [] for mode in load_modes: if mode == 'veturboio': file_path = os.path.join(args.base_dir if args.base_dir else "", f'{tensor_size}.safetensors') if args.gen_data: veturboio.save_file(tensors, file_path) start = time.time() loaded_tensor = veturboio.load(file_path, map_location=args.map_location, use_pinmem=args.use_pinmem) if mode == 'torch': file_path = os.path.join(args.base_dir if args.base_dir else "", f'{tensor_size}.pt') if args.gen_data: veturboio.save_pt(tensors, file_path) start = time.time() loaded_tensor = veturboio.load(file_path, map_location=args.map_location) end = time.time() load_times.append("%.2f" % (end - start)) if device.type == "cuda": del loaded_tensor torch.cuda.empty_cache() print_load_time(args.fs_name, tensor_size, load_times) tensor_size = tensor_size * 2 if __name__ == '__main__': main()