Files
TheRock/rocm-libraries/projects/rocalution/clients/benchmarks/rocalution_bench_cmdlines.hpp
T
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

601 lines
18 KiB
C++

/*! \file */
/* ************************************************************************
* Copyright (C) 2022 Advanced Micro Devices, Inc. All rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* ************************************************************************ */
#pragma once
#include <iostream>
#include <sstream>
#include <string.h>
#include <vector>
//
// @brief The role of this class is to expand a command line into multiple command lines.
// @details
//
// What is expanding a command line into multiple command lines?
// Let's consider the following command line './foo -m 10' where option '-m' of ./foo
// takes only one argument, here 10.
//
// An expansion mechanism is implemented in this class to provide the set of command lines
// './foo -m 10',
// './foo -m 2',
// './foo -m 7',
// './foo -m -4'
//
// from: ./foo -m 10 2 7 -4
//
// It allows to generate a set of command lines to be useful in a benchmarking context.
//
// Rules:
// - any keyword starting with '-' is considered as an option.
// - each option having exactly one argument is subject to a possible expansion, there is no limit on the number of options to expand.
//
//
// Number of command lines generated : product of all the options' number (>=1) of arguments
// examples:
// cmd: './foo -m 10 2 7 -k 32 -l f -v' gives
// './foo -m 10 -k 32 -l f'
// './foo -m 2 -k 32 -l f'
// './foo -m 7 -k 32 -l f'
// num cmds: max(1,3) * max(1,1) * max(1,0) = 3
// cmd: './foo -m 10 2 7 -k 32 64 -l f g' gives
// './foo -m 10 -k 32 -l f'
// './foo -m 2 -k 32 -l f'
// './foo -m 7 -k 32 -l f'
// './foo -m 10 -k 64 -l f'
// './foo -m 2 -k 64 -l f'
// './foo -m 7 -k 64 -l f'
// './foo -m 10 -k 32 -l g'
// './foo -m 2 -k 32 -l g'
// './foo -m 7 -k 32 -l g'
// './foo -m 10 -k 64 -l g'
// './foo -m 2 -k 64 -l g'
// './foo -m 7 -k 64 -l g'
// num cmds: max(1,3) * max(1,2) * max(1,2) = 12
//
// Specific options:
//
// option: --bench-x, to precede the option the user want to be the first one.
// example
// cmd: './foo -m 10 2 7 --bench-x -k 32 64 -l f g' gives
// './foo -m 32 -k 10 -l f'
// './foo -m 64 -k 10 -l f'
// './foo -m 32 -k 2 -l f'
// './foo -m 64 -k 2 -l f'
// './foo -m 32 -k 7 -l f'
// './foo -m 64 -k 7 -l f'
// './foo -m 32 -k 10 -l g'
// './foo -m 64 -k 10 -l g'
// './foo -m 32 -k 2 -l g'
// './foo -m 64 -k 2 -l g'
// './foo -m 32 -k 7 -l g'
// './foo -m 64 -k 7 -l g'
//
// option: --bench-o, output filename.
// option: --bench-n, number of runs.
// option: --bench-std, prevent from standard output to be disabled.
//
class rocalution_bench_cmdlines
{
private:
struct val
{
//
// Everything is public.
//
public:
int argc{};
char** argv{};
~val()
{
if(this->argv != nullptr)
{
delete[] this->argv;
this->argv = nullptr;
}
}
val(){};
val(int n)
: argc(n)
{
this->argv = new char*[this->argc];
}
val& operator()(int n)
{
this->argc = n;
if(this->argv)
{
delete[] this->argv;
}
this->argv = new char*[this->argc];
return *this;
}
};
struct cmdline
{
public:
//
// @brief Return the output filename.
//
const char* get_ofilename() const
{
return this->m_ofilename;
};
//
// @brief Return the number of plots.
//
int get_nplots() const
{
return this->get_nsamples() / this->m_options[this->m_option_index_x].args.size();
};
int get_noptions_x() const
{
return this->m_options[this->m_option_index_x].args.size();
};
int get_noptions() const
{
return this->m_options.size();
};
int get_option_nargs(int i)
{
return this->m_options[i].args.size();
}
const char* get_option_arg(int i, int j)
{
return this->m_options[i].args[j].name;
}
const char* get_option_name(int i)
{
return this->m_options[i].name;
}
int get_nsamples() const
{
return this->m_nsamples;
}
int get_option_index_x() const
{
return this->m_option_index_x;
}
int get_nruns() const
{
return this->m_bench_nruns;
}
bool is_stdout_disabled() const
{
return this->m_is_stdout_disabled;
}
//
// Constructor.
//
cmdline(int argc, char** argv)
{
//
// Any option --bench-?
//
//
// Try to get the option --bench-n.
//
int detected_option_bench_n
= detect_option(argc, argv, "--bench-n", this->m_bench_nruns);
if(detected_option_bench_n == -1)
{
std::cerr << "missing parameter ?" << std::endl;
exit(1);
}
//
// Try to get the option --bench-o.
//
int detected_option_bench_o
= detect_option_string(argc, argv, "--bench-o", this->m_ofilename);
if(detected_option_bench_o == -1)
{
std::cerr << "missing parameter ?" << std::endl;
exit(1);
}
//
// Try to get the option --bench-x.
//
const char* option_x = nullptr;
int detected_option_bench_x = detect_option_string(argc, argv, "--bench-x", option_x);
if(detected_option_bench_x == -1 || false == is_option(option_x))
{
std::cerr << "wrong position of option --bench-x ?" << std::endl;
exit(1);
}
this->m_name = argv[0];
this->m_has_bench_option
= (detected_option_bench_x || detected_option_bench_o || detected_option_bench_n);
this->m_is_stdout_disabled = (false == detect_flag(argc, argv, "--bench-std"));
int jarg = -1;
for(int iarg = 1; iarg < argc; ++iarg)
{
if(argv[iarg] == option_x)
{
jarg = iarg;
break;
}
}
int iarg = 1;
while(iarg < argc)
{
//
// Any argument starting with the character '-' is considered as an option.
//
if(is_option(argv[iarg]))
{
if(!strcmp(argv[iarg], "--bench-std"))
{
++iarg;
}
else if(!strcmp(argv[iarg], "--bench-o"))
{
iarg += 2;
}
else if(!strcmp(argv[iarg], "--bench-x"))
{
++iarg;
}
else if(!strcmp(argv[iarg], "--bench-n"))
{
iarg += 2;
}
else
{
//
// Create the option.
//
cmdline_option option(argv[iarg]);
//
// Calculate the number of arguments based on the position of the next option, if any.
//
const int option_nargs = count_option_nargs(iarg, argc, argv);
const int next_option_index = iarg + 1 + option_nargs;
for(int k = iarg + 1; k < next_option_index; ++k)
{
option.args.push_back(cmdline_arg(argv[k]));
}
//
// If this option has been flagged being the 'X' field.
// otherwise, other ('Y') options will be classified from the order of their appearances as Y1, Y2, Y3.
//
if(jarg == iarg) //
{
this->m_option_index_x = this->m_options.size();
}
//
// Insert the option created.
//
this->m_options.push_back(option);
iarg = next_option_index;
}
}
else
{
//
// Regular argument.
//
this->m_args.push_back(cmdline_arg(argv[iarg]));
++iarg;
}
}
this->m_nsamples = 1;
for(size_t ioption = 0; ioption < this->m_options.size(); ++ioption)
{
size_t n = this->m_options[ioption].args.size();
this->m_nsamples *= std::max(n, static_cast<size_t>(1));
}
}
void expand(val* p)
{
const int num_options = this->m_options.size();
const auto num_samples = this->m_nsamples;
for(int i = 0; i < num_samples; ++i)
{
p[i](1 + this->m_args.size() + num_options * 2);
p[i].argc = 0;
}
//
// Program name.
//
for(int i = 0; i < num_samples; ++i)
{
p[i].argv[p[i].argc++] = this->m_name;
}
//
// Arguments without options
//
for(auto& arg : this->m_args)
{
for(int i = 0; i < num_samples; ++i)
p[i].argv[p[i].argc++] = arg.name;
}
const int option_x_nargs = this->m_options[this->m_option_index_x].args.size();
int N = option_x_nargs;
for(int iopt = 0; iopt < num_options; ++iopt)
{
cmdline_option& option = this->m_options[iopt];
//
//
//
for(int isample = 0; isample < num_samples; ++isample)
{
p[isample].argv[p[isample].argc++] = option.name;
}
if(iopt == this->m_option_index_x)
{
//
//
//
{
const int ngroups = num_samples / option_x_nargs;
for(int jgroup = 0; jgroup < ngroups; ++jgroup)
{
for(int ix = 0; ix < option_x_nargs; ++ix)
{
const int flat_index = jgroup * option_x_nargs + ix;
p[flat_index].argv[p[flat_index].argc++] = option.args[ix].name;
}
}
}
//
//
//
for(int isample = 0; isample < num_samples; ++isample)
{
if(p[isample].argc != p[0].argc)
{
std::cerr << "invalid struct line " << __LINE__ << std::endl;
}
}
}
else
{
const int option_narg = option.args.size();
if(option_narg > 1)
{
const int ngroups = num_samples / (N * option_narg);
for(int jgroup = 0; jgroup < ngroups; ++jgroup)
{
for(int option_iarg = 0; option_iarg < option_narg; ++option_iarg)
{
for(int i = 0; i < N; ++i)
{
const int flat_index
= N * (jgroup * option_narg + option_iarg) + i;
p[flat_index].argv[p[flat_index].argc++]
= option.args[option_iarg].name;
}
}
}
N *= std::max(option_narg, 1);
}
else
{
if(option_narg == 1)
{
for(int isample = 0; isample < num_samples; ++isample)
{
p[isample].argv[p[isample].argc++] = option.args[0].name;
}
}
}
}
}
}
private:
static inline int count_option_nargs(int iarg, int argc, char** argv)
{
int c = 0;
for(int j = iarg + 1; j < argc; ++j)
{
if(is_option(argv[j]))
{
return c;
}
++c;
}
return c;
}
static bool detect_flag(int argc, char** argv, const char* option_name)
{
for(int iarg = 1; iarg < argc; ++iarg)
{
if(!strcmp(argv[iarg], option_name))
{
return true;
}
}
return false;
}
template <typename T>
static int detect_option(int argc, char** argv, const char* option_name, T& value)
{
for(int iarg = 1; iarg < argc; ++iarg)
{
if(!strcmp(argv[iarg], option_name))
{
++iarg;
if(iarg < argc)
{
std::istringstream iss(argv[iarg]);
iss >> value;
return 1;
}
else
{
std::cerr << "missing value for option --bench-n " << std::endl;
return -1;
}
}
}
return 0;
}
static int
detect_option_string(int argc, char** argv, const char* option_name, const char*& value)
{
for(int iarg = 1; iarg < argc; ++iarg)
{
if(!strcmp(argv[iarg], option_name))
{
++iarg;
if(iarg < argc)
{
value = argv[iarg];
return 1;
}
else
{
std::cerr << "missing value for option " << option_name << std::endl;
return -1;
}
}
}
return 0;
}
//
// argument name.
//
struct cmdline_arg
{
char* name{};
cmdline_arg(char* name_)
: name(name_){};
};
//
// argument option.
//
struct cmdline_option
{
char* name{};
std::vector<cmdline_arg> args{};
cmdline_option(char* name_)
: name(name_){};
};
static inline bool is_option(const char* arg)
{
return arg[0] == '-';
}
//
// Name.
//
char* m_name;
//
// set of options.
//
std::vector<cmdline_option> m_options;
//
// set of arguments.
//
std::vector<cmdline_arg> m_args;
bool m_has_bench_option{};
int m_bench_nruns{1};
int m_option_index_x;
int m_nsamples;
bool m_is_stdout_disabled{true};
const char* m_ofilename{};
};
private:
cmdline m_cmd;
val* m_cmdset{};
public:
//
// @brief Get the output filename.
//
const char* get_ofilename() const;
//
// @brief Get the number of samples..
//
int get_nsamples() const;
int get_option_index_x() const;
int get_option_nargs(int i);
const char* get_option_arg(int i, int j);
const char* get_option_name(int i);
int get_noptions_x() const;
int get_noptions() const;
bool is_stdout_disabled() const;
//
// @brief Get the number of runs per sample.
//
int get_nruns() const;
void get(int isample, int& argc, char** argv) const;
void get_argc(int isample, int& argc_) const;
//
// @brief Constructor.
//
rocalution_bench_cmdlines(int argc, char** argv);
static bool applies(int argc, char** argv);
//
// @brief Some info.
//
void info() const;
};