benchmark-upload 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. #!/usr/bin/env python
  2. """
  3. Benchmark the uploading of a file using s3transfer. You can also chose how
  4. type of file that is uploaded (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 that is generated for you::
  9. ./benchmark-upload --file-size 10MB --file-type filename \\
  10. --s3-bucket mybucket
  11. To benchmark with your own local file::
  12. ./benchmark-upload --source-file myfile --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. TEMP_FILE = 'temp'
  22. TEMP_KEY = 'temp'
  23. KB = 1024
  24. SIZE_SUFFIX = {
  25. 'kb': 1024,
  26. 'mb': 1024**2,
  27. 'gb': 1024**3,
  28. 'tb': 1024**4,
  29. 'kib': 1024,
  30. 'mib': 1024**2,
  31. 'gib': 1024**3,
  32. 'tib': 1024**4,
  33. }
  34. def human_readable_to_bytes(value):
  35. """Converts a human readable size to bytes.
  36. :param value: A string such as "10MB". If a suffix is not included,
  37. then the value is assumed to be an integer representing the size
  38. in bytes.
  39. :returns: The converted value in bytes as an integer
  40. """
  41. value = value.lower()
  42. if value[-2:] == 'ib':
  43. # Assume IEC suffix.
  44. suffix = value[-3:].lower()
  45. else:
  46. suffix = value[-2:].lower()
  47. has_size_identifier = len(value) >= 2 and suffix in SIZE_SUFFIX
  48. if not has_size_identifier:
  49. try:
  50. return int(value)
  51. except ValueError:
  52. raise ValueError("Invalid size value: %s" % value)
  53. else:
  54. multiplier = SIZE_SUFFIX[suffix]
  55. return int(value[: -len(suffix)]) * multiplier
  56. def create_file(filename, file_size):
  57. with open(filename, 'wb') as f:
  58. for i in range(0, file_size, KB):
  59. f.write(b'a' * i)
  60. def benchmark_upload(args):
  61. source_file = args.source_file
  62. session = get_session()
  63. client = session.create_client('s3')
  64. tempdir = None
  65. try:
  66. # If a source file was not specified, then create a temporary file of
  67. # that size for the user.
  68. if not source_file:
  69. tempdir = tempfile.mkdtemp()
  70. source_file = os.path.join(tempdir, TEMP_FILE)
  71. create_file(source_file, args.file_size)
  72. upload_file_script = (
  73. './upload-file --file-name %s --file-type %s --s3-bucket %s '
  74. '--s3-key %s'
  75. % (source_file, args.file_type, args.s3_bucket, TEMP_KEY)
  76. )
  77. benchmark_args = ['./benchmark', upload_file_script]
  78. if args.output_file:
  79. benchmark_args.extend(['--output-file', args.output_file])
  80. subprocess.check_call(benchmark_args)
  81. finally:
  82. if tempdir:
  83. shutil.rmtree(tempdir)
  84. client.delete_object(Bucket=args.s3_bucket, Key=TEMP_KEY)
  85. def main():
  86. parser = argparse.ArgumentParser(usage=__doc__)
  87. source_file_group = parser.add_mutually_exclusive_group(required=True)
  88. source_file_group.add_argument(
  89. '--source-file',
  90. help=(
  91. 'The local file to upload. Note this is optional. You can also '
  92. 'use --file-size which will create a temporary file for you.'
  93. ),
  94. )
  95. source_file_group.add_argument(
  96. '--file-size',
  97. type=human_readable_to_bytes,
  98. help=(
  99. 'The size of the temporary file to create. You can also specify '
  100. 'your own file with --source-file'
  101. ),
  102. )
  103. parser.add_argument(
  104. '--file-type',
  105. choices=['filename', 'seekable', 'nonseekable'],
  106. required=True,
  107. help='The way to represent the file when uploading',
  108. )
  109. parser.add_argument(
  110. '--s3-bucket',
  111. required=True,
  112. help='The S3 bucket to upload the file to',
  113. )
  114. parser.add_argument(
  115. '--output-file',
  116. help=(
  117. 'The file to output the data collected to. The default '
  118. 'location performance.csv'
  119. ),
  120. )
  121. args = parser.parse_args()
  122. benchmark_upload(args)
  123. if __name__ == '__main__':
  124. main()