Use a more robust method of finding out which events to report

Summary:
[Changelog][Internal]

Use the [list of supported events](https://www.w3.org/TR/event-timing/#sec-events-exposed) explicitly to both filter and transform reported event types, which makes this both more robust and less ambiguous.

The mapping is using a compile-time hash/lookup, similarly to how we do it with the ViewProps in the RN core.

Reviewed By: rubennorte

Differential Revision: D42342655

fbshipit-source-id: 3d0b2465fd5611db110c4792913e0a92e76cd067
This commit is contained in:
Ruslan Shestopalyuk 2023-01-04 08:57:40 -08:00 коммит произвёл Facebook GitHub Bot
Родитель 3aea05651d
Коммит 21dbc67c03
2 изменённых файлов: 75 добавлений и 18 удалений

Просмотреть файл

@ -10,7 +10,7 @@
#include <react/renderer/core/EventLogger.h> #include <react/renderer/core/EventLogger.h>
#include "NativePerformanceObserver.h" #include "NativePerformanceObserver.h"
#include <algorithm> #include <unordered_map>
// All the unflushed entries beyond this amount will get discarded, with // All the unflushed entries beyond this amount will get discarded, with
// the amount of discarded ones sent back to the observers' callbacks as // the amount of discarded ones sent back to the observers' callbacks as
@ -167,14 +167,14 @@ double PerformanceEntryReporter::getMarkTime(
} }
void PerformanceEntryReporter::event( void PerformanceEntryReporter::event(
const std::string &name, std::string name,
double startTime, double startTime,
double duration, double duration,
double processingStart, double processingStart,
double processingEnd, double processingEnd,
uint32_t interactionId) { uint32_t interactionId) {
logEntry( logEntry(
{name, {std::move(name),
static_cast<int>(PerformanceEntryType::EVENT), static_cast<int>(PerformanceEntryType::EVENT),
startTime, startTime,
duration, duration,
@ -203,31 +203,89 @@ void PerformanceEntryReporter::scheduleFlushBuffer() {
} }
} }
static bool isDiscreteEvent(const char *name) { struct StrKey {
return !std::strstr(name, "Move") && !std::strstr(name, "Layout"); uint32_t key;
} constexpr StrKey(const char *s)
: key(folly::hash::fnv32_buf(s, std::strlen(s))) {}
constexpr bool operator==(const StrKey &rhs) const {
return key == rhs.key;
}
};
struct StrKeyHash {
constexpr size_t operator()(const StrKey &strKey) const {
return static_cast<size_t>(strKey.key);
}
};
// Supported events for reporting, see
// https://www.w3.org/TR/event-timing/#sec-events-exposed
// Not all of these are currently supported by RN, but we map them anyway for
// future-proofing.
static const std::unordered_map<StrKey, const char *, StrKeyHash>
SUPPORTED_EVENTS = {
{"topAuxClick", "auxclick"},
{"topClick", "click"},
{"topContextMenu", "contextmenu"},
{"topDblClick", "dblclick"},
{"topMouseDown", "mousedown"},
{"topMouseEnter", "mouseenter"},
{"topMouseLeave", "mouseleave"},
{"topMouseOut", "mouseout"},
{"topMouseOver", "mouseover"},
{"topMouseUp", "mouseup"},
{"topPointerOver", "pointerover"},
{"topPointerEnter", "pointerenter"},
{"topPointerDown", "pointerdown"},
{"topPointerUp", "pointerup"},
{"topPointerCancel", "pointercancel"},
{"topPointerOut", "pointerout"},
{"topPointerLeave", "pointerleave"},
{"topGotPointerCapture", "gotpointercapture"},
{"topLostPointerCapture", "lostpointercapture"},
{"topTouchStart", "touchstart"},
{"topTouchEnd", "touchend"},
{"topTouchCancel", "touchcancel"},
{"topKeyDown", "keydown"},
{"topKeyPress", "keypress"},
{"topKeyUp", "keyup"},
{"topBeforeInput", "beforeinput"},
{"topInput", "input"},
{"topCompositionStart", "compositionstart"},
{"topCompositionUpdate", "compositionupdate"},
{"topCompositionEnd", "compositionend"},
{"topDragStart", "dragstart"},
{"topDragEnd", "dragend"},
{"topDragEnter", "dragenter"},
{"topDragLeave", "dragleave"},
{"topDragOver", "dragover"},
{"topDrop", "drop"},
};
EventTag PerformanceEntryReporter::onEventStart(const char *name) { EventTag PerformanceEntryReporter::onEventStart(const char *name) {
if (!isReportingEvents() || !isDiscreteEvent(name)) { if (!isReportingEvents()) {
return 0; return 0;
} }
auto it = SUPPORTED_EVENTS.find(name);
if (it == SUPPORTED_EVENTS.end()) {
return 0;
}
const char *reportedName = it->second;
sCurrentEventTag_++; sCurrentEventTag_++;
if (sCurrentEventTag_ == 0) { if (sCurrentEventTag_ == 0) {
// The tag wrapped around (which is highly unlikely, but still) // The tag wrapped around (which is highly unlikely, but still)
sCurrentEventTag_ = 1; sCurrentEventTag_ = 1;
} }
if (std::strstr(name, "top") == name) {
// Skip the "top" prefix if present
name += 3;
}
auto timeStamp = JSExecutor::performanceNow(); auto timeStamp = JSExecutor::performanceNow();
{ {
std::lock_guard<std::mutex> lock(eventsInFlightMutex_); std::lock_guard<std::mutex> lock(eventsInFlightMutex_);
eventsInFlight_.emplace( eventsInFlight_.emplace(std::make_pair(
std::make_pair(sCurrentEventTag_, EventEntry{name, timeStamp, 0.0})); sCurrentEventTag_, EventEntry{reportedName, timeStamp, 0.0}));
} }
return sCurrentEventTag_; return sCurrentEventTag_;
} }
@ -259,13 +317,12 @@ void PerformanceEntryReporter::onEventEnd(EventTag tag) {
} }
auto &entry = it->second; auto &entry = it->second;
auto &name = entry.name; auto &name = entry.name;
std::transform(name.begin(), name.end(), name.begin(), ::tolower);
// TODO: Define the way to assign interaction IDs to the event chains // TODO: Define the way to assign interaction IDs to the event chains
// (T141358175) // (T141358175)
const uint32_t interactionId = 0; const uint32_t interactionId = 0;
event( event(
std::move(name), name,
entry.startTime, entry.startTime,
timeStamp - entry.startTime, timeStamp - entry.startTime,
entry.dispatchTime, entry.dispatchTime,

Просмотреть файл

@ -91,7 +91,7 @@ class PerformanceEntryReporter : public EventLogger {
void clearMeasures(const std::optional<std::string> &measureName); void clearMeasures(const std::optional<std::string> &measureName);
void event( void event(
const std::string &name, std::string name,
double startTime, double startTime,
double duration, double duration,
double processingStart, double processingStart,
@ -125,7 +125,7 @@ class PerformanceEntryReporter : public EventLogger {
uint32_t droppedEntryCount_{0}; uint32_t droppedEntryCount_{0};
struct EventEntry { struct EventEntry {
std::string name; const char *name;
double startTime{0.0}; double startTime{0.0};
double dispatchTime{0.0}; double dispatchTime{0.0};
}; };