OLD | NEW |
(Empty) | |
| 1 import datetime, logging, os, time |
| 2 from autotest_lib.client.bin import test, utils |
| 3 from autotest_lib.client.common_lib import error |
| 4 |
| 5 class wb_kupdate(test.test): |
| 6 version = 1 |
| 7 |
| 8 |
| 9 def _check_parameters(self, mount_point, write_size, file_count, |
| 10 old_cleanup=False): |
| 11 """ |
| 12 Check all test parameters. |
| 13 |
| 14 @param mount_point: the path to the desired mount_point. |
| 15 @param write_size: the size of data in MB to write. |
| 16 @param file_count: the number of files to write. |
| 17 @param old_cleanup: removes previous mount_point if it exists and is |
| 18 not mounted. Default is False. |
| 19 """ |
| 20 # Check mount_point. |
| 21 if not os.path.exists(mount_point): |
| 22 logging.info('%s does not exist. Creating directory.', mount_point) |
| 23 elif not os.path.ismount(mount_point) and old_cleanup: |
| 24 logging.info('Removing previous mount_point directory') |
| 25 os.rmdir(mount_point) |
| 26 logging.info('Creating new mount_point.') |
| 27 else: |
| 28 raise error.TestError('Mount point: %s already exists.' % |
| 29 mount_point) |
| 30 |
| 31 os.makedirs(mount_point) |
| 32 # Check write_size > 0. |
| 33 if not (write_size > 0): |
| 34 raise error.TestError('Write size should be a positive integer.') |
| 35 |
| 36 # Check file_count > 0. |
| 37 if not (file_count > 0) : |
| 38 raise error.TestError('File count shoulde be a positive integer.') |
| 39 |
| 40 |
| 41 def _reset_device(self): |
| 42 """ |
| 43 Reset the test. Reinitialize sparse file. |
| 44 """ |
| 45 # Umount device. |
| 46 logging.debug('Cleanup - unmounting loopback device.') |
| 47 utils.system('umount %s' % self.mount_point, ignore_status=True) |
| 48 |
| 49 # Remove sparse_file. |
| 50 logging.debug('Cleanup - removing sparse file.') |
| 51 os.remove(self.sparse_file) |
| 52 |
| 53 # Remove mount_point directory. |
| 54 logging.debug('Cleanup - removing the mount_point.') |
| 55 os.rmdir(self.mount_point) |
| 56 |
| 57 |
| 58 def _create_partition(self): |
| 59 """ |
| 60 Create and initialize the sparse file. |
| 61 """ |
| 62 # Recreate sparse_file. |
| 63 utils.system('dd if=/dev/zero of=%s bs=1M seek=1024 count=1' % |
| 64 self.sparse_file) |
| 65 |
| 66 # Format sparse_file. |
| 67 utils.system('echo "y" | mkfs -t %s %s' % |
| 68 (self.file_system, self.sparse_file)) |
| 69 |
| 70 # Mount sparse_file. |
| 71 utils.system('mount -o loop -t %s %s %s' % |
| 72 (self.file_system, self.sparse_file, self.mount_point)) |
| 73 |
| 74 |
| 75 def _needs_more_time(self, start_time, duration, _now=None): |
| 76 """ |
| 77 Checks to see if the test has run its course. |
| 78 |
| 79 @param start_time: a datetime object specifying the start time of the |
| 80 test. |
| 81 @param duration: test duration in minutes. |
| 82 @param _now: used mostly for testing - ensures that the function returns |
| 83 pass/fail depnding on the value of _now. |
| 84 |
| 85 @return: True if the test still needs to run longer. |
| 86 False if the test has run for 'duration' minutes. |
| 87 """ |
| 88 if not _now: |
| 89 time_diff = datetime.datetime.now() - start_time |
| 90 else: |
| 91 time_diff = _now - start_time |
| 92 return time_diff <= datetime.timedelta(seconds=duration*60) |
| 93 |
| 94 |
| 95 def _write_data(self, destination, counter, write_size): |
| 96 """ |
| 97 Writes data to the cache/memory. |
| 98 |
| 99 @param destination: the absolute path to where the data needs to be |
| 100 written. |
| 101 @param counter: the file counter. |
| 102 @param write_size: the size of data to be written. |
| 103 |
| 104 @return: the time when the write completed as a datetime object. |
| 105 """ |
| 106 # Write data to disk. |
| 107 file_name = os.path.join(destination, 'test_file_%s' % counter) |
| 108 write_cmd = ('dd if=/dev/zero of=%s bs=1M count=%s' % |
| 109 (file_name, write_size)) |
| 110 utils.system(write_cmd) |
| 111 |
| 112 # Time the write operation. |
| 113 write_completion_time = datetime.datetime.now() |
| 114 |
| 115 # Return write completion time. |
| 116 return write_completion_time |
| 117 |
| 118 |
| 119 def _get_disk_usage(self, file_name): |
| 120 """ |
| 121 Returns the disk usage of given file. |
| 122 |
| 123 @param file_name: the name of the file. |
| 124 |
| 125 @return: the disk usage as an integer. |
| 126 """ |
| 127 # Check du stats. |
| 128 cmd = '%s %s' % (self._DU_CMD, file_name) |
| 129 |
| 130 # Expected value for output = '1028\tfoo' |
| 131 output = utils.system_output(cmd) |
| 132 |
| 133 # Desired ouput = (1028, foo) |
| 134 output = output.split('\t') |
| 135 |
| 136 return int(output[0]) |
| 137 |
| 138 |
| 139 def _wait_until_data_flushed(self, start_time, max_wait_time): |
| 140 """ |
| 141 Check to see if the sparse file size increases. |
| 142 |
| 143 @param start_time: the time when data was actually written into the |
| 144 cache. |
| 145 @param max_wait_time: the max amount of time to wait. |
| 146 |
| 147 @return: time waited as a datetime.timedelta object. |
| 148 """ |
| 149 current_size = self._get_disk_usage(self.sparse_file) |
| 150 flushed_size = current_size |
| 151 |
| 152 logging.debug('current_size: %s' % current_size) |
| 153 logging.debug('flushed_size: %s' % flushed_size) |
| 154 |
| 155 # Keep checking until du value changes. |
| 156 while current_size == flushed_size: |
| 157 # Get flushed_size. |
| 158 flushed_size = self._get_disk_usage(self.sparse_file) |
| 159 logging.debug('flushed_size: %s' % flushed_size) |
| 160 time.sleep(1) |
| 161 |
| 162 # Check if data has been synced to disk. |
| 163 if not self._needs_more_time(start_time, max_wait_time): |
| 164 raise error.TestError('Data not flushed. Waited for %s minutes ' |
| 165 'for data to flush out.' % max_wait_time) |
| 166 |
| 167 # Return time waited. |
| 168 return datetime.datetime.now() - start_time |
| 169 |
| 170 |
| 171 def initialize(self): |
| 172 """ |
| 173 Initialize all private and global member variables. |
| 174 """ |
| 175 self._DU_CMD = 'du' |
| 176 self.partition = None |
| 177 self.mount_point = '' |
| 178 self.sparse_file = '' |
| 179 self.result_map = {} |
| 180 self.file_system = None |
| 181 |
| 182 |
| 183 def run_once(self, mount_point, file_count, write_size, |
| 184 max_flush_time=1, file_system=None, remove_previous=False, |
| 185 sparse_file=os.path.join(os.getcwd(),'sparse_file'), |
| 186 old_cleanup=False): |
| 187 """ |
| 188 Control execution of the test. |
| 189 |
| 190 @param mount_point: the absolute path to the mount point. |
| 191 @param file_count: the number of files to write. |
| 192 @param write_size: the size of each file in MB. |
| 193 @param max_flush_time: the maximum time to wait for the writeback to |
| 194 flush dirty data to disk. Default = 1 minute. |
| 195 @param file_system: the new file system to be mounted, if any. |
| 196 Default = None. |
| 197 @param remove_previous: boolean that allows the removal of previous |
| 198 files before creating a new one. Default = False. |
| 199 @param sparse_file: the absolute path to the sparse file. |
| 200 @param old_cleanup: removes previous mount_point if it exists and is |
| 201 not mounted. Default is False. |
| 202 """ |
| 203 # Check validity of parameters. |
| 204 self._check_parameters(mount_point, write_size, file_count, |
| 205 old_cleanup) |
| 206 |
| 207 # Initialize class variables. |
| 208 self.mount_point = mount_point |
| 209 self.sparse_file = sparse_file |
| 210 self.file_system = file_system |
| 211 |
| 212 # Initialize partition values. |
| 213 self._create_partition() |
| 214 |
| 215 # Flush read and write cache. |
| 216 utils.drop_caches() |
| 217 |
| 218 # Start iterations. |
| 219 logging.info('Starting test operations.') |
| 220 test_start_time = datetime.datetime.now() |
| 221 counter = 1 |
| 222 |
| 223 # Run test until file_count files are successfully written to disk. |
| 224 while counter < file_count: |
| 225 logging.info('Iteration %s.', counter) |
| 226 |
| 227 # Write data to disk. |
| 228 write_completion_time = self._write_data(self.mount_point, counter, |
| 229 write_size) |
| 230 logging.debug('Write time:%s', |
| 231 write_completion_time.strftime("%H:%M:%S")) |
| 232 |
| 233 # Wait until data get synced to disk. |
| 234 time_taken = self._wait_until_data_flushed(write_completion_time, |
| 235 max_flush_time) |
| 236 |
| 237 # Log time statistics. |
| 238 logging.info('Time taken to flush data: %s seconds.', |
| 239 time_taken.seconds) |
| 240 |
| 241 # Check if there is a need to remove the previously written file. |
| 242 if remove_previous: |
| 243 logging.debug('Removing previous file instance.') |
| 244 os.remove(file_name) |
| 245 else: |
| 246 logging.debug('Not removing previous file instance.') |
| 247 |
| 248 # Flush cache. |
| 249 logging.debug('Flush cache between iterations.') |
| 250 utils.drop_caches() |
| 251 |
| 252 # Update the result map. |
| 253 self.result_map[counter] = time_taken.seconds |
| 254 |
| 255 # Increment the counter. |
| 256 counter += 1 |
| 257 |
| 258 |
| 259 def postprocess(self): |
| 260 """ |
| 261 Cleanup routine. |
| 262 """ |
| 263 # Write out keyval map. |
| 264 self.write_perf_keyval(self.result_map) |
| 265 |
| 266 # Cleanup device. |
| 267 self._reset_device() |
| 268 |
| 269 logging.info('Test operations completed.') |
OLD | NEW |