-
-
Notifications
You must be signed in to change notification settings - Fork 38
feat: Resolve benchmark github action #1886
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
79a5061
f71862a
25f021a
8433ec0
1326e7b
d87db81
daabfcd
1bd8e14
5a0293a
5d5b565
918547f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,91 @@ | ||
| name: Measure resolve duration | ||
|
|
||
| on: | ||
| workflow_dispatch: | ||
|
|
||
| env: | ||
| BENCHMARK_REPO: software-mansion-labs/typegpu-benchmarker | ||
|
|
||
| jobs: | ||
| measure: | ||
| runs-on: ubuntu-latest | ||
|
|
||
| steps: | ||
| - name: Clone benchmarking repo | ||
| uses: actions/checkout@v5 | ||
| with: | ||
| repository: ${{ env.BENCHMARK_REPO }} | ||
| ref: main | ||
| token: ${{ secrets.BENCHMARKER_REPO_ACCESS_TOKEN }} | ||
|
|
||
| - name: Install pnpm | ||
| uses: pnpm/action-setup@v4 | ||
| with: | ||
| run_install: false | ||
|
|
||
| - name: Install Node.js 22.x | ||
| uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: 22.x | ||
| cache: 'pnpm' | ||
|
|
||
| - name: Install deps | ||
| run: | | ||
| pnpm install --frozen-lockfile | ||
| - name: Install Deno | ||
| uses: denoland/setup-deno@v2 | ||
| with: | ||
| deno-version: v2.x | ||
|
|
||
| - name: Run benchmarks | ||
| run: | | ||
| pnpm run measure | ||
| - name: Save benchmark results across the jobs | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: data | ||
| path: benchmarks | ||
| plot: | ||
| runs-on: ubuntu-latest | ||
| needs: measure | ||
|
|
||
| steps: | ||
| - name: Clone benchmarking repo | ||
| uses: actions/checkout@v5 | ||
| with: | ||
| repository: ${{ env.BENCHMARK_REPO }} | ||
| ref: main | ||
| token: ${{ secrets.BENCHMARKER_REPO_ACCESS_TOKEN }} | ||
|
|
||
| - name: Install pnpm | ||
| uses: pnpm/action-setup@v4 | ||
| with: | ||
| run_install: false | ||
|
|
||
| - name: Download benchmark data | ||
| uses: actions/download-artifact@v4 | ||
| with: | ||
| name: data | ||
| path: benchmarks | ||
|
|
||
| - name: Setup Python | ||
| uses: actions/setup-python@v5 | ||
| with: | ||
| python-version: '>=3.11' | ||
|
|
||
| - name: Create venv | ||
| run: | | ||
| python3 -m venv .venv | ||
| - name: Plot | ||
| shell: bash | ||
| run: | | ||
| . .venv/bin/activate | ||
| pip install -r requirements.txt | ||
| pnpm run plot | ||
| - name: Commit and push results and plot | ||
| run: | | ||
| git config user.name "github-actions" | ||
| git config user.email "[email protected]" | ||
| git add . | ||
| git commit -m "Automated benchmark update" || echo "No changes" | ||
| git push origin main |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,123 @@ | ||||||||||||||||||||||||
| import { ChevronLeft, ChevronRight } from 'lucide-react'; | ||||||||||||||||||||||||
| import { useCallback, useEffect, useState } from 'react'; | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| const plots = [ | ||||||||||||||||||||||||
| 'https://raw.githubusercontent.com/software-mansion-labs/typegpu-benchmarker/main/plots/combined-resolveDuration-full.png', | ||||||||||||||||||||||||
| 'https://raw.githubusercontent.com/software-mansion-labs/typegpu-benchmarker/main/plots/combined-resolveDuration-full-log.png', | ||||||||||||||||||||||||
| 'https://raw.githubusercontent.com/software-mansion-labs/typegpu-benchmarker/main/plots/combined-resolveDuration-latest5.png', | ||||||||||||||||||||||||
| 'https://raw.githubusercontent.com/software-mansion-labs/typegpu-benchmarker/main/plots/combined-resolveDuration-under10k.png', | ||||||||||||||||||||||||
| ]; | ||||||||||||||||||||||||
| const slideCount = plots.length; | ||||||||||||||||||||||||
| const extendedPlots = [plots[slideCount - 1], ...plots, plots[0]]; | ||||||||||||||||||||||||
| const extendedSlideCount = extendedPlots.length; | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| function PlotSlide({ url }: { url: string }) { | ||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||
| <div className='flex h-[60vh] max-h-[50vw] w-full flex-shrink-0 justify-center'> | ||||||||||||||||||||||||
| <img | ||||||||||||||||||||||||
| className='h-full rounded-2xl object-contain' | ||||||||||||||||||||||||
| src={`${url}?t=${Date.now()}`} // TODO: proper versioning ;) | ||||||||||||||||||||||||
| alt={`${new URL(url).pathname.split('/').pop()}`} | ||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| const buttonUtilityClasses = | ||||||||||||||||||||||||
| '-translate-y-1/2 absolute top-1/2 rounded-full border border-gray-700 bg-gray-800 p-4 text-gray-150 transition-all duration-300 ease-in-out hover:bg-gray-700 hover:text-white active:bg-gray-500 active:text-white z-1'; | ||||||||||||||||||||||||
| const chevronUtilityClasses = 'w-4 h-4 sm:w-8 sm:h-8'; | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| export default function PlotGallery() { | ||||||||||||||||||||||||
| const [currentIndex, setCurrentIndex] = useState(1); | ||||||||||||||||||||||||
| const [isTransitioning, setIsTransitioning] = useState(false); | ||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
I would go for this - isTransitioning does not need to cause re-renders and it will simplify transition handling |
||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| const nextSlide = useCallback((isTransitioning: boolean) => { | ||||||||||||||||||||||||
| if (isTransitioning) return; | ||||||||||||||||||||||||
| setIsTransitioning(true); | ||||||||||||||||||||||||
| setCurrentIndex((prev) => prev + 1); // to avoid deps | ||||||||||||||||||||||||
| }, []); | ||||||||||||||||||||||||
|
Comment on lines
+34
to
+38
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. + const slideCount = plots.length;
Suggested change
|
||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| const prevSlide = useCallback((isTransitioning: boolean) => { | ||||||||||||||||||||||||
| if (isTransitioning) return; | ||||||||||||||||||||||||
| setIsTransitioning(true); | ||||||||||||||||||||||||
| setCurrentIndex((prev) => prev - 1); | ||||||||||||||||||||||||
| }, []); | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| const handleTransitionEnd = useCallback((index: number) => { | ||||||||||||||||||||||||
| setIsTransitioning(false); | ||||||||||||||||||||||||
| if (index === 0) { | ||||||||||||||||||||||||
| setCurrentIndex(slideCount); | ||||||||||||||||||||||||
| } else if (index === extendedSlideCount - 1) { | ||||||||||||||||||||||||
| setCurrentIndex(1); | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| }, []); | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| const goToSlide = useCallback((index: number, isTransitioning: boolean) => { | ||||||||||||||||||||||||
| if (isTransitioning) return; | ||||||||||||||||||||||||
| setIsTransitioning(true); | ||||||||||||||||||||||||
| setCurrentIndex(index + 1); | ||||||||||||||||||||||||
| }, []); | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| const getActualIndex = (): number => { | ||||||||||||||||||||||||
| if (currentIndex === 0) return slideCount - 1; | ||||||||||||||||||||||||
| if (currentIndex === extendedSlideCount - 1) return 0; | ||||||||||||||||||||||||
| return currentIndex - 1; | ||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| useEffect(() => { | ||||||||||||||||||||||||
| // TODO: add touch handling | ||||||||||||||||||||||||
| const handleKeyDown = (event: KeyboardEvent) => { | ||||||||||||||||||||||||
| if (event.key === 'ArrowLeft') prevSlide(isTransitioning); | ||||||||||||||||||||||||
| if (event.key === 'ArrowRight') nextSlide(isTransitioning); | ||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||
| window.addEventListener('keydown', handleKeyDown); | ||||||||||||||||||||||||
| return () => window.removeEventListener('keydown', handleKeyDown); | ||||||||||||||||||||||||
| }, [prevSlide, nextSlide, isTransitioning]); | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||
| <div className='relative flex-grow overflow-hidden'> | ||||||||||||||||||||||||
| <button | ||||||||||||||||||||||||
| className={`left-4 ${buttonUtilityClasses}`} | ||||||||||||||||||||||||
| type='button' | ||||||||||||||||||||||||
| onClick={() => prevSlide(isTransitioning)} | ||||||||||||||||||||||||
| > | ||||||||||||||||||||||||
| <ChevronLeft className={chevronUtilityClasses} /> | ||||||||||||||||||||||||
| </button> | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| <button | ||||||||||||||||||||||||
| className={`right-4 ${buttonUtilityClasses}`} | ||||||||||||||||||||||||
| type='button' | ||||||||||||||||||||||||
| onClick={() => nextSlide(isTransitioning)} | ||||||||||||||||||||||||
| > | ||||||||||||||||||||||||
| <ChevronRight className={chevronUtilityClasses} /> | ||||||||||||||||||||||||
| </button> | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| <div | ||||||||||||||||||||||||
| className={`flex h-full w-full transition-transform duration-200 ease-in-out ${ | ||||||||||||||||||||||||
| isTransitioning ? '' : 'transition-none' // this is necessary for smooth wrapping | ||||||||||||||||||||||||
| }`} | ||||||||||||||||||||||||
| style={{ transform: `translateX(-${currentIndex * 100}%)` }} | ||||||||||||||||||||||||
| onTransitionEnd={() => handleTransitionEnd(currentIndex)} | ||||||||||||||||||||||||
| > | ||||||||||||||||||||||||
| {extendedPlots.map((url, index) => ( | ||||||||||||||||||||||||
| <PlotSlide key={`slide-${index}-${url}`} url={url} /> | ||||||||||||||||||||||||
| ))} | ||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| <div className='-translate-x-1/2 absolute bottom-17 left-1/2 flex space-x-3'> | ||||||||||||||||||||||||
| {plots.map((url, index) => ( | ||||||||||||||||||||||||
| <button | ||||||||||||||||||||||||
| key={`dot-${index}-${url}`} | ||||||||||||||||||||||||
| type='button' | ||||||||||||||||||||||||
| onClick={() => goToSlide(index, isTransitioning)} | ||||||||||||||||||||||||
| className={`h-4 w-4 rounded-full transition-all duration-200 ease-in-out ${ | ||||||||||||||||||||||||
| index === getActualIndex() | ||||||||||||||||||||||||
| ? 'scale-125 bg-gray-500' | ||||||||||||||||||||||||
| : 'bg-gray-800 hover:bg-gray-700' | ||||||||||||||||||||||||
| }`} | ||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||
| ))} | ||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see that the page does not respond to the light theme, but /benchmark acts the same so we may ignore it (at least until the landing page rework) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| --- | ||
| import { Image } from "astro:assets"; | ||
| import PageLayout from "../../layouts/PageLayout.astro"; | ||
| import PlotGallery from "../../components/resolve/PlotGallery.tsx"; | ||
| import TypeGPULogoDark from "../../assets/typegpu-logo-dark.svg"; | ||
| --- | ||
|
|
||
| <PageLayout title="TypeGPU functions resolve complexity | TypeGPU" theme="dark"> | ||
| <main class="h-[100dvh] flex flex-col"> | ||
| <h1 class="flex items-center justify-center"> | ||
| <a href="/TypeGPU"> | ||
| <Image src={TypeGPULogoDark} alt="TypeGPU Logo" class="w-40" /> | ||
| </a> | ||
| <p class="text-lg font-sans text-gray-300">— resolve complexity</p> | ||
| </h1> | ||
|
|
||
| <PlotGallery client:only="react" /> | ||
| </main> | ||
| </PageLayout> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a little over-engineered but since it's for dev I don't really mind it (all the comments are just general feedback for learning purposes).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I appreciate the feedback. I deleted
useMemo, but I can't changeisTransitioningtouseRef.isTransitioningstate plays a crucial role in smooth carousel wrap when we transition from the last plot -> to the first plot (and first -> last).isTransitioningto false, and change the index to real plot (not the guarding one)