benchmark-download 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. #!/usr/bin/env python
  2. """
  3. Benchmark the downloading of a file using s3transfer. You can also chose how
  4. type of file that is downloaded (i.e. filename, seekable, nonseekable).
  5. Usage
  6. =====
  7. NOTE: Make sure you run ``pip install -r requirements-dev.txt`` before running.
  8. To benchmark with using a temporary file and key that is generated for you::
  9. ./benchmark-download --file-size 10MB --file-type filename \\
  10. --s3-bucket mybucket
  11. To benchmark with your own s3 key:
  12. ./benchmark-upload --existing-s3-key mykey --file-type filename \\
  13. --s3-bucket mybucket
  14. """
  15. import argparse
  16. import os
  17. import shutil
  18. import subprocess
  19. import tempfile
  20. from botocore.session import get_session
  21. from s3transfer.manager import TransferManager
  22. TEMP_FILE = 'temp'
  23. TEMP_KEY = 'temp'
  24. KB = 1024
  25. SIZE_SUFFIX = {
  26. 'kb': 1024,
  27. 'mb': 1024**2,
  28. 'gb': 1024**3,
  29. 'tb': 1024**4,
  30. 'kib': 1024,
  31. 'mib': 1024**2,
  32. 'gib': 1024**3,
  33. 'tib': 1024**4,
  34. }
  35. def human_readable_to_bytes(value):
  36. """Converts a human readable size to bytes.
  37. :param value: A string such as "10MB". If a suffix is not included,
  38. then the value is assumed to be an integer representing the size
  39. in bytes.
  40. :returns: The converted value in bytes as an integer
  41. """
  42. value = value.lower()
  43. if value[-2:] == 'ib':
  44. # Assume IEC suffix.
  45. suffix = value[-3:].lower()
  46. else:
  47. suffix = value[-2:].lower()
  48. has_size_identifier = len(value) >= 2 and suffix in SIZE_SUFFIX
  49. if not has_size_identifier:
  50. try:
  51. return int(value)
  52. except ValueError:
  53. raise ValueError("Invalid size value: %s" % value)
  54. else:
  55. multiplier = SIZE_SUFFIX[suffix]
  56. return int(value[: -len(suffix)]) * multiplier
  57. def create_file(filename, file_size):
  58. with open(filename, 'wb') as f:
  59. for i in range(0, file_size, KB):
  60. f.write(b'a' * i)
  61. def benchmark_download(args):
  62. # Create a temporary directory to use for scratch work.
  63. tempdir = tempfile.mkdtemp()
  64. temp_file = os.path.join(tempdir, TEMP_FILE)
  65. if args.target_download:
  66. temp_file = os.path.abspath(os.path.expanduser(args.target_download))
  67. session = get_session()
  68. client = session.create_client('s3')
  69. s3_key = args.existing_s3_key
  70. try:
  71. # If an existing s3 key was not specified, then create a temporary
  72. # file of that size for the user and upload it.
  73. if not args.existing_s3_key:
  74. # Create the temporary file.
  75. create_file(temp_file, args.file_size)
  76. # Create the temporary s3 key
  77. s3_key = TEMP_KEY
  78. upload_file(client, temp_file, args.s3_bucket)
  79. download_file_script = (
  80. './download-file --file-name %s --file-type %s --s3-bucket %s '
  81. '--s3-key %s' % (temp_file, args.file_type, args.s3_bucket, s3_key)
  82. )
  83. benchmark_args = ['./benchmark', download_file_script]
  84. if args.output_file:
  85. benchmark_args.extend(['--output-file', args.output_file])
  86. subprocess.check_call(benchmark_args)
  87. finally:
  88. shutil.rmtree(tempdir)
  89. if not args.existing_s3_key:
  90. client.delete_object(Bucket=args.s3_bucket, Key=s3_key)
  91. def upload_file(client, filename, bucket):
  92. with TransferManager(client) as manager:
  93. manager.upload(filename, bucket, TEMP_KEY)
  94. def main():
  95. parser = argparse.ArgumentParser()
  96. file_group = parser.add_mutually_exclusive_group(required=True)
  97. file_group.add_argument(
  98. '--file-size',
  99. type=human_readable_to_bytes,
  100. help=(
  101. 'The size of the temporary file to create and then upload to s3. '
  102. 'You can also specify your own key with --existing-s3-key to '
  103. 'avoid going through this setup step.'
  104. ),
  105. )
  106. parser.add_argument(
  107. '--file-type',
  108. choices=['filename', 'seekable', 'nonseekable'],
  109. required=True,
  110. help='The way to represent the file when downloading',
  111. )
  112. parser.add_argument(
  113. '--s3-bucket',
  114. required=True,
  115. help='The S3 bucket to download the file to',
  116. )
  117. file_group.add_argument(
  118. '--existing-s3-key',
  119. help=(
  120. 'The existing s3 key to download from. You can also use '
  121. '--file-size to create a temporary file and key to download from.'
  122. ),
  123. )
  124. parser.add_argument(
  125. '--target-download',
  126. help=(
  127. 'The filename to download to. Note that this file will '
  128. 'always be cleaned up for you.'
  129. ),
  130. )
  131. parser.add_argument(
  132. '--output-file',
  133. help=(
  134. 'The file to output the data collected to. The default '
  135. 'location performance.csv'
  136. ),
  137. )
  138. args = parser.parse_args()
  139. benchmark_download(args)
  140. if __name__ == '__main__':
  141. main()