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-9706: xrt support for adf event apis #7926

Merged
merged 8 commits into from
Mar 3, 2024

Conversation

saumyag-xilinx
Copy link
Contributor

@saumyag-xilinx saumyag-xilinx commented Feb 6, 2024

Problem solved by the commit

https://jira.xilinx.com/browse/VITIS-9706
Providing XRT support for Event APIs.

Bug / issue (if any) fixed, which PR introduced the bug, how it was discovered

None

How problem was solved, alternative solutions (if any) and why they were rejected

Implemented an Event class whose constructor xrt::aie::event is used to create event object.
The member function start_profiling() is used to start performance counters in AI Engine as per the profiling option passed as an argument.
The read_profiling() member function will return the current performance counter value associated with the event handle.
The stop_profiling() member function stops the performance profiling associated with the event handle.

Risks (if any) associated the changes in the commit

Low

What has been tested and how, request additional testing if necessary

Tested for an application that calculates throughout

Documentation impact (if any)

NA

Copy link
Collaborator

@chvamshi-xilinx chvamshi-xilinx left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once event is created, we should be able to start , stop and read. Please make requested changes

{
public:

event(const xrt::device& device, int option, const std::string& port1_name, const std::string& port2_name, uint32_t value);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead of constructor taking all the variables, Can you have constructor which takes only device class
and have another member function to start the profiling.


}

int get_event_handle(const std::shared_ptr<xrt::aie::event_impl>& event_ptr) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this extra function required? you can directly get handle using event_ptr->getHandle() function.

device->stop_profiling(handle);
}

int getHandle() const { return handle; }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

naming convention.. Use get_handle instead of getHandle

static uint64_t
read_profiling(xrtDeviceHandle dhdl, int phdl)
static std::shared_ptr<xrt::aie::event_impl>
start_profiling(xrtDeviceHandle dhdl, int option, const char *port1_name, const char *port2_name, uint32_t value)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these can be part of event_impl class functions once you make all other changes.

if(event_hdl == invalid_handle)
throw xrt_core::error(-EINVAL, "Not a valid event handle");
device->stop_profiling(event_hdl);
event_hdl= invalid_handle;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indentation ..

using handle = int;
static constexpr handle invalid_handle = -1;

event_impl(std::shared_ptr<xrt_core::device> dev, handle hdl)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dont need to send hdl.


event::
event(const xrt::device& device)
: impl(open_event(device))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

std::move

return start_profiling(handle, option, port1Name, port2Name, value);
auto impl = open_event(handle);
auto hdl = impl->start_profiling(option, port1Name, port2Name, value);
impl->get_handle() = hdl;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dont require this line

return it->second->read_profiling();
}
else
throw xrt_core::error(-EINVAL, "No such event handle");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indentation

event_cache.erase(pHandle);
}
else
throw xrt_core::error(-EINVAL, "No such event handle");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indentation

auto device = xrt_core::device_int::get_core_device(dhdl);
return device->read_profiling(phdl);
auto core_device = xrt_core::device_int::get_core_device(dhdl);
auto phdl = std::make_shared<xrt::aie::event_impl>(core_device, xrt::aie::event_impl::invalid_handle);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove hdl from constructor

Copy link
Collaborator

@stsoe stsoe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add comments to minimum public APIs and format the public APIs properly.

Copy link
Collaborator

@stsoe stsoe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The public APIs are still not documented or formatted correctly; I am referring to xrt_aie.h.

@saumyag-xilinx saumyag-xilinx requested a review from stsoe February 22, 2024 04:55
Copy link
Collaborator

@stsoe stsoe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Quite a few requests, please review with @chvamshi-xilinx
You can pick and choose as you like, but the public API comments are most important.

* event() - Constructor from a device
*
* @param device
* The device on which the profiling event should start
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit too obfuscated. Line 175 is the first that hints at this having something to do with profiling.
The class name event is rather generic, but I think this event is specifically for profiling. Would it be better to make that clear by moving event under namespace xrt::aie::profiling ? And if so then change start/read/stop_profiling to just start/read/stop ?

Sorry for being picky here, but this is a public API that we can't change in the future, so we better get it right the first time.

What happens when you create an event? What is an event?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Noted. Thank you for the suggestion Soren. Also for clarity on the event APIs, I'm referring UG-1076

Comment on lines 180 to 197
/**
* start_profiling() - Start AIE performance profiling
*
* @param option
* Profiling option
* @param port1_name
* Profiling port 1 name.
* @param port2_name
* Profiling port 2 name.
* @param value
* The number of bytes to trigger the profiling event.
*
* This function configures the performance counters in AI Engine by given
* port names and value. The port names and value will have different
* meanings on different options.
*/
int
start_profiling(int option, const std::string& port1_name, const std::string& port2_name, uint32_t value) const;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will not work in a public API. What is option? It's an int what happens if I pass my lucky number 17? Kidding aside, we need a class enum here. Also, the other parameters are not clear at all, what is profiling port? What does number of bytes to trigger the profiling event mean? Is 0 bytes good? It's not useable in a public API without a lot more documentation and explanation as to what happens with out or range numbers. How do know what port names to use?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Noted.
I have added an enum class of profiling option. Also, the other parameters like profiling port etc are the PLIO/ GMIO ports here. I am referring (UG-1076) for implementation.

Comment on lines 203 to 204
uint64_t
read_profiling() const;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does the profiling counter value represent? I am beginning to wonder who the consumer of these event APIs will be? Will it be end-user from application, or will it be internal XRT (xdp?) using this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The consumer is the end user from application. To understand the adf APIs I referred UG-1076

