| # Copyright 2014 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import logging, os, re, struct, time |
| |
| from autotest_lib.client.bin import test |
| from autotest_lib.client.bin import utils |
| from autotest_lib.client.common_lib import error |
| from autotest_lib.client.common_lib.cros import chrome |
| from autotest_lib.client.cros import cros_logging |
| |
| |
| class graphics_Idle(test.test): |
| """Class for graphics_Idle. See 'control' for details.""" |
| version = 1 |
| _gpu_type = None |
| _cpu_type = None |
| |
| |
| def run_once(self): |
| # Try to protect against runaway previous tests. |
| if not utils.wait_for_idle_cpu(20.0, 0.1): |
| logging.warning('Could not get idle CPU before running tests.') |
| # We use kiosk mode to make sure Chrome is idle. |
| with chrome.Chrome(logged_in=False, extra_browser_args=['--kiosk']): |
| self._gpu_type = utils.get_gpu_family() |
| self._cpu_type = utils.get_cpu_soc_family() |
| self._board = utils.get_board() |
| errors = '' |
| errors += self.verify_graphics_dvfs() |
| errors += self.verify_graphics_fbc() |
| errors += self.verify_graphics_psr() |
| errors += self.verify_graphics_gem_idle() |
| errors += self.verify_graphics_i915_min_clock() |
| errors += self.verify_graphics_rc6() |
| errors += self.verify_lvds_downclock() |
| errors += self.verify_short_blanking() |
| if errors: |
| raise error.TestFail(errors) |
| |
| |
| def verify_lvds_downclock(self): |
| """On systems which support LVDS downclock, checks the kernel log for |
| a message that an LVDS downclock mode has been added.""" |
| logging.info('Running verify_lvds_downclock') |
| board = utils.get_board() |
| if not (board == 'alex' or board == 'lumpy' or |
| board == 'stout'): |
| return '' |
| |
| # Get the downclock message from the logs. |
| reader = cros_logging.LogReader() |
| reader.set_start_by_reboot(-1) |
| if not reader.can_find('Adding LVDS downclock mode'): |
| logging.error('Error: LVDS downclock quirk not applied.') |
| return 'LVDS downclock quirk not applied. ' |
| |
| return '' |
| |
| |
| def verify_short_blanking(self): |
| """On baytrail systems with a known panel, checks the kernel log for a |
| message that a short blanking mode has been added.""" |
| logging.info('Running verify_short_blanking') |
| if self._gpu_type != 'baytrail': |
| return '' |
| |
| # Open the EDID to find the panel model. |
| param_path = '/sys/class/drm/card0-eDP-1/edid' |
| if not os.path.exists(param_path): |
| logging.error('Error: %s not found.', param_path) |
| return 'Short blanking not added (no EDID found). ' |
| |
| with open(param_path, 'r') as edp_edid_file: |
| edp_edid_file.seek(8) |
| bytes = edp_edid_file.read(2) |
| manufacturer = int(struct.unpack('<H', bytes)[0]) |
| bytes = edp_edid_file.read(2) |
| product_code = int(struct.unpack('<H', bytes)[0]) |
| |
| # This is not the panel we are looking for (AUO B116XTN02.2) |
| if manufacturer != 0xaf06 or product_code != 0x225c: |
| return '' |
| |
| # Get the downclock message from the logs. |
| reader = cros_logging.LogReader() |
| reader.set_start_by_reboot(-1) |
| if not reader.can_find('Modified preferred into a short blanking mode'): |
| logging.error('Error: short blanking not added.') |
| return 'Short blanking not added. ' |
| |
| return '' |
| |
| |
| def verify_graphics_rc6(self): |
| """ On systems which support RC6 (non atom), check that we are able to |
| get into rc6; idle before doing so, and retry every second for 20 |
| seconds.""" |
| logging.info('Running verify_graphics_rc6') |
| if (self._gpu_type == 'broadwell' or self._gpu_type == 'haswell' or |
| self._gpu_type == 'ivybridge' or self._gpu_type == 'sandybridge'): |
| tries = 0 |
| found = False |
| while found == False and tries < 20: |
| time.sleep(1) |
| param_path = '/sys/kernel/debug/dri/0/i915_drpc_info' |
| if not os.path.exists(param_path): |
| logging.error('Error: %s not found.', param_path) |
| break |
| with open(param_path, 'r') as drpc_info_file: |
| for line in drpc_info_file: |
| match = re.search(r'Current RC state: (.*)', line) |
| if match and match.group(1) != 'on': |
| found = True |
| break |
| |
| tries += 1 |
| |
| if not found: |
| utils.log_process_activity() |
| logging.error('Error: did not see the GPU in RC6.') |
| return 'Did not see the GPU in RC6. ' |
| |
| return '' |
| |
| |
| def verify_graphics_i915_min_clock(self): |
| """ On i915 systems, check that we get into the lowest clock frequency; |
| idle before doing so, and retry every second for 20 seconds.""" |
| logging.info('Running verify_graphics_i915_min_clock') |
| if (self._gpu_type == 'baytrail' or self._gpu_type == 'broadwell' or |
| self._gpu_type == 'haswell' or self._gpu_type == 'ivybridge' or |
| self._gpu_type == 'sandybridge'): |
| tries = 0 |
| found = False |
| while not found and tries < 80: |
| time.sleep(0.25) |
| param_path = '/sys/kernel/debug/dri/0/i915_cur_delayinfo' |
| if not os.path.exists(param_path): |
| logging.error('Error: %s not found.', param_path) |
| break |
| |
| with open(param_path, 'r') as delayinfo_file: |
| for line in delayinfo_file: |
| # This file has a different format depending on the board, |
| # so we parse both. Also, it would be tedious to add the |
| # minimum clock for each board, so instead we use 650MHz |
| # which is the max of the minimum clocks. |
| match = re.search(r'CAGF: (.*)MHz', line) |
| if match and int(match.group(1)) <= 650: |
| found = True |
| break |
| |
| match = re.search(r'current GPU freq: (.*) MHz', line) |
| if match and int(match.group(1)) <= 650: |
| found = True |
| break |
| |
| tries += 1 |
| |
| if not found: |
| utils.log_process_activity() |
| logging.error('Error: did not see the min i915 clock') |
| return 'Did not see the min i915 clock. ' |
| |
| return '' |
| |
| |
| def verify_graphics_dvfs(self): |
| """ On systems which support DVFS, check that we get into the lowest |
| clock frequency; idle before doing so, and retry every second for 20 |
| seconds.""" |
| logging.info('Running verify_graphics_dvfs') |
| if self._gpu_type == 'mali': |
| if self._cpu_type == 'exynos5': |
| node = '/sys/devices/11800000.mali/' |
| enable_node = 'dvfs' |
| enable_value = 'on' |
| elif self._cpu_type == 'rockchip': |
| node = '/sys/devices/ffa30000.gpu/' |
| enable_node = 'dvfs_enable' |
| enable_value = '1' |
| else: |
| logging.error('Error: Unknown CPU type (%s) for mali GPU.', |
| self._cpu_type) |
| return 'Unknown CPU type for mali GPU. ' |
| |
| clock_path = utils.locate_file('clock', node) |
| enable_path = utils.locate_file(enable_node, node) |
| freqs_path = utils.locate_file('available_frequencies', node) |
| |
| enable = utils.read_one_line(enable_path) |
| logging.info('DVFS enable = %s', enable) |
| if not enable == enable_value: |
| logging.error('Error: DVFS is not enabled') |
| return 'DVFS is not enabled. ' |
| |
| # available_frequencies are always sorted in ascending order |
| lowest_freq = int(utils.read_one_line(freqs_path)) |
| |
| # daisy_* (exynos5250) boards set idle frequency to 266000000 |
| # See: crbug.com/467401 and crosbug.com/p/19710 |
| if self._board.startswith('daisy'): |
| lowest_freq = 266000000 |
| |
| logging.info('Expecting idle DVFS clock = %u', lowest_freq) |
| |
| tries = 0 |
| found = False |
| while not found and tries < 80: |
| time.sleep(0.25) |
| clock = int(utils.read_one_line(clock_path)) |
| if clock <= lowest_freq: |
| logging.info('Found idle DVFS clock = %u', clock) |
| found = True |
| break |
| |
| tries += 1 |
| |
| if not found: |
| utils.log_process_activity() |
| logging.error('Error: DVFS clock (%u) > min (%u)', |
| clock, lowest_freq) |
| return 'Did not see the min DVFS clock. ' |
| |
| return '' |
| |
| |
| def verify_graphics_fbc(self): |
| """ On systems which support FBC, check that we can get into FBC; |
| idle before doing so, and retry every second for 20 seconds.""" |
| logging.info('Running verify_graphics_fbc') |
| |
| # Link's FBC is disabled (crbug.com/338588). |
| # TODO(marcheu): remove this when/if we fix this bug. |
| board = utils.get_board() |
| if board == 'link': |
| return '' |
| |
| # Machines which don't have a monitor can't get FBC. |
| if utils.has_no_monitor(): |
| return '' |
| |
| if (self._gpu_type == 'haswell' or self._gpu_type == 'ivybridge' or |
| self._gpu_type == 'sandybridge'): |
| tries = 0 |
| found = False |
| while not found and tries < 20: |
| time.sleep(1) |
| # Kernel 3.4 has i915_fbc, kernel 3.8+ has i915_fbc_status, |
| # so we check for both. |
| param_path = '/sys/kernel/debug/dri/0/i915_fbc_status' |
| if not os.path.exists(param_path): |
| param_path = '/sys/kernel/debug/dri/0/i915_fbc' |
| if not os.path.exists(param_path): |
| logging.error('Error: %s not found.', param_path) |
| break |
| with open(param_path, 'r') as fbc_info_file: |
| for line in fbc_info_file: |
| if re.search('FBC enabled', line): |
| found = True |
| break |
| |
| tries += 1 |
| |
| if not found: |
| logging.error('Error: did not see FBC enabled.') |
| return 'Did not see FBC enabled. ' |
| |
| |
| return '' |
| |
| |
| def verify_graphics_psr(self): |
| """ On systems which support PSR, check that we can get into PSR; |
| idle before doing so, and retry every second for 20 seconds.""" |
| logging.info('Running verify_graphics_psr') |
| |
| board = utils.get_board() |
| if board != 'samus': |
| return '' |
| |
| tries = 0 |
| found = False |
| while not found and tries < 20: |
| time.sleep(1) |
| param_path = '/sys/kernel/debug/dri/0/i915_edp_psr_state' |
| if not os.path.exists(param_path): |
| logging.error('Error: %s not found.', param_path) |
| break |
| with open(param_path, 'r') as fbc_info_file: |
| for line in fbc_info_file: |
| match = re.search(r'Performance_Counter: (.*)', line) |
| if match and int(match.group(1)) > 0: |
| found = True |
| break |
| |
| tries += 1 |
| |
| if not found: |
| logging.error('Error: did not see PSR enabled.') |
| return 'Did not see PSR enabled. ' |
| |
| |
| return '' |
| |
| |
| def verify_graphics_gem_idle(self): |
| """ On systems which have i915, check that we can get all gem objects |
| to become idle (i.e. the i915_gem_active list need to go to 0); |
| idle before doing so, and retry every second for 20 seconds.""" |
| logging.info('Running verify_graphics_gem_idle') |
| if (self._gpu_type == 'baytrail' or self._gpu_type == 'broadwell' or |
| self._gpu_type == 'haswell' or self._gpu_type == 'ivybridge' or |
| self._gpu_type == 'sandybridge'): |
| tries = 0 |
| found = False |
| while not found and tries < 240: |
| time.sleep(0.25) |
| gem_path = '/sys/kernel/debug/dri/0/i915_gem_active' |
| if not os.path.exists(gem_path): |
| logging.error('Error: %s not found.', gem_path) |
| break |
| with open(gem_path, 'r') as gem_file: |
| for line in gem_file: |
| if re.search('Total 0 objects', line): |
| found = True |
| break |
| |
| tries += 1 |
| |
| if not found: |
| utils.log_process_activity() |
| logging.error('Error: did not reach 0 gem actives.') |
| return 'Did not reach 0 gem actives. ' |
| |
| return '' |
| |
| |