1#!/usr/bin/python2
2#
3# Copyright Google Inc. 2014
4"""Module to generate the 7-day crosperf reports."""
5
6from __future__ import print_function
7
8import argparse
9import datetime
10import os
11import sys
12
13from cros_utils import constants
14from cros_utils import command_executer
15
16WEEKDAYS = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
17DATA_ROOT_DIR = os.path.join(constants.CROSTC_WORKSPACE, 'weekly_test_data')
18EXPERIMENT_FILE = os.path.join(DATA_ROOT_DIR, 'weekly_report')
19MAIL_PROGRAM = '~/var/bin/mail-sheriff'
20
21
22def Generate_Vanilla_Report_File(vanilla_image_paths, board, remote,
23                                 chromeos_root, cmd_executer):
24
25  experiment_header = """
26name: weekly_vanilla_report
27cache_only: True
28same_specs: False
29board: %s
30remote: %s
31""" % (board, remote)
32
33  experiment_tests = """
34benchmark: all_toolchain_perf {
35  suite: telemetry_Crosperf
36  iterations: 3
37}
38"""
39
40  filename = '%s_%s_vanilla.exp' % (EXPERIMENT_FILE, board)
41  if os.path.exists(filename):
42    cmd = 'rm %s' % filename
43    cmd_executer.RunCommand(cmd)
44
45  with open(filename, 'w') as f:
46    f.write(experiment_header)
47    f.write(experiment_tests)
48
49    # Add each vanilla image
50    for test_path in vanilla_image_paths:
51      pieces = test_path.split('/')
52      test_name = pieces[-1]
53      test_image = """
54%s {
55  chromeos_root: %s
56  chromeos_image: %s
57}
58""" % (test_name, chromeos_root, os.path.join(test_path,
59                                              'chromiumos_test_image.bin'))
60      f.write(test_image)
61
62  return filename
63
64
65def Generate_Test_File(test_image_paths, vanilla_image_path, board, remote,
66                       chromeos_root, cmd_executer):
67
68  experiment_header = """
69name: weekly_report
70cache_only: True
71same_specs: False
72board: %s
73remote: %s
74""" % (board, remote)
75
76  experiment_tests = """
77benchmark: all_toolchain_perf {
78  suite: telemetry_Crosperf
79  iterations: 3
80}
81"""
82
83  filename = '%s_%s.exp' % (EXPERIMENT_FILE, board)
84  if os.path.exists(filename):
85    cmd = 'rm %s' % filename
86    cmd_executer.RunCommand(cmd)
87
88  with open(filename, 'w') as f:
89    f.write(experiment_header)
90    f.write(experiment_tests)
91
92    # Add vanilla image (first)
93    vanilla_image = """
94%s {
95  chromeos_root: %s
96  chromeos_image: %s
97}
98""" % (vanilla_image_path.split('/')[-1], chromeos_root,
99       os.path.join(vanilla_image_path, 'chromiumos_test_image.bin'))
100
101    f.write(vanilla_image)
102
103    # Add each test image
104    for test_path in test_image_paths:
105      pieces = test_path.split('/')
106      test_name = pieces[-1]
107      test_image = """
108%s {
109  chromeos_root: %s
110  chromeos_image: %s
111}
112""" % (test_name, chromeos_root, os.path.join(test_path,
113                                              'chromiumos_test_image.bin'))
114      f.write(test_image)
115
116  return filename
117
118
119def Main(argv):
120
121  parser = argparse.ArgumentParser()
122  parser.add_argument('-b', '--board', dest='board', help='Target board.')
123  parser.add_argument('-r', '--remote', dest='remote', help='Target device.')
124  parser.add_argument('-v',
125                      '--vanilla_only',
126                      dest='vanilla_only',
127                      action='store_true',
128                      default=False,
129                      help='Generate a report comparing only the vanilla '
130                      'images.')
131
132  options = parser.parse_args(argv[1:])
133
134  if not options.board:
135    print('Must specify a board.')
136    return 1
137
138  if not options.remote:
139    print('Must specify at least one remote.')
140    return 1
141
142  cmd_executer = command_executer.GetCommandExecuter(log_level='average')
143
144  # Find starting index, for cycling through days of week, generating
145  # reports starting 6 days ago from today. Generate list of indices for
146  # order in which to look at weekdays for report:
147  todays_index = datetime.datetime.today().isoweekday()
148  indices = []
149  start = todays_index + 1
150  end = start + 7
151  for i in range(start, end):
152    indices.append(i % 7)
153  # E.g. if today is Sunday, then start report with last Monday, so
154  # indices = [1, 2, 3, 4, 5, 6, 0].
155
156  # Find all the test image tar files, untar them and add them to
157  # the list. Also find and untar vanilla image tar files, and keep
158  # track of the first vanilla image.
159  report_image_paths = []
160  vanilla_image_paths = []
161  first_vanilla_image = None
162  for i in indices:
163    day = WEEKDAYS[i]
164    data_path = os.path.join(DATA_ROOT_DIR, options.board, day)
165    if os.path.exists(data_path):
166      # First, untar the test image.
167      tar_file_name = '%s_test_image.tar' % day
168      tar_file_path = os.path.join(data_path, tar_file_name)
169      image_dir = '%s_test_image' % day
170      image_path = os.path.join(data_path, image_dir)
171      if os.path.exists(tar_file_path):
172        if not os.path.exists(image_path):
173          os.makedirs(image_path)
174        cmd = ('cd %s; tar -xvf %s -C %s --strip-components 1' %
175               (data_path, tar_file_path, image_path))
176        ret = cmd_executer.RunCommand(cmd)
177        if not ret:
178          report_image_paths.append(image_path)
179      # Next, untar the vanilla image.
180      vanilla_file = '%s_vanilla_image.tar' % day
181      v_file_path = os.path.join(data_path, vanilla_file)
182      image_dir = '%s_vanilla_image' % day
183      image_path = os.path.join(data_path, image_dir)
184      if os.path.exists(v_file_path):
185        if not os.path.exists(image_path):
186          os.makedirs(image_path)
187        cmd = ('cd %s; tar -xvf %s -C %s --strip-components 1' %
188               (data_path, v_file_path, image_path))
189        ret = cmd_executer.RunCommand(cmd)
190        if not ret:
191          vanilla_image_paths.append(image_path)
192        if not first_vanilla_image:
193          first_vanilla_image = image_path
194
195  # Find a chroot we can use.  Look for a directory containing both
196  # an experiment file and a chromeos directory (the experiment file will
197  # only be created if both images built successfully, i.e. the chroot is
198  # good).
199  chromeos_root = None
200  timestamp = datetime.datetime.strftime(datetime.datetime.now(),
201                                         '%Y-%m-%d_%H:%M:%S')
202  results_dir = os.path.join(
203      os.path.expanduser('~/nightly_test_reports'), '%s.%s' % (
204          timestamp, options.board), 'weekly_tests')
205
206  for day in WEEKDAYS:
207    startdir = os.path.join(constants.CROSTC_WORKSPACE, day)
208    num_dirs = os.listdir(startdir)
209    for d in num_dirs:
210      exp_file = os.path.join(startdir, d, 'toolchain_experiment.txt')
211      chroot = os.path.join(startdir, d, 'chromeos')
212      if os.path.exists(chroot) and os.path.exists(exp_file):
213        chromeos_root = chroot
214      if chromeos_root:
215        break
216    if chromeos_root:
217      break
218
219  if not chromeos_root:
220    print('Unable to locate a usable chroot. Exiting without report.')
221    return 1
222
223  # Create the Crosperf experiment file for generating the weekly report.
224  if not options.vanilla_only:
225    filename = Generate_Test_File(report_image_paths, first_vanilla_image,
226                                  options.board, options.remote, chromeos_root,
227                                  cmd_executer)
228  else:
229    filename = Generate_Vanilla_Report_File(vanilla_image_paths, options.board,
230                                            options.remote, chromeos_root,
231                                            cmd_executer)
232
233  # Run Crosperf on the file to generate the weekly report.
234  cmd = ('%s/toolchain-utils/crosperf/crosperf '
235         '%s --no_email=True --results_dir=%s' %
236         (constants.CROSTC_WORKSPACE, filename, results_dir))
237  retv = cmd_executer.RunCommand(cmd)
238  if retv == 0:
239    # Send the email, if the crosperf command worked.
240    filename = os.path.join(results_dir, 'msg_body.html')
241    if (os.path.exists(filename) and
242        os.path.exists(os.path.expanduser(MAIL_PROGRAM))):
243      vanilla_string = ' '
244      if options.vanilla_only:
245        vanilla_string = ' Vanilla '
246      command = ('cat %s | %s -s "Weekly%sReport results, %s" -team -html' %
247                 (filename, MAIL_PROGRAM, vanilla_string, options.board))
248    retv = cmd_executer.RunCommand(command)
249
250  return retv
251
252
253if __name__ == '__main__':
254  retval = Main(sys.argv)
255  sys.exit(retval)
256