Compare commits
3 commits
main
...
feat/start
Author | SHA1 | Date | |
---|---|---|---|
9bc373d87a | |||
fb7e1c64fd | |||
1128e8f3ad |
23
src/plugins/startupTimings/StartupTimingPage.css
Normal file
23
src/plugins/startupTimings/StartupTimingPage.css
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
.vc-startuptimings-server-trace {
|
||||||
|
color: var(--header-primary);
|
||||||
|
user-select: text;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vc-startuptimings-grid {
|
||||||
|
color: var(--header-primary);
|
||||||
|
display: grid;
|
||||||
|
gap: 2px 10px;
|
||||||
|
user-select: text;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vc-startuptimings-4-cols {
|
||||||
|
grid-template-columns: repeat(3, auto) 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vc-startuptimings-3-cols {
|
||||||
|
grid-template-columns: repeat(2, auto) 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vc-startuptimings-2-cols {
|
||||||
|
grid-template-columns: auto 1fr;
|
||||||
|
}
|
|
@ -16,11 +16,35 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import "./StartupTimingPage.css";
|
||||||
|
|
||||||
|
import { classNameFactory } from "@api/Styles";
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
import { Flex } from "@components/Flex";
|
import { Flex } from "@components/Flex";
|
||||||
|
import { Margins } from "@utils/margins";
|
||||||
|
import { classes } from "@utils/misc";
|
||||||
import { findByPropsLazy } from "@webpack";
|
import { findByPropsLazy } from "@webpack";
|
||||||
import { Forms, React } from "@webpack/common";
|
import { Forms, React } from "@webpack/common";
|
||||||
|
|
||||||
|
|
||||||
|
export const cl = classNameFactory("vc-startuptimings-");
|
||||||
|
|
||||||
|
interface ITTITrackerEvent {
|
||||||
|
emoji: string;
|
||||||
|
name: string;
|
||||||
|
start: number;
|
||||||
|
end: number;
|
||||||
|
hasData(): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ITTITracker {
|
||||||
|
serializeTTITracker(): Record<string, string | number | boolean | null | undefined>;
|
||||||
|
[event: string]: ITTITrackerEvent | string | boolean | null | any;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Time-To-Interactive Tracker */
|
||||||
|
const TTITracker: ITTITracker = findByPropsLazy("serializeTTITracker");
|
||||||
|
|
||||||
interface AppStartPerformance {
|
interface AppStartPerformance {
|
||||||
prefix: string;
|
prefix: string;
|
||||||
logs: Log[];
|
logs: Log[];
|
||||||
|
@ -91,11 +115,11 @@ function TimingSection({ title, logs, traceEnd }: TimingSectionProps) {
|
||||||
<Forms.FormSection title={title} tag="h1">
|
<Forms.FormSection title={title} tag="h1">
|
||||||
<code>
|
<code>
|
||||||
{traceEnd && (
|
{traceEnd && (
|
||||||
<div style={{ color: "var(--header-primary)", marginBottom: 5, userSelect: "text" }}>
|
<div className={cl("server-trace")} style={{ marginBottom: 5 }}>
|
||||||
Trace ended at: {(new Date(traceEnd)).toTimeString()}
|
Trace ended at: {(new Date(traceEnd)).toTimeString()}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div style={{ color: "var(--header-primary)", display: "grid", gridTemplateColumns: "repeat(3, auto) 1fr", gap: "2px 10px", userSelect: "text" }}>
|
<div className={classes(cl("grid"), cl("4-cols"))}>
|
||||||
<span>Start</span>
|
<span>Start</span>
|
||||||
<span>Interval</span>
|
<span>Interval</span>
|
||||||
<span>Delta</span>
|
<span>Delta</span>
|
||||||
|
@ -119,13 +143,66 @@ function ServerTrace({ trace }: ServerTraceProps) {
|
||||||
return (
|
return (
|
||||||
<Forms.FormSection title="Server Trace" tag="h2">
|
<Forms.FormSection title="Server Trace" tag="h2">
|
||||||
<code>
|
<code>
|
||||||
<Flex flexDirection="column" style={{ color: "var(--header-primary)", gap: 5, userSelect: "text" }}>
|
<Flex flexDirection="column" className={cl("server-trace")} style={{ gap: 5 }}>
|
||||||
{lines.map(line => (
|
{lines.map(line => (
|
||||||
<span>{line}</span>
|
<span>{line}</span>
|
||||||
))}
|
))}
|
||||||
</Flex>
|
</Flex>
|
||||||
</code>
|
</code>
|
||||||
</Forms.FormSection>
|
</Forms.FormSection >
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function TTIAnalytics() {
|
||||||
|
const analytics = TTITracker.serializeTTITracker();
|
||||||
|
const filteredAnalytics = Object.entries(analytics).filter(([key, value]) => value != null && !/_start$|_end$/.test(key));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ErrorBoundary>
|
||||||
|
<Forms.FormSection title="TTI Analytics" tag="h2">
|
||||||
|
<code>
|
||||||
|
<div className={classes(cl("grid"), cl("2-cols"))}>
|
||||||
|
{filteredAnalytics.map(([key, value]) => (
|
||||||
|
<React.Fragment>
|
||||||
|
<span><pre>{key}</pre></span>
|
||||||
|
<span><pre>{`${value}`}</pre></span>
|
||||||
|
</React.Fragment>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</code>
|
||||||
|
</Forms.FormSection>
|
||||||
|
</ErrorBoundary>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TTITimingsProps {
|
||||||
|
records: [string, ITTITrackerEvent][];
|
||||||
|
title: string;
|
||||||
|
type: "registered" | "unregistered";
|
||||||
|
}
|
||||||
|
|
||||||
|
function TTITimings({ records, title, type }: TTITimingsProps) {
|
||||||
|
const isRegistered = type === "registered";
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ErrorBoundary>
|
||||||
|
<Forms.FormSection title={title} tag="h2">
|
||||||
|
<code>
|
||||||
|
<div className={classes(cl("grid"), cl(isRegistered ? "3-cols" : "2-cols"))}>
|
||||||
|
{isRegistered && <span>Duration</span>}
|
||||||
|
<span>Key</span>
|
||||||
|
<span style={{ marginBottom: 5 }}>Event</span>
|
||||||
|
{records.map(([key, event]) => (
|
||||||
|
<React.Fragment key={key}>
|
||||||
|
{isRegistered && <span><pre>{event.end - event.start}ms</pre></span>}
|
||||||
|
<span><pre>{key}</pre></span>
|
||||||
|
<span><pre>{event.emoji} {event.name}</pre></span>
|
||||||
|
</React.Fragment>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</code>
|
||||||
|
</Forms.FormSection>
|
||||||
|
</ErrorBoundary>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,6 +211,12 @@ function StartupTimingPage() {
|
||||||
|
|
||||||
const serverTrace = AppStartPerformance.logGroups.find(g => g.serverTrace)?.serverTrace;
|
const serverTrace = AppStartPerformance.logGroups.find(g => g.serverTrace)?.serverTrace;
|
||||||
|
|
||||||
|
const registeredTTITimings: [string, ITTITrackerEvent][] = (Object.entries(TTITracker))
|
||||||
|
.filter(([, value]) => value?.hasData?.());
|
||||||
|
|
||||||
|
const unregisteredTTITimings: [string, ITTITrackerEvent][] = (Object.entries(TTITracker))
|
||||||
|
.filter(([, value]) => value?.hasData && !value.hasData());
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<TimingSection
|
<TimingSection
|
||||||
|
@ -141,9 +224,26 @@ function StartupTimingPage() {
|
||||||
logs={AppStartPerformance.logs}
|
logs={AppStartPerformance.logs}
|
||||||
traceEnd={AppStartPerformance.endTime_}
|
traceEnd={AppStartPerformance.endTime_}
|
||||||
/>
|
/>
|
||||||
{/* Lazy Divider */}
|
<Forms.FormDivider className={classes(Margins.top16, Margins.bottom16)} />
|
||||||
<div style={{ marginTop: 5 }}> </div>
|
|
||||||
{serverTrace && <ServerTrace trace={serverTrace} />}
|
{serverTrace && <ServerTrace trace={serverTrace} />}
|
||||||
|
<Forms.FormDivider className={classes(Margins.top16, Margins.bottom16)} />
|
||||||
|
|
||||||
|
<TTIAnalytics />
|
||||||
|
<Forms.FormDivider className={classes(Margins.top16, Margins.bottom16)} />
|
||||||
|
|
||||||
|
<TTITimings
|
||||||
|
title="Registered TTI Timings"
|
||||||
|
records={registeredTTITimings}
|
||||||
|
type="registered"
|
||||||
|
/>
|
||||||
|
<Forms.FormDivider className={classes(Margins.top16, Margins.bottom16)} />
|
||||||
|
|
||||||
|
<TTITimings
|
||||||
|
title="Unregistered TTI Timings"
|
||||||
|
records={unregisteredTTITimings}
|
||||||
|
type="unregistered"
|
||||||
|
/>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue