perf(pos): R2R-сборка + замеры первого запуска Windows + Defender-гайд

- Публикация win-x64 с ReadyToRun (по одному RID, nice — dev-vm не уронили).
- Замеры на Windows-VM: первый запуск (свежая распаковка) 3.8–5.4 с (было 7.5 с),
  прогретый 219 мс. Первый запуск упирается в Defender (скан свежего неподписанного
  114 МБ exe) + холодное чтение диска, не в JIT.
- docs/pos.md: раздел «первый запуск медленный — что делать» (исключение Defender,
  прогрев при установке, подпись exe). Trimming оставлен выкл. (Avalonia на рефлексии).
- Мелочь: убран warning CS8826 (имена параметров partial-методов смены).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
nns 2026-10-08 09:44:06 +05:00
parent 6b959ac59d
commit 9cca062061
3 changed files with 25 additions and 4 deletions

View file

@ -137,7 +137,14 @@ Testcontainers) + headless UI (Avalonia.Headless, 15 проверок) + офл
## Доводка 08.10 (по итогам проверки Mac-Claude)
1. [ ] Настоящий GUI-тест на Windows 11 (интерактивная сессия tester) + скриншоты реального окна.
2. [ ] Первый запуск на Windows 7.5с → <2с: R2R-сборка, trimming, замеры; Defender — в docs.
2. [x] R2R-сборка win-x64 (один RID, nice, чтобы не уронить dev-vm — 2.3Gi free + swap, ОК).
Замеры первого запуска на Windows-VM: **первый (свежая распаковка) 3.8–5.4 с** (было 7.5 с
без R2R), **прогретый 219 мс** (было 143–168). Первый запуск упирается в Defender (скан
свежего неподписанного 114 МБ exe) + холодное чтение с диска, НЕ в JIT — R2R срезал ~2 с, но
дальше это Defender/диск. Митигации в docs/pos.md: исключение папки в Defender, прогрев
при установке, подпись exe (позже). Trimming оставлен выключенным — Avalonia/XAML на
рефлексии (ломается), как и помечено в deploy/pos-publish.sh. «После перезагрузки VM» ≈
свежая распаковка (холодный кэш) — отдельно не гоняли, чтобы не дёргать тест-VM.
3. [ ] Выбор точки продаж при регистрации устройства (список активных, сохранение, смена — админ).
4. [ ] Быстрый вход кассира по PIN (4–6 цифр), хэш на сервере, блок после 5 ошибок.
5. [ ] Возврат по чеку — полноценный экран выбора позиций + тесты.

View file

@ -87,4 +87,18 @@ Linux x64. Быстрая, без лишнего; офлайн-режим; се
## Производительность (замеры)
- Поиск по штрихкоду — ~14 мс, по названию на 30 000 товаров — ~47 мс (локальный SQLite с индексами).
- Первичная загрузка 30 000 товаров — ~9 с (однократно при настройке).
- Сборка self-contained + ReadyToRun; замеры холодного старта — см. docs/pos-progress.md.
- Сборка self-contained + ReadyToRun (R2R). Холодный старт: Linux ~120 мс; Windows
прогретый — **~220 мс** (R2R) / ~150 мс (без R2R).
### Первый запуск на Windows медленный (4–5 с) — что делать
Самый первый запуск кассы сразу после установки занимает 4–5 с (с R2R; без R2R было
7,5 с). Это НЕ код кассы: Windows Defender на лету сканирует свежий неподписанный
exe (~114 МБ, self-contained), плюс холодное чтение файла с диска. Каждый следующий
запуск — ~0,2 с. Как ускорить первый запуск на кассовом ПК:
1. **Исключение в Defender** для папки кассы (одноразово, администратором):
`Add-MpPreference -ExclusionPath "C:\food-market-pos"` (PowerShell от админа).
2. **Прогрев при установке** — установщик может один раз запустить `foodmarket.Pos.exe`
(например, `--smoke`) после распаковки, чтобы Defender просканировал файлы заранее.
3. **Подпись exe** (code signing) — позже; подписанный бинарник Defender сканирует
быстрее и не держит пользователя на SmartScreen.
Замеры холодного старта (Linux/Windows, R2R и без) — см. docs/pos-progress.md.

View file

@ -568,8 +568,8 @@ public partial class ShiftViewModel : ViewModelBase
public decimal ExpectedCash => ShiftMath.ExpectedCash(OpeningFloat, SalesCash, ReturnsCash, DrawerIn, DrawerOut);
public decimal Difference => ShiftMath.CashDifference(ActualCash, ExpectedCash);
partial void OnOpeningFloatChanged(decimal v) => RaiseCalc();
partial void OnActualCashChanged(decimal v) => RaiseCalc();
partial void OnOpeningFloatChanged(decimal value) => RaiseCalc();
partial void OnActualCashChanged(decimal value) => RaiseCalc();
private void RaiseCalc() { OnPropertyChanged(nameof(ExpectedCash)); OnPropertyChanged(nameof(Difference)); }
/// <summary>Сообщить оболочке новый номер смены (или null — закрыта).</summary>