Atest: send saved time of acloud_create to metrics.

This CL enables 2 detect types for storing the duration of acloud create
and find+build, and send the duration to metrics unless --no-metrics is
passed.

Bug: 160390329

Test: m clean
  atest-src -v --start-avd hello_world_test
  # will see 'Totally saved 232s.'

  atest-src -v --start-avd hello_world_test
  # will see 'Totally saved 4s.'

Change-Id: I3ea0c5f65da39da4c2f4316133e2c3814b9a4562
diff --git a/atest/atest.py b/atest/atest.py
index 684d093..c468a8a 100755
--- a/atest/atest.py
+++ b/atest/atest.py
@@ -647,28 +647,31 @@
 
     Returns:
         If the target is valid:
-            A tuple of (multiprocessing.Process, string of report file path)
+            A tuple of (multiprocessing.Process,
+                        string of report file path,
+                        start time of acloud_create)
         else:
-            None, None
+            None, None, None
     """
     if not any((args.acloud_create, args.start_avd)):
-        return None, None
+        return None, None, None
     if args.start_avd:
         args.acloud_create = ['--num=1']
     acloud_args = ' '.join(args.acloud_create)
     target = os.getenv('TARGET_PRODUCT', "")
     if 'cf_x86' in target:
+        start = time.time()
         report_file = at.get_report_file(results_dir, acloud_args)
         acloud_proc = _run_multi_proc(
             func=ACLOUD_CREATE,
             args=[report_file],
             kwargs={'args':acloud_args,
                     'no_metrics_notice':args.no_metrics})
-        return acloud_proc, report_file
+        return acloud_proc, report_file, start
     atest_utils.colorful_print(
         '{} is not cf_x86 family; will not create any AVD.'.format(target),
         constants.RED)
-    return None, None
+    return None, None, None
 
 # pylint: disable=too-many-statements
 # pylint: disable=too-many-branches
@@ -694,7 +697,7 @@
         cwd=os.getcwd(),
         os=os_pyver)
     _non_action_validator(args)
-    proc_acloud, report_file = acloud_create_validator(results_dir, args)
+    proc_acloud, report_file, acloud_start = acloud_create_validator(results_dir, args)
     mod_info = module_info.ModuleInfo(force_build=args.rebuild_module_info)
     if args.rebuild_module_info:
         proc_idx = _run_multi_proc(INDEX_TARGETS)
@@ -710,7 +713,9 @@
     build_targets = set()
     test_infos = set()
     if _will_run_tests(args):
+        find_start = time.time()
         build_targets, test_infos = translator.translate(args)
+        find_duration = time.time() - find_start
         if not test_infos:
             return constants.EXIT_CODE_TEST_NOT_FOUND
         if not is_from_test_mapping(test_infos):
@@ -739,8 +744,9 @@
         build_targets.add(mod_info.module_info_target)
         build_start = time.time()
         success = atest_utils.build(build_targets, verbose=args.verbose)
+        build_duration = time.time() - build_start
         metrics.BuildFinishEvent(
-            duration=metrics_utils.convert_duration(time.time() - build_start),
+            duration=metrics_utils.convert_duration(build_duration),
             success=success,
             targets=build_targets)
         if not success:
@@ -748,6 +754,22 @@
         if proc_acloud:
             proc_acloud.join()
             status = at.probe_acloud_status(report_file)
+            acloud_duration = time.time() - acloud_start
+            find_build_duration = find_duration + build_duration
+            if find_build_duration - acloud_duration >= 0:
+                # find+build took longer, saved acloud create time.
+                logging.debug('Saved acloud create time: %ss.',
+                              acloud_duration)
+                metrics.LocalDetectEvent(
+                    detect_type=constants.DETECT_TYPE_ACLOUD_CREATE,
+                    result=round(acloud_duration))
+            else:
+                # acloud create took longer, saved find+build time.
+                logging.debug('Saved Find and Build time: %ss.',
+                              find_build_duration)
+                metrics.LocalDetectEvent(
+                    detect_type=constants.DETECT_TYPE_FIND_BUILD,
+                    result=round(find_build_duration))
             if status != 0:
                 return status
     elif constants.TEST_STEP not in steps:
diff --git a/atest/cli_translator.py b/atest/cli_translator.py
index bea43b4..0f5d097 100644
--- a/atest/cli_translator.py
+++ b/atest/cli_translator.py
@@ -175,7 +175,7 @@
                 find_test_err_msg, constants.MAGENTA)))
         else:
             print('(This can happen after a repo sync or if the test'
-                  ' is new. Running: with "%s" may resolve the issue.)'
+                  ' is new. Running with "%s" may resolve the issue.)'
                   '\n' % (atest_utils.colorize(
                       constants.REBUILD_MODULE_INFO_FLAG,
                       constants.RED)))
diff --git a/atest/constants_default.py b/atest/constants_default.py
index 4c95f74..5d73bb8 100644
--- a/atest/constants_default.py
+++ b/atest/constants_default.py
@@ -174,8 +174,11 @@
 TF_PREPARATION = 'tf-preparation'
 
 # Detect type for local_detect_event.
-# Next expansion : DETECT_TYPE_XXX = 1
+# Next expansion : DETECT_TYPE_XXX = 3
 DETECT_TYPE_BUG_DETECTED = 0
+DETECT_TYPE_ACLOUD_CREATE = 1
+DETECT_TYPE_FIND_BUILD = 2
+
 # Considering a trade-off between speed and size, we set UPPER_LIMIT to 100000
 # to make maximum file space 10M(100000(records)*100(byte/record)) at most.
 # Therefore, to update history file will spend 1 sec at most in each run.