tritonserver学习之二:tritonserver编译
tritonserver学习之三:tritonserver运行流程
tritonserver学习之六:自定义c++、python custom backend实践
tritonserver学习之八:redis_caches实践
tritonserver学习之九:tritonserver grpc异步模式
1、命令行解析的两个函数
1.1 getopt
int getopt(intargc, char * const argv[], const char *optstring);
getopt用来解析命令行参数,但是只能解析短选项,例如:-b 100,不能解析长选项--prefix。
参数说明:
argc:main()函数传递过来的参数的个数
argv:main()函数传递过来的参数的字符串指针数组
optstring:选项字符串,告知 getopt()可以处理哪个选项以及哪个选项需要参数
重点说明optstring字段:
char *optstring = “ab:c::”;
单个字符a 表示选项a没有参数 格式:-a即可,不加参数
单字符加冒号b: 表示选项b有且必须加参数 格式:-b 100或-b100, -b=100这种格式是错误的
单字符加2个冒号c:: 表示选项c可以有,也可以无 格式:-c200,其它格式错误
函数返回值:
如果选项成功找到,返回选项字母;
如果所有命令行选项都解析完毕,返回 -1;
如果遇到选项字符不在 optstring 中,返回字符 '?';
如果遇到丢失参数,那么返回值依赖于 optstring 中第一个字符,如果第一个字符是 ':' 则返回':',
否则返回'?'并提示出错误信息。
几个重要的全局变量:
optarg —— 指向当前选项参数(如果有)的指针。
optind —— 再次调用 getopt() 时的下一个 argv指针的索引。
optopt —— 最后一个未知选项。
opterr —— 如果不希望getopt()打印出错信息,则只要将全域变量opterr设为0即可。
示例:
#include <iostream>
#include <thread>
#include<getopt.h>
int main(int argc, char *argv[])
{
unsigned int n = std::thread::hardware_concurrency();
std::cout << " concurrent threads are supported = " << n << std::endl;
int opt;
std::string str = "a::b:c:d";
while ((opt = getopt(argc, argv, str.data()))!= -1)
{
printf("opt = %c\t\t", opt);
printf("optarg = %s\t\t",optarg);
printf("optind = %d\t\t",optind);
printf("argv[optind] = %s\n",argv[optind]);
}
}
运行结果:
liupeng@liupengdeMacBook-Pro Downloads % ./a.out -a100 -b 200 -c200 -d
concurrent threads are supported = 8
opt = a optarg = 100 optind = 2 argv[optind] = -b
opt = b optarg = 200 optind = 4 argv[optind] = -c200
opt = c optarg = 200 optind = 5 argv[optind] = -d
opt = d optarg = (null) optind = 6 argv[optind] = (null)
选项a是可选参数,可以不带参数。
1.2 getopt_long
triton中使用的是该函数,getopt_long包含了getopt函数的所有功能,并且可以指定长选项。
int getopt_long(int argc, char * const argv[], const char *optstring,
const struct option *longopts, int*longindex);
参数说明:
longopts 指明了长参数的名称和属性
longindex 如果longindex非空,它指向的变量将记录当前找到参数符合longopts里的第几个元素的描述,即是longopts的下标值
struct option结构体:
struct option {
const char *name; /* 参数名称 */
int has_arg; /* 指明是否带有参数 */
int *flag; /* flag=NULL时,返回val;不为空时,*flag=val,返回0 */
int val; /* 用于指定函数找到选项的返回值或flag非空时指定*flag的值 */
};
函数返回值:
对于短选项,返回值同getopt函数;对于长选项,如果flag是NULL,返回val,否则返回0;
对于错误情况返回值同getopt函数
has_arg参数说明:
has_arg 指明是否带参数值,其数值可选:
no_argument 表明长选项不带参数,如:--name, --help
required_argument 表明长选项必须带参数,如:--prefix /root或 --prefix=/root
optional_argument 表明长选项的参数是可选的,如:--help或 –prefix=/root,其它都是错误
代码示例:
#include <iostream>
#include <thread>
#include <getopt.h>
int main(int argc, char *argv[])
{
unsigned int n = std::thread::hardware_concurrency();
std::cout << " concurrent threads are supported = " << n << std::endl;
int opt;
std::string str = "a::b:c:d";
static struct option long_options[] =
{
{"reqarg", required_argument,NULL, 'r'},
{"optarg", optional_argument,NULL, 'o'},
{"noarg", no_argument, NULL,'n'},
{NULL, 0, NULL, 0},
};
int option_index;
while((opt =getopt_long(argc,argv,str.data(),long_options,&option_index))!= -1)
{
printf("opt = %c\t\t", opt);
printf("optarg = %s\t\t",optarg);
printf("optind = %d\t\t",optind);
printf("argv[optind] =%s\t\t", argv[optind]);
printf("option_index = %d\n",option_index);
}
}
运行结果:
liupeng@liupengdeMacBook-Pro Downloads % ./a.out -b 200 -d --reqarg 100 --optarg 200
concurrent threads are supported = 8
opt = b optarg = 200 optind = 3 argv[optind] =-d option_index = 1
opt = d optarg = (null) optind = 4 argv[optind] =--reqarg option_index = 1
opt = r optarg = 100 optind = 6 argv[optind] =--optarg option_index = 0
opt = o optarg = (null) optind = 7 argv[optind] =200 option_index = 1
liupeng@liupengdeMacBook-Pro Downloads %
2、triton命令行处理
tritonserver版本为当前最新:2.36.0
2.1 TritonParser类-命令注册
TritonParser类的构造函数,实现了支持的命令行的注册。
构造函数位于:command_line_parser.cc文件的L814,构造函数调用了SetupOptionGroups()函数。
void
TritonParser::SetupOptionGroups()
{
SetupOptions();
option_groups_.emplace_back(GLOBAL_OPTION_GROUP, global_options_);
option_groups_.emplace_back("Server", server_options_);
option_groups_.emplace_back("Logging", logging_options_);
option_groups_.emplace_back("Model Repository", model_repo_options_);
option_groups_.emplace_back("HTTP", http_options_);
option_groups_.emplace_back("GRPC", grpc_options_);
option_groups_.emplace_back("Sagemaker", sagemaker_options_);
option_groups_.emplace_back("Vertex", vertex_options_);
option_groups_.emplace_back("Metrics", metric_options_);
option_groups_.emplace_back("Tracing", tracing_options_);
option_groups_.emplace_back("Backend", backend_options_);
option_groups_.emplace_back("Repository Agent", repo_agent_options_);
option_groups_.emplace_back("Response Cache", cache_options_);
option_groups_.emplace_back("Rate Limiter", rate_limiter_options_);
option_groups_.emplace_back(
"Memory/Device Management", memory_device_options_);
option_groups_.emplace_back("DEPRECATED", deprecated_options_);
}
具体实现:
void
TritonParser::SetupOptions()
{
global_options_.push_back(
{OPTION_HELP, "help", Option::ArgNone, "Print usage"});
server_options_.push_back(
{OPTION_ID, "id", Option::ArgStr, "Identifier for this server."});
server_options_.push_back(
{OPTION_EXIT_TIMEOUT_SECS, "exit-timeout-secs", Option::ArgInt,
"Timeout (in seconds) when exiting to wait for in-flight inferences to "
"finish. After the timeout expires the server exits even if inferences "
"are still in flight."});
}
global_options_、server_options_的定义如下:
std::vector<Option> global_options_;
std::vector<Option> server_options_;
其中,Option为命令行的结构体:
// Command-line options
struct Option {
static constexpr const char* ArgNone = "";
static constexpr const char* ArgBool = "boolean";
static constexpr const char* ArgFloat = "float";
static constexpr const char* ArgInt = "integer";
static constexpr const char* ArgStr = "string";
Option(int id, std::string flag, std::string arg_desc, std::string desc)
: id_(id), flag_(flag), arg_desc_(arg_desc), desc_(desc)
{
}
struct option GetLongOption() const
{
struct option lo {
flag_.c_str(), (!arg_desc_.empty()) ? required_argument : no_argument,
nullptr, id_
};
return lo;
}
const int id_;
const std::string flag_;
const std::string arg_desc_;
const std::string desc_;
};
该结构共4个字段,用于对命令行进行描述,GetLongOption函数完成triton Option到系统struct option结构的转换,到此,命令行完成注册,所有支持的命令行全部保存到了option_groups_,这个vector中。
2.2 TritonParser类-命令解析
命令行解析函数:
std::pair<TritonServerParameters, std::vector<char*>>
TritonParser::Parse(int argc, char** argv)
triton中解析命令行设计的方案就是使用getopt_long函数,因此第一步是将支持的命令行完成从triton系统中Option结构到系统struct option结构的转换:
std::vector<struct option> long_options;
for (const auto& group : option_groups_) {
for (const auto& o : group.second) {
long_options.push_back(o.GetLongOption());
}
}
long_options.push_back({nullptr, 0, nullptr, 0});
这几行代码位于:command_line_parser.cc文件的L1167,接下来就是使用getopt_long函数,循环对命令行进行解析,解析的命令行参数值,全部放在了结构体lparams这个TritonServerParameters结构体变量中。
3、main函数中调用
int
main(int argc, char** argv)
{
// Parse command-line to create the options for the inference
// server.
triton::server::TritonParser tp;
try {
auto res = tp.Parse(argc, argv);
g_triton_params = res.first;
g_triton_params.CheckPortCollision();
}
catch (const triton::server::ParseException& pe) {
std::cerr << pe.what() << std::endl;
std::cerr << "Usage: tritonserver [options]" << std::endl;
std::cerr << tp.Usage() << std::endl;
exit(1);
}
.........
}
代码走到g_triton_params = res.first;这一行,就已经获取到了用户输入的所有参数值,当获取到所有参数之后,调用了TritonServerParameters结构成员函数:g_triton_params.BuildTritonServerOptions(),将这些参数设置到TritonServerOptions这个核心类成员中。
以上就是triton命令行注册、解析部分,希望能帮到各位正在学习triton的同学。