Skip to content

Commit 7f27888

Browse files
mdvaccafacebook-github-bot
authored andcommitted
Add performance counters for Fabric
Summary: This diff adds performance loggers for Fabric in Android to be able to compare current version or RN with Fabric This is the summary of Points and Annotations: - **UIManager_CommitStart**: time that React starts the commit (react tree is ready to start rendering in native) - **UIManager_LayoutTime**: this is the time it takes to calculate layout in yoga - **UIManager_FabricFinishTransactionTime**: Time it takes transform "C++ mutationInstructions" into "Java MountItems" and cross boundaries from C++ to Java (including serialization of data) (THIS IS ONLY FABRIC) - **UIManager_DispatchViewUpdates**: time right before RN moves the mount operations to the Queue that is going to be processed in the next tick UI thread - **UIManager_BatchRunStart**: time right before the mountItems are going to be process in the UI Thread - **UIManager_BatchedExecutionTime**: time it took to run batched mountItems (usually layout and prop updates on views) - **UIManager_NonBatchedExecutionTime**: time it took to run non-batched mountItems (usually creation of views) Reviewed By: fkgozali Differential Revision: D13838337 fbshipit-source-id: 0a707619829e7d95ce94d9305ff434d1224afc46
1 parent c493cfe commit 7f27888

File tree

13 files changed

+187
-72
lines changed

13 files changed

+187
-72
lines changed

React/Fabric/RCTScheduler.mm

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
SchedulerDelegateProxy(void *scheduler):
2525
scheduler_(scheduler) {}
2626

