mirror of
				https://github.com/ARM-software/workload-automation.git
				synced 2025-11-04 00:52:08 +00:00 
			
		
		
		
	Merge pull request #52 from ep1cman/freqsweep
Added freqsweep instrument
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