Skip to content

Commit

Permalink
Add region filters (LLNL#430)
Browse files Browse the repository at this point in the history
* Add initial region filter implementation

* Add variables in config option specs

* Add include_regions and exclude_regions options

* Add tests for region filter options

* Improve error messages

* Add documentation for region filtering

* Rename RegionFiltering.md to RegionFiltering.rst

* Update RegionFiltering.rst
  • Loading branch information
daboehme authored Jul 27, 2022
1 parent 3712b4a commit 05202b4
Show file tree
Hide file tree
Showing 21 changed files with 698 additions and 85 deletions.
77 changes: 77 additions & 0 deletions doc/sphinx/RegionFiltering.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
Region Filtering
=======================================

For event-based measurement configurations like runtime-report or
hatchet-region-profile, you can specify filters to limit measurements
to certain regions using two ConfigManager options:

include_regions
Only take measurements for regions with the given pattern.

exclude_regions
Skip measurements for regions with the given pattern.

The options take a list of region patterns. There are three pattern types:

match
An exact match. For example, `match(this_function)`
matches `this_function`.

startswith
Match the start of the region name, e.g. `startswith(mylib_)`
matches any region starting with `mylib_`.

regex
Match a regular expression in ECMAScript grammar. E.g., `regex(.*loop.*)`
matches any region with `loop` in the name.

The default pattern is `match`. As an example, the following option
specification measures `my_function`, any region starting with `mylib_` or
`MPI_`, and any region with `loop` in the name::

include_regions=my_function,startswith(MPI_,mylib_),regex(.*loop.*)

Examples
---------------------------------------

Recall a runtime report for the `cxx-example` program provided with Caliper::

$ CALI_CONFIG=runtime-report ./examples/apps/cxx-example
Path Min time/rank Max time/rank Avg time/rank Time %
main 0.000096 0.000096 0.000096 4.541154
mainloop 0.000060 0.000060 0.000060 2.838221
foo 0.000674 0.000674 0.000674 31.882687
init 0.000013 0.000013 0.000013 0.614948

We can use the `exclude_regions` option to exclude the `init` region from
measurements::

$ CALI_CONFIG=runtime-report,exclude_regions=init ./examples/apps/cxx-example
Path Min time/rank Max time/rank Avg time/rank Time %
main 0.000113 0.000113 0.000113 5.188246
mainloop 0.000118 0.000118 0.000118 5.417815
foo 0.000675 0.000675 0.000675 30.991736

We can also limit measurements to the `foo` region. The full path to `foo`
still appears in the output. However, performance measurements will only be
taken when entering and exiting `foo`::

$ CALI_CONFIG=runtime-report,include_regions=foo ./examples/apps/cxx-example
Path Min time/rank Max time/rank Avg time/rank Time %
main
mainloop 0.001390 0.001390 0.001390 66.539014
foo 0.000699 0.000699 0.000699 33.460986

Any measurement values taken when entering `foo` are assigned to its enclosing
region - `mainloop` in this case - which is why we still see measurement values
for the `mainloop` region here. However, these do not represent the actual time
spent in `mainloop`.

We can use a pattern like `startswith(main)` to include `main` and `mainloop`.
Be careful to wrap the option values in quotes to prevent them from being
misinterpreted by the config parser::

$ CALI_CONFIG="runtime-report,include_regions=\"startswith(main)\"" ./examples/apps/cxx-example
Path Min time/rank Max time/rank Avg time/rank Time %
main 0.000112 0.000112 0.000112 5.177994
mainloop 0.000773 0.000773 0.000773 35.737402
1 change: 1 addition & 0 deletions doc/sphinx/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ This section lists how-to articles for various use cases.

CUDA
OpenMP
RegionFiltering

Reference documentation
-------------------------------
Expand Down
38 changes: 38 additions & 0 deletions doc/sphinx/services.rst
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,32 @@ only trigger snapshot for "iteration" attribute updates:
event.set#iteration=3,cali.snapshot.event.set=63,iteration=2,loop=true
event.end#iteration=3,cali.snapshot.event.end=63,iteration=3,loop=true
Value filtering
................................

With filtering, the event service only triggers snapshots for specific
values or patterns (e.g., region names). You can provide include or
exclude filters. There are three pattern types:

match
Match the exact value

startswith
Match the start of the string

regex
Match a regular expression

You can specify multiple patterns and combine them as needed, e.g. to
include only "important_region" as well as any region starting with
"MPI_" or "mylib_":

.. code-block:: sh
$ CALI_EVENT_INCLUDE_REGIONS="match(important_region),startswith(MPI_,mylib_)"
Config variables
................................

CALI_EVENT_TRIGGER
List of attributes that trigger measurement snapshots.
If empty, all user attributes trigger snapshots.
Expand All @@ -564,6 +590,18 @@ CALI_EVENT_ENABLE_SNAPSHOT_INFO

Default: true

CALI_EVENT_INCLUDE_REGIONS
Specify a value filter to only trigger snapshots for the provided
patterns. See above for the different pattern options.

Default: empty (no filter)

CALI_EVENT_EXCLUDE_REGIONS
Like above, but defines a value filter to skip snapshots for
the provided patterns.

Default: empty (no filter)

Debug
--------------------------------

Expand Down
1 change: 1 addition & 0 deletions src/caliper/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ set(CALIPER_RUNTIME_SOURCES
CustomOutputController.cpp
MemoryPool.cpp
MetadataTree.cpp
RegionFilter.cpp
RegionProfile.cpp
api.cpp
builtin_configmanager.cpp
Expand Down
86 changes: 76 additions & 10 deletions src/caliper/ConfigManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,44 @@ find_or(const std::map<std::string,std::string>& m, const std::string& k, const
return it != m.end() ? it->second : v;
}

std::string
expand_variables(const std::string& in, const std::string& val)
{
std::string ret;
std::istringstream is(in);

bool esc = false;

while (is.good()) {
char c = is.get();

if (c == '\\') {
c = is.get();
if (is.good())
ret.push_back(c);
continue;
} else if (c == '"') {
esc = !esc;
continue;
} else if (c == '{') {
c = is.get();
if (c == '}') {
ret.append(val);
continue;
} else {
ret.push_back('{');
}
}

if (!is.good())
break;

ret.push_back(c);
}

return ret;
}

} // namespace [anonymous]


Expand Down Expand Up @@ -441,11 +479,18 @@ struct ConfigManager::Options::OptionsImpl
void
append_config(config_map_t& config) {
for (const std::string &opt : enabled_options) {
auto o_it = spec.data.find(opt);
if (o_it == spec.data.end())
auto spec_it = spec.data.find(opt);
if (spec_it == spec.data.end())
continue;

config.insert(o_it->second.config.begin(), o_it->second.config.end());
if (spec_it->second.type == "bool") {
config.insert(spec_it->second.config.begin(), spec_it->second.config.end());
} else {
for (const auto &kv_p : spec_it->second.config) {
// replace "{}" variable placeholders in spec with argument, if any
config[kv_p.first] = ::expand_variables(kv_p.second, args[opt]);
}
}
}
}

Expand Down Expand Up @@ -762,6 +807,24 @@ struct ConfigManager::ConfigManagerImpl
m_error_msg = msg;
}

