Home | History | Annotate | Download | only in toolchain-utils
      1 #!/usr/bin/python2
      2 #
      3 # Copyright Google Inc. 2014
      4 """Module to generate the 7-day crosperf reports."""
      5 
      6 from __future__ import print_function
      7 
      8 import argparse
      9 import datetime
     10 import os
     11 import sys
     12 
     13 from cros_utils import constants
     14 from cros_utils import command_executer
     15 
     16 WEEKDAYS = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
     17 DATA_ROOT_DIR = os.path.join(constants.CROSTC_WORKSPACE, 'weekly_test_data')
     18 EXPERIMENT_FILE = os.path.join(DATA_ROOT_DIR, 'weekly_report')
     19 MAIL_PROGRAM = '~/var/bin/mail-sheriff'
     20 
     21 
     22 def Generate_Vanilla_Report_File(vanilla_image_paths, board, remote,
     23                                  chromeos_root, cmd_executer):
     24 
     25   experiment_header = """
     26 name: weekly_vanilla_report
     27 cache_only: True
     28 same_specs: False
     29 board: %s
     30 remote: %s
     31 """ % (board, remote)
     32 
     33   experiment_tests = """
     34 benchmark: 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 
     65 def Generate_Test_File(test_image_paths, vanilla_image_path, board, remote,
     66                        chromeos_root, cmd_executer):
     67 
     68   experiment_header = """
     69 name: weekly_report
     70 cache_only: True
     71 same_specs: False
     72 board: %s
     73 remote: %s
     74 """ % (board, remote)
     75 
     76   experiment_tests = """
     77 benchmark: 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 
    119 def 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 
    253 if __name__ == '__main__':
    254   retval = Main(sys.argv)
    255   sys.exit(retval)
    256