27-
void schedulerDidFinishTransaction(Tag rootTag, const ShadowViewMutationList &mutations) override {
27+
void schedulerDidFinishTransaction(Tag rootTag, const ShadowViewMutationList &mutations, const long commitStartTime, const long layoutTime) override {
2828
RCTScheduler *scheduler = (__bridge RCTScheduler *)scheduler_;
2929
[scheduler.delegate schedulerDidFinishTransaction:mutations rootTag:rootTag];
3030
}

ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java

+53-19
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,33 @@
66
*/
77
package com.facebook.react.fabric;
88

9+
import static com.facebook.infer.annotation.ThreadConfined.UI;
910
import static com.facebook.react.fabric.mounting.LayoutMetricsConversions.getMaxSize;
1011
import static com.facebook.react.fabric.mounting.LayoutMetricsConversions.getMinSize;
1112
import static com.facebook.react.fabric.mounting.LayoutMetricsConversions.getYogaMeasureMode;
1213
import static com.facebook.react.fabric.mounting.LayoutMetricsConversions.getYogaSize;
13-
import static com.facebook.infer.annotation.ThreadConfined.UI;
1414
import static com.facebook.react.uimanager.common.UIManagerType.FABRIC;
1515

1616
import android.annotation.SuppressLint;
17+
import android.os.SystemClock;
1718
import android.support.annotation.GuardedBy;
1819
import android.support.annotation.Nullable;
1920
import android.support.annotation.UiThread;
2021
import com.facebook.common.logging.FLog;
22+
import com.facebook.infer.annotation.Assertions;
23+
import com.facebook.infer.annotation.ThreadConfined;
24+
import com.facebook.proguard.annotations.DoNotStrip;
25+
import com.facebook.react.bridge.GuardedRunnable;
26+
import com.facebook.react.bridge.LifecycleEventListener;
27+
import com.facebook.react.bridge.NativeMap;
28+
import com.facebook.react.bridge.ReactApplicationContext;
29+
import com.facebook.react.bridge.ReactContext;
30+
import com.facebook.react.bridge.ReadableArray;
31+
import com.facebook.react.bridge.ReadableNativeMap;
32+
import com.facebook.react.bridge.UIManager;
33+
import com.facebook.react.bridge.UiThreadUtil;
34+
import com.facebook.react.bridge.WritableMap;
35+
import com.facebook.react.common.ReactConstants;
2136
import com.facebook.react.fabric.jsi.Binding;
2237
import com.facebook.react.fabric.jsi.EventBeatManager;
2338
import com.facebook.react.fabric.jsi.EventEmitterWrapper;
@@ -35,20 +50,6 @@
3550
import com.facebook.react.fabric.mounting.mountitems.UpdateLayoutMountItem;
3651
import com.facebook.react.fabric.mounting.mountitems.UpdateLocalDataMountItem;
3752
import com.facebook.react.fabric.mounting.mountitems.UpdatePropsMountItem;
38-
import com.facebook.infer.annotation.Assertions;
39-
import com.facebook.infer.annotation.ThreadConfined;
40-
import com.facebook.proguard.annotations.DoNotStrip;
41-
import com.facebook.react.bridge.GuardedRunnable;
42-
import com.facebook.react.bridge.LifecycleEventListener;
43-
import com.facebook.react.bridge.NativeMap;
44-
import com.facebook.react.bridge.ReactApplicationContext;
45-
import com.facebook.react.bridge.ReactContext;
46-
import com.facebook.react.bridge.ReadableArray;
47-
import com.facebook.react.bridge.ReadableNativeMap;
48-
import com.facebook.react.bridge.UIManager;
49-
import com.facebook.react.bridge.UiThreadUtil;
50-
import com.facebook.react.bridge.WritableMap;
51-
import com.facebook.react.common.ReactConstants;
5253
import com.facebook.react.modules.core.ReactChoreographer;
5354
import com.facebook.react.uimanager.IllegalViewOperationException;
5455
import com.facebook.react.uimanager.ReactRootViewTagGenerator;
@@ -109,6 +110,13 @@ public class FabricUIManager implements UIManager, LifecycleEventListener {
109110

110111
@ThreadConfined(UI)
111112
private boolean mIsMountingEnabled = true;
113+
private long mRunStartTime = 0l;
114+
private long mBatchedExecutionTime = 0l;
115+
private long mNonBatchedExecutionTime = 0l;
116+
private long mDispatchViewUpdatesTime = 0l;
117+
private long mCommitStartTime = 0l;
118+
private long mLayoutTime = 0l;
119+
private long mFinishTransactionTime = 0l;
112120

113121
public FabricUIManager(
114122
ReactApplicationContext reactContext,
@@ -268,7 +276,17 @@ private long measure(
268276
*/
269277
@DoNotStrip
270278
@SuppressWarnings("unused")
271-
private void scheduleMountItems(final MountItem mountItems) {
279+
private void scheduleMountItems(
280+
final MountItem mountItems,
281+
long commitStartTime,
282+
long layoutTime,
283+
long finishTransactionStartTime) {
284+
285+
// TODO T31905686: support multithreading
286+
mCommitStartTime = commitStartTime;
287+
mLayoutTime = layoutTime;
288+
mFinishTransactionTime = SystemClock.uptimeMillis() - finishTransactionStartTime;
289+
mDispatchViewUpdatesTime = SystemClock.uptimeMillis();
272290
synchronized (mMountItemsLock) {
273291
mMountItems.add(mountItems);
274292
}
@@ -294,26 +312,32 @@ private void flushMountItems() {
294312
mPreMountItems = new ArrayList<>();
295313
}
296314

315+
mRunStartTime = SystemClock.uptimeMillis();
297316
List<MountItem> mountItemsToDispatch;
298317
synchronized (mMountItemsLock) {
299318
mountItemsToDispatch = mMountItems;
300319
mMountItems = new ArrayList<>();
301320
}
302321

322+
long nonBatchedExecutionStartTime = SystemClock.uptimeMillis();
303323
Systrace.beginSection(
304324
Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
305325
"FabricUIManager::premountViews (" + preMountItemsToDispatch.size() + " batches)");
306326
for (MountItem mountItem : preMountItemsToDispatch) {
307327
mountItem.execute(mMountingManager);
308328
}
329+
mNonBatchedExecutionTime = SystemClock.uptimeMillis() - nonBatchedExecutionStartTime;
309330
Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
310331

311332
Systrace.beginSection(
312333
Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
313334
"FabricUIManager::mountViews (" + mountItemsToDispatch.size() + " batches)");
335+
336+
long batchedExecutionStartTime = SystemClock.uptimeMillis();
314337
for (MountItem mountItem : mountItemsToDispatch) {
315338
mountItem.execute(mMountingManager);
316339
}
340+
mBatchedExecutionTime = SystemClock.uptimeMillis() - batchedExecutionStartTime;
317341
Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
318342
} catch (Exception ex) {
319343
FLog.e(ReactConstants.TAG, "Exception thrown when executing UIFrameGuarded", ex);
@@ -379,7 +403,9 @@ public void onHostDestroy() {}
379403
@Override
380404
public void dispatchCommand(
381405
final int reactTag, final int commandId, final ReadableArray commandArgs) {
382-
scheduleMountItems(new DispatchCommandMountItem(reactTag, commandId, commandArgs));
406+
synchronized (mMountItemsLock) {
407+
mMountItems.add(new DispatchCommandMountItem(reactTag, commandId, commandArgs));
408+
}
383409
}
384410

385411
@Override
@@ -394,12 +420,20 @@ public void clearJSResponder() {
394420

395421
@Override
396422
public void profileNextBatch() {
397-
// do nothing for now.
423+
// TODO T31905686: Remove this method and add support for multi-threading performance counters
398424
}
399425

400426
@Override
401427
public Map<String, Long> getPerformanceCounters() {
402-
return new HashMap<>();
428+
HashMap<String, Long> performanceCounters = new HashMap<>();
429+
performanceCounters.put("CommitStartTime", mCommitStartTime);
430+
performanceCounters.put("LayoutTime", mLayoutTime);
431+
performanceCounters.put("DispatchViewUpdatesTime", mDispatchViewUpdatesTime);
432+
performanceCounters.put("RunStartTime", mRunStartTime);
433+
performanceCounters.put("BatchedExecutionTime", mBatchedExecutionTime);
434+
performanceCounters.put("NonBatchedExecutionTime", mNonBatchedExecutionTime);
435+
performanceCounters.put("FinishFabricTransactionTime", mFinishTransactionTime);
436+
return performanceCounters;
403437
}
404438

405439
private class DispatchUIFrameCallback extends GuardedFrameCallback {

ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.cpp

+7-3
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <react/uimanager/primitives.h>
2121
#include <react/uimanager/Scheduler.h>
2222
#include <react/uimanager/SchedulerDelegate.h>
23+
#include <react/uimanager/TimeUtils.h>
2324

2425
using namespace facebook::jni;
2526
using namespace facebook::jsi;
@@ -249,12 +250,15 @@ local_ref<JMountItem::javaobject> createDeleteMountItem(const jni::global_ref<jo
249250
return deleteInstruction(javaUIManager, mutation.oldChildShadowView.tag);
250251
}
251252

252-
void Binding::schedulerDidFinishTransaction(const Tag rootTag, const ShadowViewMutationList &mutations) {
253+
void Binding::schedulerDidFinishTransaction(const Tag rootTag, const ShadowViewMutationList &mutations, const long commitStartTime, const long layoutTime) {
253254
SystraceSection s("FabricUIManager::schedulerDidFinishTransaction");
254255
std::vector<local_ref<jobject>> queue;
255256
// Upper bound estimation of mount items to be delivered to Java side.
256257
int size = mutations.size() * 3 + 42;
257258

259+
long finishTransactionStartTime = getTime();
260+
261+
258262
local_ref<JArrayClass<JMountItem::javaobject>> mountItemsArray = JArrayClass<JMountItem::javaobject>::newArray(size);
259263

260264
auto mountItems = *(mountItemsArray);
@@ -341,9 +345,9 @@ void Binding::schedulerDidFinishTransaction(const Tag rootTag, const ShadowViewM
341345

342346
static auto scheduleMountItems =
343347
jni::findClassStatic(UIManagerJavaDescriptor)
344-
->getMethod<void(JMountItem::javaobject)>("scheduleMountItems");
348+
->getMethod<void(JMountItem::javaobject,jlong,jlong,jlong)>("scheduleMountItems");
345349

346-
scheduleMountItems(javaUIManager_, batch.get());
350+
scheduleMountItems(javaUIManager_, batch.get(), commitStartTime, layoutTime, finishTransactionStartTime);
347351
}
348352

349353
void Binding::setPixelDensity(float pointScaleFactor) {

ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ class Binding : public jni::HybridClass<Binding>, public SchedulerDelegate {
4646

4747
void stopSurface(jint surfaceId);
4848

49-
void schedulerDidFinishTransaction(const Tag rootTag, const ShadowViewMutationList &mutations);
49+
void schedulerDidFinishTransaction(const Tag rootTag, const ShadowViewMutationList &mutations, const long commitStartTime, const long layoutTime);
5050

5151
void schedulerDidRequestPreliminaryViewAllocation(const SurfaceId surfaceId, const ComponentName componentName, bool isLayoutable, const ComponentHandle componentHandle);
5252

ReactCommon/fabric/uimanager/Scheduler.cpp

+49-28
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#include <react/core/LayoutContext.h>
1111
#include <react/uimanager/ComponentDescriptorRegistry.h>
12+
#include <react/uimanager/TimeUtils.h>
1213
#include <react/uimanager/UIManager.h>
1314
#include <react/uimanager/UIManagerBinding.h>
1415
#include <react/uimanager/UITemplateProcessor.h>
@@ -85,6 +86,7 @@ void Scheduler::startSurface(
8586
void Scheduler::renderTemplateToSurface(
8687
SurfaceId surfaceId,
8788
const std::string &uiTemplate) {
89+
long commitStartTime = getTime();
8890
try {
8991
if (uiTemplate.size() == 0) {
9092
return;
@@ -106,7 +108,8 @@ void Scheduler::renderTemplateToSurface(
106108
ShadowNodeFragment{.children =
107109
std::make_shared<SharedShadowNodeList>(
108110
SharedShadowNodeList{tree})});
109-
});
111+
},
112+
commitStartTime);
110113
});
111114
} catch (const std::exception &e) {
112115
LOG(ERROR) << " >>>> EXCEPTION <<< rendering uiTemplate in "
@@ -115,16 +118,20 @@ void Scheduler::renderTemplateToSurface(
115118
}
116119

117120
void Scheduler::stopSurface(SurfaceId surfaceId) const {
118-
shadowTreeRegistry_.visit(surfaceId, [](const ShadowTree &shadowTree) {
119-
// As part of stopping the Surface, we have to commit an empty tree.
120-
return shadowTree.tryCommit(
121-
[&](const SharedRootShadowNode &oldRootShadowNode) {
122-
return std::make_shared<RootShadowNode>(
123-
*oldRootShadowNode,
124-
ShadowNodeFragment{
125-
.children = ShadowNode::emptySharedShadowNodeSharedList()});
126-
});
127-
});
121+
long commitStartTime = getTime();
122+
shadowTreeRegistry_.visit(
123+
surfaceId, [commitStartTime](const ShadowTree &shadowTree) {
124+
// As part of stopping the Surface, we have to commit an empty tree.
125+
return shadowTree.tryCommit(
126+
[&](const SharedRootShadowNode &oldRootShadowNode) {
127+
return std::make_shared<RootShadowNode>(
128+
*oldRootShadowNode,
129+
ShadowNodeFragment{
130+
.children =
131+
ShadowNode::emptySharedShadowNodeSharedList()});
132+
},
133+
commitStartTime);
134+
});
128135

129136
auto shadowTree = shadowTreeRegistry_.remove(surfaceId);
130137
shadowTree->setDelegate(nullptr);
@@ -140,15 +147,19 @@ Size Scheduler::measureSurface(
140147
SurfaceId surfaceId,
141148
const LayoutConstraints &layoutConstraints,
142149
const LayoutContext &layoutContext) const {
150+
long commitStartTime = getTime();
151+
143152
Size size;
144153
shadowTreeRegistry_.visit(surfaceId, [&](const ShadowTree &shadowTree) {
145-
shadowTree.tryCommit([&](const SharedRootShadowNode &oldRootShadowNode) {
146-
auto rootShadowNode =
147-
oldRootShadowNode->clone(layoutConstraints, layoutContext);
148-
rootShadowNode->layout();
149-
size = rootShadowNode->getLayoutMetrics().frame.size;
150-
return nullptr;
151-
});
154+
shadowTree.tryCommit(
155+
[&](const SharedRootShadowNode &oldRootShadowNode) {
156+
auto rootShadowNode =
157+
oldRootShadowNode->clone(layoutConstraints, layoutContext);
158+
rootShadowNode->layout();
159+
size = rootShadowNode->getLayoutMetrics().frame.size;
160+
return nullptr;
161+
},
162+
commitStartTime);
152163
});
153164
return size;
154165
}
@@ -157,10 +168,14 @@ void Scheduler::constraintSurfaceLayout(
157168
SurfaceId surfaceId,
158169
const LayoutConstraints &layoutConstraints,
159170
const LayoutContext &layoutContext) const {
171+
long commitStartTime = getTime();
172+
160173
shadowTreeRegistry_.visit(surfaceId, [&](const ShadowTree &shadowTree) {
161-
shadowTree.commit([&](const SharedRootShadowNode &oldRootShadowNode) {
162-
return oldRootShadowNode->clone(layoutConstraints, layoutContext);
163-
});
174+
shadowTree.commit(
175+
[&](const SharedRootShadowNode &oldRootShadowNode) {
176+
return oldRootShadowNode->clone(layoutConstraints, layoutContext);
177+
},
178+
commitStartTime);
164179
});
165180
}
166181

@@ -178,23 +193,29 @@ SchedulerDelegate *Scheduler::getDelegate() const {
178193

179194
void Scheduler::shadowTreeDidCommit(
180195
const ShadowTree &shadowTree,
181-
const ShadowViewMutationList &mutations) const {
196+
const ShadowViewMutationList &mutations,
197+
long commitStartTime,
198+
long layoutTime) const {
182199
if (delegate_) {
183200
delegate_->schedulerDidFinishTransaction(
184-
shadowTree.getSurfaceId(), mutations);
201+
shadowTree.getSurfaceId(), mutations, commitStartTime, layoutTime);
185202
}
186203
}
187204

188205
#pragma mark - UIManagerDelegate
189206

190207
void Scheduler::uiManagerDidFinishTransaction(
191208
SurfaceId surfaceId,
192-
const SharedShadowNodeUnsharedList &rootChildNodes) {
209+
const SharedShadowNodeUnsharedList &rootChildNodes,
210+
long startCommitTime) {
193211
shadowTreeRegistry_.visit(surfaceId, [&](const ShadowTree &shadowTree) {
194-
shadowTree.commit([&](const SharedRootShadowNode &oldRootShadowNode) {
195-
return std::make_shared<RootShadowNode>(
196-
*oldRootShadowNode, ShadowNodeFragment{.children = rootChildNodes});
197-
});
212+
shadowTree.commit(
213+
[&](const SharedRootShadowNode &oldRootShadowNode) {
214+
return std::make_shared<RootShadowNode>(
215+
*oldRootShadowNode,
216+
ShadowNodeFragment{.children = rootChildNodes});
217+
},
218+
startCommitTime);
198219
});
199220
}
200221

ReactCommon/fabric/uimanager/Scheduler.h

+5-2
Original file line numberDiff line numberDiff line change
@@ -81,15 +81,18 @@ class Scheduler final : public UIManagerDelegate, public ShadowTreeDelegate {
8181

8282
void uiManagerDidFinishTransaction(
8383
SurfaceId surfaceId,
84-
const SharedShadowNodeUnsharedList &rootChildNodes) override;
84+
const SharedShadowNodeUnsharedList &rootChildNodes,
85+
long startCommitTime) override;
8586
void uiManagerDidCreateShadowNode(
8687
const SharedShadowNode &shadowNode) override;
8788

8889
#pragma mark - ShadowTreeDelegate
8990

9091
void shadowTreeDidCommit(
9192
const ShadowTree &shadowTree,
92-
const ShadowViewMutationList &mutations) const override;
93+
const ShadowViewMutationList &mutations,
94+
long commitStartTime,
95+
long layoutTime) const override;
9396

9497
private:
9598
SchedulerDelegate *delegate_;

ReactCommon/fabric/uimanager/SchedulerDelegate.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@ class SchedulerDelegate {
2626
*/
2727
virtual void schedulerDidFinishTransaction(
2828
Tag rootTag,
29-
const ShadowViewMutationList &mutations) = 0;
29+
const ShadowViewMutationList &mutations,
30+
const long commitStartTime,
31+
const long layoutTime) = 0;
3032

3133
/*
3234
* Called right after a new ShadowNode was created.

0 commit comments

Comments
 (0)