Files
react-native/ReactCommon/reactperflogger/reactperflogger/NativeModulePerfLogger.h
T
Ramanpreet Nara 4830085f40 Guard all NativeModulePerfLogger calls with a null check
Summary:
## Motivation
We got this crash T67304907, which shows a `EXC_BAD_ACCESS / KERN_INVALID_ADDRESS` when calling this line:
```
  NativeModulePerfLogger::getInstance().asyncMethodCallBatchPreprocessStart();
```
There are no arguments in that call, so I figured the only error could be when we try to invoke `getInstance()` or `asyncMethodCallBatchPreprocessStart()`.

This diff:
1. Removes the `NativeModulePerfLogger::getInstance()` bit. Now NativeModulePerfLogger is used via regular static C functions. So, there's no way that simply invoking one of the logging functions crashes the application: there's no vtable lookup.
2. Inside each logging function, when perf-logging is disabled, the global perflogger should be `nullptr`. This diff makes it so that in that case, we won't execute any code in the control group of the perf-logging experiment.

## Changes
**How do we enable NativeModule perf-logging?**
- Previously:
   - `NativeModulePerfLogger::setInstance(std::make_shared<FBReactNativeModulePerfLogger>(...))`
   - `TurboModulePerfLogger::setInstance(std::make_shared<FBReactNativeModulePerfLogger>(...))`.
- Now:
   - `BridgeNativeModulePerfLogger::enableLogging(std::make_unique<FBReactNativeModulePerfLogger>(...))`
   - `TurboModulePerfLogger::enableLogging(std::make_unique<FBReactNativeModulePerfLogger>(...))`

**How do we do NativeModule perf-logging now?**
- Previously:
   -  `NativeModulePerfLogger::getInstance().command(...args)`
   -  `TurboModulePerfLogger::getInstance().command(...args)`.
- Now:
   - `BridgeNativeModulePerfLogger::command(...args)`
   - `TurboModulePerfLogger::command(...args)`.

The benefit of this approach is that each method in `BridgeNativeModulePerfLogger` is guarded with an if check. Example:

```
void moduleCreateConstructStart(const char *moduleName, int32_t id) {
  NativeModulePerfLogger *logger = g_perfLogger.get();
  if (logger != nullptr) {
    logger->moduleCreateConstructStart(moduleName, id);
  }
}
```

Therefore, we don't actually execute any code when perf-logging is disabled.

Changelog:
[Internal]

Reviewed By: fkgozali

Differential Revision: D21669888

fbshipit-source-id: 80c73754c430ce787404b563878bad146295e01f
2020-05-20 20:19:30 -07:00

162 lines
5.7 KiB
C++

