Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 91 additions & 0 deletions .github/workflows/benchmark.yml
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
3 changes: 3 additions & 0 deletions apps/typegpu-docs/astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ export default defineConfig({
'Cross-Origin-Opener-Policy': 'same-origin',
},
},
image: {
domains: ['raw.githubusercontent.com'],
},
Comment on lines +39 to +41
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need that?

markdown: {
remarkPlugins: [remarkMath],
rehypePlugins: [rehypeMathJax],
Expand Down
128 changes: 128 additions & 0 deletions apps/typegpu-docs/src/components/resolve/PlotGallery.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import { ChevronLeft, ChevronRight } from 'lucide-react';
import { useCallback, useEffect, useMemo, 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',
];

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() {
// this is for infinite effect
const extendedPlots = useMemo(
() => [plots[plots.length - 1], ...plots, plots[0]],
[],
);

const [currentIndex, setCurrentIndex] = useState(1);
const [isTransitioning, setIsTransitioning] = useState(false);

const nextSlide = useCallback((isTransitioning: boolean) => {
if (isTransitioning) return;
setIsTransitioning(true);
setCurrentIndex((prev) => prev + 1); // to avoid deps
}, []);

const prevSlide = useCallback((isTransitioning: boolean) => {
console.log(isTransitioning);
if (isTransitioning) return;
setIsTransitioning(true);
setCurrentIndex((prev) => prev - 1);
}, []);

const handleTransitionEnd = useCallback((index: number) => {
setIsTransitioning(false);

if (index === 0) {
setCurrentIndex(plots.length);
} else if (index === extendedPlots.length - 1) {
setCurrentIndex(1);
}
}, [extendedPlots]);

const goToSlide = useCallback((index: number, isTransitioning: boolean) => {
if (isTransitioning) return;
setIsTransitioning(true);
setCurrentIndex(index + 1);
}, []);

const getActualIndex = (): number => {
if (currentIndex === 0) return plots.length - 1;
if (currentIndex === extendedPlots.length - 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 ending
}`}
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>
);
}
19 changes: 19 additions & 0 deletions apps/typegpu-docs/src/pages/resolve/index.astro
Copy link
Contributor

Choose a reason for hiding this comment

The 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>