1+ # frozen_string_literal: true
2+
13require 'benchmark'
24require 'find'
35require 'zip'
6+ require 'tempfile'
7+ require 'fileutils'
8+ require 'securerandom'
49
510module VCAP ::CloudController
611 module Benchmark
712 class Blobstore
13+ SIZES = [
14+ [ '0.005MB' , ( 0.005 * 1024 * 1024 ) . to_i ] ,
15+ [ '0.01MB' , ( 0.01 * 1024 * 1024 ) . to_i ] ,
16+ [ '0.1MB' , ( 0.1 * 1024 * 1024 ) . to_i ] ,
17+ [ '1MB' , 1 * 1024 * 1024 ] ,
18+ [ '10MB' , 10 * 1024 * 1024 ] ,
19+ [ '100MB' , 100 * 1024 * 1024 ] ,
20+ [ '200MB' , 200 * 1024 * 1024 ] ,
21+ [ '300MB' , 300 * 1024 * 1024 ] ,
22+ [ '400MB' , 400 * 1024 * 1024 ] ,
23+ [ '500MB' , 500 * 1024 * 1024 ] ,
24+ [ '600MB' , 600 * 1024 * 1024 ] ,
25+ [ '700MB' , 700 * 1024 * 1024 ] ,
26+ [ '800MB' , 800 * 1024 * 1024 ] ,
27+ [ '900MB' , 900 * 1024 * 1024 ] ,
28+ [ '1000MB' , 1000 * 1024 * 1024 ]
29+ ] . freeze
30+
31+ CHUNK_1MB = '0' . b * ( 1024 * 1024 )
32+
833 def perform
34+ big_droplet_guids = [ ]
935 resource_dir = generate_resources
10-
11- resource_timing = resource_match ( resource_dir )
12- puts ( "resource match timing: #{ resource_timing * 1000 } ms" )
36+ log_timing ( 'resource match timing' , resource_match ( resource_dir ) )
1337
1438 zip_output_dir = Dir . mktmpdir
1539 zip_file = zip_resources ( resource_dir , zip_output_dir )
1640
17- package_guid , resource_timing = upload_package ( zip_file )
18- puts ( "package upload timing: #{ resource_timing * 1000 } ms" )
19-
20- resource_timing = download_package ( package_guid , resource_dir )
21- puts ( "package download timing: #{ resource_timing * 1000 } ms" )
41+ package_guid , timing = upload_package ( zip_file )
42+ log_timing ( 'package upload timing' , timing )
43+ log_timing ( 'package download timing' , download_package ( package_guid , resource_dir ) )
2244
23- bytes_read , resource_timing = download_buildpacks ( resource_dir )
45+ bytes_read , timing = download_buildpacks ( resource_dir )
2446 puts ( "downloaded #{ Buildpack . count } buildpacks, total #{ bytes_read } bytes read" )
25- puts ( " buildpack download timing: #{ resource_timing * 1000 } ms" )
47+ log_timing ( ' buildpack download timing' , timing )
2648
27- droplet_guid , resource_timing = upload_droplet ( zip_file )
28- puts ( "droplet upload timing: #{ resource_timing * 1000 } ms" )
49+ droplet_results = [ ]
2950
30- resource_timing = download_droplet ( droplet_guid , resource_dir )
31- puts ( "droplet download timing: #{ resource_timing * 1000 } ms" )
51+ SIZES . each do |label , bytes |
52+ Tempfile . create ( [ "big-droplet-#{ label } " , '.bin' ] , resource_dir ) do |tempfile |
53+ write_file_of_size ( tempfile . path , bytes )
3254
33- big_droplet_file = Tempfile . new ( 'big-droplet' , resource_dir )
34- big_droplet_file . write ( 'abc' * 1024 * 1024 * 100 )
35- big_droplet_guid , resource_timing = upload_droplet ( big_droplet_file . path )
36- puts ( "big droplet upload timing: #{ resource_timing * 1000 } ms" )
55+ guid , upload_timing = upload_droplet ( tempfile . path )
56+ big_droplet_guids << guid
57+ droplet_results << { label : "droplet #{ label } " , guid : guid , upload_timing : upload_timing }
58+ end
59+ end
60+ # rubocop:disable Style/CombinableLoops
61+ droplet_results . each do |r |
62+ log_timing ( "#{ r [ :label ] } upload timing" , r [ :upload_timing ] )
63+ end
3764
38- resource_timing = download_droplet ( big_droplet_guid , resource_dir )
39- puts ( "big droplet download timing: #{ resource_timing * 1000 } ms" )
65+ droplet_results . each do |r |
66+ log_timing ( "#{ r [ :label ] } download timing" , download_droplet ( r [ :guid ] , resource_dir ) )
67+ end
68+ # rubocop:enable Style/CombinableLoops
4069 ensure
41- FileUtils . remove_dir ( resource_dir , true )
42- FileUtils . remove_dir ( zip_output_dir , true )
43- package_blobstore_client . delete ( package_guid ) if package_guid
44- droplet_blobstore_client . delete ( droplet_guid ) if droplet_guid
45- droplet_blobstore_client . delete ( big_droplet_guid ) if big_droplet_guid
70+ FileUtils . remove_dir ( resource_dir , true ) if resource_dir
71+ FileUtils . remove_dir ( zip_output_dir , true ) if zip_output_dir
72+
73+ safe_delete ( package_blobstore_client , package_guid )
74+ Array ( big_droplet_guids ) . each { | g | safe_delete ( droplet_blobstore_client , g ) }
4675 end
4776
4877 def resource_match ( dir_path )
@@ -60,46 +89,69 @@ def upload_package(package_path)
6089 end
6190
6291 def download_package ( package_guid , tmp_dir )
63- tempfile = Tempfile . new ( 'package-download-benchmark' , tmp_dir )
64- ::Benchmark . realtime do
65- package_blobstore_client . download_from_blobstore ( package_guid , tempfile . path )
92+ Tempfile . create ( 'package-download-benchmark' , tmp_dir ) do |tempfile |
93+ ::Benchmark . realtime do
94+ package_blobstore_client . download_from_blobstore ( package_guid , tempfile . path )
95+ end
6696 end
6797 end
6898
6999 def download_buildpacks ( tmp_dir )
70- tempfile = Tempfile . new ( 'buildpack-download-benchmark' , tmp_dir )
71- bytes_read = 0
72-
73- timing = ::Benchmark . realtime do
74- bytes_read = Buildpack . map do |buildpack |
75- buildpack_blobstore_client . download_from_blobstore ( buildpack . key , tempfile . path )
76- File . stat ( tempfile . path ) . size
77- end . sum
100+ Tempfile . create ( 'buildpack-download-benchmark' , tmp_dir ) do |tempfile |
101+ bytes_read = 0
102+ timing = ::Benchmark . realtime do
103+ bytes_read = Buildpack . map do |buildpack |
104+ buildpack_blobstore_client . download_from_blobstore ( buildpack . key , tempfile . path )
105+ File . stat ( tempfile . path ) . size
106+ end . sum
107+ end
108+ [ bytes_read , timing ]
78109 end
79-
80- [ bytes_read , timing ]
81110 end
82111
83112 def upload_droplet ( droplet_path )
84113 copy_to_blobstore ( droplet_path , droplet_blobstore_client )
85114 end
86115
87116 def download_droplet ( droplet_guid , tmp_dir )
88- tempfile = Tempfile . new ( 'droplet-download-benchmark' , tmp_dir )
89-
90- :: Benchmark . realtime do
91- droplet_blobstore_client . download_from_blobstore ( droplet_guid , tempfile . path )
117+ Tempfile . create ( 'droplet-download-benchmark' , tmp_dir ) do | tempfile |
118+ :: Benchmark . realtime do
119+ droplet_blobstore_client . download_from_blobstore ( droplet_guid , tempfile . path )
120+ end
92121 end
93122 end
94123
95124 private
96125
126+ def log_timing ( label , seconds )
127+ puts ( "#{ label } : #{ ( seconds * 1000 ) . round ( 3 ) } ms" )
128+ end
129+
130+ def safe_delete ( client , guid )
131+ return if guid . nil?
132+
133+ client . delete ( guid )
134+ rescue StandardError => e
135+ # don't fail the benchmark run if cleanup fails
136+ warn ( "cleanup failed for guid=#{ guid } : #{ e . class } : #{ e . message } " )
137+ end
138+
139+ def write_file_of_size ( path , bytes )
140+ File . open ( path , 'wb' ) do |f |
141+ remaining = bytes
142+ while remaining > 0
143+ to_write = [ CHUNK_1MB . bytesize , remaining ] . min
144+ f . write ( CHUNK_1MB , to_write )
145+ remaining -= to_write
146+ end
147+ end
148+ end
149+
97150 def generate_resources
98151 dir = Dir . mktmpdir
99152
100- 100 . times . each do |i |
101- f = File . open ( File . join ( dir , i . to_s ) , 'w' )
102- f . write ( 'foo' * ( 65_536 + i ) )
153+ 100 . times do |i |
154+ File . write ( File . join ( dir , i . to_s ) , 'foo' * ( 65_536 + i ) )
103155 end
104156
105157 dir
@@ -110,9 +162,7 @@ def zip_resources(resource_dir, output_dir)
110162 Zip ::File . open ( zip_file , create : true ) do |zipfile |
111163 Find . find ( resource_dir ) .
112164 select { |f | File . file? ( f ) } .
113- each do |file |
114- zipfile . add ( File . basename ( file ) , file )
115- end
165+ each { |file | zipfile . add ( File . basename ( file ) , file ) }
116166 end
117167 zip_file
118168 end
0 commit comments