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