Skip to content

Commit 92235a1

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

File tree

8 files changed

+376
-4
lines changed

8 files changed

+376
-4
lines changed

devtools/etdump/etdump_filter.cpp

+100
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
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+
13+
using ::executorch::runtime::DelegateDebugIntId;
14+
using ::executorch::runtime::Error;
15+
using ::executorch::runtime::kUnsetDelegateDebugIntId;
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+
DelegateDebugIntId debug_handle) {
65+
if (debug_handle == kUnsetDelegateDebugIntId) {
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+
DelegateDebugIntId delegate_debug_index) {
83+
if ((name == nullptr) == (delegate_debug_index == kUnsetDelegateDebugIntId)) {
84+
return Error::InvalidArgument; // Name and delegate debug index should be
85+
// both set or unset
86+
}
87+
88+
if (name) {
89+
return filter_name_(name);
90+
} else {
91+
return filter_delegate_debug_index_(delegate_debug_index);
92+
}
93+
}
94+
95+
size_t ETDumpFilter::get_n_regex() const {
96+
return regex_count_;
97+
}
98+
99+
} // namespace etdump
100+
} // namespace executorch

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::DelegateDebugIntId 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::DelegateDebugIntId delegate_debug_index);
104+
};
105+
106+
} // namespace etdump
107+
} // namespace executorch

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>
@@ -28,6 +29,7 @@ using ::executorch::runtime::ChainID;
2829
using ::executorch::runtime::DebugHandle;
2930
using ::executorch::runtime::DelegateDebugIdType;
3031
using ::executorch::runtime::DelegateDebugIntId;
32+
using ::executorch::runtime::Error;
3133
using ::executorch::runtime::EValue;
3234
using ::executorch::runtime::EventTracerEntry;
3335
using ::executorch::runtime::kUnsetDelegateDebugIntId;

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>

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 = [
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
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::kUnsetDelegateDebugIntId;
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", kUnsetDelegateDebugIntId);
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 =
71+
filter.filter("non_matching_event", kUnsetDelegateDebugIntId);
72+
EXPECT_TRUE(result.ok());
73+
EXPECT_FALSE(result.get());
74+
}
75+
76+
TEST_F(ETDumpFilterTest, FilterByDelegateDebugIndexSuccess) {
77+
filter.set_debug_handle_range(10, 20);
78+
Result<bool> result = filter.filter(nullptr, 15);
79+
EXPECT_TRUE(result.ok());
80+
EXPECT_TRUE(result.get());
81+
}
82+
83+
TEST_F(ETDumpFilterTest, FilterByDelegateDebugIndexFailure) {
84+
filter.set_debug_handle_range(10, 20);
85+
Result<bool> result = filter.filter(nullptr, 25);
86+
EXPECT_TRUE(result.ok());
87+
EXPECT_FALSE(result.get());
88+
}
89+
90+
TEST_F(ETDumpFilterTest, NaiveFilterNameInputCanSucceed) {
91+
Result<bool> result = filter.filter("any_input", kUnsetDelegateDebugIntId);
92+
EXPECT_TRUE(result.ok());
93+
EXPECT_TRUE(result.get());
94+
}
95+
96+
TEST_F(ETDumpFilterTest, NaiveFilterDebugHandleInputCanSucceed) {
97+
Result<bool> result = filter.filter(nullptr, 12345);
98+
EXPECT_TRUE(result.ok());
99+
EXPECT_TRUE(result.get());
100+
}
101+
102+
TEST_F(ETDumpFilterTest, IllegalInput) {
103+
filter.add_regex("pattern");
104+
Result<bool> result = filter.filter("matching_event", 1);
105+
EXPECT_EQ(result.error(), Error::InvalidArgument);
106+
}
107+
108+
TEST_F(ETDumpFilterTest, NoMatchFirstThenMatch) {
109+
filter.add_regex("non_matching_pattern");
110+
Result<bool> result_1 =
111+
filter.filter("matching_event", kUnsetDelegateDebugIntId);
112+
EXPECT_TRUE(result_1.ok());
113+
EXPECT_FALSE(result_1.get());
114+
filter.add_regex("matching_.*");
115+
Result<bool> result_2 =
116+
filter.filter("matching_event", kUnsetDelegateDebugIntId);
117+
EXPECT_TRUE(result_2.ok());
118+
EXPECT_TRUE(result_2.get());
119+
}
120+
121+
TEST_F(ETDumpFilterTest, MatchRegexFirstThen) {
122+
filter.add_regex("matching.*");
123+
Result<bool> result_1 =
124+
filter.filter("matching_event", kUnsetDelegateDebugIntId);
125+
EXPECT_TRUE(result_1.ok());
126+
EXPECT_TRUE(result_1.get());
127+
filter.add_regex("non_matching_pattern");
128+
Result<bool> result_2 =
129+
filter.filter("matching_event", kUnsetDelegateDebugIntId);
130+
EXPECT_TRUE(result_2.ok());
131+
EXPECT_TRUE(result_2.get());
132+
}

0 commit comments

Comments
 (0)