-
Notifications
You must be signed in to change notification settings - Fork 24.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: extract performance observers to native layer and push entr…
…ies to each observer refactor: use map for user timing API for better performance
- Loading branch information
Showing
15 changed files
with
696 additions
and
315 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
6 changes: 3 additions & 3 deletions
6
packages/react-native/ReactCommon/react/performance/timeline/CMakeLists.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
110 changes: 110 additions & 0 deletions
110
packages/react-native/ReactCommon/react/performance/timeline/ConsumableEntryMap.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
/* | ||
* Copyright (c) Meta Platforms, Inc. and affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
#pragma once | ||
|
||
#include <numeric> | ||
#include <optional> | ||
#include <string> | ||
#include <unordered_map> | ||
#include <vector> | ||
#include "PerformanceEntry.h" | ||
|
||
namespace facebook::react { | ||
|
||
class ConsumableEntryMap { | ||
public: | ||
ConsumableEntryMap() = default; | ||
|
||
void add(const PerformanceEntry& entry) { | ||
auto& list = entryMap_.at(entry.name); | ||
auto& toConsume = toConsumeMap_.at(entry.name); | ||
list.push_back(entry); | ||
totalEntryCount_ += 1; | ||
totalToConsume_ += 1; | ||
toConsume += 1; | ||
} | ||
|
||
void clear() { | ||
entryMap_.clear(); | ||
toConsumeMap_.clear(); | ||
totalEntryCount_ = 0; | ||
totalToConsume_ = 0; | ||
} | ||
|
||
void clear(const std::string& name) { | ||
if (auto node = entryMap_.find(name); node != entryMap_.end()) { | ||
totalEntryCount_ -= node->second.size(); | ||
totalToConsume_ -= node->second.size(); | ||
toConsumeMap_[name] = 0; | ||
node->second.clear(); | ||
} | ||
} | ||
|
||
std::optional<PerformanceEntry> find(const std::string& name) const { | ||
if (auto node = entryMap_.find(name); node != entryMap_.end()) { | ||
if (!node->second.empty()) { | ||
return std::make_optional<PerformanceEntry>(node->second.back()); | ||
} | ||
} | ||
|
||
return std::nullopt; | ||
} | ||
|
||
void getEntries(std::vector<PerformanceEntry>& target) const { | ||
if (allEntriesCache_.has_value()) { | ||
auto& allEntries = allEntriesCache_.value(); | ||
target.insert(target.end(), allEntries.begin(), allEntries.end()); | ||
return; | ||
} | ||
|
||
std::vector<PerformanceEntry> allEntries; | ||
// pre-allocate result vector | ||
allEntries.reserve(totalEntryCount_); | ||
|
||
for (const auto& [_, entries] : entryMap_) { | ||
allEntries.insert(allEntries.end(), entries.begin(), entries.end()); | ||
} | ||
|
||
std::stable_sort( | ||
allEntries.begin(), allEntries.end(), PerformanceEntrySorter{}); | ||
allEntriesCache_ = allEntries; | ||
target.insert(target.end(), allEntries.begin(), allEntries.end()); | ||
} | ||
|
||
/** | ||
* Retrieves buffer entries, whether consumed or not, with predicate | ||
*/ | ||
void consume(std::vector<PerformanceEntry>& target) { | ||
for (const auto& [name, entries] : entryMap_) { | ||
target.insert( | ||
target.end(), entries.end() - toConsumeMap_[name], entries.end()); | ||
toConsumeMap_[name] = 0; | ||
} | ||
} | ||
|
||
size_t getNumToConsume() const { | ||
return totalToConsume_; | ||
} | ||
|
||
void getEntries( | ||
const std::string& name, | ||
std::vector<PerformanceEntry>& target) const { | ||
if (auto node = entryMap_.find(name); node != entryMap_.end()) { | ||
target.insert(target.end(), node->second.begin(), node->second.end()); | ||
} | ||
} | ||
|
||
private: | ||
std::unordered_map<std::string, std::vector<PerformanceEntry>> entryMap_{}; | ||
std::unordered_map<std::string, size_t> toConsumeMap_{}; | ||
mutable std::optional<std::vector<PerformanceEntry>> allEntriesCache_; | ||
size_t totalEntryCount_ = 0; | ||
size_t totalToConsume_ = 0; | ||
}; | ||
|
||
} // namespace facebook::react |
70 changes: 70 additions & 0 deletions
70
packages/react-native/ReactCommon/react/performance/timeline/PerformanceEntry.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
/* | ||
* Copyright (c) Meta Platforms, Inc. and affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
#pragma once | ||
|
||
#include <string> | ||
#include <string_view> | ||
#include <unordered_set> | ||
|
||
namespace facebook::react { | ||
|
||
using DOMHighResTimeStamp = double; | ||
|
||
using PerformanceEntryInteractionId = uint32_t; | ||
|
||
enum class PerformanceEntryType { | ||
// We need to preserve these values for backwards compatibility. | ||
MARK = 1, | ||
MEASURE = 2, | ||
EVENT = 3, | ||
LONGTASK = 4, | ||
_NEXT = 5, | ||
}; | ||
|
||
struct PerformanceEntry { | ||
std::string name; | ||
PerformanceEntryType entryType; | ||
DOMHighResTimeStamp startTime; | ||
DOMHighResTimeStamp duration = 0; | ||
|
||
// For "event" entries only: | ||
std::optional<DOMHighResTimeStamp> processingStart; | ||
std::optional<DOMHighResTimeStamp> processingEnd; | ||
std::optional<PerformanceEntryInteractionId> interactionId; | ||
}; | ||
|
||
constexpr size_t NUM_PERFORMANCE_ENTRY_TYPES = | ||
(size_t)PerformanceEntryType::_NEXT - 1; // Valid types start from 1. | ||
|
||
/** | ||
* Status of the add/push operation for the `BoundedConsumableBuffer` | ||
* container | ||
*/ | ||
enum class PerformanceEntryPushStatus { | ||
// There was free space in the buffer, element was successfully pushed: | ||
OK = 0, | ||
|
||
// Element was pushed, but had to overwrite some already consumed elements: | ||
OVERWRITE = 1, | ||
|
||
// Element wasn't pushed, as buffer size limit has been reached and it's | ||
// not possible to overwrite already consumed elements anymore: | ||
DROP = 2, | ||
}; | ||
|
||
struct PerformanceEntrySorter { | ||
bool operator()(const PerformanceEntry& lhs, const PerformanceEntry& rhs) { | ||
if (lhs.startTime != rhs.startTime) { | ||
return lhs.startTime < rhs.startTime; | ||
} else { | ||
return lhs.duration < rhs.duration; | ||
} | ||
} | ||
}; | ||
|
||
} // namespace facebook::react |
69 changes: 69 additions & 0 deletions
69
packages/react-native/ReactCommon/react/performance/timeline/PerformanceEntryBuffer.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
/* | ||
* Copyright (c) Meta Platforms, Inc. and affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
#include "PerformanceEntryBuffer.h" | ||
|
||
namespace facebook::react { | ||
|
||
PerformanceEntryPushStatus PerformanceEntryCircularBuffer::add(const facebook::react::PerformanceEntry&& entry) { | ||
return entries.add(std::move(entry)); | ||
} | ||
|
||
void PerformanceEntryCircularBuffer::consume(std::vector<PerformanceEntry>& target) { | ||
entries.consume(target); | ||
} | ||
|
||
size_t PerformanceEntryCircularBuffer::pendingMessagesCount() const { | ||
return entries.getNumToConsume(); | ||
} | ||
|
||
void PerformanceEntryCircularBuffer::getEntries(std::optional<std::string_view> name, std::vector<PerformanceEntry>& target) const { | ||
entries.getEntries( | ||
target, [&](const PerformanceEntry& e) { return e.name == name; }); | ||
} | ||
|
||
void PerformanceEntryCircularBuffer::clear() { | ||
entries.clear(); | ||
} | ||
|
||
|
||
void PerformanceEntryCircularBuffer::clear(std::string_view name) { | ||
entries.clear([&](const PerformanceEntry& e) { return e.name == name; }); | ||
} | ||
|
||
PerformanceEntryPushStatus PerformanceEntryKeyedBuffer::add(const facebook::react::PerformanceEntry&& entry) { | ||
entries.add(entry); | ||
return PerformanceEntryPushStatus::OK; | ||
} | ||
|
||
void PerformanceEntryKeyedBuffer::consume(std::vector<PerformanceEntry>& target) { | ||
entries.consume(target); | ||
} | ||
|
||
size_t PerformanceEntryKeyedBuffer::pendingMessagesCount() const { | ||
return entries.getNumToConsume(); | ||
} | ||
|
||
void PerformanceEntryKeyedBuffer::getEntries(std::optional<std::string_view> name, std::vector<PerformanceEntry>& target) const { | ||
if (name.has_value()) { | ||
std::string nameStr{name.value()}; | ||
entries.getEntries(nameStr, target); | ||
} else { | ||
entries.getEntries(target); | ||
} | ||
} | ||
|
||
void PerformanceEntryKeyedBuffer::clear() { | ||
entries.clear(); | ||
} | ||
|
||
void PerformanceEntryKeyedBuffer::clear(std::string_view name) { | ||
std::string nameStr{name}; | ||
entries.clear(nameStr); | ||
} | ||
|
||
} // namespace facebook::react |
Oops, something went wrong.