Skip to content

Commit 2f98945

Browse files
DevmateUtgenCppGeneralFBOrg Botfacebook-github-bot
authored andcommitted
xplat/js/react-native-github/packages/react-native/ReactCommon/react/performance/timeline/PerformanceEntryCircularBuffer.cpp
Reviewed By: javache Differential Revision: D107364330
1 parent 64c9663 commit 2f98945

1 file changed

Lines changed: 170 additions & 0 deletions

File tree

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
#include <gtest/gtest.h>
9+
10+
#include <string>
11+
#include <variant>
12+
#include <vector>
13+
14+
#include "../PerformanceEntry.h"
15+
#include "../PerformanceEntryCircularBuffer.h"
16+
17+
namespace facebook::react {
18+
19+
namespace {
20+
21+
std::string getName(const PerformanceEntry& entry) {
22+
return std::visit([](const auto& data) { return data.name; }, entry);
23+
}
24+
25+
std::vector<std::string> getNames(
26+
const std::vector<PerformanceEntry>& entries) {
27+
std::vector<std::string> names;
28+
names.reserve(entries.size());
29+
for (const auto& entry : entries) {
30+
names.push_back(getName(entry));
31+
}
32+
return names;
33+
}
34+
35+
PerformanceEntry makeMark(const std::string& name) {
36+
return PerformanceMark{{.name = name, .startTime = HighResTimeStamp::now()}};
37+
}
38+
39+
} // namespace
40+
41+
// Overflowing the buffer must overwrite the oldest entries and increment
42+
// droppedEntriesCount by exactly the number of evictions (not by the number of
43+
// adds beyond capacity at any other rate).
44+
TEST(PerformanceEntryCircularBufferTest, AddTracksDroppedEntriesOnOverflow) {
45+
PerformanceEntryCircularBuffer buffer{3};
46+
47+
buffer.add(makeMark("a"));
48+
buffer.add(makeMark("b"));
49+
buffer.add(makeMark("c"));
50+
51+
// Filling up to capacity must not drop anything.
52+
EXPECT_EQ(0u, buffer.droppedEntriesCount);
53+
54+
buffer.add(makeMark("d"));
55+
buffer.add(makeMark("e"));
56+
57+
EXPECT_EQ(2u, buffer.droppedEntriesCount);
58+
59+
std::vector<PerformanceEntry> entries;
60+
buffer.getEntries(entries);
61+
EXPECT_EQ((std::vector<std::string>{"c", "d", "e"}), getNames(entries));
62+
}
63+
64+
// getEntries(target) must append (not replace) the buffer contents to the
65+
// caller-provided target vector, preserving any pre-existing elements.
66+
TEST(PerformanceEntryCircularBufferTest, GetEntriesAppendsToTarget) {
67+
PerformanceEntryCircularBuffer buffer{5};
68+
buffer.add(makeMark("x"));
69+
buffer.add(makeMark("y"));
70+
71+
std::vector<PerformanceEntry> target;
72+
target.push_back(makeMark("preexisting"));
73+
74+
buffer.getEntries(target);
75+
76+
EXPECT_EQ(
77+
(std::vector<std::string>{"preexisting", "x", "y"}), getNames(target));
78+
}
79+
80+
// getEntries(target, name) must only return entries matching the given name,
81+
// even when entries of other variant types share the buffer.
82+
TEST(PerformanceEntryCircularBufferTest, GetEntriesByNameFiltersAcrossTypes) {
83+
PerformanceEntryCircularBuffer buffer{10};
84+
buffer.add(
85+
PerformanceMark{{.name = "foo", .startTime = HighResTimeStamp::now()}});
86+
buffer.add(
87+
PerformanceMeasure{
88+
{.name = "bar", .startTime = HighResTimeStamp::now()}});
89+
buffer.add(
90+
PerformanceMark{{.name = "foo", .startTime = HighResTimeStamp::now()}});
91+
buffer.add(
92+
PerformanceLongTaskTiming{
93+
{.name = "foo", .startTime = HighResTimeStamp::now()}});
94+
buffer.add(
95+
PerformanceMeasure{
96+
{.name = "foo", .startTime = HighResTimeStamp::now()}});
97+
98+
std::vector<PerformanceEntry> matches;
99+
buffer.getEntries(matches, "foo");
100+
101+
EXPECT_EQ(4u, matches.size());
102+
for (const auto& entry : matches) {
103+
EXPECT_EQ("foo", getName(entry));
104+
}
105+
106+
std::vector<PerformanceEntry> noMatches;
107+
buffer.getEntries(noMatches, "missing");
108+
EXPECT_TRUE(noMatches.empty());
109+
}
110+
111+
// clear() must empty the buffer so a subsequent getEntries returns nothing,
112+
// while leaving droppedEntriesCount untouched (it tracks lifetime overflow,
113+
// not current contents).
114+
TEST(
115+
PerformanceEntryCircularBufferTest,
116+
ClearEmptiesBufferButKeepsDroppedCount) {
117+
PerformanceEntryCircularBuffer buffer{2};
118+
buffer.add(makeMark("a"));
119+
buffer.add(makeMark("b"));
120+
buffer.add(makeMark("c")); // evicts "a"
121+
ASSERT_EQ(1u, buffer.droppedEntriesCount);
122+
123+
buffer.clear();
124+
125+
std::vector<PerformanceEntry> entries;
126+
buffer.getEntries(entries);
127+
EXPECT_TRUE(entries.empty());
128+
EXPECT_EQ(1u, buffer.droppedEntriesCount);
129+
130+
// The buffer remains usable after clear.
131+
buffer.add(makeMark("d"));
132+
buffer.getEntries(entries);
133+
EXPECT_EQ((std::vector<std::string>{"d"}), getNames(entries));
134+
}
135+
136+
// clear(name) must remove only entries whose name matches, regardless of
137+
// variant type, and leave other entries (and their order) intact.
138+
TEST(PerformanceEntryCircularBufferTest, ClearByNameRemovesOnlyMatching) {
139+
PerformanceEntryCircularBuffer buffer{10};
140+
buffer.add(
141+
PerformanceMark{{.name = "keep", .startTime = HighResTimeStamp::now()}});
142+
buffer.add(
143+
PerformanceMeasure{
144+
{.name = "drop", .startTime = HighResTimeStamp::now()}});
145+
buffer.add(
146+
PerformanceMark{{.name = "drop", .startTime = HighResTimeStamp::now()}});
147+
buffer.add(
148+
PerformanceLongTaskTiming{
149+
{.name = "keep", .startTime = HighResTimeStamp::now()}});
150+
buffer.add(
151+
PerformanceMeasure{
152+
{.name = "drop", .startTime = HighResTimeStamp::now()}});
153+
154+
buffer.clear("drop");
155+
156+
std::vector<PerformanceEntry> remaining;
157+
buffer.getEntries(remaining);
158+
EXPECT_EQ(2u, remaining.size());
159+
for (const auto& entry : remaining) {
160+
EXPECT_EQ("keep", getName(entry));
161+
}
162+
163+
// Clearing a name that no longer exists is a no-op.
164+
buffer.clear("drop");
165+
remaining.clear();
166+
buffer.getEntries(remaining);
167+
EXPECT_EQ(2u, remaining.size());
168+
}
169+
170+
} // namespace facebook::react

0 commit comments

Comments
 (0)