mirror of
				https://github.com/ARM-software/workload-automation.git
				synced 2025-11-04 00:52:08 +00:00 
			
		
		
		
	exoplayer: Add exoplayer workload
This is based heavily on a combination of WA2's video workload and LISA's exoplayer workload.
This commit is contained in:
		
				
					committed by
					
						
						setrofim
					
				
			
			
				
	
			
			
			
						parent
						
							9b58662ae7
						
					
				
				
					commit
					b17a0d30c0
				
			
							
								
								
									
										187
									
								
								wa/workloads/exoplayer/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										187
									
								
								wa/workloads/exoplayer/__init__.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,187 @@
 | 
			
		||||
# SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
#
 | 
			
		||||
# Copyright (C) 2017, Arm Limited and contributors.
 | 
			
		||||
#
 | 
			
		||||
# 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.
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
from collections import defaultdict
 | 
			
		||||
import re
 | 
			
		||||
import os
 | 
			
		||||
import time
 | 
			
		||||
import urllib
 | 
			
		||||
 | 
			
		||||
from wa import ApkWorkload, Parameter, ConfigError, WorkloadError
 | 
			
		||||
from wa.framework.configuration.core import settings
 | 
			
		||||
from wa.utils.types import boolean
 | 
			
		||||
from wa.utils.misc import ensure_directory_exists
 | 
			
		||||
from devlib.utils.android import grant_app_permissions
 | 
			
		||||
 | 
			
		||||
# Regexps for benchmark synchronization
 | 
			
		||||
