From 78f5d3f2fea9a74d485bd2226a313b485652dab6 Mon Sep 17 00:00:00 2001 From: Jad Chahed Date: Thu, 4 Jul 2024 22:38:52 +0200 Subject: [PATCH 01/16] feat: hero without daily summary Signed-off-by: Jad Chahed --- website/src/common/DailySummary.tsx | 67 +++++++++++++ website/src/pages/HomePage/HomePage.tsx | 6 +- .../src/pages/HomePage/components/Hero.tsx | 99 ------------------- .../HomePage/components/HomePageHero.tsx | 98 ++++++++++++++++++ 4 files changed, 167 insertions(+), 103 deletions(-) create mode 100644 website/src/common/DailySummary.tsx delete mode 100644 website/src/pages/HomePage/components/Hero.tsx create mode 100644 website/src/pages/HomePage/components/HomePageHero.tsx diff --git a/website/src/common/DailySummary.tsx b/website/src/common/DailySummary.tsx new file mode 100644 index 000000000..d6ce9c5ff --- /dev/null +++ b/website/src/common/DailySummary.tsx @@ -0,0 +1,67 @@ +import PropTypes from "prop-types"; +import { ResponsiveLine } from "@nivo/line"; +import { twMerge } from "tailwind-merge"; +import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card"; + +const DailySummary = ({ data, setBenchmarktype, benchmarkType }) => { + const orange = "#E77002"; + + const transformedData = []; + + if (data.data !== null) { + transformedData.push({ + id: "QPSTotal", + data: data.data.map((item) => ({ + y: item.total_qps.center, + })), + }); + } + + const getBenchmarkType = () => { + setBenchmarktype(data.name); + }; + + return ( + + + {data.name} + + + {data ? ( +
+ +
+ ) : null} +
+ +
+
+
+ ); +}; + +DailySummary.propTypes = { + data: PropTypes.shape({ + name: PropTypes.string.isRequired, + data: PropTypes.array, + }), + setBenchmarktype: PropTypes.func.isRequired, + isSelected: PropTypes.bool, +}; + +export default DailySummary; diff --git a/website/src/pages/HomePage/HomePage.tsx b/website/src/pages/HomePage/HomePage.tsx index 9b68ca3e0..608904d74 100644 --- a/website/src/pages/HomePage/HomePage.tsx +++ b/website/src/pages/HomePage/HomePage.tsx @@ -14,9 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React from "react"; - -import Hero from "./components/Hero"; +import HomePageHero from "./components/HomePageHero"; import HowItWorks from "./components/HowItWorks"; import Diagram from "./components/Diagram"; import HeroMobile from "./components/HeroMobile"; @@ -24,7 +22,7 @@ import HeroMobile from "./components/HeroMobile"; export default function HomePage() { return ( <> - + {/**/} diff --git a/website/src/pages/HomePage/components/Hero.tsx b/website/src/pages/HomePage/components/Hero.tsx deleted file mode 100644 index 66f1bea49..000000000 --- a/website/src/pages/HomePage/components/Hero.tsx +++ /dev/null @@ -1,99 +0,0 @@ -/* -Copyright 2023 The Vitess Authors. - -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. -*/ -import React from "react"; -import { Link } from "react-router-dom"; -import Icon from "../../../common/Icon"; -import { Button } from "@/components/ui/button"; - -export default function Hero() { - return ( -
-
-
-
-
-
-
-

arewefastyet

-

- A Benchmarking System for Vitess -

-
-
- - - -
-
-
-
- logo -
-
- ); -} diff --git a/website/src/pages/HomePage/components/HomePageHero.tsx b/website/src/pages/HomePage/components/HomePageHero.tsx new file mode 100644 index 000000000..f8244d2a6 --- /dev/null +++ b/website/src/pages/HomePage/components/HomePageHero.tsx @@ -0,0 +1,98 @@ +import { Link } from "react-router-dom"; +import Icon from "@/common/Icon"; +import { Button } from "@/components/ui/button"; +import DailySummary from "@/common/DailySummary"; +import useApiCall from "@/utils/Hook"; +import { MacroDataValue } from "@/types"; + +interface DailySummarydata { + name: string; + data : { total_qps: MacroDataValue }[]; +} + +export default function HomePageHero() { + const { + data: dataDailySummary, + isLoading: isLoadingDailySummary, + error: errorDailySummary, + } = useApiCall(`${import.meta.env.VITE_API_URL}daily/summary`); + + return ( +
+

+ Benchmarking
+ System for
+ Vitess +

+
+ + + +
+

+ Historical results on the main{" "} + branch +

+ {/*
+ + +
*/} + + See more historical results {">"} + +
+ ); +} From 060d56681d884b3cdf316bbd121f7bede87f8834 Mon Sep 17 00:00:00 2001 From: Jad Chahed Date: Thu, 4 Jul 2024 23:27:03 +0200 Subject: [PATCH 02/16] feat: homepage desktop Signed-off-by: Jad Chahed --- package.json | 5 + website/src/components/ui/separator.tsx | 31 +++++ website/src/pages/HomePage/HomePage.tsx | 5 +- .../src/pages/HomePage/components/Diagram.tsx | 46 ++----- .../pages/HomePage/components/HowItWorks.tsx | 124 ++++++++---------- yarn.lock | 29 ++++ 6 files changed, 136 insertions(+), 104 deletions(-) create mode 100644 package.json create mode 100644 website/src/components/ui/separator.tsx create mode 100644 yarn.lock diff --git a/package.json b/package.json new file mode 100644 index 000000000..4a1c30804 --- /dev/null +++ b/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "@radix-ui/react-separator": "^1.1.0" + } +} diff --git a/website/src/components/ui/separator.tsx b/website/src/components/ui/separator.tsx new file mode 100644 index 000000000..b8b9c4be8 --- /dev/null +++ b/website/src/components/ui/separator.tsx @@ -0,0 +1,31 @@ +"use client" + +import * as React from "react" +import * as SeparatorPrimitive from "@radix-ui/react-separator" + +import { cn } from "@/library/utils" + +const Separator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>( + ( + { className, orientation = "horizontal", decorative = true, ...props }, + ref + ) => ( + + ) +) +Separator.displayName = SeparatorPrimitive.Root.displayName + +export { Separator } diff --git a/website/src/pages/HomePage/HomePage.tsx b/website/src/pages/HomePage/HomePage.tsx index 608904d74..e1a0cdc86 100644 --- a/website/src/pages/HomePage/HomePage.tsx +++ b/website/src/pages/HomePage/HomePage.tsx @@ -18,14 +18,17 @@ import HomePageHero from "./components/HomePageHero"; import HowItWorks from "./components/HowItWorks"; import Diagram from "./components/Diagram"; import HeroMobile from "./components/HeroMobile"; +import { Separator } from "@/components/ui/separator" export default function HomePage() { return ( <> - + + {/* */} {/**/} + ); diff --git a/website/src/pages/HomePage/components/Diagram.tsx b/website/src/pages/HomePage/components/Diagram.tsx index dd12e694a..67472d17c 100644 --- a/website/src/pages/HomePage/components/Diagram.tsx +++ b/website/src/pages/HomePage/components/Diagram.tsx @@ -1,40 +1,20 @@ -/* -Copyright 2023 The Vitess Authors. - -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. -*/ -import React from "react"; +import { Card, CardContent } from "@/components/ui/card"; export default function Diagram() { return (
-

- Diagramatic Overview -

- -
- execution pipeline - - execution pipeline -
+

+ Architecture +

+ + + execution pipeline + +
); } diff --git a/website/src/pages/HomePage/components/HowItWorks.tsx b/website/src/pages/HomePage/components/HowItWorks.tsx index 3ab3bdd9e..046f09677 100644 --- a/website/src/pages/HomePage/components/HowItWorks.tsx +++ b/website/src/pages/HomePage/components/HowItWorks.tsx @@ -1,49 +1,61 @@ -/* -Copyright 2023 The Vitess Authors. +import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card"; +import { ReactNode } from "react"; +import { Link } from "react-router-dom"; -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 +type HowItWorksCardItem = { + title: string; + content: ReactNode; +}; - 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. -*/ -import React, { useEffect, useRef } from "react"; - -const items = [ +const items: HowItWorksCardItem[] = [ { - title: "The Execution Engine", - content: - "At the heart of arewefastyet is the Execution engine. It orchestrates the entire benchmarking process, ensuring accuracy and reproducibility on a large scale. Each benchmark run is initiated by new releases, new PRs, and new commits on main.", + title: "Workloads", + content: ( + <> + Seven workloads are executed against every commit we decide to benchmark. These workloads define the SQL schema, the queries we execute, the configuration of the Vitess cluster, and the configuration of sysbench. The settings of our workload can be found on the + arewefastyet repository +
+
+ We have two categories of workloads: OLTP and TPCC, both are a modified version of the official workloads. + + ) }, { - title: "Dedicated Benchmarking Servers", - content: - "arewefastyet relies on dedicated hardware provided by CNCF and Equinix Metal. Our benchmarking infrastructure uses large bare-metal servers, boosting benchmark reliability and accuracy.", + title: "Frequency", + content: ( + <> + There are three cron schedules that enable us to periodically benchmark Vitess, the definition of these schedules is + available in our yaml configuration +
+
+ Generally, we benchmark the main and release branches of Vitess every night at midnight UTC. We also detect new PRs that need to be benchmarked every five minutes, and new tags/releases every minute. + ) }, { - title: "Customized Benchmark Settings", - content: - "Different benchmarks demand distinct configurations. For instance, a macro-benchmark necessitates the setup of a Vitess cluster, while a micro-benchmark does not. The default setup for macro-benchmarks examines Vitess performance in a sharded keyspace with six VTGates and two VTTablets.", + title: "Methodology", + content: ( + <> + Each commit is benchmarked ten times by each workload. Under the hood, we use sysbench with a custom configuration to perform the benchmark. We then perform statistical analysis on the ten results of a given workload to get a more accurate and reliable result. +
+
+ Every execution is done on the same hardware: 192Gb of RAM and 2x Intel Xeon Silver 4214 Processor 24-Core @ 2.20GHz. + ) }, { - title: "Starting Benchmark Runs", - content: - "Once the server is ready, the final step is initiating the benchmark run. Ansible triggers arewefastyet's CLI to set the benchmark in motion. This comprehensive process, from YAML-based pipeline configuration to dynamic server setup, ensures that every benchmark run is accurate, reproducible, and adaptable to the unique demands of each benchmark type. arewefastyet streamlines the complexities of executing benchmarks against Vitess, offering a robust and precise benchmarking solution at scale.", - }, + title: "Results", + content: ( + <> +We collect the same results as sysbench (QPS, TPS, Error rate, latency, etc), along with several Golang metrics such as the CPU used per query, and the total memory used per query. + ) + + } ]; export default function HowItWorks() { return ( -
-
-

How it works

-
+
+

How it works

+
{items.map((item, key) => ( ))} @@ -52,43 +64,15 @@ export default function HowItWorks() { ); } -function HowItWorksCard(props) { - const cardRef = useRef(); - const glowRef = useRef(); - - function glowWithMouse(event) { - const cardRect = cardRef.current.getBoundingClientRect(); - glowRef.current.style.setProperty("--x", `${event.x - cardRect.x}px`); - glowRef.current.style.setProperty("--y", `${event.y - cardRect.y}px`); - } - - useEffect(() => { - const isSmallScreen = window.innerWidth < 768; - - if (!isSmallScreen) { - window.addEventListener("mousemove", glowWithMouse); - } - - return () => { - if (!isSmallScreen) { - window.removeEventListener("mousemove", glowWithMouse); - } - }; - }, []); - +function HowItWorksCard({ title, content }: { title: string; content: ReactNode }) { return ( -
-
-

{props.title}

-

{props.content}

-
+ + + {title} + + +

{content}

+
+
); } diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 000000000..f814a3212 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,29 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@radix-ui/react-compose-refs@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.0.tgz#656432461fc8283d7b591dcf0d79152fae9ecc74" + integrity sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw== + +"@radix-ui/react-primitive@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-2.0.0.tgz#fe05715faa9203a223ccc0be15dc44b9f9822884" + integrity sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw== + dependencies: + "@radix-ui/react-slot" "1.1.0" + +"@radix-ui/react-separator@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@radix-ui/react-separator/-/react-separator-1.1.0.tgz#ee0f4d86003b0e3ea7bc6ccab01ea0adee32663e" + integrity sha512-3uBAs+egzvJBDZAzvb/n4NxxOYpnspmWxO2u5NbZ8Y6FM/NdrGSF9bop3Cf6F6C71z1rTSn8KV0Fo2ZVd79lGA== + dependencies: + "@radix-ui/react-primitive" "2.0.0" + +"@radix-ui/react-slot@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.1.0.tgz#7c5e48c36ef5496d97b08f1357bb26ed7c714b84" + integrity sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw== + dependencies: + "@radix-ui/react-compose-refs" "1.1.0" From 01bf89f472437094c2935b38f058189036f16aa9 Mon Sep 17 00:00:00 2001 From: Jad Chahed Date: Mon, 8 Jul 2024 14:12:42 +0200 Subject: [PATCH 03/16] feat: wip dailySummary Signed-off-by: Jad Chahed --- website/package.json | 3 +- website/src/assets/styles/tailwind.css | 12 + website/src/common/DailySummary.tsx | 128 +++++-- website/src/components/ui/chart.tsx | 361 ++++++++++++++++++ website/src/hooks/useDailySummaryData.ts | 16 + website/src/pages/DailyPage/DailyPage.tsx | 22 +- website/src/pages/HomePage/HomePage.tsx | 3 - .../HomePage/components/HomePageChart.tsx | 99 +++++ .../HomePage/components/HomePageHero.tsx | 72 ++-- website/src/types/index.ts | 11 +- website/yarn.lock | 234 +++++++++++- 11 files changed, 875 insertions(+), 86 deletions(-) create mode 100644 website/src/components/ui/chart.tsx create mode 100644 website/src/hooks/useDailySummaryData.ts create mode 100644 website/src/pages/HomePage/components/HomePageChart.tsx diff --git a/website/package.json b/website/package.json index 6ed98070b..f4e1936e7 100644 --- a/website/package.json +++ b/website/package.json @@ -21,7 +21,7 @@ "class-variance-authority": "^0.7.0", "clsx": "^2.1.0", "dotenv": "^16.1.4", - "lucide-react": "^0.363.0", + "lucide-react": "^0.400.0", "moment": "^2.29.4", "react": "^18.2.0", "react-dom": "^18.2.0", @@ -29,6 +29,7 @@ "react-json-pretty": "^2.2.0", "react-router-dom": "^6.11.2", "react-spinners": "^0.13.8", + "recharts": "^2.12.7", "serve": "^14.2.0", "swiper": "^9.4.1", "tailwind-merge": "^2.2.2", diff --git a/website/src/assets/styles/tailwind.css b/website/src/assets/styles/tailwind.css index 63d4c5401..12e5d2c8e 100644 --- a/website/src/assets/styles/tailwind.css +++ b/website/src/assets/styles/tailwind.css @@ -50,6 +50,12 @@ limitations under the License. --ring: 24.6 95% 53.1%; --radius: 0.5rem; + --chart-1: 12 76% 61%; + --chart-2: 173 58% 39%; + --chart-3: 197 37% 24%; + --chart-4: 43 74% 66%; + --chart-5: 27 87% 67%; + --front: 0 0% 10%; --back: 0 0% 100%; @@ -86,6 +92,12 @@ limitations under the License. --ring: 20.5 90.2% 48.2%; --radius: 0.5rem; + --chart-1: 220 70% 50%; + --chart-2: 160 60% 45%; + --chart-3: 30 80% 55%; + --chart-4: 280 65% 60%; + --chart-5: 340 75% 55%; + --front: 0 0% 100%; --back: 0 0% 10%; diff --git a/website/src/common/DailySummary.tsx b/website/src/common/DailySummary.tsx index d6ce9c5ff..50fda43d0 100644 --- a/website/src/common/DailySummary.tsx +++ b/website/src/common/DailySummary.tsx @@ -1,56 +1,106 @@ +/* +Copyright 2024 The Vitess Authors. + +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. +*/ + import PropTypes from "prop-types"; -import { ResponsiveLine } from "@nivo/line"; -import { twMerge } from "tailwind-merge"; -import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card"; +import { Card, CardHeader, CardTitle, CardContent, CardFooter } from "@/components/ui/card"; +import { DailySummarydata } from "@/types"; +import { + ChartConfig, + ChartContainer, + ChartTooltip, + ChartTooltipContent, +} from "@/components/ui/chart" +import { TrendingUp } from "lucide-react" +import { CartesianGrid, Line, LineChart, XAxis } from "recharts" +import { Button } from "@/components/ui/button"; + + +export type DailySummaryProps = { + data: DailySummarydata; + benchmarkType: string; + setBenchmarktype: (type: string) => void; +} + +export default function DailySummary({ data, benchmarkType, setBenchmarktype }: DailySummaryProps) { + const chartData: any[] | undefined = []; -const DailySummary = ({ data, setBenchmarktype, benchmarkType }) => { - const orange = "#E77002"; + const chartConfig = { + desktop: { + label: "Desktop", + color: "hsl(var(--chart-1))", + }, + mobile: { + label: "Mobile", + color: "hsl(var(--chart-2))", + }, + } satisfies ChartConfig - const transformedData = []; if (data.data !== null) { - transformedData.push({ - id: "QPSTotal", - data: data.data.map((item) => ({ - y: item.total_qps.center, - })), - }); + data.data.map((item) => ({ + totalQps: chartData.push({ + totalQps: item.total_qps.center / 2, + }), + })); } const getBenchmarkType = () => { setBenchmarktype(data.name); }; + console.log(chartData) + return ( - + - {data.name} + {data.name} - - {data ? ( -
- + + + + } + /> + -
- ) : null} -
- -
+ +
+ + + +
); }; @@ -62,6 +112,4 @@ DailySummary.propTypes = { }), setBenchmarktype: PropTypes.func.isRequired, isSelected: PropTypes.bool, -}; - -export default DailySummary; +}; \ No newline at end of file diff --git a/website/src/components/ui/chart.tsx b/website/src/components/ui/chart.tsx new file mode 100644 index 000000000..4f613da21 --- /dev/null +++ b/website/src/components/ui/chart.tsx @@ -0,0 +1,361 @@ +import * as React from "react" +import * as RechartsPrimitive from "recharts" + +import { cn } from "@/library/utils" + +// Format: { THEME_NAME: CSS_SELECTOR } +const THEMES = { light: "", dark: ".dark" } as const + +export type ChartConfig = { + [k in string]: { + label?: React.ReactNode + icon?: React.ComponentType + } & ( + | { color?: string; theme?: never } + | { color?: never; theme: Record } + ) +} + +type ChartContextProps = { + config: ChartConfig +} + +const ChartContext = React.createContext(null) + +function useChart() { + const context = React.useContext(ChartContext) + + if (!context) { + throw new Error("useChart must be used within a ") + } + + return context +} + +const ChartContainer = React.forwardRef< + HTMLDivElement, + React.ComponentProps<"div"> & { + config: ChartConfig + children: React.ComponentProps< + typeof RechartsPrimitive.ResponsiveContainer + >["children"] + } +>(({ id, className, children, config, ...props }, ref) => { + const uniqueId = React.useId() + const chartId = `chart-${id || uniqueId.replace(/:/g, "")}` + + return ( + +
+ + + {children} + +
+
+ ) +}) +ChartContainer.displayName = "Chart" + +const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => { + const colorConfig = Object.entries(config).filter( + ([_, config]) => config.theme || config.color + ) + + if (!colorConfig.length) { + return null + } + + return ( +