Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vitis 13804 : XRT-SMI re-architecture Patch 1 #8656

Merged
merged 24 commits into from
Jan 15, 2025
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/runtime_src/core/tools/common/SubCmd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,3 +167,15 @@ SubCmd::checkForSubOption(const boost::program_options::variables_map& vm, const
return option;
}

void
SubCmd::setOptionConfig(const boost::property_tree::ptree &config)
{
m_jsonConfig = JsonConfig(config.get_child("subcommands"), getName());
try{
m_jsonConfig.addProgramOptions(m_commonOptions, "common", getName());
m_jsonConfig.addProgramOptions(m_hiddenOptions, "hidden", getName());
}
catch (const std::exception& e) {
std::cerr << "Error: " << e.what() << std::endl;
}
}
3 changes: 3 additions & 0 deletions src/runtime_src/core/tools/common/SubCmd.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <boost/program_options.hpp>

#include "JSONConfigurable.h"
#include "SubCmdJsonObjects.h"
#include "OptionOptions.h"

class SubCmd : public JSONConfigurable {
Expand All @@ -38,6 +39,7 @@ class SubCmd : public JSONConfigurable {
const std::string & getExecutableName() const {return m_executableName; };

void setGlobalOptions(const boost::program_options::options_description &globalOptions) { m_globalOptions.add(globalOptions); };
void setOptionConfig(const boost::property_tree::ptree &config);

protected:
const boost::program_options::options_description & getGlobalOptions() const { return m_globalOptions; };
Expand Down Expand Up @@ -85,6 +87,7 @@ class SubCmd : public JSONConfigurable {
boost::program_options::options_description m_hiddenOptions;
boost::program_options::positional_options_description m_positionals;
boost::property_tree::ptree m_commandConfig;
JsonConfig m_jsonConfig;

template<class T>
std::vector<std::shared_ptr<T>>
Expand Down
160 changes: 160 additions & 0 deletions src/runtime_src/core/tools/common/SubCmdJsonObjects.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.

#include <iostream>
#include <string>
#include <unordered_map>

#include "boost/property_tree/ptree.hpp"
#include "boost/program_options.hpp"
#include "SubCmdJsonObjects.h"

void
OptionBasic::printOption() const
{
std::cout << "Name: " << m_name << std::endl;
std::cout << "Description: " << m_description << std::endl;
std::cout << "Tag: " << m_tag << std::endl;
}

/**
* Adds the sub-command option to the options description.
* This method checks the option type and adds the option to the provided options description
* based on its value type (BOOL, STRING, ARRAY).
* If the option type does not match the provided optionsType, the option is not added.
* If the value type is invalid, an exception is thrown.
*/
void
SubCommandOption::addProgramOption(po::options_description& options, const std::string& optionsType)
{
if (m_optionType != optionsType) return;

auto valueType = m_valueTypeMap.find(m_valueType);
if (valueType == m_valueTypeMap.end()) {
throw std::runtime_error("Invalid value type for option " + m_name);
}
switch (valueType->second){
case ValueType::boolean:
{
auto defaultVal = m_defaultValue == "true" ? true : false;
options.add_options()((m_name + "," + m_alias).c_str()
, po::value<bool>()->default_value(defaultVal)
, m_description.c_str());
break;
}
case ValueType::string:
{
options.add_options()((m_name + "," + m_alias).c_str()
, po::value<std::string>()->implicit_value(m_defaultValue)
, m_description.c_str());
break;
}
case ValueType::array:
{
options.add_options()((m_name + "," + m_alias).c_str()
, po::value<std::vector<std::string>>()->multitoken()->zero_tokens()
, m_description.c_str());
break;
}
case ValueType::none:
{
options.add_options()((m_name + "," + m_alias).c_str()
, po::bool_switch()
, m_description.c_str());
break;
}
default:
throw std::runtime_error("Invalid value type for option " + m_name);
}
}

std::unordered_map<std::string, OptionBasic>
SubCommandOption::createBasicOptions(const pt::ptree& pt)
{
std::unordered_map<std::string, OptionBasic> optionMap;
for (const auto& [key, value] : pt) {
optionMap.emplace(value.get<std::string>(std::string(const_name_literal)), OptionBasic(value));
}
return optionMap;
}

void
SubCommandOption::printOption() const
{
std::cout << "Name: " << m_name << std::endl;
std::cout << "Description: " << m_description << std::endl;
std::cout << "Tag: " << m_tag << std::endl;
std::cout << "Alias: " << m_alias << std::endl;
std::cout << "Default Value: " << m_defaultValue << std::endl;
std::cout << "Option Type: " << m_optionType << std::endl;
std::cout << "Value Type: " << m_valueType << std::endl;
for (const auto& [key, value] : m_subOptionMap) {
value.printOption();
}
}

std::unordered_map<std::string, SubCommandOption>
SubCommand::createSubCommandOptions(const pt::ptree& pt)
{
std::unordered_map<std::string, SubCommandOption> optionMap;
for (const auto& [key, value] : pt) {
optionMap.emplace(value.get<std::string>(std::string(const_name_literal)), SubCommandOption(value));
}
return optionMap;
}

void
SubCommand::addProgramOptions(po::options_description& options, const std::string& optionsType)
{
for (auto& [optionName, optionObj] : m_optionMap) {
optionObj.addProgramOption(options, optionsType);
}
}

/**
* Creates sub-commands from the property tree.
* This method parses the property tree to create a map of sub-command names to SubCommand objects.
* Only sub-commands matching the provided subCommand name are included.
*/
std::unordered_map<std::string, SubCommand>
JsonConfig::createSubCommands(const pt::ptree& pt, const std::string& subCommand)
{
std::unordered_map<std::string, SubCommand> subCommandMap;
for (const auto& [key, value] : pt) {
if (value.get<std::string>(std::string(const_name_literal)) != subCommand) {
continue;
}
subCommandMap.emplace(value.get<std::string>(std::string(const_name_literal)), SubCommand(value));
}
return subCommandMap;
}

/**
* Adds program options to the options description for a specific sub-command.
* This method finds the specified sub-command and adds its options to the provided options description.
* If the sub-command is not found, an exception is thrown.
*/
void
JsonConfig::addProgramOptions(po::options_description& options
, const std::string& optionsType
, const std::string& subCommand)
{
auto subCommandIter = m_subCommandMap.find(subCommand);
if (subCommandIter == m_subCommandMap.end()) {
throw std::runtime_error("Subcommand not found");
}
subCommandIter->second.addProgramOptions(options, optionsType);
}

void
JsonConfig::printConfigurations() const
{
for (const auto& [key, value] : m_subCommandMap) {
std::cout << "Subcommand: " << key << std::endl;
std::cout << "Description: " << value.getDescription() << std::endl;
std::cout << "Tag: " << value.getTag() << std::endl;
for (const auto& [key2, value2] : value.getOptionMap()) {
value2.printOption();
}
}
}
147 changes: 147 additions & 0 deletions src/runtime_src/core/tools/common/SubCmdJsonObjects.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.

#pragma once

#include <string>
#include <unordered_map>
stsoe marked this conversation as resolved.
Show resolved Hide resolved

#include "boost/property_tree/ptree.hpp"
#include "boost/program_options.hpp"
aktondak marked this conversation as resolved.
Show resolved Hide resolved

static constexpr std::string_view const_name_literal = "name";
static constexpr std::string_view const_description_literal = "description";
static constexpr std::string_view const_tag_literal = "tag";
static constexpr std::string_view const_alias_literal = "alias";
static constexpr std::string_view const_default_value_literal = "default_value";
static constexpr std::string_view const_option_type_literal = "option_type";
static constexpr std::string_view const_value_type_literal = "value_type";
static constexpr std::string_view const_options_literal = "options";
aktondak marked this conversation as resolved.
Show resolved Hide resolved

namespace po = boost::program_options;
namespace pt = boost::property_tree;

enum class ValueType {
boolean,
string,
array,
none
};

class OptionBasic {

public:
std::string m_name;
std::string m_description;
std::string m_tag;
OptionBasic(const pt::ptree& configurations)
: m_name(configurations.get<std::string>(std::string(const_name_literal))),
m_description(configurations.get<std::string>(std::string(const_description_literal))),
m_tag(configurations.get<std::string>(std::string(const_tag_literal)))
{}

std::string getName() const { return m_name; }
std::string getDescription() const { return m_description; }
std::string getTag() const { return m_tag; }
void printOption() const;
};


class SubCommandOption : public OptionBasic {
std::string m_alias;
std::string m_defaultValue;
std::string m_optionType;
std::string m_valueType;
pt::ptree m_ptEmpty;

/*
* Map of option name vs SubCommandOption objects. Example:
* --run can have multiple option Values like latency, throughput etc.
* latency : OptionBasic object
* throughput : OptionBasic object
* .................
* df-bw : OptionBasic object
*/
std::unordered_map<std::string, OptionBasic> m_subOptionMap;
std::unordered_map<std::string, OptionBasic>
createBasicOptions(const pt::ptree& pt);

protected:
const std::unordered_map<std::string, ValueType> m_valueTypeMap = {
{"bool", ValueType::boolean},
{"string", ValueType::string},
{"array", ValueType::array},
{"none", ValueType::none}
};

aktondak marked this conversation as resolved.
Show resolved Hide resolved
public:

SubCommandOption(const pt::ptree& configurations):
OptionBasic(configurations),
m_alias(configurations.get<std::string>(std::string(const_alias_literal), "")),
m_defaultValue(configurations.get<std::string>(std::string(const_default_value_literal), "")),
m_optionType(configurations.get<std::string>(std::string(const_option_type_literal), "")),
m_valueType(configurations.get<std::string>(std::string(const_value_type_literal), "")),
m_ptEmpty(pt::ptree()),
m_subOptionMap(createBasicOptions(configurations.get_child(std::string(const_options_literal), m_ptEmpty)))
{}

std::string getValueType() const { return m_valueType; }
std::string getAlias() const { return m_alias; }
std::string getDefaultValue() const { return m_defaultValue; }
std::string getOptionType() const { return m_optionType; }
std::unordered_map<std::string, OptionBasic> getSubOptionMap() const { return m_subOptionMap; }

void addProgramOption(po::options_description& options, const std::string& optionsType);
void printOption() const;
};

class SubCommand : public OptionBasic {
/*
* Map of option name vs SubCommandOption objects. Example:
* --device : SubCommandOption object
* --format : SubCommandOption object
* .................
* --run : SubCommandOption object
*/
std::unordered_map<std::string, SubCommandOption> m_optionMap;

std::unordered_map<std::string, SubCommandOption>
createSubCommandOptions(const pt::ptree& pt);

public:
SubCommand(const pt::ptree& configurations) :
OptionBasic(configurations),
m_optionMap(createSubCommandOptions(configurations.get_child(std::string(const_options_literal))))
{}
std::unordered_map<std::string,SubCommandOption> getOptionMap() const { return m_optionMap; }

void addProgramOptions(po::options_description& options, const std::string& optionsType);
};

/**
* @brief JsonConfig class to handle the json configurations.
* Each SubCommand class will keep an object of this class type.
* Ideally SubCommand object creation should also be done at run-time
* and there should only be one object of this class type in existence.
* But that's a task for future enhancements.
*/

class JsonConfig {
/* Map of subcommand name vs Subcommand objects
* validate : SubCommand object
* configure : SubCommand object
* examine : SubCommand object
*/
std::unordered_map<std::string, SubCommand> m_subCommandMap;
std::unordered_map<std::string, SubCommand>
stsoe marked this conversation as resolved.
Show resolved Hide resolved
createSubCommands(const pt::ptree& pt, const std::string& subCommand);
public:
JsonConfig(const pt::ptree& configurations, const std::string& subCommand)
: m_subCommandMap(createSubCommands(configurations, subCommand))
{}
JsonConfig() = default;

void addProgramOptions(po::options_description& options, const std::string& optionsType, const std::string& subCommand);
void printConfigurations() const;
};
24 changes: 21 additions & 3 deletions src/runtime_src/core/tools/common/XBMain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ namespace XBU = XBUtilities;
// 3rd Party Library - Include Files
#include <boost/format.hpp>
#include <boost/program_options.hpp>
#include <boost/property_tree/json_parser.hpp>

namespace po = boost::program_options;

Expand Down Expand Up @@ -173,9 +174,26 @@ void main_(int argc, char** argv,

subCommand->setGlobalOptions(globalSubCmdOptions);

/* xrt-smi. Tool should query device upfront and get the configurations
* from shim. This moves the resposibility for option setting to each shim
* instead of xrt-smi.
*/
if (isUserDomain) {
std::shared_ptr<xrt_core::device> device;
try {
device = XBU::get_device(boost::algorithm::to_lower_copy(sDevice), isUserDomain);
} catch (const std::runtime_error& e) {
std::cerr << boost::format("ERROR: %s\n") % e.what();
}
if (device){
boost::property_tree::ptree configTreeMain;
const std::string config = xrt_core::device_query<xrt_core::query::xrt_smi_config>(device, xrt_core::query::xrt_smi_config::type::options_config);
std::istringstream command_config_stream(config);
boost::property_tree::read_json(command_config_stream, configTreeMain);
subCommand->setOptionConfig(configTreeMain);
}
}

// -- Execute the sub-command
subCommand->execute(subcmd_options);
}



Loading
Loading