stop_profiling() const;

private:
std::shared_ptr<event_impl> impl;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is meant to be a public class, then maybe use core/include/xrt/detail/pimpl.h as base class; look at other examples.

~event_impl()
{}

int
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
int
handle

Comment on lines 870 to 872
if (it != event_cache.end()) {
return it->second->read_profiling();
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (it != event_cache.end()) {
return it->second->read_profiling();
}
if (it != event_cache.end())
return it->second->read_profiling();

:number-lines: 45

auto graph = xrt::graph(device, xclbin_uuid, "graph_name");
auto handle = event.start_profiling(int option, std::string& port1, std::string& port2, int value);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was hoping this documentation would explain the semantics of option and value :-(

Suggested change
auto handle = event.start_profiling(int option, std::string& port1, std::string& port2, int value);
auto handle = event.start_profiling(option, std::string& port1, std::string& port2, int value);

:number-lines: 35

event.stop_profiling();
double throughput = (double)output_size_in_bytes / (cycle_count *0.8 * 1e-3);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the cast?

event.stop_profiling();
double throughput = (double)output_size_in_bytes / (cycle_count *0.8 * 1e-3);
//Every AIE cycle is 0.8ns in production board
std::cout<<"Throughput of the graph: "<<throughput<<" MB/s"<<std::endl;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
std::cout<<"Throughput of the graph: "<<throughput<<" MB/s"<<std::endl;
std::cout << "Throughput of the graph: " << throughput << " MB/s" << std::endl;


event.stop_profiling();
double throughput = (double)output_size_in_bytes / (cycle_count *0.8 * 1e-3);
//Every AIE cycle is 0.8ns in production board
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
//Every AIE cycle is 0.8ns in production board
// Every AIE cycle is 0.8ns in production board

@saumyag-xilinx saumyag-xilinx force-pushed the event branch 2 times, most recently from 59e12e6 to 6ce5255 Compare February 23, 2024 16:00
saumya garg added 2 commits February 27, 2024 17:36
minor

fix review suggestions

minor change

Signed-off-by: saumya garg <[email protected]>

minor change

Signed-off-by: saumya garg <[email protected]>

minor change

Signed-off-by: saumya garg <[email protected]>
fix

Signed-off-by: saumya garg <[email protected]>

fix

Signed-off-by: saumya garg <[email protected]>
saumya garg added 4 commits February 27, 2024 17:36
Signed-off-by: saumya garg <[email protected]>
Signed-off-by: saumya garg <[email protected]>

doc update2

Signed-off-by: saumya garg <[email protected]>
Signed-off-by: saumya garg <[email protected]>
Signed-off-by: saumya garg <[email protected]>

fix

Signed-off-by: saumya garg <[email protected]>
Signed-off-by: saumya garg <[email protected]>

fix review comments

Signed-off-by: saumya garg <[email protected]>
Copy link
Collaborator

@stsoe stsoe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks a lot better now. Few more notes.

class profiling : public detail::pimpl<profiling_impl>
{
public:
enum class profiling_option : int { io_total_stream_running_to_idle_cycles = 0, io_stream_start_to_bytes_transferred_cycles = 1, io_stream_start_difference_cycles = 2, io_stream_running_event_count = 3 };
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
enum class profiling_option : int { io_total_stream_running_to_idle_cycles = 0, io_stream_start_to_bytes_transferred_cycles = 1, io_stream_start_difference_cycles = 2, io_stream_running_event_count = 3 };
enum class profiling_option : int
{
io_total_stream_running_to_idle_cycles = 0,
io_stream_start_to_bytes_transferred_cycles = 1,
io_stream_start_difference_cycles = 2,
io_stream_running_event_count = 3
};

You would maybe want to document these?

/**
 * @enum profiliing_options - ...
 *
 * @var enumerator 
 *    What it does
 * /

I know the enumerators are long, so maybe they explain what needs to be explained?

* PLIO/GMIO port 1 name.
* @param port2_name
* PLIO/GMIO port 2 name.
* @param value
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this is in some user guide. Without providing the hyperlink, you could reference UGxxxx for more detail. Without the UG, I would be baffled on the meaning of these parameters.

stop() const;

private:
std::shared_ptr<profiling_impl> impl;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uh, not needed now that you derived off of detail::pimpl

Comment on lines 133 to 135
{
device->stop_profiling(profiling_hdl);
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uh, in conjunction with user callling stop() this dtor won't work. I think you need a bit more logic to the state so stop_profiling can bail if it was already called. My point earlier was that you must handle the case where user forgets to call stop() but you must also handle the case where user does call stop() and the handle is invalid.

Destructors cannot throw, so you must have a try/catch if the function that is called can throw.

Signed-off-by: saumya garg <[email protected]>

fix review comments

Signed-off-by: saumya garg <[email protected]>
@@ -755,7 +851,16 @@ int
xrtAIEStartProfiling(xrtDeviceHandle handle, int option, const char *port1Name, const char *port2Name, uint32_t value)
{
try {
return start_profiling(handle, option, port1Name, port2Name, value);
auto event = create_profiling_event(handle);
if (option < 0 || option > 3)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

magic numbers, can you replace this with proper enums? You can fix it in next PR.

@chvamshi-xilinx chvamshi-xilinx merged commit 275a150 into Xilinx:master Mar 3, 2024
22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants