Skip to content

Add first pass of rocm kernel profiler - #10911

Merged
ytaous merged 19 commits into
microsoft:mainfrom
mwootton:rocm_profiler
Aug 27, 2022
Merged

Add first pass of rocm kernel profiler#10911
ytaous merged 19 commits into
microsoft:mainfrom
mwootton:rocm_profiler

Conversation

@mwootton

Copy link
Copy Markdown
Contributor

Description: Add a profiler to collect ROCm kernel and copy executions.

Motivation and Context
This will allow attribution of AMD gpu executions to ops.

No Issue yet?

@ghost

Deleted user (ghost) commented Mar 17, 2022

Copy link
Copy Markdown

CLA assistant check
All CLA requirements met.

@mwootton

Copy link
Copy Markdown
Contributor Author

Some background. The libroctracer api used to collect rocm execution is similar to cupti. However, it is a bit more rudimentary and requires more support code. That code ends up in every implementation. The code in this PR is based on a Kineto implementation I did which was in turn based on a standalone profiler I have done.

What I have done is refactor the code into two pieces:

  • RoctracerLogger.* is the "common" code. It does the machinations to collect and store the roctracer data. It is free of any concerns outside of roctracer.
  • rocm_profiler.* is the ORT "adapter". It switches the RoctracerLogger on and off. It takes the data collected and delivers it into the onnxruntime::profiling::EventRecord "ecosystem".

The ultimate goal here would be to use the RoctracerLogger across multiple projects. That way features and bug fixes can happen in one place. I will go back and refactor kineto to use RoctracerLogger (and an adapter). I'm not sure if it is practical to share the actual source file, ideas for that appreciated.

@mwootton

Copy link
Copy Markdown
Contributor Author

Issues to resolve:

API calls
Do we want to introduce api calls (ie. runtime)? The cupti implementation enables CUPTI_ACTIVITY_KIND_RUNTIME and CUPTI_ACTIVITY_KIND_DRIVER but ignores them in CudaProfiler::BufferCompleted. So only the gpu ops are being recorded.
These "api calls" would show up on the cpu thread, in e.g. chrome trace, as things like: "hipMalloc", "hipMemcpyAsync", "hipLaunchKernel" under the operators that called them. Yao though this would be helpful. All tracers I have worked on output these.

We will need to add an EventCategory, e.g. (SESSION_EVENT, NODE_EVENT, KERNEL_EVENT). Preference? API_EVENT?

Kernel Name Demangling
I didn't see demangling happening in the cupti implementation (and I recall they come mangled). Can we set up a common file to do this? I can send an example.

String Formatting
Is there a preferred way to do string formatting? For example I need to convert a pointer into "0x12345678". I have used fmt in the past.

@@ -0,0 +1,194 @@
// (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pls make sure to have all file headers aligned.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yeah. This is one of the files we want to share between framework profilers. I'm wondering if we should just add the files as a submodule.

: data(data), validSize(validSize) {}

~RoctracerActivityBuffer() {
free(data);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

data

Should RoctracerActivityBuffer support move/copy? if yes should we reset data? Otherwise we should mark then as deleted explicitly.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I don't anticipate anyone reusing this structure, it is just a wrapper to make sure some malloc memory is freed. These will never be copied or moved. Just keeping it simple, no interest in copy semantics or blocking operator= or copy constructors.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Then u should mark move/copy as deleted.

}

// Allocated by malloc
uint8_t* data{nullptr};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

data

Mind name it to "data_" to follow onnxruntime coding style? Same apply to entire PR.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Ah yes, the horrid google style. Missed that one, and one other, thanks.

bool invertMode() { return invert_; }
void setInvertMode(bool invert) { invert_ = invert; }
void add(std::string apiName);
void remove(std::string apiName);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

std::string

Is this passing by value a deliberately expected?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Obviously not, fixed, thanks.


//namespace profiling {

int32_t systemThreadId();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I tried to switch over to using the methods in logging.h but had issues with linking. Simple approach caused a failure at runtime to load the rocm_provider.so because the symbols couldn't be resolved. Pulling logging.cc into the rocm_provider caused a duplicated symbol. Couldn't spot an example in the cmake files of how to do this correctly. I lost interest at this point.

I am still using the original functions. End of day they are probably a bit faster as they are using tls to cache the pid,tid.

