• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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