1# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5import logging
6import os
7import time
8
9from autotest_lib.client.bin import test
10from autotest_lib.client.bin import utils as bin_utils
11from autotest_lib.client.common_lib import error, utils
12from autotest_lib.client.cros.graphics import graphics_utils
13
14# to run this test manually on a test target
15# ssh root@machine
16# cd /usr/local/autotest/tests/graphics_GpuReset/src/
17# stop ui
18# ./gpureset
19# start ui
20
21
22class graphics_GpuReset(graphics_utils.GraphicsTest):
23  """
24  Reset the GPU and check recovery mechanism.
25  """
26  version = 1
27  preserve_srcdir = True
28  loops = 1
29
30  def setup(self):
31    os.chdir(self.srcdir)
32    utils.make('clean')
33    utils.make('all')
34
35  def initialize(self):
36    # GpuReset should pretty much be the only test where we don't want to raise
37    # a test error when we detect a GPU hang.
38    super(graphics_GpuReset, self).initialize(raise_error_on_hang=False)
39
40  def cleanup(self):
41    super(graphics_GpuReset, self).cleanup()
42
43  @graphics_utils.GraphicsTest.failure_report_decorator('graphics_GpuReset')
44  def run_once(self, options=''):
45    gpu_family = bin_utils.get_gpu_family()
46    if gpu_family == 'stoney':
47        options = '-s 7 -t 1'
48        exefile = 'amdgpu_test'
49    else:
50        options = ''
51        exefile = os.path.join(self.srcdir, 'gpureset')
52        if not os.path.isfile(exefile):
53          raise error.TestFail('Failed: could not locate gpureset executable (' +
54                               exefile + ').')
55
56    cmd = '%s %s' % (exefile, options)
57
58    # If UI is running, we must stop it and restore later.
59    need_restart_ui = False
60    status_output = utils.system_output('initctl status ui')
61    # If chrome is running, result will be similar to:
62    #   ui start/running, process 11895
63    logging.info('initctl status ui returns: %s', status_output)
64    need_restart_ui = status_output.startswith('ui start')
65    summary = ''
66
67    # Run the gpureset test in a loop to stress the recovery.
68    for i in range(1, self.loops + 1):
69      summary += 'graphics_GpuReset iteration %d of %d\n' % (i, self.loops)
70      if need_restart_ui:
71        summary += 'initctl stop ui\n'
72        utils.system('initctl stop ui', ignore_status=True)
73        # TODO(ihf): Remove this code if no improvement for issue 409019.
74        logging.info('Make sure chrome is dead before triggering hang.')
75        utils.system('killall -9 chrome', ignore_status=True)
76        time.sleep(3)
77      try:
78        summary += utils.system_output(cmd, retain_output=True)
79        summary += '\n'
80      finally:
81        if need_restart_ui:
82          summary += 'initctl start ui\n'
83          utils.system('initctl start ui')
84
85    # Write a copy of stdout to help debug failures.
86    results_path = os.path.join(self.outputdir, 'summary.txt')
87    f = open(results_path, 'w+')
88    f.write('# need ui restart: %s\n' % need_restart_ui)
89    f.write('# ---------------------------------------------------\n')
90    f.write('# [' + cmd + ']\n')
91    f.write(summary)
92    f.write('\n# -------------------------------------------------\n')
93    f.write('# [graphics_GpuReset.py postprocessing]\n')
94
95    # Analyze the output. Sample:
96    # [       OK ] graphics_GpuReset
97    # [  FAILED  ] graphics_GpuReset
98    results = summary.splitlines()
99    if not results:
100      f.close()
101      raise error.TestFail('Failed: No output from test. Check /tmp/' +
102                           'test_that_latest/graphics_GpuReset/summary.txt' +
103                           ' for details.')
104    # Analyze summary and count number of passes.
105    pass_count = 0
106    for line in results:
107      if gpu_family == 'stoney':
108        if "passed" in line:
109          pass_count += 1
110        if "failed" in line:
111          raise error.TestFail('Failed: %s' % line)
112      else:
113        if line.strip().startswith('[       OK ] graphics_GpuReset'):
114          pass_count += 1
115        if line.strip().startswith('[  FAILED  ] graphics_GpuReset'):
116          msg = line.strip()[30:]
117          failed_msg = 'Test failed with %s' % msg
118          raise error.TestFail('Failed: %s' % failed_msg)
119    f.close()
120
121    # Final chance to fail.
122    if pass_count != self.loops:
123      failed_msg = 'Test failed with incomplete output. System hung? '
124      failed_msg += '(pass_count=%d of %d)' % (pass_count, self.loops)
125      raise error.TestFail('Failed: %s' % failed_msg)
126
127    # We need to wait a bit for X to come back after the 'start ui'.
128    time.sleep(5)
129