blob: f9054538818f8f37cdd4118beb6e43f6ac59a27b [file] [log] [blame]
# Copyright 2021 The IREE Authors
#
# Licensed under the Apache License v2.0 with LLVM Exceptions.
# See https://llvm.org/LICENSE.txt for license information.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
# iree_check_lists_have_same_size()
#
# Note that the caller should pass in the list variables themselves to
# LIST1 and LIST2, not the list variables' values.
function(iree_check_lists_have_same_size LIST1 LIST2)
list(LENGTH "${LIST1}" _LIST1_COUNT)
list(LENGTH "${LIST2}" _LIST2_COUNT)
if(NOT _LIST1_COUNT EQUAL _LIST2_COUNT)
message(SEND_ERROR "${LIST1} count ${_LIST1_COUNT} does not "
"match ${LIST2} count ${_LIST2_COUNT}"
)
endif()
endfunction()
# iree_mlir_benchmark_suite()
#
# Generates benchmark suites for MLIR input modules. The generated artifacts
# will be executed with `iree-benchmark-module`.
#
# Parameters:
# MODULE_NAMES: A list of input module names.
# MODULE_TAGS: A list of tags for each input module.
# MODULE_SOURCES: The initial generating source for each input module.
# MLIR_SOURCES: The input file for each input module. It can be a file in
# checked in the repository; it can also be a URL for downloading from.
# the web. When it's a URL, the file should be a a direct .mlir file
# or a tarball containing a .mlir file; for both cases, the .mlir file
# should have a name matching the one in MODULE_NAMES.
# ENTRY_FUNCTIONS: The entry function name for each input module.
# FUNCTION_INPUTS: A list of entry function inputs for each input module.
# BENCHMARK_MODES: A list strings, where ech one of them is a comma-
# separated list of benchmark mode tags.
# TARGET_BACKEND: The compiler target backend.
# TARGET_ARCHITECTURE: The detailed target backend's architecture.
# TRANSLATION_FLAGS: A list of command-line options and their values to
# pass to the IREE translation tool for artifact generation.
# DRIVER: The runtime driver.
# RUNTIME_FLAGS: A list of command-line options and their values to pass
# to the IREE runtime during benchmark exectuion.
#
# The above parameters largely fall into two categories: 1) for specifying
# the MLIR input module and its metadata, 2) for specifying the translation/
# runtime configuration.
#
# 1)
#
# MODULE_NAMES, MODULE_TAGS, MODULE_SOURCES, MLIR_SOURCES, ENTRY_FUNCTIONS,
# and FUNCTION_INPUTS together provide good flexiblity for specifying the MLIR
# input module and its metadata. For example, we can generate modules with
# idential name from different sources (TensorFlow, TFLite, PyTorch, etc.),
# and we can transform the same input module differently for benchmarking
# different aspects like fp32 vs fp16.
#
# Note that the above parameters are all lists and they should have the name
# number of elements. This enables us to use the same CMake function call to
# generate benchmarks for many models and share the specification of
# translation/runtime configurations.
#
# 2)
#
# TARGET_BACKEND and TRANSLATION_FLAGS control how the input module will be
# converted into the final IREE deployable module format. DRIVER and
# RUNTIME_FLAGS specify how the module will be executed. BENCHMARK_MODES
# can be used to give descriptions of the translation/runtime configuration
# (e.g., full-inference vs. kernel-execution) and specify more contextual
# requirements (e.g., big-core vs. little-core).
#
function(iree_mlir_benchmark_suite)
if(NOT IREE_BUILD_BENCHMARKS)
return()
endif()
cmake_parse_arguments(
PARSE_ARGV 0
_RULE
""
"DRIVER;TARGET_BACKEND;TARGET_ARCHITECTURE"
"BENCHMARK_MODES;ENTRY_FUNCTIONS;FUNCTION_INPUTS;MLIR_SOURCES;MODULE_NAMES;MODULE_SOURCES;MODULE_TAGS;TRANSLATION_FLAGS;RUNTIME_FLAGS"
)
iree_check_lists_have_same_size(_RULE_MODULE_NAMES _RULE_MODULE_TAGS)
iree_check_lists_have_same_size(_RULE_MODULE_NAMES _RULE_MODULE_SOURCES)
iree_check_lists_have_same_size(_RULE_MODULE_NAMES _RULE_MLIR_SOURCES)
iree_check_lists_have_same_size(_RULE_MODULE_NAMES _RULE_ENTRY_FUNCTIONS)
iree_check_lists_have_same_size(_RULE_MODULE_NAMES _RULE_FUNCTION_INPUTS)
# Loop over all modules and their sources to create targets.
list(LENGTH _RULE_MODULE_NAMES _MODULE_NAMES_COUNT)
math(EXPR _MAX_INDEX "${_MODULE_NAMES_COUNT} - 1")
foreach(_INDEX RANGE 0 "${_MAX_INDEX}")
# Generate all benchmarks to the root build directory. This helps for
# discovering them and execute them on devices.
list(GET _RULE_MODULE_SOURCES ${_INDEX} _MODULE_SOURCE)
set(_ROOT_ARTIFACTS_DIR "${IREE_BINARY_DIR}/benchmark_suites/${_MODULE_SOURCE}")
set(_VMFB_ARTIFACTS_DIR "${_ROOT_ARTIFACTS_DIR}/vmfb")
list(GET _RULE_MODULE_NAMES ${_INDEX} _MODULE_NAME)
list(GET _RULE_MODULE_TAGS ${_INDEX} _MODULE_TAGS)
list(GET _RULE_MLIR_SOURCES ${_INDEX} _MLIR_SOURCE)
list(GET _RULE_ENTRY_FUNCTIONS ${_INDEX} _ENTRY_FUNCTION)
list(GET _RULE_FUNCTION_INPUTS ${_INDEX} _FUNCTION_INPUTS)
# The source file used to generate benchmark artifacts.
set(_SOURCE_FILE "${_MLIR_SOURCE}")
# The CMake target's name if we need to download from the web.
set(_DOWNLOAD_TARGET_NAME "")
# If the source file is from the web, create a custom command to download it.
# And wrap that with a custom target so later we can use for dependency.
#
# Note: We actually should not do this; instead, we should directly compile
# from the initial source (i.e., TensorFlow Python models). But that is
# tangled with the pending Python testing infrastructure revamp so we'd prefer
# to not do that right now.
if("${_MLIR_SOURCE}" MATCHES "^https?://")
# Update the source file to the downloaded-to place.
string(REPLACE "/" ";" _SOURCE_URL_SEGMENTS "${_MLIR_SOURCE}")
# TODO: we can do `list(POP_BACK _SOURCE_URL_SEGMENTS _LAST_URL_SEGMENT)`
# after migrating to CMake 3.15.
list(LENGTH _SOURCE_URL_SEGMENTS _URL_SEGMENT_COUNT)
math(EXPR _SEGMENT_LAST_INDEX "${_URL_SEGMENT_COUNT} - 1")
list(GET _SOURCE_URL_SEGMENTS ${_SEGMENT_LAST_INDEX} _LAST_URL_SEGMENT)
set(_DOWNLOAD_TARGET_NAME "iree-download-benchmark-source-${_LAST_URL_SEGMENT}")
string(REPLACE "tar.gz" "mlir" _FILE_NAME "${_LAST_URL_SEGMENT}")
set(_SOURCE_FILE "${_ROOT_ARTIFACTS_DIR}/${_MODULE_NAME}.mlir")
if (NOT TARGET "${_DOWNLOAD_TARGET_NAME}")
add_custom_command(
OUTPUT "${_SOURCE_FILE}"
COMMAND
"${Python3_EXECUTABLE}" "${IREE_ROOT_DIR}/scripts/download_file.py"
"${_MLIR_SOURCE}" -o "${_ROOT_ARTIFACTS_DIR}"
DEPENDS
"${IREE_ROOT_DIR}/scripts/download_file.py"
COMMENT "Downloading ${_MLIR_SOURCE}"
)
add_custom_target("${_DOWNLOAD_TARGET_NAME}"
DEPENDS "${_SOURCE_FILE}"
)
endif()
endif()
# Next create the command and target for compiling the input module into
# IREE deployable format for each benchmark mode.
string(JOIN "-" _MODULE_DIR_NAME "${_MODULE_NAME}" "${_MODULE_TAGS}")
foreach (_BENCHMARK_MODE IN LISTS _RULE_BENCHMARK_MODES)
set(_BENCHMARK_DIR_NAME
"iree-${_RULE_DRIVER}__${_RULE_TARGET_ARCHITECTURE}__${_BENCHMARK_MODE}")
# A list of name segments for composing unique CMake target names.
set(_COMMON_NAME_SEGMENTS "${_MODULE_NAME}")
string(REPLACE "," "-" _TAGS "${_MODULE_TAGS}")
string(REPLACE "," "-" _MODE "${_BENCHMARK_MODE}")
list(APPEND _COMMON_NAME_SEGMENTS
"${_TAGS}" "${_MODE}" "${_RULE_TARGET_BACKEND}"
"${_RULE_TARGET_ARCHITECTURE}")
# The full list of translation flags.
set(_TRANSLATION_ARGS "--iree-mlir-to-vm-bytecode-module")
list(APPEND _TRANSLATION_ARGS "--iree-hal-target-backends=${_RULE_TARGET_BACKEND}")
list(SORT _RULE_TRANSLATION_FLAGS)
list(APPEND _TRANSLATION_ARGS ${_RULE_TRANSLATION_FLAGS})
# Get a unique identifier for this IREE module file by hashing the command
# line flags and input file. We will also use this for the CMake target.
string(SHA1 _VMFB_HASH "${_TRANSLATION_ARGS};${_SOURCE_FILE}")
set(_TRANSLATION_TARGET_NAME "iree-generate-benchmark-artifact-${_VMFB_HASH}")
# Register the target once and share across all benchmarks having the same
# MLIR source and translation flags.
if(NOT TARGET "${_TRANSLATION_TARGET_NAME}")
set(_VMFB_FILE "${_VMFB_ARTIFACTS_DIR}/compiled-${_VMFB_HASH}.vmfb")
add_custom_command(
OUTPUT "${_VMFB_FILE}"
COMMAND
"$<TARGET_FILE:iree_tools_iree-translate>"
${_TRANSLATION_ARGS}
"${_SOURCE_FILE}"
-o "${_VMFB_FILE}"
WORKING_DIRECTORY "${_VMFB_ARTIFACTS_DIR}"
DEPENDS
iree_tools_iree-translate
"${_DOWNLOAD_TARGET_NAME}"
COMMENT "Generating VMFB for ${_COMMON_NAME_SEGMENTS}"
)
add_custom_target("${_TRANSLATION_TARGET_NAME}"
DEPENDS "${_VMFB_FILE}"
)
# Mark dependency so that we have one target to drive them all.
add_dependencies(iree-benchmark-suites "${_TRANSLATION_TARGET_NAME}")
endif(NOT TARGET "${_TRANSLATION_TARGET_NAME}")
# Add a friendly target alias for this particular benchmark.
set(_FRIENDLY_TARGET_NAME_LIST "iree-generate-benchmark-artifact")
list(APPEND _FRIENDLY_TARGET_NAME_LIST ${_COMMON_NAME_SEGMENTS})
list(JOIN _FRIENDLY_TARGET_NAME_LIST "__" _FRIENDLY_TARGET_NAME)
add_custom_target("${_FRIENDLY_TARGET_NAME}"
DEPENDS "${_TRANSLATION_TARGET_NAME}"
)
# Finally create the command and target for the flagfile used to execute the
# generated artifacts.
set(_FLAGFILE_ARTIFACTS_DIR "${_ROOT_ARTIFACTS_DIR}/${_MODULE_DIR_NAME}/${_BENCHMARK_DIR_NAME}")
set(_FLAG_FILE "${_FLAGFILE_ARTIFACTS_DIR}/flagfile")
set(_ADDITIONAL_ARGS_CL "--additional_args=\"${_RULE_RUNTIME_FLAGS}\"")
add_custom_command(
OUTPUT "${_FLAG_FILE}"
COMMAND
"${Python3_EXECUTABLE}" "${IREE_ROOT_DIR}/scripts/generate_flagfile.py"
--module_file="../../vmfb/compiled-${_VMFB_HASH}.vmfb"
--driver=${_RULE_DRIVER}
--entry_function=${_ENTRY_FUNCTION}
--function_inputs=${_FUNCTION_INPUTS}
"${_ADDITIONAL_ARGS_CL}"
-o "${_FLAG_FILE}"
DEPENDS
"${IREE_ROOT_DIR}/scripts/generate_flagfile.py"
WORKING_DIRECTORY "${_FLAGFILE_ARTIFACTS_DIR}"
COMMENT "Generating ${_FLAG_FILE}"
)
set(_FLAGFILE_GEN_TARGET_NAME_LIST "iree-generate-benchmark-flagfile")
list(APPEND _FLAGFILE_GEN_TARGET_NAME_LIST ${_COMMON_NAME_SEGMENTS})
list(JOIN _FLAGFILE_GEN_TARGET_NAME_LIST "__" _FLAGFILE_GEN_TARGET_NAME)
add_custom_target("${_FLAGFILE_GEN_TARGET_NAME}"
DEPENDS "${_FLAG_FILE}"
)
# Mark dependency so that we have one target to drive them all.
add_dependencies(iree-benchmark-suites "${_FLAGFILE_GEN_TARGET_NAME}")
endforeach(_BENCHMARK_MODE IN LISTS _RULE_BENCHMARK_MODES)
endforeach(_INDEX RANGE 0 "${_MAX_INDEX}")
endfunction()