/*
* Copyright (c) Facebook, Inc. and its 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 <cstdint>
namespace facebook {
namespace react {
/**
* A platform-agnostic interface to do performance logging on NativeModules and
* TuboModules.
*/
class NativeModulePerfLogger {
public:
virtual ~NativeModulePerfLogger() {}
/**
* NativeModule Initialization.
*
* The initialization of two NativeModules can interleave. Therefore,
* performance markers should use the moduleName as a unique key.
*/
/**
* On iOS:
* - NativeModule initialization is split into two phases, which sometimes
* have a pause in the middle.
* - TurboModule initialization happens all at once.
*
* On Android:
* - NativeModule and TurboModule initialization happens all at once.
*
* These markers are meant for iOS NativeModules:
* - moduleDataCreateStart: very beginning of first phase.
* - moduleDataCreateEnd: after RCTModuleData has been created.
*/
virtual void moduleDataCreateStart(const char *moduleName, int32_t id) = 0;
virtual void moduleDataCreateEnd(const char *moduleName, int32_t id) = 0;
/**
* How long does it take to create the platform NativeModule object?
* - moduleCreateStart: start creating platform NativeModule
* - moduleCreateEnd: stop creating platform NativeModule
*/
virtual void moduleCreateStart(const char *moduleName, int32_t id) = 0;
virtual void moduleCreateCacheHit(const char *moduleName, int32_t id) = 0;
virtual void moduleCreateConstructStart(
const char *moduleName,
int32_t id) = 0;
virtual void moduleCreateConstructEnd(const char *moduleName, int32_t id) = 0;
virtual void moduleCreateSetUpStart(const char *moduleName, int32_t id) = 0;
virtual void moduleCreateSetUpEnd(const char *moduleName, int32_t id) = 0;
virtual void moduleCreateEnd(const char *moduleName, int32_t id) = 0;
virtual void moduleCreateFail(const char *moduleName, int32_t id) = 0;
/**
* How long, after starting JS require, does it take to start creating the
* platform NativeModule?
* - moduleJSRequireBeginningStart: start of JS require
* - moduleJSRequireBeginningEnd: start creating platform NativeModule
*/
virtual void moduleJSRequireBeginningStart(const char *moduleName) = 0;
virtual void moduleJSRequireBeginningCacheHit(const char *moduleName) = 0;
virtual void moduleJSRequireBeginningEnd(const char *moduleName) = 0;
virtual void moduleJSRequireBeginningFail(const char *moduleName) = 0;
/**
* How long does it take to return from the JS require after the platform
* NativeModule is created?
* - moduleJSRequireEndingStart: end creating platform NativeModule
* - moduleJSRequireEndingEnd: end of JS require
*/
virtual void moduleJSRequireEndingStart(const char *moduleName) = 0;
virtual void moduleJSRequireEndingEnd(const char *moduleName) = 0;
virtual void moduleJSRequireEndingFail(const char *moduleName) = 0;
// Sync method calls
virtual void syncMethodCallStart(
const char *moduleName,
const char *methodName) = 0;
virtual void syncMethodCallArgConversionStart(
const char *moduleName,
const char *methodName) = 0;
virtual void syncMethodCallArgConversionEnd(
const char *moduleName,
const char *methodName) = 0;
virtual void syncMethodCallExecutionStart(
const char *moduleName,
const char *methodName) = 0;
virtual void syncMethodCallExecutionEnd(
const char *moduleName,
const char *methodName) = 0;
virtual void syncMethodCallReturnConversionStart(
const char *moduleName,
const char *methodName) = 0;
virtual void syncMethodCallReturnConversionEnd(
const char *moduleName,
const char *methodName) = 0;
virtual void syncMethodCallEnd(
const char *moduleName,
const char *methodName) = 0;
virtual void syncMethodCallFail(
const char *moduleName,
const char *methodName) = 0;
// Async method calls
virtual void asyncMethodCallStart(
const char *moduleName,
const char *methodName) = 0;
virtual void asyncMethodCallArgConversionStart(
const char *moduleName,
const char *methodName) = 0;
virtual void asyncMethodCallArgConversionEnd(
const char *moduleName,
const char *methodName) = 0;
virtual void asyncMethodCallDispatch(
const char *moduleName,
const char *methodName) = 0;
virtual void asyncMethodCallEnd(
const char *moduleName,
const char *methodName) = 0;
/**
* In the NativeModule system, we batch async NativeModule method calls.
* When we execute a batch of NativeModule method calls, we convert the batch
* from a jsi::Value to folly::dynamic to std::vector<MethodCall>. This marker
* documents that work.
*/
virtual void asyncMethodCallBatchPreprocessStart() = 0;
virtual void asyncMethodCallBatchPreprocessEnd(int batchSize) = 0;
// Async method call execution
virtual void asyncMethodCallExecutionStart(
const char *moduleName,
const char *methodName,
int32_t id) = 0;
virtual void asyncMethodCallExecutionArgConversionStart(
const char *moduleName,
const char *methodName,
int32_t id) = 0;
virtual void asyncMethodCallExecutionArgConversionEnd(
const char *moduleName,
const char *methodName,
int32_t id) = 0;
virtual void asyncMethodCallExecutionEnd(
const char *moduleName,
const char *methodName,
int32_t id) = 0;
virtual void asyncMethodCallExecutionFail(
const char *moduleName,
const char *methodName,
int32_t id) = 0;
};
} // namespace react
} // namespace facebook