def main() -> None: # pylint: disable=too-many-statements, too-many-locals, too-many-branches; parser = argparse.ArgumentParser( description="Runs AmberScript files on Android devices." ) parser.add_argument( "amber_script_file", help="AmberScript tests to run.", nargs="+", ) parser.add_argument( "--output", help="Output directory.", default="output", ) parser.add_argument( "--settings", help="Path to a settings JSON file for this instance. " "Unlike with gfauto_fuzz, the default value is an empty string, which is ignored. ", default="", ) parser.add_argument( "--serial", help="Android device serial. If left unspecified, the tests will be run on all Android devices.", action="append", ) parsed_args = parser.parse_args(sys.argv[1:]) amber_script_files: List[Path] = [Path(a) for a in parsed_args.amber_script_file] output_path: Path = Path(parsed_args.output) serials: Optional[List[str]] = parsed_args.serial settings_str: str = parsed_args.settings settings = Settings() if settings_str: settings = settings_util.read_or_create(Path(settings_str)) binary_manager = binaries_util.get_default_binary_manager(settings) if not serials: android_devices = android_device.get_all_android_devices( binary_manager, include_device_details=False ) serials = [] for device in android_devices: serials.append(device.android.serial) for amber_script_file in amber_script_files: for serial in serials: android_device.run_amber_on_device( amber_script_file, output_path / serial, dump_image=False, dump_buffer=False, serial=serial, )
def main() -> None: parser = argparse.ArgumentParser( description= "A script that creates a README and bug_report directory for a test and its result_dir." ) parser.add_argument( "source_dir", help="Source directory containing test.json and shaders.") parser.add_argument( "result_dir", help= "Path to the result_dir of a test containing e.g. the intermediate shader files, log.txt, etc.", ) parser.add_argument( "--output_dir", help= "Output directory where the README and bug_report directory will be written.", default=".", ) parsed_args = parser.parse_args(sys.argv[1:]) source_dir = Path(parsed_args.source_dir) result_dir = Path(parsed_args.result_dir) output_dir = Path(parsed_args.output_dir) check_dir_exists(source_dir) check_dir_exists(result_dir) test = test_util.metadata_read_from_path(source_dir / test_util.TEST_METADATA) binary_manager = binaries_util.get_default_binary_manager( settings=Settings()).get_child_binary_manager( binary_list=list(test.binaries) + list(test.device.binaries)) check(test.HasField("glsl"), AssertionError("Only glsl tests currently supported")) check( test.device.HasField("preprocess"), AssertionError("Only preprocess device tests currently supported"), ) fuzz_test_util.tool_crash_summary_bug_report_dir(source_dir, result_dir, output_dir, binary_manager)
def read(settings_path: Path) -> Settings: result = proto_util.file_to_message(settings_path, Settings()) return result
Used to read and write the Settings proto. See settings.proto. """ import traceback from pathlib import Path from gfauto import binaries_util, devices_util, proto_util from gfauto.gflogging import log from gfauto.settings_pb2 import Settings DEFAULT_SETTINGS_FILE_PATH = Path("settings.json") DEFAULT_SETTINGS = Settings( maximum_duplicate_crashes=3, maximum_fuzz_failures=10, reduce_tool_crashes=True, reduce_crashes=True, reduce_bad_images=True, ) class NoSettingsFile(Exception): pass def read_or_create(settings_path: Path) -> Settings: try: return read(settings_path) except FileNotFoundError as exception: if settings_path.exists(): raise
def main() -> None: # pylint: disable=too-many-statements, too-many-locals, too-many-branches; parser = argparse.ArgumentParser( description="Interestingness test that runs a test using Amber, " "calculates the crash signature based on the result, and returns 0 " "if the signature matches the expected crash signature.") parser.add_argument( "source_dir", help= "The source directory containing the shaders and the test.json file that describes how to run the test.", ) parser.add_argument( "--override_shader_job", nargs=2, metavar=("shader_job_name", "shader_job_json"), help= 'Override one of the shader jobs. E.g.: "--override_shader_job variant temp/variant.json". Note that ' "the output directory will be set to shader_job_json/ (with the .json extension removed) by default in this case. ", ) parser.add_argument( "--override_shader", nargs=3, metavar=("shader_name", "suffix", "shader_path"), help= 'Override one of the shaders. E.g.: "--override_shader variant .frag.spv temp/my_shader.spv". Note that ' "the output directory will be set to shader_path/ (with the .spv extension removed) by default in this case. ", ) parser.add_argument( "--use_default_binaries", help="Use the latest binaries, ignoring those defined in the test.json. " "Implies --fallback_binaries. Passing --settings is recommended to ensure the latest binaries are used.", action="store_true", ) parser.add_argument( "--fallback_binaries", help= "Fallback to the latest binaries if they are not defined in the test.json.", action="store_true", ) parser.add_argument( "--output", help= "Output directory. Required unless --override_shader[_job] is used; see --override_shader[_job] for details.", default=None, ) parser.add_argument( "--settings", help="Path to a settings JSON file for this instance. " "Unlike with gfauto_fuzz, the default value is an empty string, which is ignored. " "You only need to use a settings file if you pass --use_default_binaries and you want to use the latest binary versions. " 'In this case, use e.g. "--settings settings.json" so that a default settings file is generated with the latest binary version numbers ' "and then run gfauto_interestingness_test again to use those latest binaries.", default="", ) parsed_args = parser.parse_args(sys.argv[1:]) source_dir: Path = Path(parsed_args.source_dir) override_shader_job: Optional[Tuple[str, str]] = parsed_args.override_shader_job override_shader: Optional[Tuple[str, str, str]] = parsed_args.override_shader settings_str: str = parsed_args.settings settings = Settings() if settings_str: settings = settings_util.read_or_create(Path(settings_str)) use_default_binaries: bool = parsed_args.use_default_binaries fallback_binaries: bool = parsed_args.fallback_binaries or use_default_binaries output: Path if parsed_args.output: output = Path(parsed_args.output) elif override_shader_job: output = Path(override_shader_job[1]).with_suffix("") elif override_shader: output = Path(override_shader[2]).with_suffix("") else: raise AssertionError( "Need --output or --override_shader[_job] parameter.") binary_manager = binaries_util.get_default_binary_manager( settings=settings) if not fallback_binaries: binary_manager = binary_manager.get_child_binary_manager( binary_list=[]) shader_job_overrides: List[tool.NameAndShaderJob] = [] if override_shader_job: shader_job_overrides.append( tool.NameAndShaderJob(name=override_shader_job[0], shader_job=Path(override_shader_job[1]))) shader_overrides: tool.ShaderJobNameToShaderOverridesMap = {} if override_shader: override = tool.ShaderPathWithNameAndSuffix( name=override_shader[0], suffix=override_shader[1], path=Path(override_shader[2]), ) shader_overrides[override.name] = {override.suffix: override} # E.g. shader_overrides == # { # "variant": { # ".frag.spv": ShaderPathWithNameAndSuffix("variant", ".frag.spv", Path("path/to/shader.frag.spv")) # } # } # We don't need to read this to run the shader, but we need it afterwards anyway. test = test_util.metadata_read_from_path(source_dir / test_util.TEST_METADATA) output_dir = fuzz_glsl_test.run_shader_job( source_dir=source_dir, output_dir=output, binary_manager=binary_manager, test=test, ignore_test_and_device_binaries=use_default_binaries, shader_job_overrides=shader_job_overrides, shader_job_shader_overrides=shader_overrides, ) log(f"gfauto_interestingness_test: finished running {str(source_dir)} in {str(output_dir)}." ) if override_shader_job: log(f"The {override_shader_job[0]} shader was overridden with {override_shader_job[1]}" ) status = result_util.get_status(output_dir) if test.expected_status: log("") log(f"Expected status: {test.expected_status}") log(f"Actual status: {status}") log_contents = util.file_read_text(result_util.get_log_path(output_dir)) signature = signature_util.get_signature_from_log_contents(log_contents) log("") log(f"Expected signature: {test.crash_signature}") log(f"Actual signature: {signature}") log("") # The |crash_regex_override| overrides all other checks. if test.crash_regex_override: log(f"Testing crash_regex_override: {test.crash_regex_override}") override_pattern: Pattern[str] = re.compile(test.crash_regex_override, re.DOTALL) match: Optional[Match[str]] = override_pattern.fullmatch(log_contents) if match: log("Match!") log("Interesting") sys.exit(0) else: log("No match; not interesting") sys.exit(1) if test.expected_status: if status != test.expected_status: log("status != expected_status; not interesting") sys.exit(1) else: # There is no expected status given, so just assume it needs to be one of the "bad" statuses: if status not in ( fuzz.STATUS_CRASH, fuzz.STATUS_TOOL_CRASH, fuzz.STATUS_UNRESPONSIVE, ): log("shader run did not fail; not interesting.") sys.exit(1) if signature != test.crash_signature: log("signature != crash_signature; not interesting") sys.exit(1) log("Interesting!")
def fuzz_and_reduce_bug( active_device: str, seed: int, check_result: Callable[[], None], settings: Optional[Settings] = None, ignored_signatures: Optional[List[str]] = None, ) -> None: """ Fuzz, find a bug, reduce it. Linux only. """ # Test only works on Linux. if util.get_platform() != "Linux": return here = util.norm_path(Path(__file__).absolute()).parent temp_dir: Path = here.parent / "temp" assert temp_dir.is_dir() os.chdir(temp_dir) # Create ROOT file in temp/ if needed. fuzz.try_get_root_file() work_dir = temp_dir / fuzz.get_random_name()[:8] util.mkdir_p_new(work_dir) os.chdir(work_dir) log(f"Changed to {str(work_dir)}") if settings is None: settings = Settings() settings.CopyFrom(settings_util.DEFAULT_SETTINGS) settings.device_list.CopyFrom( DeviceList( active_device_names=[active_device], devices=[ Device( name="amdllpc", shader_compiler=DeviceShaderCompiler( binary="amdllpc", args=[ "-gfxip=9.0.0", "-verify-ir", "-auto-layout-desc" ], ), binaries=[ Binary( name="amdllpc", tags=["Release"], version="c21d76dceaf26361f9b6b3838a955ec3301506b5", ), ], ), Device( name="swift_shader", swift_shader=DeviceSwiftShader(), binaries=[ Binary( name="swift_shader_icd", tags=["Release"], version="6d69aae0e1ab49190ea46cd1c999fd3d02e016b9", ), ], ignored_crash_signatures=ignored_signatures, ), ], )) spirv_tools_version = "983b5b4fccea17cab053de24d51403efb4829158" settings.latest_binary_versions.extend([ Binary( name="glslangValidator", tags=["Release"], version="1afa2b8cc57b92c6b769eb44a6854510b6921a0b", ), Binary(name="spirv-opt", tags=["Release"], version=spirv_tools_version), Binary(name="spirv-dis", tags=["Release"], version=spirv_tools_version), Binary(name="spirv-as", tags=["Release"], version=spirv_tools_version), Binary(name="spirv-val", tags=["Release"], version=spirv_tools_version), Binary(name="spirv-fuzz", tags=["Release"], version=spirv_tools_version), Binary(name="spirv-reduce", tags=["Release"], version=spirv_tools_version), Binary( name="graphicsfuzz-tool", tags=[], version="7b143bcb3ad38b64ddc17d132886636b229b6684", ), ]) # Add default binaries; the ones above have priority. settings.latest_binary_versions.extend(binaries_util.DEFAULT_BINARIES) settings.extra_graphics_fuzz_generate_args.append("--small") settings.extra_graphics_fuzz_generate_args.append("--single-pass") settings.extra_graphics_fuzz_reduce_args.append("--max-steps") settings.extra_graphics_fuzz_reduce_args.append("2") settings_util.write(settings, settings_util.DEFAULT_SETTINGS_FILE_PATH) # Add shaders. binary_manager = binaries_util.get_default_binary_manager(settings) graphicsfuzz_tool = binary_manager.get_binary_path_by_name( "graphicsfuzz-tool") sample_shaders_path: Path = graphicsfuzz_tool.path.parent.parent.parent / "shaders" / "samples" / "310es" util.copy_dir(sample_shaders_path, Path() / fuzz.REFERENCES_DIR) util.copy_dir(sample_shaders_path, Path() / fuzz.DONORS_DIR) fuzz.main_helper( settings_path=settings_util.DEFAULT_SETTINGS_FILE_PATH, iteration_seed_override=seed, override_sigint=False, use_amber_vulkan_loader=True, ) check_result() os.chdir(here) shutil.rmtree(work_dir)
See settings.proto. """ import traceback from pathlib import Path from gfauto import binaries_util, devices_util, proto_util from gfauto.gflogging import log from gfauto.settings_pb2 import Settings DEFAULT_SETTINGS_FILE_PATH = Path("settings.json") DEFAULT_SETTINGS = Settings( maximum_duplicate_crashes=3, maximum_fuzz_failures=10, reduce_tool_crashes=True, reduce_crashes=True, reduce_bad_images=True, _comment= "https://github.com/google/graphicsfuzz/blob/master/gfauto/gfauto/settings.proto", ) class NoSettingsFile(Exception): pass def read_or_create(settings_path: Path) -> Settings: try: return read(settings_path) except FileNotFoundError as exception: if settings_path.exists():
def glsl_shader_job_wrong_image_to_amber_script_for_google_cts( source_dir: Path, output_amber: Path, work_dir: Path, short_description: str, comment_text: str, copyright_year: str, extra_commands: str, is_coverage_gap: bool = False, ) -> Path: """Converts a GLSL shader job of a wrong image case to an Amber script suitable for adding to the CTS.""" check( not short_description.endswith("."), AssertionError("Short description should not end with period."), ) check( "because shader" not in comment_text, AssertionError( 'In comment_text: change "because shader" to "because the shader"' ), ) shader_jobs = get_shader_jobs(source_dir) test = test_util.metadata_read_from_path(source_dir / test_util.TEST_METADATA) binary_manager = binaries_util.get_default_binary_manager( settings=Settings() ).get_child_binary_manager( binary_list=list(test.device.binaries) + list(test.binaries) ) spirv_opt_args = list(test.glsl.spirv_opt_args) or None spirv_opt_hash: Optional[str] = None if spirv_opt_args: spirv_opt_hash = binary_manager.get_binary_by_name( binaries_util.SPIRV_OPT_NAME ).version # Compile all shader jobs shader_job_files = [ amber_converter.ShaderJobFile( shader_job.name, compile_shader_job( shader_job.name, shader_job.shader_job, work_dir / shader_job.name, binary_manager, spirv_opt_args=spirv_opt_args, skip_validation=test.skip_validation, common_spirv_args=list(test.common_spirv_args), ).spirv_asm_shader_job, shader_job.shader_job, "", ) for shader_job in shader_jobs ] reference_asm_spirv_job: Optional[amber_converter.ShaderJobFile] = None if shader_job_files[0].name_prefix == test_util.REFERENCE_DIR: reference_asm_spirv_job = shader_job_files[0] del shader_job_files[0] return amber_converter.spirv_asm_shader_job_to_amber_script( amber_converter.ShaderJobFileBasedAmberTest( reference_asm_spirv_job=reference_asm_spirv_job, variants_asm_spirv_job=shader_job_files, ), output_amber, amber_converter.AmberfySettings( copyright_header_text=get_copyright_header_google(copyright_year), add_graphics_fuzz_comment=True, short_description=short_description, comment_text=comment_text, use_default_fence_timeout=True, spirv_opt_args=spirv_opt_args, spirv_opt_hash=spirv_opt_hash, extra_commands=extra_commands, is_coverage_gap=is_coverage_gap, ), )