2026-09-19 00:12:30 +00:00
|
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
|
|
use App\Models\BenchmarkRun;
|
|
|
|
|
|
use Illuminate\Support\Facades\Cache;
|
|
|
|
|
|
use Livewire\Attributes\Computed;
|
|
|
|
|
|
use Livewire\Component;
|
|
|
|
|
|
use Livewire\WithPagination;
|
|
|
|
|
|
|
2026-10-05 03:18:21 +00:00
|
|
|
|
new class extends Component
|
|
|
|
|
|
{
|
2026-09-19 00:12:30 +00:00
|
|
|
|
use WithPagination;
|
|
|
|
|
|
|
|
|
|
|
|
public array $filters = [
|
2026-10-05 04:37:33 +00:00
|
|
|
|
'gpu' => [],
|
|
|
|
|
|
'model' => [],
|
|
|
|
|
|
'quant' => [],
|
|
|
|
|
|
'engine' => [],
|
|
|
|
|
|
'suite' => [],
|
2026-09-19 00:12:30 +00:00
|
|
|
|
];
|
|
|
|
|
|
|
2026-10-07 10:22:07 +00:00
|
|
|
|
/** @var array<int, bool> session_summary_id => expanded */
|
|
|
|
|
|
public array $expanded = [];
|
|
|
|
|
|
|
2026-10-05 04:37:33 +00:00
|
|
|
|
public function updatedFilters(): void
|
|
|
|
|
|
{
|
|
|
|
|
|
$this->resetPage();
|
2026-10-07 10:22:07 +00:00
|
|
|
|
$this->expanded = [];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public function toggleExpand(int $sessionId): void
|
|
|
|
|
|
{
|
|
|
|
|
|
$this->expanded[$sessionId] = ! ($this->expanded[$sessionId] ?? false);
|
2026-10-05 04:37:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-19 00:12:30 +00:00
|
|
|
|
public function resetFilters(): void
|
|
|
|
|
|
{
|
2026-10-05 04:37:33 +00:00
|
|
|
|
$this->filters = [
|
|
|
|
|
|
'gpu' => [],
|
|
|
|
|
|
'model' => [],
|
|
|
|
|
|
'quant' => [],
|
|
|
|
|
|
'engine' => [],
|
|
|
|
|
|
'suite' => [],
|
|
|
|
|
|
];
|
|
|
|
|
|
$this->resetPage();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public function toggleFilter(string $field, string $value): void
|
|
|
|
|
|
{
|
|
|
|
|
|
if (! array_key_exists($field, $this->filters)) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
$this->filters[$field] = array_values(array_unique(
|
|
|
|
|
|
in_array($value, $this->filters[$field], true)
|
|
|
|
|
|
? array_diff($this->filters[$field], [$value])
|
|
|
|
|
|
: array_merge($this->filters[$field], [$value])
|
|
|
|
|
|
));
|
|
|
|
|
|
|
2026-09-19 00:12:30 +00:00
|
|
|
|
$this->resetPage();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-10-05 04:37:33 +00:00
|
|
|
|
public function filterLabel(string $field): string
|
|
|
|
|
|
{
|
|
|
|
|
|
$count = count($this->filters[$field] ?? []);
|
|
|
|
|
|
|
|
|
|
|
|
return $count === 0 ? '' : ' ('.$count.')';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-19 00:12:30 +00:00
|
|
|
|
#[Computed]
|
|
|
|
|
|
public function sessions()
|
|
|
|
|
|
{
|
|
|
|
|
|
$ttl = (int) config('festbench.home_cache_ttl', 300);
|
|
|
|
|
|
$user = auth()->user();
|
|
|
|
|
|
// Guest views are shared-cacheable; logged-in views may contain the
|
|
|
|
|
|
// user's private bands, so they get a user-scoped key.
|
|
|
|
|
|
$cacheKey = 'summary:'.($user?->id ?? 'guest').':'.md5(json_encode([$this->filters, $this->getPage()]));
|
|
|
|
|
|
|
|
|
|
|
|
return Cache::remember($cacheKey, $ttl, function () use ($user) {
|
|
|
|
|
|
$bands = $this->bandQuery($user)->paginate(10);
|
|
|
|
|
|
|
|
|
|
|
|
$runIds = $bands->getCollection()->map(fn ($b) => $b->id)->all();
|
|
|
|
|
|
$suiteRows = $runIds === []
|
|
|
|
|
|
? collect()
|
|
|
|
|
|
: \Illuminate\Support\Facades\DB::table('session_suite_rows')
|
|
|
|
|
|
->whereIn('session_summary_id', $runIds)
|
|
|
|
|
|
->orderBy('sequence')
|
|
|
|
|
|
->get()
|
|
|
|
|
|
->groupBy('session_summary_id');
|
|
|
|
|
|
|
|
|
|
|
|
$bands->getCollection()->transform(fn ($band) => (object) [
|
|
|
|
|
|
'band' => $band,
|
|
|
|
|
|
'suites' => $suiteRows->get($band->id, collect()),
|
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
|
|
return $bands;
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private function bandQuery($user)
|
|
|
|
|
|
{
|
|
|
|
|
|
return \Illuminate\Support\Facades\DB::table('session_summaries')
|
|
|
|
|
|
->where(function ($q) use ($user) {
|
|
|
|
|
|
$q->where('visibility', 'public');
|
|
|
|
|
|
if ($user !== null) {
|
|
|
|
|
|
$q->orWhere(function ($own) use ($user) {
|
|
|
|
|
|
$own->where('visibility', 'private')->where('user_id', $user->id);
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
2026-10-05 04:37:33 +00:00
|
|
|
|
->when($this->filters['gpu'], fn ($q, array $gpus) => $q->whereIn('gpu', $gpus))
|
|
|
|
|
|
->when($this->filters['model'], fn ($q, array $models) => $q->whereIn('model_id', $models))
|
|
|
|
|
|
->when($this->filters['quant'], fn ($q, array $quants) => $q->whereIn('model_quant', $quants))
|
|
|
|
|
|
->when($this->filters['engine'], fn ($q, array $engines) => $q->whereIn('engine', $engines))
|
|
|
|
|
|
->when($this->filters['suite'], fn ($q, array $suites) => $q->whereExists(function ($sub) use ($suites) {
|
2026-09-19 00:12:30 +00:00
|
|
|
|
$sub->select(\Illuminate\Support\Facades\DB::raw(1))
|
|
|
|
|
|
->from('session_suite_rows')
|
|
|
|
|
|
->whereColumn('session_suite_rows.session_summary_id', 'session_summaries.id')
|
2026-10-05 04:37:33 +00:00
|
|
|
|
->whereIn('session_suite_rows.suite', $suites);
|
2026-09-19 00:12:30 +00:00
|
|
|
|
}))
|
|
|
|
|
|
->orderByDesc('ran_at')
|
|
|
|
|
|
->orderBy('sequence');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-10-05 04:37:33 +00:00
|
|
|
|
#[Computed]
|
|
|
|
|
|
public function gpus(): array
|
|
|
|
|
|
{
|
|
|
|
|
|
return Cache::remember('summary:gpus', 300, function () {
|
|
|
|
|
|
return \Illuminate\Support\Facades\DB::table('session_summaries')
|
|
|
|
|
|
->where('visibility', 'public')
|
|
|
|
|
|
->whereNotNull('gpu')
|
|
|
|
|
|
->distinct()->orderBy('gpu')->pluck('gpu')->all();
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-19 00:12:30 +00:00
|
|
|
|
#[Computed]
|
|
|
|
|
|
public function models(): array
|
|
|
|
|
|
{
|
|
|
|
|
|
return Cache::remember('summary:models', 300, function () {
|
|
|
|
|
|
return \Illuminate\Support\Facades\DB::table('session_summaries')
|
|
|
|
|
|
->where('visibility', 'public')
|
2026-10-05 04:37:33 +00:00
|
|
|
|
->whereNotNull('model_id')
|
2026-09-19 00:12:30 +00:00
|
|
|
|
->distinct()->orderBy('model_id')->pluck('model_id')->all();
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-10-05 04:37:33 +00:00
|
|
|
|
#[Computed]
|
|
|
|
|
|
public function quants(): array
|
|
|
|
|
|
{
|
|
|
|
|
|
return Cache::remember('summary:quants', 300, function () {
|
|
|
|
|
|
return \Illuminate\Support\Facades\DB::table('session_summaries')
|
|
|
|
|
|
->where('visibility', 'public')
|
|
|
|
|
|
->whereNotNull('model_quant')
|
|
|
|
|
|
->distinct()->orderBy('model_quant')->pluck('model_quant')->all();
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[Computed]
|
|
|
|
|
|
public function engines(): array
|
|
|
|
|
|
{
|
|
|
|
|
|
return Cache::remember('summary:engines', 300, function () {
|
|
|
|
|
|
return \Illuminate\Support\Facades\DB::table('session_summaries')
|
|
|
|
|
|
->where('visibility', 'public')
|
|
|
|
|
|
->whereNotNull('engine')
|
|
|
|
|
|
->distinct()->orderBy('engine')->pluck('engine')->all();
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-19 00:12:30 +00:00
|
|
|
|
#[Computed]
|
|
|
|
|
|
public function suites(): array
|
|
|
|
|
|
{
|
|
|
|
|
|
return Cache::remember('summary:suites', 300, function () {
|
|
|
|
|
|
return \Illuminate\Support\Facades\DB::table('session_suite_rows')
|
|
|
|
|
|
->join('session_summaries', 'session_summaries.id', '=', 'session_suite_rows.session_summary_id')
|
|
|
|
|
|
->where('session_summaries.visibility', 'public')
|
|
|
|
|
|
->distinct()->orderBy('suite')->pluck('suite')->all();
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
?>
|
|
|
|
|
|
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<div class="flex items-center justify-between">
|
|
|
|
|
|
<div>
|
2026-09-30 13:50:59 +00:00
|
|
|
|
<flux:heading size="xl">{{ __('FestBench - Benchmarks') }}</flux:heading>
|
2026-10-07 10:22:07 +00:00
|
|
|
|
<flux:subheading>{{ __('GPU, model, suite scores — click a total to expand benchmark rows.') }}</flux:subheading>
|
2026-09-19 00:12:30 +00:00
|
|
|
|
</div>
|
|
|
|
|
|
<flux:button variant="ghost" icon="table-cells" href="{{ route('results') }}" wire:navigate>{{ __('All task rows') }}</flux:button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="mt-6 flex flex-wrap items-end gap-3">
|
2026-10-05 04:37:33 +00:00
|
|
|
|
@php
|
|
|
|
|
|
$filterGroups = [
|
|
|
|
|
|
['field' => 'gpu', 'label' => __('GPU'), 'options' => $this->gpus],
|
|
|
|
|
|
['field' => 'model', 'label' => __('Model'), 'options' => $this->models],
|
|
|
|
|
|
['field' => 'quant', 'label' => __('Quant'), 'options' => $this->quants],
|
|
|
|
|
|
['field' => 'engine', 'label' => __('Inference engine'), 'options' => $this->engines],
|
|
|
|
|
|
['field' => 'suite', 'label' => __('Suite'), 'options' => $this->suites],
|
|
|
|
|
|
];
|
|
|
|
|
|
@endphp
|
|
|
|
|
|
|
|
|
|
|
|
@foreach ($filterGroups as $group)
|
|
|
|
|
|
<flux:dropdown position="bottom" align="start">
|
|
|
|
|
|
<flux:button size="sm" variant="outline" class="justify-between {{ count($this->filters[$group['field']]) > 0 ? 'border-sky-400 text-sky-600 dark:border-sky-500 dark:text-sky-400' : '' }}">
|
|
|
|
|
|
{{ $group['label'] }}{{ $this->filterLabel($group['field']) }}
|
|
|
|
|
|
<flux:icon.chevron-down variant="mini" />
|
|
|
|
|
|
</flux:button>
|
|
|
|
|
|
|
|
|
|
|
|
<flux:menu class="min-w-48 max-h-72 overflow-y-auto p-1">
|
|
|
|
|
|
@foreach ($group['options'] as $option)
|
|
|
|
|
|
@php $checked = in_array($option, $this->filters[$group['field']], true); @endphp
|
|
|
|
|
|
<flux:menu.item
|
|
|
|
|
|
wire:click="toggleFilter('{{ $group['field'] }}', '{{ addslashes($option) }}')"
|
|
|
|
|
|
class="cursor-pointer"
|
|
|
|
|
|
>
|
|
|
|
|
|
<span class="flex items-center gap-2">
|
|
|
|
|
|
@if ($checked)
|
|
|
|
|
|
<flux:icon.check variant="mini" class="size-4 text-sky-500" />
|
|
|
|
|
|
@else
|
|
|
|
|
|
<span class="size-4"></span>
|
|
|
|
|
|
@endif
|
|
|
|
|
|
<span class="text-sm">{{ $option }}</span>
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</flux:menu.item>
|
|
|
|
|
|
@endforeach
|
|
|
|
|
|
</flux:menu>
|
|
|
|
|
|
</flux:dropdown>
|
|
|
|
|
|
@endforeach
|
2026-09-19 00:12:30 +00:00
|
|
|
|
|
|
|
|
|
|
<flux:button size="sm" variant="ghost" wire:click="resetFilters" icon="x-mark">{{ __('Clear') }}</flux:button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
@if ($this->sessions->count() > 0)
|
|
|
|
|
|
<div class="mt-6 flex flex-col gap-4">
|
|
|
|
|
|
@foreach ($this->sessions as $session)
|
2026-10-07 10:22:07 +00:00
|
|
|
|
@php $isExpanded = $this->expanded[$session->band->id] ?? false; @endphp
|
2026-09-19 00:12:30 +00:00
|
|
|
|
<flux:card class="!p-0">
|
|
|
|
|
|
<div class="flex flex-wrap items-center gap-x-4 gap-y-1 border-b border-zinc-200 px-4 py-3 dark:border-zinc-700">
|
|
|
|
|
|
<flux:icon name="cpu" class="size-4 text-zinc-500" />
|
|
|
|
|
|
<span class="text-sm font-semibold">{{ $session->band->gpu ?? 'unknown GPU' }}</span>
|
|
|
|
|
|
@if ($session->band->gpu_count)
|
|
|
|
|
|
<flux:badge size="xs" color="zinc">×{{ $session->band->gpu_count }}</flux:badge>
|
|
|
|
|
|
@endif
|
|
|
|
|
|
<span class="text-sm">{{ $session->band->model_id ?? 'unknown model' }}</span>
|
2026-09-21 02:49:23 +00:00
|
|
|
|
@if ($session->band->label)
|
|
|
|
|
|
<flux:badge size="xs" color="amber">{{ $session->band->label }}</flux:badge>
|
2026-10-05 03:18:21 +00:00
|
|
|
|
@endif
|
|
|
|
|
|
@if ($session->band->model_quant)
|
|
|
|
|
|
<flux:badge size="xs" color="zinc">{{ $session->band->model_quant }}</flux:badge>
|
|
|
|
|
|
@endif
|
|
|
|
|
|
@if ($session->band->engine)
|
|
|
|
|
|
<flux:badge size="xs" color="sky">{{ $session->band->engine }}</flux:badge>
|
|
|
|
|
|
@endif
|
2026-09-19 00:12:30 +00:00
|
|
|
|
<flux:spacer />
|
|
|
|
|
|
<span class="text-sm text-zinc-500">{{ $session->band->runner_name ?? 'anonymous' }}</span>
|
|
|
|
|
|
<span class="text-xs text-zinc-400">{{ optional($session->band->ran_at)->format('M j Y') }}</span>
|
|
|
|
|
|
</div>
|
2026-10-05 04:20:19 +00:00
|
|
|
|
@php
|
|
|
|
|
|
$devlogicSuites = ['softbench', 'prosebench', 'psychbench', 'depthsweep'];
|
|
|
|
|
|
$sysopsSuites = ['infrabench', 'scenariobench'];
|
2026-10-05 04:47:04 +00:00
|
|
|
|
$suiteFilterActive = ! empty($this->filters['suite']);
|
|
|
|
|
|
$visibleSuites = $suiteFilterActive
|
|
|
|
|
|
? $session->suites->filter(fn ($r) => in_array($r->suite, $this->filters['suite'], true))
|
|
|
|
|
|
: $session->suites;
|
|
|
|
|
|
$devlogicRows = $visibleSuites->filter(fn ($r) => in_array($r->suite, $devlogicSuites));
|
|
|
|
|
|
$sysopsRows = $visibleSuites->filter(fn ($r) => in_array($r->suite, $sysopsSuites));
|
2026-10-07 10:22:07 +00:00
|
|
|
|
$hasDevlogic = $devlogicRows->isNotEmpty() && ($suiteFilterActive || $session->band->devlogic_tps !== null);
|
|
|
|
|
|
$hasSysops = $sysopsRows->isNotEmpty() && ($suiteFilterActive || $session->band->sysops_tps !== null);
|
2026-10-05 04:20:19 +00:00
|
|
|
|
@endphp
|
2026-10-07 10:22:07 +00:00
|
|
|
|
{{-- Devlogic section: total strip (click to expand) + suite rows (when expanded) --}}
|
|
|
|
|
|
@if ($hasDevlogic)
|
2026-10-05 04:47:04 +00:00
|
|
|
|
@unless ($suiteFilterActive)
|
2026-10-07 10:22:07 +00:00
|
|
|
|
<button type="button"
|
|
|
|
|
|
wire:click="toggleExpand({{ $session->band->id }})"
|
|
|
|
|
|
class="flex w-full flex-wrap items-center gap-x-4 gap-y-1 border-l-2 border-sky-400 bg-sky-50/50 px-4 py-2 text-left transition hover:bg-sky-50 dark:border-sky-500 dark:bg-sky-950/20 dark:hover:bg-sky-950/40"
|
|
|
|
|
|
>
|
|
|
|
|
|
<flux:icon name="{{ $isExpanded ? 'chevron-down' : 'chevron-right' }}" variant="mini" class="size-4 text-sky-500" />
|
2026-10-05 04:20:19 +00:00
|
|
|
|
<span class="text-xs font-semibold uppercase tracking-wider text-sky-600 dark:text-sky-400">{{ __('Devlogic total') }}</span>
|
|
|
|
|
|
<span class="text-sm">
|
|
|
|
|
|
<span class="font-mono font-semibold">{{ number_format($session->band->devlogic_tps, 1) }}</span>
|
|
|
|
|
|
<span class="text-xs text-zinc-400">{{ __('tok/s') }}</span>
|
|
|
|
|
|
</span>
|
|
|
|
|
|
<span class="text-sm">
|
|
|
|
|
|
<span class="font-mono font-semibold">{{ number_format($session->band->devlogic_tokens) }}</span>
|
|
|
|
|
|
<span class="text-xs text-zinc-400">{{ __('tokens') }}</span>
|
|
|
|
|
|
</span>
|
|
|
|
|
|
<span class="text-sm">
|
|
|
|
|
|
<flux:badge size="xs" color="emerald">✔ {{ $session->band->devlogic_passed }}</flux:badge>
|
|
|
|
|
|
<flux:badge size="xs" color="{{ $session->band->devlogic_failed > 0 ? 'rose' : 'zinc' }}">✘ {{ $session->band->devlogic_failed }}</flux:badge>
|
|
|
|
|
|
</span>
|
2026-10-07 10:22:07 +00:00
|
|
|
|
</button>
|
2026-10-05 04:47:04 +00:00
|
|
|
|
@endunless
|
2026-10-07 10:22:07 +00:00
|
|
|
|
@if ($isExpanded || $suiteFilterActive)
|
2026-10-05 04:20:19 +00:00
|
|
|
|
<div class="hidden px-4 pt-2 md:grid md:grid-cols-[7.5rem_4.5rem_7rem_15rem_6rem_1fr] md:gap-x-4 md:items-center">
|
|
|
|
|
|
<span class="text-[10px] font-semibold uppercase tracking-wider text-zinc-400">{{ __('Benchmark') }}</span>
|
|
|
|
|
|
<span class="text-[10px] font-semibold uppercase tracking-wider text-zinc-400">{{ __('Thinking') }}</span>
|
|
|
|
|
|
<span class="text-[10px] font-semibold uppercase tracking-wider text-zinc-400">{{ __('Result') }}</span>
|
|
|
|
|
|
<span class="text-[10px] font-semibold uppercase tracking-wider text-zinc-400">{{ __('Speed (tok/s)') }} <span class="font-normal normal-case">{{ __('weighted average') }}</span></span>
|
|
|
|
|
|
<span class="text-[10px] font-semibold uppercase tracking-wider text-zinc-400">{{ __('Tokens') }}</span>
|
|
|
|
|
|
<span></span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="divide-y divide-zinc-100 dark:divide-zinc-800">
|
|
|
|
|
|
@foreach ($devlogicRows as $row)
|
|
|
|
|
|
@php
|
|
|
|
|
|
$detailUrl = $row->suite === 'scenariobench'
|
|
|
|
|
|
? route('sessions.scenarios', $session->band->id)
|
|
|
|
|
|
: route('runs.show', $row->run_id) . ($row->level && $row->suite === 'depthsweep' ? '?level=' . $row->level : '');
|
|
|
|
|
|
@endphp
|
|
|
|
|
|
<a href="{{ $detailUrl }}" wire:navigate
|
|
|
|
|
|
class="flex flex-wrap items-center gap-x-4 gap-y-1 px-4 py-2.5 hover:bg-zinc-50 dark:hover:bg-zinc-800/60 md:grid md:grid-cols-[7.5rem_4.5rem_7rem_15rem_6rem_1fr] md:gap-x-4 md:items-center">
|
|
|
|
|
|
<span><flux:badge size="xs">{{ $row->suite }}</flux:badge></span>
|
|
|
|
|
|
<span>
|
|
|
|
|
|
@if ($row->level)
|
|
|
|
|
|
<flux:badge size="xs" color="sky">{{ $row->level }}</flux:badge>
|
|
|
|
|
|
@endif
|
Split band total into Devlogic and Sysops; remove config badge
Replace the single Band total with two adjacent metric groups:
- Devlogic total: softbench, prosebench, psychbench, depthsweep
(all non-infra, non-scenario suites)
- Sysops total: infrabench + scenariobench
Each group independently shows geo-mean tok/s, total tokens, and
pass/fail counts. Scenariobench contributes per-observation
gen_tokens/wall rates to the sysops geo-mean.
Remove the server-config badge (e.g. 'llama.cpp DFlash spec-decode,
131k ctx, fa on') from the front-page card header. Label, quant, and
engine badges remain.
Migration drops the old total_* columns and adds devlogic_* and
sysops_* columns to session_summaries.
2026-10-05 03:38:13 +00:00
|
|
|
|
</span>
|
2026-10-05 04:20:19 +00:00
|
|
|
|
<span class="flex items-center gap-1.5">
|
|
|
|
|
|
<flux:badge size="xs" color="emerald">✔ {{ $row->passed }}</flux:badge>
|
|
|
|
|
|
<flux:badge size="xs" color="{{ $row->failed > 0 ? 'rose' : 'zinc' }}">✘ {{ $row->failed }}</flux:badge>
|
Split band total into Devlogic and Sysops; remove config badge
Replace the single Band total with two adjacent metric groups:
- Devlogic total: softbench, prosebench, psychbench, depthsweep
(all non-infra, non-scenario suites)
- Sysops total: infrabench + scenariobench
Each group independently shows geo-mean tok/s, total tokens, and
pass/fail counts. Scenariobench contributes per-observation
gen_tokens/wall rates to the sysops geo-mean.
Remove the server-config badge (e.g. 'llama.cpp DFlash spec-decode,
131k ctx, fa on') from the front-page card header. Label, quant, and
engine badges remain.
Migration drops the old total_* columns and adds devlogic_* and
sysops_* columns to session_summaries.
2026-10-05 03:38:13 +00:00
|
|
|
|
</span>
|
2026-10-05 04:20:19 +00:00
|
|
|
|
<span>
|
|
|
|
|
|
@if ($row->weighted_user_tps !== null)
|
|
|
|
|
|
<span class="font-mono text-sm">{{ number_format($row->weighted_user_tps, 1) }}</span>
|
|
|
|
|
|
@elseif ($row->gen_tps !== null)
|
|
|
|
|
|
<span class="font-mono text-sm">{{ number_format($row->gen_tps, 1) }} <span class="text-xs text-zinc-400">{{ __('gen') }}</span></span>
|
|
|
|
|
|
@endif
|
Split band total into Devlogic and Sysops; remove config badge
Replace the single Band total with two adjacent metric groups:
- Devlogic total: softbench, prosebench, psychbench, depthsweep
(all non-infra, non-scenario suites)
- Sysops total: infrabench + scenariobench
Each group independently shows geo-mean tok/s, total tokens, and
pass/fail counts. Scenariobench contributes per-observation
gen_tokens/wall rates to the sysops geo-mean.
Remove the server-config badge (e.g. 'llama.cpp DFlash spec-decode,
131k ctx, fa on') from the front-page card header. Label, quant, and
engine badges remain.
Migration drops the old total_* columns and adds devlogic_* and
sysops_* columns to session_summaries.
2026-10-05 03:38:13 +00:00
|
|
|
|
</span>
|
2026-10-05 04:20:19 +00:00
|
|
|
|
<span class="font-mono text-sm">{{ number_format($row->total_tokens) }}</span>
|
|
|
|
|
|
<span class="text-xs text-zinc-400 md:justify-self-end">{{ __('per-task detail') }} →</span>
|
|
|
|
|
|
</a>
|
|
|
|
|
|
@endforeach
|
|
|
|
|
|
</div>
|
2026-10-07 10:22:07 +00:00
|
|
|
|
@endif
|
2026-10-05 04:20:19 +00:00
|
|
|
|
@endif
|
2026-10-07 10:22:07 +00:00
|
|
|
|
{{-- Sysops section: total strip (click to expand) + suite rows (when expanded) --}}
|
|
|
|
|
|
@if ($hasSysops)
|
2026-10-05 04:47:04 +00:00
|
|
|
|
@unless ($suiteFilterActive)
|
2026-10-07 10:22:07 +00:00
|
|
|
|
<button type="button"
|
|
|
|
|
|
wire:click="toggleExpand({{ $session->band->id }})"
|
|
|
|
|
|
class="flex w-full flex-wrap items-center gap-x-4 gap-y-1 border-l-2 border-amber-400 bg-amber-50/50 px-4 py-2 text-left transition hover:bg-amber-50 dark:border-amber-500 dark:bg-amber-950/20 dark:hover:bg-amber-950/40"
|
|
|
|
|
|
>
|
|
|
|
|
|
<flux:icon name="{{ $isExpanded ? 'chevron-down' : 'chevron-right' }}" variant="mini" class="size-4 text-amber-500" />
|
2026-10-05 04:20:19 +00:00
|
|
|
|
<span class="text-xs font-semibold uppercase tracking-wider text-amber-600 dark:text-amber-400">{{ __('Sysops total') }}</span>
|
|
|
|
|
|
<span class="text-sm">
|
|
|
|
|
|
<span class="font-mono font-semibold">{{ number_format($session->band->sysops_tps, 1) }}</span>
|
|
|
|
|
|
<span class="text-xs text-zinc-400">{{ __('tok/s') }}</span>
|
|
|
|
|
|
</span>
|
|
|
|
|
|
<span class="text-sm">
|
|
|
|
|
|
<span class="font-mono font-semibold">{{ number_format($session->band->sysops_tokens) }}</span>
|
|
|
|
|
|
<span class="text-xs text-zinc-400">{{ __('tokens') }}</span>
|
|
|
|
|
|
</span>
|
|
|
|
|
|
<span class="text-sm">
|
|
|
|
|
|
<flux:badge size="xs" color="emerald">✔ {{ $session->band->sysops_passed }}</flux:badge>
|
|
|
|
|
|
<flux:badge size="xs" color="{{ $session->band->sysops_failed > 0 ? 'rose' : 'zinc' }}">✘ {{ $session->band->sysops_failed }}</flux:badge>
|
|
|
|
|
|
</span>
|
2026-10-07 10:22:07 +00:00
|
|
|
|
</button>
|
2026-10-05 04:47:04 +00:00
|
|
|
|
@endunless
|
2026-10-07 10:22:07 +00:00
|
|
|
|
@if ($isExpanded || $suiteFilterActive)
|
2026-10-05 04:20:19 +00:00
|
|
|
|
<div class="hidden px-4 pt-2 md:grid md:grid-cols-[7.5rem_4.5rem_7rem_15rem_6rem_1fr] md:gap-x-4 md:items-center">
|
|
|
|
|
|
<span class="text-[10px] font-semibold uppercase tracking-wider text-zinc-400">{{ __('Benchmark') }}</span>
|
|
|
|
|
|
<span class="text-[10px] font-semibold uppercase tracking-wider text-zinc-400">{{ __('Thinking') }}</span>
|
|
|
|
|
|
<span class="text-[10px] font-semibold uppercase tracking-wider text-zinc-400">{{ __('Result') }}</span>
|
|
|
|
|
|
<span class="text-[10px] font-semibold uppercase tracking-wider text-zinc-400">{{ __('Speed (tok/s)') }} <span class="font-normal normal-case">{{ __('weighted average') }}</span></span>
|
|
|
|
|
|
<span class="text-[10px] font-semibold uppercase tracking-wider text-zinc-400">{{ __('Tokens') }}</span>
|
|
|
|
|
|
<span></span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="divide-y divide-zinc-100 dark:divide-zinc-800">
|
|
|
|
|
|
@foreach ($sysopsRows as $row)
|
|
|
|
|
|
@php
|
|
|
|
|
|
$detailUrl = $row->suite === 'scenariobench'
|
|
|
|
|
|
? route('sessions.scenarios', $session->band->id)
|
|
|
|
|
|
: route('runs.show', $row->run_id) . ($row->level && $row->suite === 'depthsweep' ? '?level=' . $row->level : '');
|
|
|
|
|
|
@endphp
|
|
|
|
|
|
<a href="{{ $detailUrl }}" wire:navigate
|
|
|
|
|
|
class="flex flex-wrap items-center gap-x-4 gap-y-1 px-4 py-2.5 hover:bg-zinc-50 dark:hover:bg-zinc-800/60 md:grid md:grid-cols-[7.5rem_4.5rem_7rem_15rem_6rem_1fr] md:gap-x-4 md:items-center">
|
|
|
|
|
|
<span><flux:badge size="xs">{{ $row->suite }}</flux:badge></span>
|
|
|
|
|
|
<span>
|
|
|
|
|
|
@if ($row->level)
|
|
|
|
|
|
<flux:badge size="xs" color="sky">{{ $row->level }}</flux:badge>
|
|
|
|
|
|
@endif
|
Split band total into Devlogic and Sysops; remove config badge
Replace the single Band total with two adjacent metric groups:
- Devlogic total: softbench, prosebench, psychbench, depthsweep
(all non-infra, non-scenario suites)
- Sysops total: infrabench + scenariobench
Each group independently shows geo-mean tok/s, total tokens, and
pass/fail counts. Scenariobench contributes per-observation
gen_tokens/wall rates to the sysops geo-mean.
Remove the server-config badge (e.g. 'llama.cpp DFlash spec-decode,
131k ctx, fa on') from the front-page card header. Label, quant, and
engine badges remain.
Migration drops the old total_* columns and adds devlogic_* and
sysops_* columns to session_summaries.
2026-10-05 03:38:13 +00:00
|
|
|
|
</span>
|
2026-10-05 04:20:19 +00:00
|
|
|
|
<span class="flex items-center gap-1.5">
|
|
|
|
|
|
<flux:badge size="xs" color="emerald">✔ {{ $row->passed }}</flux:badge>
|
|
|
|
|
|
<flux:badge size="xs" color="{{ $row->failed > 0 ? 'rose' : 'zinc' }}">✘ {{ $row->failed }}</flux:badge>
|
Split band total into Devlogic and Sysops; remove config badge
Replace the single Band total with two adjacent metric groups:
- Devlogic total: softbench, prosebench, psychbench, depthsweep
(all non-infra, non-scenario suites)
- Sysops total: infrabench + scenariobench
Each group independently shows geo-mean tok/s, total tokens, and
pass/fail counts. Scenariobench contributes per-observation
gen_tokens/wall rates to the sysops geo-mean.
Remove the server-config badge (e.g. 'llama.cpp DFlash spec-decode,
131k ctx, fa on') from the front-page card header. Label, quant, and
engine badges remain.
Migration drops the old total_* columns and adds devlogic_* and
sysops_* columns to session_summaries.
2026-10-05 03:38:13 +00:00
|
|
|
|
</span>
|
2026-10-05 04:20:19 +00:00
|
|
|
|
<span>
|
|
|
|
|
|
@if ($row->weighted_user_tps !== null)
|
|
|
|
|
|
<span class="font-mono text-sm">{{ number_format($row->weighted_user_tps, 1) }}</span>
|
|
|
|
|
|
@elseif ($row->gen_tps !== null)
|
|
|
|
|
|
<span class="font-mono text-sm">{{ number_format($row->gen_tps, 1) }} <span class="text-xs text-zinc-400">{{ __('gen') }}</span></span>
|
|
|
|
|
|
@endif
|
Split band total into Devlogic and Sysops; remove config badge
Replace the single Band total with two adjacent metric groups:
- Devlogic total: softbench, prosebench, psychbench, depthsweep
(all non-infra, non-scenario suites)
- Sysops total: infrabench + scenariobench
Each group independently shows geo-mean tok/s, total tokens, and
pass/fail counts. Scenariobench contributes per-observation
gen_tokens/wall rates to the sysops geo-mean.
Remove the server-config badge (e.g. 'llama.cpp DFlash spec-decode,
131k ctx, fa on') from the front-page card header. Label, quant, and
engine badges remain.
Migration drops the old total_* columns and adds devlogic_* and
sysops_* columns to session_summaries.
2026-10-05 03:38:13 +00:00
|
|
|
|
</span>
|
2026-10-05 04:20:19 +00:00
|
|
|
|
<span class="font-mono text-sm">{{ number_format($row->total_tokens) }}</span>
|
|
|
|
|
|
<span class="text-xs text-zinc-400 md:justify-self-end">{{ __('per-task detail') }} →</span>
|
|
|
|
|
|
</a>
|
|
|
|
|
|
@endforeach
|
2026-09-30 19:47:01 +00:00
|
|
|
|
</div>
|
2026-10-07 10:22:07 +00:00
|
|
|
|
@endif
|
2026-09-30 19:47:01 +00:00
|
|
|
|
@endif
|
2026-09-19 00:12:30 +00:00
|
|
|
|
</flux:card>
|
|
|
|
|
|
@endforeach
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="mt-4">
|
|
|
|
|
|
{{ $this->sessions->links() }}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
@else
|
|
|
|
|
|
<div class="mt-6">
|
|
|
|
|
|
<flux:callout variant="brand">
|
|
|
|
|
|
<flux:callout.heading>{{ __('No sessions') }}</flux:callout.heading>
|
|
|
|
|
|
<flux:callout.text>{{ __('No benchmark sessions match the current filters.') }}</flux:callout.text>
|
|
|
|
|
|
</flux:callout>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
@endif
|
|
|
|
|
|
</div>
|