diff --git a/doric-android/devkit/src/main/AndroidManifest.xml b/doric-android/devkit/src/main/AndroidManifest.xml
index d5e29b36..55f66ac0 100644
--- a/doric-android/devkit/src/main/AndroidManifest.xml
+++ b/doric-android/devkit/src/main/AndroidManifest.xml
@@ -12,6 +12,8 @@
android:theme="@style/Theme.Design.Light.NoActionBar" />
-
+
diff --git a/doric-android/devkit/src/main/java/pub/doric/devkit/DoricDev.java b/doric-android/devkit/src/main/java/pub/doric/devkit/DoricDev.java
index 9310c121..ed26d78c 100644
--- a/doric-android/devkit/src/main/java/pub/doric/devkit/DoricDev.java
+++ b/doric-android/devkit/src/main/java/pub/doric/devkit/DoricDev.java
@@ -21,6 +21,7 @@ import pub.doric.DoricContextManager;
import pub.doric.DoricNativeDriver;
import pub.doric.devkit.ui.DoricDevActivity;
import pub.doric.devkit.util.SimulatorUtil;
+import pub.doric.performance.DoricPerformanceProfile;
import pub.doric.utils.DoricLog;
public class DoricDev {
@@ -51,6 +52,12 @@ public class DoricDev {
private DoricDev() {
this.isRunningInEmulator = SimulatorUtil.isSimulator(Doric.application());
DoricNativeDriver.getInstance().getRegistry().registerMonitor(new DoricDevMonitor());
+ DoricNativeDriver.getInstance().getRegistry().setGlobalPerformanceAnchorHook(new DoricPerformanceProfile.AnchorHook() {
+ @Override
+ public void onAnchor(String name, long prepare, long start, long end) {
+
+ }
+ });
}
public static DoricDev getInstance() {
@@ -240,7 +247,7 @@ public class DoricDev {
if (reloadingContexts.get(context.getContextId()) == null) {
reloadingContexts.put(context.getContextId(), context);
}
-
+
for (StatusCallback callback : callbacks) {
callback.onReload(context, script);
}
diff --git a/doric-android/devkit/src/main/java/pub/doric/devkit/DoricDevPerformanceAnchorHook.java b/doric-android/devkit/src/main/java/pub/doric/devkit/DoricDevPerformanceAnchorHook.java
new file mode 100644
index 00000000..15829f66
--- /dev/null
+++ b/doric-android/devkit/src/main/java/pub/doric/devkit/DoricDevPerformanceAnchorHook.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright [2021] [Doric.Pub]
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pub.doric.devkit;
+
+import pub.doric.performance.DoricPerformanceProfile;
+
+/**
+ * @Description: pub.doric.devkit
+ * @Author: pengfei.zhou
+ * @CreateDate: 2021/7/20
+ */
+public class DoricDevPerformanceAnchorHook implements DoricPerformanceProfile.AnchorHook {
+ @Override
+ public void onAnchor(String name, long prepare, long start, long end) {
+
+ }
+}
diff --git a/doric-android/devkit/src/main/java/pub/doric/devkit/ui/DoricDevActivity.java b/doric-android/devkit/src/main/java/pub/doric/devkit/ui/DoricDevActivity.java
index c45c95ed..bde66b58 100644
--- a/doric-android/devkit/src/main/java/pub/doric/devkit/ui/DoricDevActivity.java
+++ b/doric-android/devkit/src/main/java/pub/doric/devkit/ui/DoricDevActivity.java
@@ -417,7 +417,6 @@ public class DoricDevActivity extends AppCompatActivity implements DoricDev.Stat
Intent intent = new Intent(holder.itemView.getContext(), DoricDevPerfActivity.class);
intent.putExtra(DORIC_CONTEXT_ID_KEY, context.getContextId());
v.getContext().startActivity(intent);
- ((Activity) v.getContext()).finish();
}
});
}
@@ -428,7 +427,6 @@ public class DoricDevActivity extends AppCompatActivity implements DoricDev.Stat
Intent intent = new Intent(holder.itemView.getContext(), DoricShowNodeTreeActivity.class);
intent.putExtra(DORIC_CONTEXT_ID_KEY, context.getContextId());
v.getContext().startActivity(intent);
- ((Activity) v.getContext()).finish();
}
});
final String[] items = actionMap.keySet().toArray(new String[0]);
diff --git a/doric-android/devkit/src/main/java/pub/doric/devkit/ui/DoricDevPerfActivity.java b/doric-android/devkit/src/main/java/pub/doric/devkit/ui/DoricDevPerfActivity.java
index 2e96eab0..c77b9f14 100644
--- a/doric-android/devkit/src/main/java/pub/doric/devkit/ui/DoricDevPerfActivity.java
+++ b/doric-android/devkit/src/main/java/pub/doric/devkit/ui/DoricDevPerfActivity.java
@@ -16,9 +16,26 @@
package pub.doric.devkit.ui;
+import android.graphics.Color;
import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+
+import pub.doric.devkit.R;
/**
* @Description: pub.doric.devkit.ui
@@ -29,5 +46,88 @@ public class DoricDevPerfActivity extends DoricDevBaseActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_doricdev_perf);
+ TextView textView = findViewById(R.id.tv_title);
+ textView.setText(String.format("Doric %s <%s>", doricContext.getSource(), doricContext.getContextId()));
+ RecyclerView recyclerView = findViewById(R.id.list);
+ recyclerView.setLayoutManager(new LinearLayoutManager(this));
+ recyclerView.setAdapter(new MyAdapter());
+ }
+
+ private static class PerfCellHolder extends RecyclerView.ViewHolder {
+ private TextView tvName;
+ private LinearLayout layoutWaterfall;
+ private View waterfallPrepared;
+ private View waterfallWorked;
+ private LinearLayout layoutExpand;
+ private TextView tvFuncName;
+ private TextView tvParameter;
+ private TextView tvCost;
+
+ public PerfCellHolder(@NonNull View itemView) {
+ super(itemView);
+ }
+ }
+
+ private static class AnchorNode {
+ String name;
+ long prepare;
+ }
+
+ private class MyAdapter extends RecyclerView.Adapter {
+ private List anchorNodes = new ArrayList<>();
+
+ private MyAdapter() {
+ Map anchorMap = doricContext.getPerformanceProfile().getAnchorMap();
+ for (String key : anchorMap.keySet()) {
+ if (key.endsWith("#prepare")) {
+ Long prepare = anchorMap.get(key);
+ if (prepare != null) {
+ AnchorNode anchorNode = new AnchorNode();
+ anchorNode.name = key.substring(0, key.lastIndexOf("#prepare"));
+ anchorNode.prepare = prepare;
+ anchorNodes.add(anchorNode);
+ }
+ }
+ }
+ Collections.sort(anchorNodes, new Comparator() {
+ @Override
+ public int compare(AnchorNode o1, AnchorNode o2) {
+ return (int) (o1.prepare - o2.prepare);
+ }
+ });
+ }
+
+ @Override
+ public PerfCellHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ View cell = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_doricdev_perf, parent, false);
+ PerfCellHolder cellHolder = new PerfCellHolder(cell);
+ cellHolder.tvName = cell.findViewById(R.id.tv_name);
+ cellHolder.layoutWaterfall = cell.findViewById(R.id.layout_waterfall);
+ cellHolder.waterfallPrepared = cell.findViewById(R.id.waterfall_prepared);
+ cellHolder.waterfallWorked = cell.findViewById(R.id.waterfall_worked);
+ cellHolder.layoutExpand = cell.findViewById(R.id.layout_expand);
+ cellHolder.tvFuncName = cell.findViewById(R.id.tv_func_name);
+ cellHolder.tvParameter = cell.findViewById(R.id.tv_parameter);
+ cellHolder.tvCost = cell.findViewById(R.id.tv_cost);
+ return cellHolder;
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull PerfCellHolder holder, int position) {
+ holder.itemView.setBackgroundColor(position % 2 == 0 ? Color.parseColor("#ecf0f1") : Color.WHITE);
+ holder.layoutExpand.setVisibility(View.GONE);
+ AnchorNode anchorNode = anchorNodes.get(position);
+ if (anchorNode.name.startsWith("Call")) {
+ holder.tvName.setText("Call");
+ } else {
+ holder.tvName.setText(anchorNode.name);
+ }
+ }
+
+ @Override
+ public int getItemCount() {
+ return anchorNodes.size();
+ }
}
}
diff --git a/doric-android/devkit/src/main/res/layout/activity_doricdev_perf.xml b/doric-android/devkit/src/main/res/layout/activity_doricdev_perf.xml
new file mode 100644
index 00000000..b0818566
--- /dev/null
+++ b/doric-android/devkit/src/main/res/layout/activity_doricdev_perf.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/doric-android/devkit/src/main/res/layout/item_doricdev_perf.xml b/doric-android/devkit/src/main/res/layout/item_doricdev_perf.xml
new file mode 100644
index 00000000..8ed30631
--- /dev/null
+++ b/doric-android/devkit/src/main/res/layout/item_doricdev_perf.xml
@@ -0,0 +1,79 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/doric-android/doric/src/main/java/pub/doric/DoricContext.java b/doric-android/doric/src/main/java/pub/doric/DoricContext.java
index b3678d90..31b31ffc 100644
--- a/doric-android/doric/src/main/java/pub/doric/DoricContext.java
+++ b/doric-android/doric/src/main/java/pub/doric/DoricContext.java
@@ -108,6 +108,10 @@ public class DoricContext {
this.source = source;
this.extra = extra;
this.performanceProfile = new DoricPerformanceProfile(contextId);
+ DoricPerformanceProfile.AnchorHook anchorHook = getDriver().getRegistry().getGlobalPerformanceAnchorHook();
+ if (anchorHook != null) {
+ this.performanceProfile.addAnchorHook(anchorHook);
+ }
}
public DoricPerformanceProfile getPerformanceProfile() {
diff --git a/doric-android/doric/src/main/java/pub/doric/DoricRegistry.java b/doric-android/doric/src/main/java/pub/doric/DoricRegistry.java
index 6d3962de..d2a5dfae 100644
--- a/doric-android/doric/src/main/java/pub/doric/DoricRegistry.java
+++ b/doric-android/doric/src/main/java/pub/doric/DoricRegistry.java
@@ -28,6 +28,7 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import pub.doric.engine.DoricJSEngine;
+import pub.doric.performance.DoricPerformanceProfile;
import pub.doric.plugin.AnimatePlugin;
import pub.doric.plugin.CoordinatorPlugin;
import pub.doric.plugin.DoricJavaPlugin;
@@ -246,4 +247,16 @@ public class DoricRegistry {
public void setDefaultErrorDrawable(Drawable defaultErrorDrawable) {
this.defaultErrorDrawable = defaultErrorDrawable;
}
+
+
+ private DoricPerformanceProfile.GlobalAnchorHook globalPerformanceAnchorHook;
+
+ public void setGlobalPerformanceAnchorHook(DoricPerformanceProfile.GlobalAnchorHook anchorHook) {
+ globalPerformanceAnchorHook = anchorHook;
+ }
+
+ public DoricPerformanceProfile.GlobalAnchorHook getGlobalPerformanceAnchorHook() {
+ return globalPerformanceAnchorHook;
+ }
+
}
diff --git a/doric-android/doric/src/main/java/pub/doric/engine/DoricJSEngine.java b/doric-android/doric/src/main/java/pub/doric/engine/DoricJSEngine.java
index 8feaaa88..f21dbcca 100644
--- a/doric-android/doric/src/main/java/pub/doric/engine/DoricJSEngine.java
+++ b/doric-android/doric/src/main/java/pub/doric/engine/DoricJSEngine.java
@@ -67,6 +67,10 @@ public class DoricJSEngine implements Handler.Callback, DoricTimerExtension.Time
public DoricJSEngine() {
mDoricRegistry = new DoricRegistry(this);
+ DoricPerformanceProfile.AnchorHook anchorHook = mDoricRegistry.getGlobalPerformanceAnchorHook();
+ if (anchorHook != null) {
+ globalProfile.addAnchorHook(anchorHook);
+ }
globalProfile.prepare(DoricPerformanceProfile.PART_INIT);
handlerThread = new HandlerThread(this.getClass().getSimpleName());
handlerThread.start();
diff --git a/doric-android/doric/src/main/java/pub/doric/performance/DoricPerformanceProfile.java b/doric-android/doric/src/main/java/pub/doric/performance/DoricPerformanceProfile.java
index 981ed116..7016984d 100644
--- a/doric-android/doric/src/main/java/pub/doric/performance/DoricPerformanceProfile.java
+++ b/doric-android/doric/src/main/java/pub/doric/performance/DoricPerformanceProfile.java
@@ -57,6 +57,10 @@ public class DoricPerformanceProfile {
void onAnchor(String name, long prepare, long start, long end);
}
+ public interface GlobalAnchorHook extends AnchorHook {
+ void onAnchor(DoricPerformanceProfile profile, String name, long prepare, long start, long end);
+ }
+
public DoricPerformanceProfile(String name) {
this.name = name;
}
@@ -113,10 +117,6 @@ public class DoricPerformanceProfile {
print(anchorName);
}
- public Map getAnchorMap() {
- return this.anchorMap;
- }
-
private void print(final String anchorName) {
if (!enable) {
return;
@@ -139,7 +139,11 @@ public class DoricPerformanceProfile {
Log.d(TAG, String.format("%s: %s prepared %dms, cost %dms.",
name, anchorName, start - prepare, end - start));
for (AnchorHook hook : hooks) {
- hook.onAnchor(anchorName, prepare, start, end);
+ if (hook instanceof GlobalAnchorHook) {
+ ((GlobalAnchorHook) hook).onAnchor(DoricPerformanceProfile.this, anchorName, prepare, start, end);
+ } else {
+ hook.onAnchor(anchorName, prepare, start, end);
+ }
}
}
});
diff --git a/doric-iOS/Pod/Classes/DoricContextManager.m b/doric-iOS/Pod/Classes/DoricContextManager.m
index f9611dde..ba8fdc8d 100644
--- a/doric-iOS/Pod/Classes/DoricContextManager.m
+++ b/doric-iOS/Pod/Classes/DoricContextManager.m
@@ -54,6 +54,9 @@ + (instancetype)instance {
- (void)createContext:(DoricContext *)context script:(NSString *)script source:(NSString *)source {
context.contextId = [NSString stringWithFormat:@"%ld", (long) ++self.counter];
context.performanceProfile = [[DoricPerformanceProfile alloc] initWithName:context.contextId];
+ if (context.driver.registry.globalPerformanceAnchorHook) {
+ [context.performanceProfile addAnchorHook:context.driver.registry.globalPerformanceAnchorHook];
+ }
dispatch_sync(self.mapQueue, ^() {
[self.contextMapTable setObject:context forKey:context.contextId];
});
diff --git a/doric-iOS/Pod/Classes/DoricRegistry.h b/doric-iOS/Pod/Classes/DoricRegistry.h
index 28b05901..1cbc1f2f 100644
--- a/doric-iOS/Pod/Classes/DoricRegistry.h
+++ b/doric-iOS/Pod/Classes/DoricRegistry.h
@@ -27,10 +27,12 @@
NS_ASSUME_NONNULL_BEGIN
@class DoricLibrary;
@class DoricJSEngine;
+@protocol DoricPerformanceGlobalAnchorHookProtocol;
@interface DoricRegistry : NSObject
@property(nonatomic, strong) UIImage *defaultPlaceHolderImage;
@property(nonatomic, strong) UIImage *defaultErrorImage;
+@property(nonatomic, strong) id globalPerformanceAnchorHook;
- (instancetype)initWithJSEngine:(DoricJSEngine *)jsEngine;
diff --git a/doric-iOS/Pod/Classes/Engine/DoricJSEngine.m b/doric-iOS/Pod/Classes/Engine/DoricJSEngine.m
index 11650a62..fbd91362 100644
--- a/doric-iOS/Pod/Classes/Engine/DoricJSEngine.m
+++ b/doric-iOS/Pod/Classes/Engine/DoricJSEngine.m
@@ -58,7 +58,11 @@ @implementation DoricJSEngine
- (instancetype)init {
if (self = [super init]) {
_initialized = NO;
+ _registry = [[DoricRegistry alloc] initWithJSEngine:self];
_profile = [[DoricPerformanceProfile alloc] initWithName:@"JSEngine"];
+ if (_registry.globalPerformanceAnchorHook) {
+ [_profile addAnchorHook:_registry.globalPerformanceAnchorHook];
+ }
[_profile prepare:@"Init"];
_jsThread = [[NSThread alloc] initWithTarget:self selector:@selector(threadRun) object:nil];
[_jsThread start];
@@ -95,7 +99,6 @@ - (instancetype)init {
@"localeLanguage": [[NSLocale currentLocale] objectForKey:NSLocaleLanguageCode] ?: @"",
@"localeCountry": [[NSLocale currentLocale] objectForKey:NSLocaleCountryCode] ?: @"",
}.mutableCopy;
- self.registry = [[DoricRegistry alloc] initWithJSEngine:self];
[self ensureRunOnJSThread:^() {
[self.profile start:@"Init"];
self.timers = [[NSMutableDictionary alloc] init];
diff --git a/doric-iOS/Pod/Classes/Performance/DoricPerformanceProfile.h b/doric-iOS/Pod/Classes/Performance/DoricPerformanceProfile.h
index 20659ac0..9f2190d5 100644
--- a/doric-iOS/Pod/Classes/Performance/DoricPerformanceProfile.h
+++ b/doric-iOS/Pod/Classes/Performance/DoricPerformanceProfile.h
@@ -31,9 +31,17 @@ NS_ASSUME_NONNULL_BEGIN
end:(NSNumber *)end;
@end
+@class DoricPerformanceProfile;
+
+@protocol DoricPerformanceGlobalAnchorHookProtocol
+- (void)onAnchorName:(NSString *)name
+ prepare:(NSNumber *)prepare
+ start:(NSNumber *)start
+ end:(NSNumber *)end
+ in:(DoricPerformanceProfile *)profile;
+@end
@interface DoricPerformanceProfile : NSObject
-@property(nonatomic, strong) NSMutableDictionary *anchorMap;
- (instancetype)initWithName:(NSString *)name;
diff --git a/doric-iOS/Pod/Classes/Performance/DoricPerformanceProfile.m b/doric-iOS/Pod/Classes/Performance/DoricPerformanceProfile.m
index 0fba8acf..f0b2ad42 100644
--- a/doric-iOS/Pod/Classes/Performance/DoricPerformanceProfile.m
+++ b/doric-iOS/Pod/Classes/Performance/DoricPerformanceProfile.m
@@ -28,6 +28,7 @@ @interface DoricPerformanceProfile ()
@property(nonatomic, strong) dispatch_queue_t anchorQueue;
@property(nonatomic, assign) BOOL enable;
@property(nonatomic, strong) NSHashTable> *hooks;
+@property(nonatomic, strong) NSMutableDictionary *anchorMap;
@end
@implementation DoricPerformanceProfile
@@ -114,7 +115,11 @@ - (void)print:(NSString *)anchorName {
@(end.integerValue - start.integerValue)
);
for (id hook in self.hooks) {
- [hook onAnchorName:anchorName prepare:prepare start:start end:end];
+ if ([hook conformsToProtocol:@protocol(DoricPerformanceGlobalAnchorHookProtocol)]) {
+ [hook onAnchorName:anchorName prepare:end start:end end:end in:self];
+ } else {
+ [hook onAnchorName:anchorName prepare:prepare start:start end:end];
+ }
}
});
}