void
set_error(const std::string& msg, std::istream& is) {
m_error = true;
m_error_msg = msg;

size_t maxctx = 16;

if (is.good()) {
is.unget();
m_error_msg.append(" at ");

for (char c = is.get(); is.good() && --maxctx > 0; c = is.get())
m_error_msg.push_back(c);
if (maxctx == 0)
m_error_msg.append("...");
}
}

// sets error if err is set
void
check_error(const std::string& err) {
Expand Down Expand Up @@ -878,7 +941,7 @@ struct ConfigManager::ConfigManagerImpl
val = util::read_word(is, ",=()\n");

if (val.empty())
set_error("Expected value after \"" + key + "=\"");
set_error("Expected value after \"" + key + "=\"", is);
}
else
is.unget();
Expand Down Expand Up @@ -927,8 +990,7 @@ struct ConfigManager::ConfigManagerImpl
} while (is.good() && c == ',');

if (c != ')') {
set_error("Expected ')'");
is.unget();
set_error("Expected ')'", is);
args.clear();
}

Expand Down Expand Up @@ -1027,7 +1089,7 @@ struct ConfigManager::ConfigManagerImpl
char c = util::read_char(is);

if (c != '(') {
set_error("Expected '(' after \"load\"");
set_error("Expected '(' after \"load\"", is);
return;
}

Expand All @@ -1037,7 +1099,7 @@ struct ConfigManager::ConfigManagerImpl
if (!filename.empty())
load_file(filename);
else
set_error("Expected filename for \"load\"");
set_error("Expected filename for \"load\"", is);

if (m_error)
return;
Expand All @@ -1046,8 +1108,7 @@ struct ConfigManager::ConfigManagerImpl
} while (is.good() && c == ',');

if (c != ')') {
set_error("Missing ')' after \"load(\"");
is.unget();
set_error("Missing ')' after \"load(\"", is);
}
}

Expand Down Expand Up @@ -1113,6 +1174,11 @@ struct ConfigManager::ConfigManagerImpl
c = util::read_char(is);
} while (!m_error && is.good() && c == ',');

if (!m_error && is.good()) {
// We read something unexpected
set_error(std::string("Unexpected \'").append(1, c).append("\'"), is);
}

return ret;
}

Expand Down
Loading

0 comments on commit 05202b4

Please sign in to comment.