Skip to content

Commit 5076f8c

Browse files
FindHaofacebook-github-bot
authored andcommitted
Update website for launch diff (#37)
Summary: This pull request updates the website to visualize the new `launch_diff` event data generated by the parser. It introduces several new React components to display complex diff information in a user-friendly way. The main `KernelOverview` page is now much more powerful, allowing users to see not just the compilation details of a kernel, but also a detailed breakdown of how its parameters and arguments changed across multiple launches. ## Detailed Changes ### New Components - **`ArgumentViewer.tsx`**: A new component to display kernel arguments in a structured and readable format. - **`DiffViewer.tsx`**: A versatile component to visualize the `launch_diff` data. It can render different types of diffs, including argument diffs, value distributions, and simple summaries. - **`StackDiffViewer.tsx`**: A specialized component for displaying differences in stack traces between launches. ### Page Updates - **`KernelOverview.tsx`**: - **Launch Analysis Section**: A major new section has been added to display the `launch_diff` information. It shows total launches, which parameters were constant, and which ones varied, using the new `ArgumentViewer` and `DiffViewer` components. - **Compilation Metadata**: The layout has been improved to better handle long metadata values, preventing UI clutter. - **Stack Trace**: The stack trace is now explicitly labeled as the "Compilation Stack Trace". ### Data Loading Logic - **`dataLoader.ts`**: - The data loading logic has been updated to handle the new `launch_diff` event type. - `processKernelData` now uses a two-pass approach. The first pass gathers all compilation events, and the second pass attaches the corresponding `launch_diff` data. This ensures that the launch analysis is correctly associated with each kernel. - Interfaces (`LogEntry`, `ProcessedKernel`) have been updated to include the `launchDiff` data. Pull Request resolved: #37 Reviewed By: davidberard98 Differential Revision: D78667053 Pulled By: FindHao fbshipit-source-id: 361bb839ae2c9ebe6ac772de840854d5b3a358e6
1 parent dff8344 commit 5076f8c

File tree

5 files changed

+622
-81
lines changed

5 files changed

+622
-81
lines changed
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
import React, { useState } from 'react';
2+
3+
// Renders the value distribution (e.g., "16 (2 times, in launches: 1-2)")
4+
const DistributionCell: React.FC<{ data: any }> = ({ data }) => {
5+
if (!data) return null;
6+
if (data.diff_type === 'summary') {
7+
return <span className="text-gray-500 italic">{data.summary_text}</span>;
8+
}
9+
if (data.diff_type === 'distribution' && data.values) {
10+
return (
11+
<ul className="list-none m-0 p-0 space-y-1">
12+
{data.values.map((item: any, index: number) => {
13+
const launchRanges = item.launches
14+
.map((r: any) => (r.start === r.end ? `${r.start + 1}` : `${r.start + 1}-${r.end + 1}`))
15+
.join(', ');
16+
return (
17+
<li key={index}>
18+
<span className="font-mono bg-gray-100 px-1 rounded">{JSON.stringify(item.value)}</span>
19+
<span className="text-gray-500 text-xs ml-2">({item.count} times, in launches: {launchRanges})</span>
20+
</li>
21+
);
22+
})}
23+
</ul>
24+
);
25+
}
26+
return <span className="font-mono">{JSON.stringify(data)}</span>;
27+
};
28+
29+
// Renders a single row in the ArgumentViewer table
30+
const ArgumentRow: React.FC<{
31+
argName: string;
32+
argData: any;
33+
isDiffViewer?: boolean;
34+
}> = ({ argName, argData, isDiffViewer = false }) => {
35+
// Case 1: This is a complex argument with internal differences
36+
if (isDiffViewer && argData.diff_type === "argument_diff") {
37+
const [isCollapsed, setIsCollapsed] = useState(false);
38+
const { sames, diffs } = argData;
39+
const hasSames = Object.keys(sames).length > 0;
40+
const hasDiffs = Object.keys(diffs).length > 0;
41+
42+
return (
43+
<div className="bg-gray-50 border-b border-gray-200 last:border-b-0">
44+
<div
45+
className="flex items-center space-x-4 p-2 cursor-pointer"
46+
onClick={() => setIsCollapsed(!isCollapsed)}
47+
>
48+
<div className="w-48 flex-shrink-0 font-semibold text-gray-800 break-all">{argName}</div>
49+
<div className="flex-1 text-gray-500 italic text-sm flex items-center">
50+
Complex argument with internal differences
51+
{/* Dropdown arrow icon */}
52+
<svg className={`w-4 h-4 ml-2 transform transition-transform ${isCollapsed ? '' : 'rotate-90'}`} fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M9 5l7 7-7 7"></path></svg>
53+
</div>
54+
</div>
55+
{!isCollapsed && (
56+
<div className="pb-2 px-4 space-y-3">
57+
{hasSames && (
58+
<div>
59+
<h6 className="text-sm font-semibold text-gray-600 mb-1">Unchanged Properties</h6>
60+
<div className="space-y-1 pl-4">
61+
{Object.entries(sames).map(([key, value]) => (
62+
<div key={key} className="flex items-start text-sm">
63+
<span className="w-28 font-mono text-gray-500 flex-shrink-0">{key}:</span>
64+
<span className="font-mono">{JSON.stringify(value)}</span>
65+
</div>
66+
))}
67+
</div>
68+
</div>
69+
)}
70+
{hasDiffs && (
71+
<div>
72+
<h6 className="text-sm font-semibold text-gray-600 mb-1">Differing Properties</h6>
73+
<div className="space-y-2 pl-4">
74+
{Object.entries(diffs).map(([key, value]) => (
75+
<div key={key} className="flex items-start text-sm">
76+
<span className="w-28 font-mono text-gray-500 flex-shrink-0">{key}:</span>
77+
<div className="flex-1"><DistributionCell data={value} /></div>
78+
</div>
79+
))}
80+
</div>
81+
</div>
82+
)}
83+
</div>
84+
)}
85+
</div>
86+
);
87+
}
88+
89+
// Case 2: This is a simple argument (in the "Sames" table)
90+
return (
91+
<div className="flex items-start space-x-4 p-2 border-b border-gray-200 last:border-b-0">
92+
<div className="w-48 flex-shrink-0 font-semibold text-gray-800 break-all">{argName}</div>
93+
<div className="w-48 flex-shrink-0 text-gray-600">{argData.type}</div>
94+
<div className="flex-1 font-mono text-sm">
95+
{typeof argData.value !== 'object' || argData.value === null ?
96+
<span>{String(argData.value)}</span> :
97+
<pre className="text-xs whitespace-pre-wrap break-all">{JSON.stringify(argData, null, 2)}</pre>
98+
}
99+
</div>
100+
</div>
101+
);
102+
};
103+
104+
// Main container component
105+
const ArgumentViewer: React.FC<{ args: Record<string, any>; isDiffViewer?: boolean; }> = ({ args, isDiffViewer = false }) => {
106+
if (!args || Object.keys(args).length === 0) {
107+
return <div className="text-sm text-gray-500 p-2">No arguments to display.</div>;
108+
}
109+
110+
// A "complex view" is needed if we are showing diffs and at least one of them is a complex argument_diff
111+
const isComplexView = isDiffViewer && Object.values(args).some(arg => arg.diff_type === 'argument_diff');
112+
113+
return (
114+
<div className="border border-gray-200 rounded-md bg-white">
115+
{/* Render header only for the simple, non-complex table view */}
116+
{!isComplexView && (
117+
<div className="flex items-center space-x-4 p-2 bg-gray-100 font-bold text-gray-800 border-b border-gray-200">
118+
<div className="w-48 flex-shrink-0">Argument Name</div>
119+
<div className="w-48 flex-shrink-0">Type</div>
120+
<div className="flex-1">Value</div>
121+
</div>
122+
)}
123+
124+
{/* Rows */}
125+
<div>
126+
{Object.entries(args).map(([argName, argData]) => (
127+
<ArgumentRow key={argName} argName={argName} argData={argData} isDiffViewer={isDiffViewer} />
128+
))}
129+
</div>
130+
</div>
131+
);
132+
};
133+
134+
export default ArgumentViewer;

website/src/components/DiffViewer.tsx

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import ArgumentViewer from "./ArgumentViewer";
2+
import React from "react";
3+
import StackDiffViewer from "./StackDiffViewer";
4+
5+
interface DiffViewerProps {
6+
diffs: any;
7+
}
8+
9+
const DiffViewer: React.FC<DiffViewerProps> = ({ diffs }) => {
10+
if (!diffs || Object.keys(diffs).length === 0) {
11+
return (
12+
<p className="text-sm text-gray-500">No differing fields detected.</p>
13+
);
14+
}
15+
16+
// Separate different kinds of diffs
17+
const extractedArgs = diffs.extracted_args;
18+
const stackDiff = diffs.stack;
19+
const otherDiffs = Object.fromEntries(
20+
Object.entries(diffs).filter(
21+
([key]) => key !== "extracted_args" && key !== "stack"
22+
)
23+
);
24+
25+
const renderSimpleDiff = (_key: string, data: any) => {
26+
if (data.diff_type === "summary") {
27+
return <p className="font-mono text-sm text-gray-800">{data.summary_text}</p>;
28+
}
29+
if (data.diff_type === "distribution") {
30+
return (
31+
<ul className="list-disc list-inside pl-2 text-sm">
32+
{data.values.map((item: any, index: number) => {
33+
const launchRanges = item.launches
34+
.map((r: any) =>
35+
r.start === r.end
36+
? `${r.start + 1}`
37+
: `${r.start + 1}-${r.end + 1}`
38+
)
39+
.join(", ");
40+
return (
41+
<li key={index} className="font-mono text-gray-800 break-all">
42+
<span className="font-mono bg-gray-100 px-1 rounded">
43+
{JSON.stringify(item.value)}
44+
</span>
45+
<span className="text-gray-500 text-xs ml-2">
46+
({item.count} times, in launches: {launchRanges})
47+
</span>
48+
</li>
49+
);
50+
})}
51+
</ul>
52+
);
53+
}
54+
// Fallback for unexpected structures
55+
return <pre>{JSON.stringify(data, null, 2)}</pre>;
56+
};
57+
58+
return (
59+
<div className="space-y-4">
60+
{extractedArgs && Object.keys(extractedArgs).length > 0 && (
61+
<div>
62+
<h5 className="text-md font-semibold mb-2 text-gray-700">
63+
Extracted Arguments
64+
</h5>
65+
<ArgumentViewer args={extractedArgs} isDiffViewer={true} />
66+
</div>
67+
)}
68+
69+
{Object.keys(otherDiffs).length > 0 && (
70+
<div>
71+
<h5 className="text-md font-semibold mb-2 text-gray-700">
72+
Other Differing Fields
73+
</h5>
74+
<div className="space-y-3">
75+
{Object.entries(otherDiffs).map(([key, value]) => (
76+
<div
77+
key={key}
78+
className="w-full p-2 bg-white rounded border border-gray-200"
79+
>
80+
<span className="text-sm font-medium text-gray-600 block mb-1 break-all">
81+
{key}
82+
</span>
83+
<div className="pl-4">{renderSimpleDiff(key, value)}</div>
84+
</div>
85+
))}
86+
</div>
87+
</div>
88+
)}
89+
90+
{stackDiff && <StackDiffViewer stackDiff={stackDiff} />}
91+
92+
</div>
93+
);
94+
};
95+
96+
export default DiffViewer;
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import React, { useState } from 'react';
2+
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
3+
import { oneLight } from 'react-syntax-highlighter/dist/esm/styles/prism';
4+
5+
// A single frame of a stack trace
6+
const StackTraceFrame: React.FC<{ frame: any }> = ({ frame }) => (
7+
<div className="font-mono text-xs break-all">
8+
<span className="text-gray-500">{frame.filename}</span>:
9+
<span className="font-semibold text-blue-600">{frame.line}</span> in{" "}
10+
<span className="font-semibold text-green-700">{frame.name}</span>
11+
{frame.line_code && (
12+
<div className="pl-6 mt-1 bg-gray-100 rounded">
13+
<SyntaxHighlighter
14+
language="python"
15+
style={oneLight}
16+
customStyle={{
17+
margin: 0,
18+
padding: '0.25em 0.5em',
19+
fontSize: '0.75rem',
20+
background: 'transparent'
21+
}}
22+
>
23+
{frame.line_code}
24+
</SyntaxHighlighter>
25+
</div>
26+
)}
27+
</div>
28+
);
29+
30+
31+
const StackDiffViewer: React.FC<{ stackDiff: any }> = ({ stackDiff }) => {
32+
const [isCollapsed, setIsCollapsed] = useState(true);
33+
34+
if (!stackDiff || stackDiff.diff_type !== 'distribution') {
35+
return null;
36+
}
37+
38+
return (
39+
<div>
40+
<h5
41+
className="text-md font-semibold mb-2 text-gray-700 cursor-pointer flex items-center"
42+
onClick={() => setIsCollapsed(!isCollapsed)}
43+
>
44+
Stack Traces
45+
{/* Dropdown arrow icon */}
46+
<svg
47+
className={`w-4 h-4 ml-2 transform transition-transform ${isCollapsed ? '' : 'rotate-90'}`}
48+
fill="none"
49+
stroke="currentColor"
50+
viewBox="0 0 24 24"
51+
xmlns="http://www.w3.org/2000/svg"
52+
>
53+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M9 5l7 7-7 7"></path>
54+
</svg>
55+
</h5>
56+
{!isCollapsed && (
57+
<div className="space-y-2">
58+
{stackDiff.values.map((item: any, index: number) => {
59+
const launchRanges = item.launches
60+
.map((r: any) => (r.start === r.end ? `${r.start + 1}` : `${r.start + 1}-${r.end + 1}`))
61+
.join(", ");
62+
63+
return (
64+
<div key={index} className="bg-white p-2 rounded border border-gray-200">
65+
<p className="text-xs font-semibold text-gray-600 mb-1">
66+
Variant seen {item.count} times (in launches: {launchRanges})
67+
</p>
68+
<div className="space-y-1 bg-gray-50 p-1 rounded">
69+
{Array.isArray(item.value) ? item.value.map((frame: any, frameIndex: number) => (
70+
<StackTraceFrame key={frameIndex} frame={frame} />
71+
)) : <p>Invalid stack format</p>}
72+
</div>
73+
</div>
74+
);
75+
})}
76+
</div>
77+
)}
78+
</div>
79+
);
80+
};
81+
82+
export default StackDiffViewer;

0 commit comments

Comments
 (0)