diff --git a/desktop/app/src/chrome/FpsGraph.tsx b/desktop/app/src/chrome/FpsGraph.tsx
index ccdc711f8..39f6364c6 100644
--- a/desktop/app/src/chrome/FpsGraph.tsx
+++ b/desktop/app/src/chrome/FpsGraph.tsx
@@ -84,7 +84,12 @@ export default function FpsGraph({
return (
-
+
);
}
diff --git a/desktop/app/src/chrome/NetworkGraph.tsx b/desktop/app/src/chrome/NetworkGraph.tsx
new file mode 100644
index 000000000..be31bbf4d
--- /dev/null
+++ b/desktop/app/src/chrome/NetworkGraph.tsx
@@ -0,0 +1,72 @@
+/**
+ * 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.
+ *
+ * @format
+ */
+
+import React, {useEffect, useRef, useState} from 'react';
+import {onBytesReceived} from '../dispatcher/tracking';
+
+export default function NetworkGraph({
+ width,
+ height,
+}: {
+ width: number;
+ height: number;
+}) {
+ const canvasRef = useRef(null);
+ const lastTime = useRef(performance.now());
+ const lastBytes = useRef(0);
+ const pluginStats = useRef>({});
+ const [hoverText, setHoverText] = useState('');
+
+ useEffect(() => {
+ return onBytesReceived((plugin, bytes) => {
+ lastBytes.current += bytes;
+ if (!pluginStats.current[plugin]) {
+ pluginStats.current[plugin] = bytes;
+ } else {
+ pluginStats.current[plugin] += bytes;
+ }
+ });
+ }, []);
+
+ useEffect(() => {
+ const interval = setInterval(() => {
+ const deltaTime = performance.now() - lastTime.current;
+ lastTime.current = performance.now();
+ const deltaBytes = lastBytes.current;
+ lastBytes.current = 0;
+
+ // cause kiloBytesPerSecond === bytes per millisecond
+ const kiloBytesPerSecond = Math.round(deltaBytes / deltaTime);
+
+ const ctx = canvasRef.current!.getContext('2d')!;
+ ctx.clearRect(0, 0, width, height);
+ ctx.strokeStyle = kiloBytesPerSecond >= 1000 ? '#f00' : '#ccc';
+ ctx.textAlign = 'end';
+ ctx.strokeText(`${kiloBytesPerSecond} kB/s`, width - 5, 5 + height / 2);
+
+ setHoverText(
+ 'Total data traffic per plugin:\n\n' +
+ Object.entries(pluginStats.current)
+ .sort(([_p, bytes], [_p2, bytes2]) => bytes2 - bytes)
+ .map(([key, bytes]) => `${key}: ${Math.round(bytes / 1000)}kb`)
+ .join('\n'),
+ );
+ }, 1000);
+
+ return () => {
+ clearInterval(interval);
+ };
+ }, []);
+
+ return (
+
+
+
+ );
+}
diff --git a/desktop/app/src/chrome/TitleBar.tsx b/desktop/app/src/chrome/TitleBar.tsx
index 6de15fee3..5e2c4c9ae 100644
--- a/desktop/app/src/chrome/TitleBar.tsx
+++ b/desktop/app/src/chrome/TitleBar.tsx
@@ -45,6 +45,7 @@ import React from 'react';
import {State} from '../reducers';
import {reportUsage} from '../utils/metrics';
import FpsGraph from './FpsGraph';
+import NetworkGraph from './NetworkGraph';
import MetroButton from './MetroButton';
const AppTitleBar = styled(FlexRow)<{focused?: boolean}>(({focused}) => ({
@@ -167,6 +168,7 @@ class TitleBar extends React.Component {
)}
+ {!isProduction() && }
{!isProduction() && }
{config.showFlipperRating ? : null}