Example #1
0
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,
            )
Example #2
0
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)
Example #3
0
def read(settings_path: Path) -> Settings:
    result = proto_util.file_to_message(settings_path, Settings())
    return result
Example #4
0
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!")
Example #6
0
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)
Example #7
0
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():
Example #8
0
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,
        ),
    )