mirror of
				https://github.com/ARM-software/workload-automation.git
				synced 2025-10-31 07:04:17 +00:00 
			
		
		
		
	Added freqsweep instrument
Added an instrument to sweep workloads across all available frequenices
This commit is contained in:
		
							
								
								
									
										141
									
								
								wlauto/instrumentation/freqsweep/__init__.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										141
									
								
								wlauto/instrumentation/freqsweep/__init__.py
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,141 @@ | |||||||
|  | #    Copyright 2015 ARM Limited | ||||||
|  | # | ||||||
|  | # 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. | ||||||
|  | # pylint: disable=access-member-before-definition,attribute-defined-outside-init | ||||||
|  |  | ||||||
|  | import os | ||||||
|  | from wlauto import Instrument, Parameter | ||||||
|  | from wlauto.exceptions import ConfigError, InstrumentError | ||||||
|  | from wlauto.utils.types import caseless_string | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class FreqSweep(Instrument): | ||||||
|  |     name = 'freq_sweep' | ||||||
|  |     description = """ | ||||||
|  |     Sweeps workloads through all available frequencies on a device. | ||||||
|  |  | ||||||
|  |     When enabled this instrument will take all workloads specified in an agenda | ||||||
|  |     and run them at all available frequencies for all clusters. | ||||||
|  |  | ||||||
|  |     Recommendations: | ||||||
|  |         - Setting the runner to 'by_spec' increases the chance of successfully | ||||||
|  |           completing an agenda without encountering hotplug issues | ||||||
|  |         - If possible disable dynamic hotplug on the target device | ||||||
|  |     """ | ||||||
|  |  | ||||||
|  |     parameters = [ | ||||||
|  |         Parameter('sweeps', kind=list, | ||||||
|  |                   description=""" | ||||||
|  |                   By default this instrument will sweep across all available | ||||||
|  |                   frequencies for all available clusters. If you wish to only | ||||||
|  |                   sweep across certain frequencies on particular clusters you | ||||||
|  |                   can do so by specifying this parameter. | ||||||
|  |  | ||||||
|  |                   Sweeps should be a lists of dictionaries that can contain: | ||||||
|  |                     - Cluster (mandatory): The name of the cluster this sweep will be | ||||||
|  |                                            performed on. E.g A7 | ||||||
|  |                     - Frequencies: A list of frequencies (in KHz) to use. If this is | ||||||
|  |                                    not provided all frequencies available for this | ||||||
|  |                                    cluster will be used. | ||||||
|  |                                    E.g: [800000, 900000, 100000] | ||||||
|  |                     - label: Workload specs will be named '{spec id}_{label}_{frequency}'. | ||||||
|  |                              If a label is not provided it will be named 'sweep{sweep No.}' | ||||||
|  |  | ||||||
|  |                  Example sweep specification: | ||||||
|  |  | ||||||
|  |                      freq_sweep: | ||||||
|  |                          sweeps: | ||||||
|  |                              - cluster: A53 | ||||||
|  |                                label: littles | ||||||
|  |                                frequencies: [800000, 900000, 100000] | ||||||
|  |                              - cluster: A57 | ||||||
|  |                                label: bigs | ||||||
|  |                   """), | ||||||
|  |     ] | ||||||
|  |  | ||||||
|  |     def validate(self): | ||||||
|  |         if not self.device.core_names: | ||||||
|  |             raise ConfigError('The Device does not appear to have core_names configured.') | ||||||
|  |  | ||||||
|  |     def initialize(self, context):  # pylint: disable=r0912 | ||||||
|  |         if not self.device.is_rooted: | ||||||
|  |             raise InstrumentError('The device must be rooted to sweep frequencies') | ||||||
|  |  | ||||||
|  |         if 'userspace' not in self.device.list_available_cluster_governors(0): | ||||||
|  |             raise InstrumentError("'userspace' cpufreq governor must be enabled") | ||||||
|  |  | ||||||
|  |         # Create sweeps for each core type using num_cpus cores | ||||||
|  |         if not self.sweeps: | ||||||
|  |             self.sweeps = [] | ||||||
|  |             for core in set(self.device.core_names): | ||||||
|  |                 sweep_spec = {} | ||||||
|  |                 sweep_spec['cluster'] = core | ||||||
|  |                 sweep_spec['label'] = core | ||||||
|  |                 self.sweeps.append(sweep_spec) | ||||||
|  |  | ||||||
|  |         new_specs = [] | ||||||
|  |         old_specs = [] | ||||||
|  |         for job in context.runner.job_queue: | ||||||
|  |             if job.spec not in old_specs: | ||||||
|  |                 old_specs.append(job.spec) | ||||||
|  |  | ||||||
|  |         # Validate sweeps, add missing sections and create workload specs | ||||||
|  |         for i, sweep_spec in enumerate(self.sweeps): | ||||||
|  |             if 'cluster' not in sweep_spec: | ||||||
|  |                 raise ConfigError('cluster must be define for all sweeps') | ||||||
|  |             # Check if cluster exists on device | ||||||
|  |             if caseless_string(sweep_spec['cluster']) not in self.device.core_names: | ||||||
|  |                 raise ConfigError('Only {} cores are present on this device, you specified {}' | ||||||
|  |                                   .format(", ".join(set(self.device.core_names)), sweep_spec['cluster'])) | ||||||
|  |  | ||||||
|  |             # Default to all available frequencies | ||||||
|  |             if 'frequencies' not in sweep_spec: | ||||||
|  |                 self.device.enable_cpu(self.device.core_names.index(sweep_spec['cluster'])) | ||||||
|  |                 sweep_spec['frequencies'] = self.device.list_available_core_frequencies(sweep_spec['cluster']) | ||||||
|  |  | ||||||
|  |             # Check that given frequencies are valid of the core cluster | ||||||
|  |             else: | ||||||
|  |                 self.device.enable_cpu(self.device.core_names.index(sweep_spec['cluster'])) | ||||||
|  |                 available_freqs = self.device.list_available_core_frequencies(sweep_spec['cluster']) | ||||||
|  |                 for freq in sweep_spec['frequencies']: | ||||||
|  |                     if freq not in available_freqs: | ||||||
|  |                         raise ConfigError('Frequency {} is not supported by {} cores'.format(freq, sweep_spec['cluster'])) | ||||||
|  |  | ||||||
|  |             # Add default labels | ||||||
|  |             if 'label' not in sweep_spec: | ||||||
|  |                 sweep_spec['label'] = "sweep{}".format(i + 1) | ||||||
|  |  | ||||||
|  |             new_specs.extend(self.get_sweep_workload_specs(old_specs, sweep_spec, context)) | ||||||
|  |  | ||||||
|  |         # Update config to refect jobs that will actually run. | ||||||
|  |         context.config.workload_specs = new_specs | ||||||
|  |         config_file = os.path.join(context.host_working_directory, 'run_config.json') | ||||||
|  |         with open(config_file, 'wb') as wfh: | ||||||
|  |             context.config.serialize(wfh) | ||||||
|  |         context.runner.init_queue(new_specs) | ||||||
|  |  | ||||||
|  |     def get_sweep_workload_specs(self, old_specs, sweep_spec, context): | ||||||
|  |         new_specs = [] | ||||||
|  |         for old_spec in old_specs: | ||||||
|  |             for freq in sweep_spec['frequencies']: | ||||||
|  |                 spec = old_spec.copy() | ||||||
|  |                 spec.runtime_parameters['{}_governor'.format(sweep_spec['cluster'])] = "userspace" | ||||||
|  |                 spec.runtime_parameters['{}_frequency'.format(sweep_spec['cluster'])] = freq | ||||||
|  |                 spec.id = '{}_{}_{}'.format(spec.id, sweep_spec['label'], freq) | ||||||
|  |                 spec.classifiers['core'] = sweep_spec['cluster'] | ||||||
|  |                 spec.classifiers['freq'] = freq | ||||||
|  |                 spec.load(self.device, context.config.ext_loader) | ||||||
|  |                 spec.workload.init_resources(context) | ||||||
|  |                 spec.workload.validate() | ||||||
|  |                 new_specs.append(spec) | ||||||
|  |         return new_specs | ||||||
		Reference in New Issue
	
	Block a user