Skip to content

Commit afa0c62

Browse files
Gasoonjiafacebook-github-bot
authored andcommitted
etdumpfilter impl (#9752)
Summary: Pull Request resolved: #9752 Introduce ETDumpFilter for filtering logged delegation intermediate data. Details can be found in #9260 Differential Revision: D72025517
1 parent fa6f822 commit afa0c62

File tree

8 files changed

+362
-3
lines changed

8 files changed

+362
-3
lines changed

Diff for: devtools/etdump/etdump_filter.cpp

+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
#include <executorch/devtools/etdump/etdump_filter.h>
10+
11+
#include <executorch/runtime/core/error.h>
12+
#include <executorch/runtime/platform/assert.h>
13+
14+
using ::executorch::runtime::DebugHandle;
15+
using ::executorch::runtime::Error;
16+
17+
namespace executorch {
18+
namespace etdump {
19+
20+
ETDumpFilter::ETDumpFilter()
21+
: regex_count_(0), range_start_(0), range_end_(0) {}
22+
23+
Result<bool> ETDumpFilter::add_regex(const char* pattern) {
24+
if (regex_count_ >= MAX_REGEX_PATTERNS) {
25+
return Error::OutOfResources; // Error code for exceeding max patterns
26+
}
27+
size_t len = strlen(pattern);
28+
if (len >= MAX_PATTERN_LENGTH) {
29+
return Error::InvalidArgument; // Pattern too long
30+
}
31+
strcpy(regex_patterns_[regex_count_], pattern);
32+
regex_patterns_[regex_count_][len] = '\0';
33+
regex_count_++;
34+
return true;
35+
}
36+
37+
Result<bool> ETDumpFilter::set_debug_handle_range(size_t start, size_t end) {
38+
if (start >= end) {
39+
return Error::InvalidArgument; // Start is greater than end
40+
}
41+
if (start < 0 || end < 0) {
42+
return Error::InvalidArgument; // Start or end is negative
43+
}
44+
range_start_ = start;
45+
range_end_ = end;
46+
return true;
47+
}
48+
49+
Result<bool> ETDumpFilter::filter_name_(const char* name) {
50+
if (name == nullptr) {
51+
return Error::InvalidArgument; // Name is null
52+
}
53+
if (regex_count_ == 0) {
54+
return true;
55+
}
56+
for (size_t i = 0; i < regex_count_; ++i) {
57+
if (RE2::FullMatch(name, regex_patterns_[i])) {
58+
return true;
59+
}
60+
}
61+
return false;
62+
}
63+
Result<bool> ETDumpFilter::filter_delegate_debug_index_(
64+
DebugHandle debug_handle) {
65+
if (debug_handle == runtime::kUnsetDebugHandle) {
66+
return Error::InvalidArgument; // Delegate debug index is unset
67+
}
68+
69+
if (range_start_ == 0 && range_end_ == 0) {
70+
return true;
71+
}
72+
73+
if (debug_handle < range_start_ || debug_handle >= range_end_) {
74+
return false;
75+
}
76+
77+
return true;
78+
}
79+
80+
Result<bool> ETDumpFilter::filter(
81+
const char* name,
82+
DebugHandle delegate_debug_index) {
83+
if (name) {
84+
return filter_name_(name);
85+
} else {
86+
return filter_delegate_debug_index_(delegate_debug_index);
87+
}
88+
}
89+
90+
size_t ETDumpFilter::get_n_regex() const {
91+
return regex_count_;
92+
}
93+
94+
} // namespace etdump
95+
} // namespace executorch

Diff for: devtools/etdump/etdump_filter.h

+107
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
#pragma once
10+
11+
#include <re2/re2.h>
12+
13+
#include <executorch/runtime/core/event_tracer.h>
14+
#include <executorch/runtime/core/result.h>
15+
#include <executorch/runtime/platform/platform.h>
16+
17+
namespace executorch {
18+
namespace etdump {
19+
20+
using ::executorch::runtime::Result;
21+
22+
/**
23+
* ETDumpFilter is a class that filters intermediate output based on output's
24+
* name by full regex filtering, or delegate debug indices by range-based
25+
* filtering.
26+
*
27+
* Note that this filter supports up to MAX_REGEX_PATTERNS regex patterns with a
28+
* maximum length of MAX_PATTERN_LENGTH characters each.
29+
*/
30+
31+
class ETDumpFilter : public ::executorch::runtime::EventTracerFilterBase {
32+
public:
33+
static const size_t MAX_REGEX_PATTERNS =
34+
4; // Maximum number of regex patterns
35+
static const size_t MAX_PATTERN_LENGTH = 32; // Maximum length of a pattern
36+
ETDumpFilter();
37+
~ETDumpFilter() override = default;
38+
/**
39+
* Adds a regex pattern to the filter.
40+
*
41+
* @param[in] pattern A c string representing the regex pattern to be added.
42+
*
43+
* @return A Result<bool> indicating the success or failure of adding the
44+
* regex pattern.
45+
* - True if the pattern is successfully added.
46+
* - False if the pattern could not be added or if the maximum number
47+
* of patterns is exceeded.
48+
* - An error code if number of pattern has reached to cap, or any
49+
* error occurs during regex compilation.
50+
*/
51+
Result<bool> add_regex(const char* pattern);
52+
/**
53+
* Sets the range for the delegate debug index filtering as [start, end).
54+
* Note that this function will flush the existing range.
55+
*
56+
* @param[in] start The start of the range for filtering.
57+
* @param[in] end The end of the range for filtering.
58+
*
59+
* @return A Result<bool> indicating the success or failure of setting the
60+
* range.
61+
* - True if the range is successfully set.
62+
* - False if the start is greater than the end.
63+
* - An error code if an error occurs.
64+
*/
65+
Result<bool> set_debug_handle_range(size_t start, size_t end);
66+
67+
/**
68+
* Filters events based on the given name or delegate debug index.
69+
*
70+
* Note that everytime only one of either the name or delegate_debug_index
71+
* should be passed in.
72+
*
73+
* @param[in] name A pointer to a string representing the `name` of the
74+
* event. If `delegate_debug_index` is not set to kUnsetDebugHandle, `name`
75+
* should be set to nullptr.
76+
*
77+
* @param[in] delegate_debug_index A DebugHandle representing the debug index
78+
* of the delegate. If `name` is not nullptr, this should be set to
79+
* kUnsetDebugHandle.
80+
*
81+
* @return A Result<bool> indicating whether the event matches the filter
82+
* criteria.
83+
* - True if the event matches the filter, or filter is unset.
84+
* - False if the event does not match or is unknown.
85+
* - An error code if an error occurs during filtering.
86+
*/
87+
Result<bool> filter(
88+
const char* name,
89+
::executorch::runtime::DebugHandle delegate_debug_index) override;
90+
91+
/**
92+
* Returns the number of regex patterns in the filter.
93+
*/
94+
size_t get_n_regex() const;
95+
96+
private:
97+
char regex_patterns_[MAX_REGEX_PATTERNS][MAX_PATTERN_LENGTH];
98+
size_t regex_count_;
99+
size_t range_start_;
100+
size_t range_end_;
101+
Result<bool> filter_name_(const char* name);
102+
Result<bool> filter_delegate_debug_index_(
103+
::executorch::runtime::DebugHandle delegate_debug_index);
104+
};
105+
106+
} // namespace etdump
107+
} // namespace executorch

Diff for: devtools/etdump/etdump_flatcc.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <executorch/devtools/etdump/etdump_schema_flatcc_builder.h>
1616
#include <executorch/devtools/etdump/etdump_schema_flatcc_reader.h>
1717
#include <executorch/devtools/etdump/utils.h>
18+
#include <executorch/runtime/core/error.h>
1819
#include <executorch/runtime/core/exec_aten/exec_aten.h>
1920
#include <executorch/runtime/core/exec_aten/util/scalar_type_util.h>
2021
#include <executorch/runtime/platform/assert.h>
@@ -27,6 +28,7 @@ using ::executorch::runtime::ArrayRef;
2728
using ::executorch::runtime::ChainID;
2829
using ::executorch::runtime::DebugHandle;
2930
using ::executorch::runtime::DelegateDebugIdType;
31+
using ::executorch::runtime::Error;
3032
using ::executorch::runtime::EValue;
3133
using ::executorch::runtime::EventTracerEntry;
3234
using ::executorch::runtime::LoggedEValueType;

Diff for: devtools/etdump/etdump_flatcc.h

-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
#pragma once
1010

1111
#include <cstdint>
12-
#include <memory>
1312

1413
#include <executorch/devtools/etdump/data_sinks/buffer_data_sink.h>
1514
#include <executorch/devtools/etdump/data_sinks/data_sink_base.h>

Diff for: devtools/etdump/targets.bzl

+21
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,27 @@ def define_common_targets():
101101
for aten_mode in get_aten_mode_options():
102102
aten_suffix = "_aten" if aten_mode else ""
103103

104+
runtime.cxx_library(
105+
name = "etdump_filter" + aten_suffix,
106+
srcs = [
107+
"etdump_filter.cpp",
108+
],
109+
exported_headers = [
110+
"etdump_filter.h",
111+
],
112+
deps = [
113+
"//executorch/runtime/platform:platform",
114+
],
115+
exported_deps = [
116+
"fbsource//third-party/re2:re2",
117+
"//executorch/runtime/core:event_tracer" + aten_suffix,
118+
],
119+
visibility = [
120+
"//executorch/...",
121+
"@EXECUTORCH_CLIENTS",
122+
],
123+
)
124+
104125
runtime.cxx_library(
105126
name = "etdump_flatcc" + aten_suffix,
106127
srcs = [

Diff for: devtools/etdump/tests/etdump_filter_test.cpp

+121
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
#include <gtest/gtest.h>
10+
11+
#include <executorch/devtools/etdump/etdump_filter.h>
12+
#include <executorch/runtime/platform/runtime.h>
13+
14+
#include <cstring>
15+
16+
using ::executorch::etdump::ETDumpFilter;
17+
using ::executorch::runtime::Error;
18+
using ::executorch::runtime::kUnsetDebugHandle;
19+
using ::executorch::runtime::Result;
20+
21+
class ETDumpFilterTest : public ::testing::Test {
22+
protected:
23+
ETDumpFilter filter;
24+
25+
void SetUp() override {
26+
torch::executor::runtime_init();
27+
}
28+
29+
void TearDown() override {}
30+
};
31+
32+
TEST_F(ETDumpFilterTest, AddRegexPatternSuccess) {
33+
Result<bool> result = filter.add_regex("test.*");
34+
EXPECT_TRUE(result.ok());
35+
EXPECT_TRUE(result.get());
36+
}
37+
38+
TEST_F(ETDumpFilterTest, AddRegexPatternFailure) {
39+
// Add maximum number of patterns
40+
for (size_t i = 0; i < ETDumpFilter::MAX_REGEX_PATTERNS; ++i) {
41+
Result<bool> result = filter.add_regex("pattern");
42+
EXPECT_TRUE(result.ok());
43+
EXPECT_TRUE(result.get());
44+
}
45+
// Attempt to add one more pattern
46+
Result<bool> result = filter.add_regex("extra_pattern");
47+
EXPECT_FALSE(result.ok());
48+
}
49+
50+
TEST_F(ETDumpFilterTest, SetDebugHandleRangeSuccess) {
51+
Result<bool> result = filter.set_debug_handle_range(10, 20);
52+
EXPECT_TRUE(result.ok());
53+
EXPECT_TRUE(result.get());
54+
}
55+
56+
TEST_F(ETDumpFilterTest, SetDebugHandleRangeFailure) {
57+
Result<bool> result = filter.set_debug_handle_range(20, 10);
58+
EXPECT_EQ(result.error(), Error::InvalidArgument);
59+
}
60+
61+
TEST_F(ETDumpFilterTest, FilterByNameSuccess) {
62+
filter.add_regex("event.*");
63+
Result<bool> result = filter.filter("event_name", kUnsetDebugHandle);
64+
EXPECT_TRUE(result.ok());
65+
EXPECT_TRUE(result.get());
66+
}
67+
68+
TEST_F(ETDumpFilterTest, PartialMatchingFailed) {
69+
filter.add_regex("event.*");
70+
Result<bool> result = filter.filter("non_matching_event", kUnsetDebugHandle);
71+
EXPECT_TRUE(result.ok());
72+
EXPECT_FALSE(result.get());
73+
}
74+
75+
TEST_F(ETDumpFilterTest, FilterByDelegateDebugIndexSuccess) {
76+
filter.set_debug_handle_range(10, 20);
77+
Result<bool> result = filter.filter(nullptr, 15);
78+
EXPECT_TRUE(result.ok());
79+
EXPECT_TRUE(result.get());
80+
}
81+
82+
TEST_F(ETDumpFilterTest, FilterByDelegateDebugIndexFailure) {
83+
filter.set_debug_handle_range(10, 20);
84+
Result<bool> result = filter.filter(nullptr, 25);
85+
EXPECT_TRUE(result.ok());
86+
EXPECT_FALSE(result.get());
87+
}
88+
89+
TEST_F(ETDumpFilterTest, NaiveFilterNameInputCanSucceed) {
90+
Result<bool> result = filter.filter("any_input", kUnsetDebugHandle);
91+
EXPECT_TRUE(result.ok());
92+
EXPECT_TRUE(result.get());
93+
}
94+
95+
TEST_F(ETDumpFilterTest, NaiveFilterDebugHandleInputCanSucceed) {
96+
Result<bool> result = filter.filter(nullptr, 12345);
97+
EXPECT_TRUE(result.ok());
98+
EXPECT_TRUE(result.get());
99+
}
100+
101+
TEST_F(ETDumpFilterTest, NoMatchFirstThenMatch) {
102+
filter.add_regex("non_matching_pattern");
103+
Result<bool> result_1 = filter.filter("matching_event", kUnsetDebugHandle);
104+
EXPECT_TRUE(result_1.ok());
105+
EXPECT_FALSE(result_1.get());
106+
filter.add_regex("matching_.*");
107+
Result<bool> result_2 = filter.filter("matching_event", kUnsetDebugHandle);
108+
EXPECT_TRUE(result_2.ok());
109+
EXPECT_TRUE(result_2.get());
110+
}
111+
112+
TEST_F(ETDumpFilterTest, MatchRegexFirstThen) {
113+
filter.add_regex("matching.*");
114+
Result<bool> result_1 = filter.filter("matching_event", kUnsetDebugHandle);
115+
EXPECT_TRUE(result_1.ok());
116+
EXPECT_TRUE(result_1.get());
117+
filter.add_regex("non_matching_pattern");
118+
Result<bool> result_2 = filter.filter("matching_event", kUnsetDebugHandle);
119+
EXPECT_TRUE(result_2.ok());
120+
EXPECT_TRUE(result_2.get());
121+
}

Diff for: devtools/etdump/tests/targets.bzl

+11
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,14 @@ def define_common_targets():
2121
"//executorch/runtime/core/exec_aten/testing_util:tensor_util",
2222
],
2323
)
24+
25+
runtime.cxx_test(
26+
name = "etdump_filter_test",
27+
srcs = [
28+
"etdump_filter_test.cpp",
29+
],
30+
deps = [
31+
"//executorch/devtools/etdump:etdump_filter",
32+
"//executorch/runtime/platform:platform",
33+
],
34+
)

0 commit comments

Comments
 (0)