private:
void addEventRecord(const roctracerRow &item, int64_t pstart, const std::initializer_list<std::pair<std::string, std::string>> &args, std::map<uint64_t, std::vector<EventRecord>> &event_map);

RoctracerLogger *d;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

d

a better name?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is just indicating that it is emulating "d pointer" pattern, i.e. pimpl. I can't think of another name that would add any value. Whatever makes you happy.

if (!singleton().externalCorrelationEnabled_) {
return;
}
t_externalIds[type].push_back(id);

@RandySheriffH RandySheriffH (RandySheriffH) Mar 29, 2022

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

t_externalIds[type].push_back(id);

so for rocm profiler, the pushCorrelationID(...) will not place an id on device?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is a limitation of libroctracer. If we have roctracer pass back digest-style api calls (a buffer at a time like cupti does) then those pages lack the call arguments. So, as you can see, we are collecting the calls and args inline. Roctracer only generates external correlation events when using that page-at-time method. This is fine, my inline method is faster, gets the args, and can generate external correlation.

Unless you understand more about external correlation implementation than I do... your statement about "place an id on device" is a misconception. All that happens is that a mapping from internal correlation id to (one or more) external correlation ids is generated when the api call is made. The 'device' is running ops and tracking them by internal correlation id (that is shares with the generating api call), just like normal.

Because I have 'bitten the bullet' and I am doing inline collection I can implement external correlation here. Without using inline callbacks cupti would have to do this for me and deliver a bunch of records. My way is clearly faster, so it probably turned into an advantage.

@RandySheriffH RandySheriffH (RandySheriffH) left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pls do paste some profiled numbers as example in PR description, and add at least one test case.

@mwootton

Copy link
Copy Markdown
Contributor Author

image

@mwootton

Copy link
Copy Markdown
Contributor Author

I'm going to create a second PR with the cupti changes (api calls and name demangling). The cupti side will need to use demangle.cc and demangle.h (which are in providers/rocm right now). What is a good common location for those 2 files in your opinion?

@mwootton
mwootton marked this pull request as ready for review May 12, 2022 16:46

//namespace onnxruntime {

//namespace profiling {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

profiling

Uncomment the namespace?
Like discussed - we prefer RocTracer to go with built-in threading utilities. But reallly we have to add it here, let's put them into a namespace.

@RandySheriffH

RandySheriffH (RandySheriffH) commented May 31, 2022

Copy link
Copy Markdown
Contributor

I'm going to create a second PR with the cupti changes (api calls and name demangling). The cupti side will need to use demangle.cc and demangle.h (which are in providers/rocm right now). What is a good common location for those 2 files in your opinion?

Would u mind to merge the content of demangle.* into profiler_common.*?

@mwootton

mwootton commented Jun 9, 2022

Copy link
Copy Markdown
Contributor Author

30 second run:
image

Close up:
image

python benchmark.py -g -m bert-base-cased --sequence_length 384 --batch_sizes 128 --provider=rocm -p fp16 --disable_embed_layer_norm

I'll attempt to link against the profiler_common code again. If I can get it to work I'll move the demangle into there.
Also, I fixed the issue where the gpuTraceBuffers weren't being cleared when everything else was. I will push the remaining changes soon.

@mwootton

Copy link
Copy Markdown
Contributor Author

So I half-missed your comment about moving demangle into profiler-common. I did put those files into into core/common, but that is not exactly what you asked. But I think I would have had an issue with what you asked:

There is no profiler_common.cc, it is all declaration and it is in "onnxruntime/include/onnxruntime/core/common/profiler_common.h". So there is no place for the demangle implementation.
There is "/onnxruntime/onnxruntime/core/common/profiler.cc" (and matching profiler.h) but that is more of the external interface to profiling, not profiler utils.

So where would you want the demangle implementation added?

@RandySheriffH

Copy link
Copy Markdown
Contributor

So I half-missed your comment about moving demangle into profiler-common. I did put those files into into core/common, but that is not exactly what you asked. But I think I would have had an issue with what you asked:

There is no profiler_common.cc, it is all declaration and it is in "onnxruntime/include/onnxruntime/core/common/profiler_common.h". So there is no place for the demangle implementation. There is "/onnxruntime/onnxruntime/core/common/profiler.cc" (and matching profiler.h) but that is more of the external interface to profiling, not profiler utils.

So where would you want the demangle implementation added?

You could create there be a profile_common.cc.

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 9 pipeline(s).

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 8 pipeline(s).

