Skip to content

Commit 67f7471

Browse files
authored
Omnitrace sample documentation (#179)
* Documentation for omnitrace-sample * Improve omnitrace-sample - improve the printing of the env updates - remove env settings when something is deactivated - restore env settings when something is deactivated
1 parent 78a06e7 commit 67f7471

File tree

15 files changed

+788
-91
lines changed

15 files changed

+788
-91
lines changed

README.md

Lines changed: 100 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,43 @@ such as the memory usage, page-faults, and context-switches, and thread-level me
8585
## Documentation
8686

8787
The full documentation for [omnitrace](https://github.com/AMDResearch/omnitrace) is available at [amdresearch.github.io/omnitrace](https://amdresearch.github.io/omnitrace/).
88+
See the [Getting Started documentation](https://amdresearch.github.io/omnitrace/getting_started) for general tips and a detailed discussion about sampling vs. binary instrumentation.
8889

8990
## Quick Start
9091

92+
### Installation
93+
94+
- Visit [Releases](https://github.com/AMDResearch/omnitrace/releases) page
95+
- Select appropriate installer (recommendation: `.sh` scripts do not require super-user priviledges unlike the DEB/RPM installers)
96+
- If targeting a ROCm application, find the installer script with the matching ROCm version
97+
- If you are unsure about your Linux distro, check `/etc/os-release`
98+
- If no installer script matches your target OS, try one of the Ubuntu 18.04 `*.sh` installers
99+
- This installation may be built against older library versions supported on your distro via backwards compatibility
100+
101+
### Setup
102+
103+
> NOTE: Replace `/opt/omnitrace` below with installation prefix as necessary.
104+
105+
- Option 1: Source `setup-env.sh` script
106+
107+
```bash
108+
source /opt/omnitrace/share/omnitrace/setup-env.sh
109+
```
110+
111+
- Option 2: Load modulefile
112+
113+
```bash
114+
module use /opt/omnitrace/share/modulefiles
115+
module load omnitrace
116+
```
117+
118+
- Option 3: Manual
119+
120+
```bash
121+
export PATH=/opt/omnitrace/bin:${PATH}
122+
export LD_LIBRARY_PATH=/opt/omnitrace/lib:${LD_LIBRARY_PATH}
123+
```
124+
91125
### Omnitrace Settings
92126

93127
Generate an omnitrace configuration file using `omnitrace-avail -G omnitrace.cfg`. Optionally, use `omnitrace-avail -G omnitrace.cfg --all` for
@@ -111,9 +145,23 @@ Once the configuration file is adjusted to your preferences, either export the p
111145
or place this file in `${HOME}/.omnitrace.cfg` to ensure these values are always read as the default. If you wish to change any of these settings,
112146
you can override them via environment variables or by specifying an alternative `OMNITRACE_CONFIG_FILE`.
113147

114-
### Omnitrace Executable
148+
### Call-Stack Sampling
115149

116-
The `omnitrace` executable is used to instrument an existing binary.
150+
The `omnitrace-sample` executable is used to execute call-stack sampling on a target application without binary instrumentation.
151+
Use a double-hypen (`--`) to separate the command-line arguments for `omnitrace-sample` from the target application and it's arguments.
152+
153+
```shell
154+
omnitrace-sample --help
155+
omnitrace-sample <omnitrace-options> -- <exe> <exe-options>
156+
omnitrace-sample -f 1000 -- ls -la
157+
```
158+
159+
### Binary Instrumentation
160+
161+
The `omnitrace` executable is used to instrument an existing binary. Call-stack sampling can be enabled alongside
162+
the execution an instrumented binary, to help "fill in the gaps" between the instrumentation via setting the `OMNITRACE_USE_SAMPLING`
163+
configuration variable to `ON`.
164+
Similar to `omnitrace-sample`, use a double-hypen (`--`) to separate the command-line arguments for `omnitrace` from the target application and it's arguments.
117165

118166
```shell
119167
omnitrace --help
@@ -183,9 +231,57 @@ omnitrace -ME '^(libhsa-runtime64|libz\\.so)' -- /path/to/app
183231
omnitrace -E 'rocr::atomic|rocr::core|rocr::HSA' -- /path/to/app
184232
```
185233

186-
### Visualizing Perfetto Results
234+
### Python Profiling and Tracing
235+
236+
Use the `omnitrace-python` script to profile/trace Python interpreter function calls.
237+
Use a double-hypen (`--`) to separate the command-line arguments for `omnitrace-python` from the target script and it's arguments.
238+
239+
```shell
240+
omnitrace-python --help
241+
omnitrace-python <omnitrace-options> -- <python-script> <script-args>
242+
omnitrace-python -- ./script.py
243+
```
244+
245+
Please note, the first argument after the double-hyphen *must be a Python script*, e.g. `omnitrace-python -- ./script.py`.
246+
247+
If you need to specify a specific python interpreter version, use `omnitrace-python-X.Y` where `X.Y` is the Python
248+
major and minor version:
249+
250+
```shell
251+
omnitrace-python-3.8 -- ./script.py
252+
```
253+
254+
If you need to specify the full path to a Python interpreter, set the `PYTHON_EXECUTABLE` environment variable:
255+
256+
```shell
257+
PYTHON_EXECUTABLE=/opt/conda/bin/python omnitrace-python -- ./script.py
258+
```
259+
260+
If you want to restrict the data collection to specific function(s) and its callees, pass the `-b` / `--builtin` option after decorating the
261+
function(s) with `@profile`. Use the `@noprofile` decorator for excluding/ignoring function(s) and its callees:
262+
263+
```python
264+
def foo():
265+
pass
266+
267+
@noprofile
268+
def bar():
269+
foo()
270+
271+
@profile
272+
def spam():
273+
foo()
274+
bar()
275+
```
276+
277+
Each time `spam` is called during profiling, the profiling results will include 1 entry for `spam` and 1 entry
278+
for `foo` via the direct call within `spam`. There will be no entries for `bar` or the `foo` invocation within it.
279+
280+
### Trace Visualization
187281

188-
Visit [ui.perfetto.dev](https://ui.perfetto.dev) in your browser and open up the `.proto` file(s) created by omnitrace.
282+
- Visit [ui.perfetto.dev](https://ui.perfetto.dev) in the web-browser
283+
- Select "Open trace file" from panel on the left
284+
- Locate the omnitrace perfetto output (extension: `.proto`)
189285

190286
![omnitrace-perfetto](source/docs/images/omnitrace-perfetto.png)
191287

source/bin/omnitrace-sample/impl.cpp

Lines changed: 121 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,17 @@
5252
#endif
5353

5454
namespace color = tim::log::color;
55-
using tim::log::stream;
5655
using namespace timemory::join;
5756
using tim::get_env;
57+
using tim::log::colorized;
58+
using tim::log::stream;
5859

5960
namespace
6061
{
61-
int verbose = 0;
62-
}
62+
int verbose = 0;
63+
auto updated_envs = std::set<std::string_view>{};
64+
auto original_envs = std::set<std::string>{};
65+
} // namespace
6366

6467
std::string
6568
get_command(const char* _argv0)
@@ -92,7 +95,11 @@ get_initial_environment()
9295
{
9396
int idx = 0;
9497
while(environ[idx] != nullptr)
95-
_env.emplace_back(strdup(environ[idx++]));
98+
{
99+
auto* _v = environ[idx++];
100+
original_envs.emplace(_v);
101+
_env.emplace_back(strdup(_v));
102+
}
96103
}
97104

98105
update_env(_env, "LD_PRELOAD",
@@ -106,22 +113,25 @@ get_initial_environment()
106113
update_env(_env, "OMNITRACE_USE_SAMPLING", true);
107114
update_env(_env, "OMNITRACE_CRITICAL_TRACE", false);
108115
update_env(_env, "OMNITRACE_USE_PROCESS_SAMPLING", false);
116+
109117
// update_env(_env, "OMNITRACE_USE_PID", false);
110118
// update_env(_env, "OMNITRACE_TIME_OUTPUT", false);
111119
// update_env(_env, "OMNITRACE_OUTPUT_PATH", "omnitrace-output/%tag%/%launch_time%");
112120

113121
#if defined(OMNITRACE_USE_ROCTRACER) || defined(OMNITRACE_USE_ROCPROFILER)
114122
update_env(_env, "HSA_TOOLS_LIB", _dl_libpath);
115-
update_env(_env, "HSA_TOOLS_REPORT_LOAD_FAILURE", "1");
123+
if(!getenv("HSA_TOOLS_REPORT_LOAD_FAILURE"))
124+
update_env(_env, "HSA_TOOLS_REPORT_LOAD_FAILURE", "1");
116125
#endif
117126

118127
#if defined(OMNITRACE_USE_ROCPROFILER)
119128
update_env(_env, "ROCP_TOOL_LIB", _omni_libpath);
120-
update_env(_env, "ROCP_HSA_INTERCEPT", "1");
129+
if(!getenv("ROCP_HSA_INTERCEPT")) update_env(_env, "ROCP_HSA_INTERCEPT", "1");
121130
#endif
122131

123132
#if defined(OMNITRACE_USE_OMPT)
124-
update_env(_env, "OMP_TOOL_LIBRARIES", _dl_libpath);
133+
if(!getenv("OMP_TOOL_LIBRARIES"))
134+
update_env(_env, "OMP_TOOL_LIBRARIES", _dl_libpath, true);
125135
#endif
126136

127137
free(_dl_libpath);
@@ -140,11 +150,58 @@ get_internal_libpath(const std::string& _lib)
140150
return omnitrace::common::join("/", _dir, "..", "lib", _lib);
141151
}
142152

153+
void
154+
print_updated_environment(std::vector<char*> _env)
155+
{
156+
std::sort(_env.begin(), _env.end(), [](auto* _lhs, auto* _rhs) {
157+
if(!_lhs) return false;
158+
if(!_rhs) return true;
159+
return std::string_view{ _lhs } < std::string_view{ _rhs };
160+
});
161+
162+
std::vector<char*> _updates = {};
163+
std::vector<char*> _general = {};
164+
165+
for(auto* itr : _env)
166+
{
167+
if(itr == nullptr) continue;
168+
169+
auto _is_omni = (std::string_view{ itr }.find("OMNITRACE") == 0);
170+
auto _updated = false;
171+
for(const auto& vitr : updated_envs)
172+
{
173+
if(std::string_view{ itr }.find(vitr) == 0)
174+
{
175+
_updated = true;
176+
break;
177+
}
178+
}
179+
180+
if(_updated)
181+
_updates.emplace_back(itr);
182+
else if(verbose >= 1 && _is_omni)
183+
_general.emplace_back(itr);
184+
}
185+
186+
if(_general.size() + _updates.size() == 0 || verbose < 0) return;
187+
188+
std::cerr << std::endl;
189+
190+
for(auto& itr : _general)
191+
stream(std::cerr, color::source()) << itr << "\n";
192+
for(auto& itr : _updates)
193+
stream(std::cerr, color::source()) << itr << "\n";
194+
195+
std::cerr << std::endl;
196+
}
197+
143198
template <typename Tp>
144199
void
145200
update_env(std::vector<char*>& _environ, std::string_view _env_var, Tp&& _env_val,
146201
bool _append)
147202
{
203+
updated_envs.emplace(_env_var);
204+
148205
auto _key = join("", _env_var, "=");
149206
for(auto& itr : _environ)
150207
{
@@ -153,11 +210,13 @@ update_env(std::vector<char*>& _environ, std::string_view _env_var, Tp&& _env_va
153210
{
154211
if(_append)
155212
{
156-
auto _val = std::string{ itr }.substr(_key.length());
157-
free(itr);
158-
itr = strdup(
159-
omnitrace::common::join('=', _env_var, join(":", _env_val, _val))
160-
.c_str());
213+
if(std::string_view{ itr }.find(join("", _env_val)) ==
214+
std::string_view::npos)
215+
{
216+
auto _val = std::string{ itr }.substr(_key.length());
217+
free(itr);
218+
itr = strdup(join('=', _env_var, join(":", _env_val, _val)).c_str());
219+
}
161220
}
162221
else
163222
{
@@ -171,6 +230,22 @@ update_env(std::vector<char*>& _environ, std::string_view _env_var, Tp&& _env_va
171230
strdup(omnitrace::common::join('=', _env_var, _env_val).c_str()));
172231
}
173232

233+
void
234+
remove_env(std::vector<char*>& _environ, std::string_view _env_var)
235+
{
236+
auto _key = join("", _env_var, "=");
237+
auto _match = [&_key](auto itr) { return std::string_view{ itr }.find(_key) == 0; };
238+
239+
_environ.erase(std::remove_if(_environ.begin(), _environ.end(), _match),
240+
_environ.end());
241+
242+
for(const auto& itr : original_envs)
243+
{
244+
if(std::string_view{ itr }.find(_key) == 0)
245+
_environ.emplace_back(strdup(itr.c_str()));
246+
}
247+
}
248+
174249
std::vector<char*>
175250
parse_args(int argc, char** argv, std::vector<char*>& _env)
176251
{
@@ -200,6 +275,11 @@ parse_args(int argc, char** argv, std::vector<char*>& _env)
200275
exit(_pec);
201276
};
202277

278+
auto* _dl_libpath =
279+
realpath(get_internal_libpath("libomnitrace-dl.so").c_str(), nullptr);
280+
auto* _omni_libpath =
281+
realpath(get_internal_libpath("libomnitrace.so").c_str(), nullptr);
282+
203283
auto parser = parser_t(argv[0]);
204284

205285
parser.on_error([](parser_t&, const parser_err_t& _err) {
@@ -273,6 +353,7 @@ parse_args(int argc, char** argv, std::vector<char*>& _env)
273353
.dtype("bool")
274354
.action([&](parser_t& p) {
275355
auto _colorized = !p.get<bool>("monochrome");
356+
colorized() = _colorized;
276357
p.set_use_color(_colorized);
277358
update_env(_env, "OMNITRACE_COLORIZED_LOG", (_colorized) ? "1" : "0");
278359
update_env(_env, "COLORIZED_LOG", (_colorized) ? "1" : "0");
@@ -599,6 +680,12 @@ parse_args(int argc, char** argv, std::vector<char*>& _env)
599680
_update("OMNITRACE_TRACE_THREAD_LOCKS", _v.count("mutex-locks") > 0);
600681
_update("OMNITRACE_TRACE_THREAD_RW_LOCKS", _v.count("rw-locks") > 0);
601682
_update("OMNITRACE_TRACE_THREAD_SPIN_LOCKS", _v.count("spin-locks") > 0);
683+
684+
if(_v.count("all") > 0 || _v.count("ompt") > 0)
685+
update_env(_env, "OMP_TOOL_LIBRARIES", _dl_libpath, true);
686+
687+
if(_v.count("all") > 0 || _v.count("kokkosp") > 0)
688+
update_env(_env, "KOKKOS_PROFILE_LIBRARY", _omni_libpath, true);
602689
});
603690

604691
parser.add_argument({ "-E", "--exclude" }, "Exclude data from these backends")
@@ -619,14 +706,32 @@ parse_args(int argc, char** argv, std::vector<char*>& _env)
619706
_update("OMNITRACE_TRACE_THREAD_LOCKS", _v.count("mutex-locks") > 0);
620707
_update("OMNITRACE_TRACE_THREAD_RW_LOCKS", _v.count("rw-locks") > 0);
621708
_update("OMNITRACE_TRACE_THREAD_SPIN_LOCKS", _v.count("spin-locks") > 0);
709+
710+
if(_v.count("all") > 0 ||
711+
(_v.count("roctracer") > 0 && _v.count("rocprofiler") > 0))
712+
{
713+
remove_env(_env, "HSA_TOOLS_LIB");
714+
remove_env(_env, "HSA_TOOLS_REPORT_LOAD_FAILURE");
715+
}
716+
717+
if(_v.count("all") > 0 || _v.count("rocprofiler") > 0)
718+
{
719+
remove_env(_env, "ROCP_TOOL_LIB");
720+
remove_env(_env, "ROCP_HSA_INTERCEPT");
721+
}
722+
723+
if(_v.count("all") > 0 || _v.count("ompt") > 0)
724+
remove_env(_env, "OMP_TOOL_LIBRARIES");
725+
726+
if(_v.count("all") > 0 || _v.count("kokkosp") > 0)
727+
remove_env(_env, "KOKKOS_PROFILE_LIBRARY");
622728
});
623729

624730
_add_separator("HARDWARE COUNTER OPTIONS", "");
625731
parser
626732
.add_argument({ "-C", "--cpu-events" },
627733
"Set the CPU hardware counter events to record (ref: "
628734
"`omnitrace-avail -H -c CPU`)")
629-
.set_default(std::set<std::string>{})
630735
.action([&](parser_t& p) {
631736
auto _events =
632737
join(array_config{ "," }, p.get<std::vector<std::string>>("cpu-events"));
@@ -638,7 +743,6 @@ parse_args(int argc, char** argv, std::vector<char*>& _env)
638743
.add_argument({ "-G", "--gpu-events" },
639744
"Set the GPU hardware counter events to record (ref: "
640745
"`omnitrace-avail -H -c GPU`)")
641-
.set_default(std::set<std::string>{})
642746
.action([&](parser_t& p) {
643747
auto _events =
644748
join(array_config{ "," }, p.get<std::vector<std::string>>("gpu-events"));
@@ -695,5 +799,8 @@ parse_args(int argc, char** argv, std::vector<char*>& _env)
695799
throw std::runtime_error(
696800
"Error! '--profile' argument conflicts with '--flat-profile' argument");
697801

802+
free(_dl_libpath);
803+
free(_omni_libpath);
804+
698805
return _outv;
699806
}

source/bin/omnitrace-sample/omnitrace-sample.cpp

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,7 @@ main(int argc, char** argv)
5252
_argv.emplace_back(argv[i]);
5353
}
5454

55-
std::sort(_env.begin(), _env.end(), [](auto* _lhs, auto* _rhs) {
56-
if(!_lhs) return false;
57-
if(!_rhs) return true;
58-
return std::string_view{ _lhs } < std::string_view{ _rhs };
59-
});
60-
61-
for(auto* itr : _env)
62-
if(itr != nullptr && std::string_view{ itr }.find("OMNITRACE") == 0)
63-
std::cout << itr << "\n";
55+
print_updated_environment(_env);
6456

6557
if(!_argv.empty())
6658
{

0 commit comments

Comments
 (0)