REGEXPS = {
 | 
			
		||||
    'start'    : '.*Displayed com.google.android.exoplayer2.demo/.PlayerActivity',
 | 
			
		||||
    'duration' : '.*period \[(?P<duration>[0-9]+.*)\]',
 | 
			
		||||
    'end'      : '.*state \[.+, .+, E\]'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
DOWNLOAD_URLS = {
 | 
			
		||||
    'mp4_1080p': 'http://distribution.bbb3d.renderfarming.net/video/mp4/bbb_sunflower_1080p_30fps_normal.mp4',
 | 
			
		||||
    'mov_720p':  'http://download.blender.org/peach/bigbuckbunny_movies/big_buck_bunny_720p_h264.mov',
 | 
			
		||||
    'mov_480p':  'http://download.blender.org/peach/bigbuckbunny_movies/big_buck_bunny_480p_h264.mov',
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ExoPlayer(ApkWorkload):
 | 
			
		||||
    """
 | 
			
		||||
    Android ExoPlayer
 | 
			
		||||
 | 
			
		||||
    ExoPlayer is the basic video player library that is used by the YouTube
 | 
			
		||||
    android app. The aim of this workload is to test a proxy for YouTube
 | 
			
		||||
    performance on targets where running the real YouTube app is not possible
 | 
			
		||||
    due its dependencies.
 | 
			
		||||
 | 
			
		||||
    ExoPlayer sources: https://github.com/google/ExoPlayer
 | 
			
		||||
 | 
			
		||||
    The 'demo' application is used by this workload.  It can easily be built by
 | 
			
		||||
    loading the ExoPlayer sources into Android Studio.
 | 
			
		||||
 | 
			
		||||
    Version r2.4.0 built from commit d979469 is known to work
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    name = 'exoplayer'
 | 
			
		||||
 | 
			
		||||
    video_directory = os.path.join(settings.dependencies_directory, name)
 | 
			
		||||
 | 
			
		||||
    package_names = ['com.google.android.exoplayer2.demo']
 | 
			
		||||
    versions = ['2.4.0']
 | 
			
		||||
    action = 'com.google.android.exoplayer.demo.action.VIEW'
 | 
			
		||||
    default_format = 'mov_720p'
 | 
			
		||||
 | 
			
		||||
    parameters = [
 | 
			
		||||
        Parameter('version', allowed_values=versions, default=versions[-1], override=True),
 | 
			
		||||
        Parameter('duration', kind=int, default=20,
 | 
			
		||||
                  description="""
 | 
			
		||||
                  Playback duration of the video file. This becomes the duration of the workload.
 | 
			
		||||
                  If provided must be shorter than the length of the media.
 | 
			
		||||
                  """),
 | 
			
		||||
        Parameter('format', allowed_values=DOWNLOAD_URLS.keys(),
 | 
			
		||||
                  description="""
 | 
			
		||||
                  Specifies which format video file to play. Default is {}
 | 
			
		||||
                  """.format(default_format)),
 | 
			
		||||
        Parameter('filename',
 | 
			
		||||
                  description="""
 | 
			
		||||
                   The name of the video file to play. This can be either a path
 | 
			
		||||
                   to the file anywhere on your file system, or it could be just a
 | 
			
		||||
                   name, in which case, the workload will look for it in
 | 
			
		||||
                   ``{}``
 | 
			
		||||
                   *Note*: either format or filename should be specified, but not both!
 | 
			
		||||
                  """.format(video_directory)),
 | 
			
		||||
        Parameter('force_dependency_push', kind=boolean, default=False,
 | 
			
		||||
                  description="""
 | 
			
		||||
                  If true, video will always be pushed to device, regardless
 | 
			
		||||
                  of whether the file is already on the device.  Default is ``False``.
 | 
			
		||||
                  """),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    def validate(self):
 | 
			
		||||
        if self.format and self.filename:
 | 
			
		||||
            raise ConfigError('Either format *or* filename must be specified; but not both.')
 | 
			
		||||
 | 
			
		||||
        if not self.format and not self.filename:
 | 
			
		||||
            self.format = self.default_format
 | 
			
		||||
 | 
			
		||||
    def _find_host_video_file(self):
 | 
			
		||||
        """Pick the video file we're going to use, download it if necessary"""
 | 
			
		||||
        if self.filename:
 | 
			
		||||
            if self.filename[0] in './' or len(self.filename) > 1 and self.filename[1] == ':':
 | 
			
		||||
                filepath = os.path.abspath(self.filename)
 | 
			
		||||
            else:
 | 
			
		||||
                filepath = os.path.join(self.video_directory, self.filename)
 | 
			
		||||
            if not os.path.isfile(filepath):
 | 
			
		||||
                raise WorkloadError('{} does not exist.'.format(filepath))
 | 
			
		||||
            return filepath
 | 
			
		||||
        else:
 | 
			
		||||
            # Search for files we've already downloaded
 | 
			
		||||
            files = []
 | 
			
		||||
            for filename in os.listdir(self.video_directory):
 | 
			
		||||
                format_ext, format_resolution = self.format.split('_')
 | 
			
		||||
                _, file_ext = os.path.splitext(filename)
 | 
			
		||||
                if file_ext == '.' + format_ext and format_resolution in filename:
 | 
			
		||||
                    files.append(os.path.join(self.video_directory, filename))
 | 
			
		||||
 | 
			
		||||
            if not files:
 | 
			
		||||
                # Download a file with the requested format
 | 
			
		||||
                url = DOWNLOAD_URLS[self.format]
 | 
			
		||||
                filepath = os.path.join(self.video_directory, os.path.basename(url))
 | 
			
		||||
                self.logger.info('Downloading {} to {}...'.format(url, filepath))
 | 
			
		||||
                urllib.urlretrieve(url, filepath)
 | 
			
		||||
                return filepath
 | 
			
		||||
            else:
 | 
			
		||||
                if len(files) > 1:
 | 
			
		||||
                    self.logger.warn('Multiple files found for {} format. Using {}.'
 | 
			
		||||
                                     .format(self.format, files[0]))
 | 
			
		||||
                    self.logger.warn('Use "filename"parameter instead of '
 | 
			
		||||
                                     '"format" to specify a different file.')
 | 
			
		||||
                return files[0]
 | 
			
		||||
 | 
			
		||||
    def init_resources(self, context):
 | 
			
		||||
        ensure_directory_exists(self.video_directory)
 | 
			
		||||
        self.host_video_file = self._find_host_video_file()
 | 
			
		||||
 | 
			
		||||
    def setup(self, context):
 | 
			
		||||
        super(ExoPlayer, self).setup(context)
 | 
			
		||||
 | 
			
		||||
        grant_app_permissions(self.target, self.package)
 | 
			
		||||
 | 
			
		||||
        self.device_video_file = self.target.path.join(self.target.working_directory,
 | 
			
		||||
                                                       os.path.basename(self.host_video_file))
 | 
			
		||||
        if self.force_dependency_push or not self.target.file_exists(self.device_video_file):
 | 
			
		||||
            self.logger.info('Copying {} to device.'.format(self.host_video_file))
 | 
			
		||||
            self.target.push(self.host_video_file, self.device_video_file, timeout=120)
 | 
			
		||||
 | 
			
		||||
        self.play_cmd = 'am start -a {} -d "file://{}"'.format(self.action,
 | 
			
		||||
                                                               self.device_video_file)
 | 
			
		||||
 | 
			
		||||
        self.monitor = self.target.get_logcat_monitor(REGEXPS.values())
 | 
			
		||||
        self.monitor.start()
 | 
			
		||||
 | 
			
		||||
    def run(self, context):
 | 
			
		||||
        self.target.execute(self.play_cmd)
 | 
			
		||||
 | 
			
		||||
        self.monitor.wait_for(REGEXPS['start'])
 | 
			
		||||
        self.logger.info('Playing media file')
 | 
			
		||||
 | 
			
		||||
        line = self.monitor.wait_for(REGEXPS['duration'])[0]
 | 
			
		||||
        media_duration_s = int(round(float(re.search(REGEXPS['duration'], line)
 | 
			
		||||
                                           .group('duration'))))
 | 
			
		||||
 | 
			
		||||
        self.logger.info('Media duration is {} seconds'.format(media_duration_s))
 | 
			
		||||
 | 
			
		||||
        if self.duration > media_duration_s:
 | 
			
		||||
            raise ConfigError(
 | 
			
		||||
                "'duration' param ({}) longer than media duration ({})".format(
 | 
			
		||||
                    self.duration, media_duration_s))
 | 
			
		||||
 | 
			
		||||
        if self.duration:
 | 
			
		||||
            self.logger.info('Waiting {} seconds before ending playback'
 | 
			
		||||
                           .format(self.duration))
 | 
			
		||||
            time.sleep(self.duration)
 | 
			
		||||
        else:
 | 
			
		||||
            self.logger.info('Waiting for playback completion ({} seconds)'
 | 
			
		||||
                           .format(media_duration_s))
 | 
			
		||||
            self.monitor.wait_for(REGEXPS['end'], timeout = media_duration_s + 30)
 | 
			
		||||
 | 
			
		||||
    def teardown(self, context):
 | 
			
		||||
        super(ExoPlayer, self).teardown(context)
 | 
			
		||||
        self.monitor.stop()
 | 
			
		||||
		Reference in New Issue
	
	Block a user