Comment thread cmake/onnxruntime_providers.cmake Outdated
@ytaous

ytaous commented Aug 16, 2022

Copy link
Copy Markdown
Contributor

Please fix "Python format (pull_request) " error, thx

@ytaous

ytaous commented Aug 16, 2022

Copy link
Copy Markdown
Contributor

RandySheriffH (@RandySheriffH) - please have another look? thx

@ytaous

ytaous commented Aug 18, 2022

Copy link
Copy Markdown
Contributor

/azp run Windows CPU CI Pipeline, Windows GPU CI Pipeline, Windows GPU TensorRT CI Pipeline, Windows WebAssembly CI Pipeline, orttraining-amd-gpu-ci-pipeline, orttraining-linux-ci-pipeline, orttraining-linux-gpu-ci-pipeline, orttraining-ortmodule-distributed, onnxruntime-python-checks-ci-pipeline

@ytaous

ytaous commented Aug 18, 2022

Copy link
Copy Markdown
Contributor

/azp run Linux CPU CI Pipeline, Linux CPU Minimal Build E2E CI Pipeline, Linux GPU CI Pipeline, Linux GPU TensorRT CI Pipeline, Linux Nuphar CI Pipeline, Linux OpenVINO CI Pipeline, MacOS CI Pipeline, ONNX Runtime Web CI Pipeline, onnxruntime-binary-size-checks-ci-pipeline

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 8 pipeline(s).

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 9 pipeline(s).

@ytaous

ytaous commented Aug 24, 2022

Copy link
Copy Markdown
Contributor

Lint / Python format (pull_request)

please fix this, otherwise it will block u from merging it, thx
mwootton

@ytaous

ytaous commented Aug 26, 2022

Copy link
Copy Markdown
Contributor

/azp run Windows CPU CI Pipeline, Windows GPU CI Pipeline, Windows GPU TensorRT CI Pipeline, Windows WebAssembly CI Pipeline, orttraining-amd-gpu-ci-pipeline, orttraining-linux-ci-pipeline, orttraining-linux-gpu-ci-pipeline, orttraining-ortmodule-distributed, onnxruntime-python-checks-ci-pipeline

@ytaous

ytaous commented Aug 26, 2022

Copy link
Copy Markdown
Contributor

/azp run Linux CPU CI Pipeline, Linux CPU Minimal Build E2E CI Pipeline, Linux GPU CI Pipeline, Linux GPU TensorRT CI Pipeline, Linux Nuphar CI Pipeline, Linux OpenVINO CI Pipeline, MacOS CI Pipeline, ONNX Runtime Web CI Pipeline, onnxruntime-binary-size-checks-ci-pipeline

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 8 pipeline(s).

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 9 pipeline(s).

@ytaous

ytaous commented Aug 26, 2022

Copy link
Copy Markdown
Contributor

please run "black" on your local machine, it will correct the format for you.

@lgtm-com

lgtm-com Bot commented Aug 26, 2022

Copy link
Copy Markdown

This pull request fixes 5 alerts when merging 74084d2 into a972db0 - view on LGTM.com

fixed alerts:

  • 5 for Uncontrolled data used in path expression

@ytaous

ytaous commented Aug 27, 2022

Copy link
Copy Markdown
Contributor

/azp run Linux CPU CI Pipeline, Linux CPU Minimal Build E2E CI Pipeline, Linux GPU CI Pipeline, Linux GPU TensorRT CI Pipeline, Linux Nuphar CI Pipeline, Linux OpenVINO CI Pipeline, MacOS CI Pipeline, ONNX Runtime Web CI Pipeline, onnxruntime-binary-size-checks-ci-pipeline

@ytaous

ytaous commented Aug 27, 2022

Copy link
Copy Markdown
Contributor

/azp run Windows CPU CI Pipeline, Windows GPU CI Pipeline, Windows GPU TensorRT CI Pipeline, Windows WebAssembly CI Pipeline, orttraining-amd-gpu-ci-pipeline, orttraining-linux-ci-pipeline, orttraining-linux-gpu-ci-pipeline, orttraining-ortmodule-distributed, onnxruntime-python-checks-ci-pipeline

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 9 pipeline(s).

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 8 pipeline(s).

@ytaous
ytaous merged commit 817dc94 into microsoft:main Aug 27, 2022
@ytaous

ytaous commented Aug 27, 2022

Copy link
Copy Markdown
Contributor

Thank you for the contribution !!

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.

4 participants