run_perf_tests: Add option to find test binary in out dir.

This allows us to run the perf test runner script from any
directory and use that as a basis to find the most recently
modified test suite binary. This saves us from chdir()ing into
test directory every time we want to run a test suite.

Ideally this should move into the test utils folder to be used
by the gold tests script as well.

Bug: angleproject:7671
Change-Id: Iead98670bb5f7627ae32f7ac41b4ebcee2726841
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3904427
Reviewed-by: Roman Lavrov <romanl@google.com>
Reviewed-by: Cody Northrop <cnorthrop@google.com>
Commit-Queue: Jamie Madill <jmadill@chromium.org>
diff --git a/src/tests/py_utils/angle_test_util.py b/src/tests/py_utils/angle_test_util.py
index 14d3b05..cc2a916 100644
--- a/src/tests/py_utils/angle_test_util.py
+++ b/src/tests/py_utils/angle_test_util.py
@@ -8,6 +8,7 @@
 import importlib
 import io
 import logging
+import os
 import signal
 import subprocess
 import sys
@@ -155,7 +156,9 @@
             test_suite, cmd_args, log_output=show_test_stdout)
         return result, output.decode(), json_results
 
-    runner_cmd = [ExecutablePathInCurrentDir(test_suite)] + cmd_args + (runner_args or [])
+    cmd = ExecutablePathInCurrentDir(test_suite) if os.path.exists(
+        os.path.basename(test_suite)) else test_suite
+    runner_cmd = [cmd] + cmd_args + (runner_args or [])
 
     logging.debug(' '.join(runner_cmd))
     with contextlib.ExitStack() as stack:
diff --git a/src/tests/run_perf_tests.py b/src/tests/run_perf_tests.py
index cbab89f..91285e9 100755
--- a/src/tests/run_perf_tests.py
+++ b/src/tests/run_perf_tests.py
@@ -9,6 +9,7 @@
 
 import argparse
 import fnmatch
+import glob
 import importlib
 import io
 import json
@@ -20,7 +21,8 @@
 import subprocess
 import sys
 
-PY_UTILS = str(pathlib.Path(__file__).resolve().parent / 'py_utils')
+SCRIPT_DIR = str(pathlib.Path(__file__).resolve().parent)
+PY_UTILS = str(pathlib.Path(SCRIPT_DIR) / 'py_utils')
 if PY_UTILS not in sys.path:
     os.stat(PY_UTILS) and sys.path.insert(0, PY_UTILS)
 import android_helper
@@ -396,13 +398,36 @@
     return results, histograms
 
 
+def _find_test_suite_directory(test_suite):
+    if os.path.exists(angle_test_util.ExecutablePathInCurrentDir(test_suite)):
+        return '.'
+
+    # Find most recent binary in search paths.
+    newest_binary = None
+    newest_mtime = None
+
+    for path in glob.glob('out/*'):
+        binary_path = str(pathlib.Path(SCRIPT_DIR).parent.parent / path / test_suite)
+        if os.path.exists(binary_path):
+            binary_mtime = os.path.getmtime(binary_path)
+            if (newest_binary is None) or (binary_mtime > newest_mtime):
+                newest_binary = binary_path
+                newest_mtime = binary_mtime
+
+    if newest_binary:
+        logging.info('Found %s in %s' % (test_suite, os.path.dirname(newest_binary)))
+        return os.path.dirname(newest_binary)
+    return None
+
+
 def main():
     parser = argparse.ArgumentParser()
     parser.add_argument('--isolated-script-test-output', type=str)
     parser.add_argument('--isolated-script-test-perf-output', type=str)
     parser.add_argument(
         '-f', '--filter', '--isolated-script-test-filter', type=str, help='Test filter.')
-    parser.add_argument('--test-suite', help='Test suite to run.', default=ANGLE_PERFTESTS)
+    parser.add_argument(
+        '--test-suite', '--suite', help='Test suite to run.', default=ANGLE_PERFTESTS)
     parser.add_argument('--xvfb', help='Use xvfb.', action='store_true')
     parser.add_argument(
         '--shard-count',
@@ -453,6 +478,11 @@
         '--show-test-stdout', help='Prints all test stdout during execution.', action='store_true')
     parser.add_argument(
         '--perf-counters', help='Colon-separated list of extra perf counter metrics.')
+    parser.add_argument(
+        '-a',
+        '--auto-dir',
+        help='Run with the most recent test suite found in the build directories.',
+        action='store_true')
 
     args, extra_flags = parser.parse_known_args()
 
@@ -471,6 +501,14 @@
     if angle_test_util.HasGtestShardsAndIndex(env):
         args.shard_count, args.shard_index = angle_test_util.PopGtestShardsAndIndex(env)
 
+    if args.auto_dir:
+        test_suite_dir = _find_test_suite_directory(args.test_suite)
+        if not test_suite_dir:
+            logging.fatal('Could not find test suite: %s' % args.test_suite)
+            return EXIT_FAILURE
+        else:
+            os.chdir(test_suite_dir)
+
     angle_test_util.Initialize(args.test_suite)
 
     # Get test list