1# Copyright (c) 2019 Arm Limited. 2# 3# SPDX-License-Identifier: MIT 4# 5# Permission is hereby granted, free of charge, to any person obtaining a copy 6# of this software and associated documentation files (the "Software"), to 7# deal in the Software without restriction, including without limitation the 8# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9# sell copies of the Software, and to permit persons to whom the Software is 10# furnished to do so, subject to the following conditions: 11# 12# The above copyright notice and this permission notice shall be included in all 13# copies or substantial portions of the Software. 14# 15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21# SOFTWARE. 22 23#!/bin/sh 24 25# Global: Global variables and global settings {{{ 26# Treat unset variables as an error when substituting 27set -u 28 29CMD=$( basename $0 ) 30 31# All supported strategy options 32ALL_STRATEGY_OPTIONS=("native" "reshaped_rhs_only" "reshaped") 33 34# Names of example binary for each strategy 35EXAMPLE_BIN_NATIVE="benchmark_cl_gemm_native" 36EXAMPLE_BIN_RESHAPED_RHS_ONLY="benchmark_cl_gemm_reshaped_rhs_only" 37EXAMPLE_BIN_RESHAPED="benchmark_cl_gemm_reshaped" 38 39# Default data type 40DEFAULT_DATA_TYPE="F32" 41 42# Default output directory 43DEFAULT_OUT_DIR="out" 44 45# Number of iterations for each benchmark run 46NUM_ITERATION=5 47# Global }}} 48 49# Functions {{{ 50####################################### 51# Print gemm shape file help message 52# Globals: 53# None 54# Arguments: 55# None 56# Returns: 57# None 58####################################### 59function help_gemm_shape_file() { 60 cat >&2 << EOF 61Gemm shape file: 62 Gemm shape file is a headerless csv file with fields separated by commas 63 64 A gemm shape is a list of 4 positive integers <M, N, K, B> describing the shapes of the two matrices (LHS and RHS) 65 with: 66 M - Number of lhs matrix rows 67 N - Number of rhs matrix columns 68 K - Number of lhs matrix columns/rhs matrix rows 69 B - Batch size 70 71 An example gemm shape file looks like: 72 100,100,30,1 73 100,100,30,3 74 ... 75 76EOF 77} 78 79####################################### 80# Print gemm config file for native help message 81# Globals: 82# None 83# Arguments: 84# None 85# Returns: 86# None 87####################################### 88function help_gemm_config_file_native() { 89 cat >&2 << EOF 90Gemm config file (Strategy native): 91 Gemm config file is a headerless csv file with fields separated by commas 92 93 A gemm config is a list of 3 positive integers <m0, n0, k0>, with: 94 m0 - Number of rows processed by the matrix multiplication 95 n0 - Number of columns processed by the matrix multiplication 96 k0 - Number of partial accumulations performed by the matrix multiplication 97 98 Only the following configurations of M0, N0 and K0 are currently supported: 99 M0 = 1, 2, 3, 4, 5, 6, 7, 8 100 N0 = 2, 3, 4, 8, 16 101 K0 = 2, 3, 4, 8, 16 102 103 An example gemm config file looks like: 104 1,4,4 105 2,3,8 106 ... 107 108EOF 109} 110 111####################################### 112# Print gemm config file for reshaped_rhs_only help message 113# Globals: 114# None 115# Arguments: 116# None 117# Returns: 118# None 119####################################### 120function help_gemm_config_file_reshaped_rhs_only() { 121 cat >&2 << EOF 122Gemm config file (Strategy reshaped_rhs_only): 123 Gemm config file is a headerless csv file with fields separated by commas. 124 125 Note also comments and extraneous empty lines are not permitted. 126 127 A gemm config is a list of 4 positive integers <m0, n0, k0, h0> and 3 boolean values: 128 m0 - Number of rows processed by the matrix multiplication 129 n0 - Number of columns processed by the matrix multiplication 130 k0 - Number of partial accumulations performed by the matrix multiplication 131 h0 - Number of horizontal blocks of size (k0xn0) stored on the same output row 132 interleave_rhs - Interleave rhs matrix (1) / Do not interleave rhs matrix (0) 133 transpose_rhs - Transpose rhs matrix (1) / Do not transpose rhs matrix (0) 134 export_to_cl_image_rhs - Export rhs matrix to cl_image (1) / Do not export rhs matrix to cl_image (0). Can only be true 135 with certain combinations of the GEMMParams and other configs. Please refer to CLGEMMReshapeRHSMatrixKernel 136 for more details 137 138 Only the following configurations of M0, N0 and K0 are currently supported: 139 M0 = 1, 2, 3, 4, 5, 6, 7, 8 140 N0 = 2, 3, 4, 8, 16 141 K0 = 2, 3, 4, 8, 16 142 H0 >= 1 143 144 An example gemm config file looks like: 145 4,4,4,1,1,1,0 146 4,4,4,3,1,0,1 147 ... 148 149EOF 150} 151 152####################################### 153# Print gemm config file for reshaped help message 154# Globals: 155# None 156# Arguments: 157# None 158# Returns: 159# None 160####################################### 161function help_gemm_config_file_reshaped() { 162 cat >&2 << EOF 163Gemm config file (Strategy reshaped): 164 Gemm config file is a headerless csv file with fields separated by commas 165 166 A gemm config is a list of 5 positive integers <m0, n0, k0, v0, h0> and 4 boolean values: 167 m0 - Number of rows processed by the matrix multiplication 168 n0 - Number of columns processed by the matrix multiplication 169 k0 - Number of partial accumulations performed by the matrix multiplication 170 v0 - Number of vertical blocks of size (m0xk0) stored on the same output row 171 h0 - Number of horizontal blocks of size (k0xn0) stored on the same output row 172 interleave_lhs - Interleave lhs matrix (1) / Do not interleave lhs matrix (0) 173 interleave_rhs - Interleave rhs matrix (1) / Do not interleave rhs matrix (0) 174 transpose_rhs - Transpose rhs matrix but not lhs matrix (1) / Do not transpose rhs matrix but do transpose lhs matrix (0) 175 export_to_cl_image_rhs - Export rhs matrix to cl_image (1) / Do not export rhs matrix to cl_image (0). Can only be true 176 with certain combinations of the GEMMParams and other configs. Please refer to CLGEMMReshapeRHSMatrixKernel 177 for more details 178 179 If rhs matrix is transposed only the following configurations are currently supported: 180 M0 = 2, 3, 4, 5, 6, 7, 8 181 N0 = 2, 3, 4, 8, 16 182 K0 = 2, 3, 4, 8, 16 183 V0 >= 1 184 H0 >= 1 185 186 If lhs matrix is transposed only the following configurations are currently supported: 187 M0 = 2, 3, 4, 8 188 N0 = 2, 3, 4, 8, 16 189 K0 = 2, 3, 4, 8, 16 190 V0 >= 1 191 H0 >= 1 192 193 An example gemm config file looks like: 194 4,4,4,1,3,1,1,1,0 195 4,4,4,3,3,1,1,0,1 196 ... 197 198EOF 199} 200 201####################################### 202# Print usage of this program and exit with Error 203# Globals: 204# Assumes all globals are required 205# Arguments: 206# None 207# Returns: 208# Error(1) 209####################################### 210function usage() { 211 cat >&2 << EOF 212Run gemm examples of a selected strategy, over provided tunable configurationsa and gemm shapes. 213Save the benchmark results to json files in an output directory. 214 215Usage: ${CMD} [-h] -s <strategy> -e <example_binary_dir> -g <gemm_shape_file> -c <gemm_config_file> [-d <data_type>] [-o <out_dir>] 216 217Options: 218 -h 219 Print help messages. If a strategy is specified with -s <strategy>, then only display messages relevant to that 220 strategy. Otherwise if no strategy is specified, display messages for all available strategies. 221 222 -s <strategy> 223 Strategy option. 224 Options: ${ALL_STRATEGY_OPTIONS[@]}. 225 226 -e <example_binary_dir> 227 Path to directory that holds all example binaries 228 229 -g <gemm_shape_file> 230 Path to gemm shape csv file 231 232 -c <gemm_config_file> 233 Path to gemm config csv file 234 235 -d <data_type> 236 Data type option with which to run benchmark examples 237 Default: ${DEFAULT_DATA_TYPE} 238 Supported options: 239 Strategy : Data Types 240 Native : F32 241 Reshaped : F16, F32 242 Reshaped RHS Only : F16, F32 243 244 -o <out_dir> 245 Path to output directory that holds output json files 246 Default: ${DEFAULT_OUT_DIR} 247 248EOF 249# Print help messages about gemm shapes and various gemm configs 250$HELP && help_gemm_shape_file 251$HELP && ( [ "${STRATEGY_OPTION}" == "" ] || [ "${STRATEGY_OPTION}" == "native" ] ) && help_gemm_config_file_native 252$HELP && ( [ "${STRATEGY_OPTION}" == "" ] || [ "${STRATEGY_OPTION}" == "reshaped_rhs_only" ] ) && help_gemm_config_file_reshaped_rhs_only 253$HELP && ( [ "${STRATEGY_OPTION}" == "" ] || [ "${STRATEGY_OPTION}" == "reshaped" ] ) && help_gemm_config_file_reshaped 254exit 1 255} 256 257####################################### 258# Print error message and exit with Error. 259# Globals: 260# None 261# Arguments: 262# $1 - Error message 263# Returns: 264# None 265####################################### 266function error_msg() { 267 echo "Error: $1" 1>&2 268 exit 1 269} 270 271####################################### 272# Convert string to lower-case 273# Globals: 274# None 275# Arguments: 276# target - String 277# Returns: 278# (stdout) - String in lowercase 279####################################### 280function to_lower() { 281 local target=$1 282 echo "$target" | tr '[:upper:]' '[:lower:]' 283} 284 285####################################### 286# Test if the argument is an integer 287# Globals: 288# None 289# Arguments: 290# in - Input 291# Returns: 292# true/false 293####################################### 294function is_integer() { 295 local in=$1 296 [ "$in" -eq "$in" ] 2> /dev/null 297} 298 299####################################### 300# Test if a string is in an array of strings 301# Globals: 302# None 303# Arguments: 304# target - String to test 305# array - Array of strings to search 306# Returns: 307# true/false 308####################################### 309function arr_contains() { 310 local target=$1 311 shift 312 local array 313 array=("$@") 314 for s in "${array[@]}" 315 do 316 [ "$s" == "${target}" ] && return 317 done 318 false 319} 320 321####################################### 322# Run a single example with all tunable gemm configurations on all gemm parameters 323# Globals: 324# OUT_DIR 325# OUT_EXTENSION 326# EXAMPLE_BIN_DIR 327# NUM_ITERATION 328# GEMM_CONFIGS_FILE 329# GEMM_SHAPES_FILE 330# Arguments: 331# example_bin Name of the example binary to run 332# Returns: 333# None 334####################################### 335function run() { 336 local example_bin=$1 337 echo "Running all configs for ${example_bin}" 1>&2 338 local example_args 339 local expr_count=1 340 # Total number of experiment runs scheduled for this session 341 local total_num_experiment 342 local num_params 343 local num_configs 344 local match_expression_shape="^([^,]*,){3}[^,]*$" 345 local match_expression_config="^(\s*[0-9]+\s*,)+\s*[0-9]\s*$" 346 # Don't count empty lines and lines starting with # (comments) 347 num_params=$( grep -E "$match_expression_shape" "${GEMM_SHAPES_FILE}" | wc -l | cut -d " " -f 1) 348 num_configs=$( grep -E "$match_expression_config" "${GEMM_CONFIGS_FILE}" | wc -l | cut -d " " -f 1) 349 (( total_num_experiment=${num_params} * ${num_configs} )) 350 # Time elapsed since the beginning in seconds 351 local time_elapsed_s 352 # Time estimated to finish in seconds 353 local time_est_s 354 echo "Running a total number of ${total_num_experiment} experiments" 1>&2 355 356 while read gemm_shape 357 do 358 while read gemm_config 359 do 360 # Ignore empty lines and lines starting with # (comments) 361 if echo "$gemm_shape" | grep -Eq "$match_expression_shape" && echo "$gemm_config" | grep -Eq "$match_expression_config";then 362 echo "Running..." 1>&2 363 example_args="${gemm_shape},${gemm_config},--type=${DATA_TYPE}" 364 # Run experiment 365 ${EXAMPLE_BIN_DIR}/${example_bin} --example_args=${example_args} --iterations=${NUM_ITERATION} --json-file=${OUT_DIR}/${expr_count}.${OUT_EXTENSION} --instruments=OPENCL_TIMER_MS 366 # Print progress 367 print_progress ${expr_count} ${total_num_experiment} 368 # Print time statistics 369 time_elapsed_s=$SECONDS 370 echo "Time elapsed since beginning: $(( $time_elapsed_s / 60 ))m $(( $time_elapsed_s % 60 ))s" 1>&2 371 (( time_est_s=(${total_num_experiment} - ${expr_count}) * ${time_elapsed_s} / ${expr_count} )) 372 echo "Time estimated to finish: $(( $time_est_s / 60 ))m $(( $time_est_s % 60 ))s" 1>&2 373 (( expr_count++ )) 374 echo "Done." 1>&2 375 fi 376 done < "${GEMM_CONFIGS_FILE}" 377 done < "${GEMM_SHAPES_FILE}" 378 echo "Finished running all configs for ${example_bin}" 1>&2 379 echo "All results saved to ${OUT_DIR}" 1>&2 380} 381 382####################################### 383# Print the progress of the current session 384# Globals: 385# None 386# Arguments: 387# current Current number of items 388# total Total number of items 389# Returns: 390# None 391####################################### 392function print_progress() { 393 local current 394 local total 395 current=$1 396 total=$2 397 # Width of progress bar 398 local width 399 width=20 400 (( current_width= $width * current / total )) 401 echo -n -e "Progress [" 1>&2 402 for i in $(seq 1 ${width}); do 403 if [[ $i -le ${current_width} ]]; then 404 echo -n "#" 1>&2 405 else 406 echo -n " " 1>&2 407 fi 408 done 409 echo "] $current / $total Experiments" 1>&2 410} 411 412# Functions }}} 413 414# Main: Main script {{{ 415# Path to directory containing all benchmark examples binaries 416EXAMPLE_BIN_DIR="" 417# Path to gemm shapes file 418GEMM_SHAPES_FILE="" 419# Path to gemm configs file 420GEMM_CONFIGS_FILE="" 421STRATEGY_OPTION="" 422# Data type to use 423DATA_TYPE=${DEFAULT_DATA_TYPE} 424# Path to output directory 425OUT_DIR=${DEFAULT_OUT_DIR} 426# Output benchmark result file extension 427OUT_EXTENSION="gemmtuner_benchmark" 428# Toggle help 429HELP=false 430 431# Obtain options 432while getopts "hs:e:g:c:d:o:" opt; do 433 case "$opt" in 434 h) HELP=true ;; 435 s) STRATEGY_OPTION=$(to_lower "${OPTARG}");; 436 e) EXAMPLE_BIN_DIR="${OPTARG}";; 437 g) GEMM_SHAPES_FILE="${OPTARG}";; 438 c) GEMM_CONFIGS_FILE="${OPTARG}";; 439 d) DATA_TYPE="${OPTARG}";; 440 o) OUT_DIR="${OPTARG}";; 441 esac 442done 443shift $((OPTIND - 1)) 444 445# Lazily print usage (after arguments have been parsed) 446$HELP && 447 usage 448 449# Parse and validate options 450# Verify all compulsory arguments are passed in 451( [ ! -z "${STRATEGY_OPTION}" ] && [ ! -z "${EXAMPLE_BIN_DIR}" ] && [ ! -z "${GEMM_SHAPES_FILE}" ] && [ ! -z "${GEMM_CONFIGS_FILE}" ] ) || 452 usage 453 454# Verify example binaries directory exists 455[ -d "${EXAMPLE_BIN_DIR}" ] || 456 error_msg "${EXAMPLE_BIN_DIR} does not exist." 457 458# Verify all benchmark example binaries exist 459[ -f "${EXAMPLE_BIN_DIR}/${EXAMPLE_BIN_RESHAPED_RHS_ONLY}" ] || 460 error_msg "Cannot find ${EXAMPLE_BIN_RESHAPED_RHS_ONLY} at ${EXAMPLE_BIN_DIR}" 461 462# Verify Gemm shapes file exists 463[ -f "${GEMM_SHAPES_FILE}" ] || 464 error_msg "Cannot find gemm shapes file ${GEMM_SHAPES_FILE}" 465 466# Verify Gemm configs file exists 467[ -f "${GEMM_CONFIGS_FILE}" ] || 468 error_msg "Cannot find gemm configs file ${GEMM_CONFIGS_FILE}" 469 470# Verify strategy option is valid 471arr_contains "${STRATEGY_OPTION}" "${ALL_STRATEGY_OPTIONS[@]}" || 472 error_msg "Does not support strategy ${STRATEGY_OPTION}" 473 474# Make sure existing benchmark outputs are not overwritten 475[ ! -d "${OUT_DIR}" ] || 476 error_msg "Output directory ${OUT_DIR} already exists!" 477 478# Make output directory 479echo "Making output directory ${OUT_DIR}" 1>&2 480mkdir -p ${OUT_DIR} || error_msg "Failed to make output directory ${OUT_DIR}" 481date +%s > ${OUT_DIR}/start_time_unix_seconds 482 483# Run selected strategy with all configurations 484# Restart the built-in timer 485SECONDS=0 486[ "${STRATEGY_OPTION}" == "native" ] && run $EXAMPLE_BIN_NATIVE 487[ "${STRATEGY_OPTION}" == "reshaped_rhs_only" ] && run $EXAMPLE_BIN_RESHAPED_RHS_ONLY 488[ "${STRATEGY_OPTION}" == "reshaped" ] && run $EXAMPLE_BIN_RESHAPED 489 490date +%s > ${OUT_DIR}/end_time_unix_seconds 491# Main: Main script }}} 492