Problemi principali per i titoli di Windows
Il gruppo Microsoft Windows Gaming and Graphics Technologies Developer Relations esegue l'analisi delle prestazioni per molti giochi di Windows ogni anno. Durante queste sessioni, si ottiene un'esperienza pratica per collegare il feedback e le query degli sviluppatori ricevuti ogni giorno. Occasionalmente aiutiamo a tenere traccia di un misterioso arresto anomalo o di un altro problema in un titolo, che ci offre ulteriori informazioni sui problemi riscontrati dagli sviluppatori.
Questo articolo evidenzia molti dei problemi comuni riscontrati nei giochi PC di generazione corrente.
- Prestazioni limitate dalla CPU
- Gestione batch scarsa
- Copia eccessiva della memoria
- Uso eccessivo dell'invio di disegno dinamico
- Sovraccarico elevato nell'elaborazione file
- Installazione lenta e frustrante
- Mancanza di considerazione della memoria fisica
- Over-Reliance on Real-Time Audio Sample Rate Conversion
- Frammento di memoria virtuale
- Manipolazione del controllo Floating-Point Word
- Installazione facoltativa del runtime DirectX
- Uso eccessivo della sincronizzazione dei thread
- Uso di RDTSC
prestazioni CPU-Limited
La maggior parte dei giochi è limitata dalle prestazioni della CPU nei sistemi con unità di elaborazione grafica ad alte prestazioni (GPU). Questo è talvolta dovuto a un uso insufficiente dell'invio in batch per gli invii di estrazione, ma più in genere, questo è dovuto ad altri sistemi di gioco che utilizzano una grande parte dei cicli di CPU disponibili. Nei pochi casi in cui abbiamo visto la GPU come limitazione, la causa è la frequenza di riempimento molto elevata o la richiesta di pixel shader, in impostazioni ad alta risoluzione o prestazioni del vertex shader basso da una scheda video.
Poiché la maggior parte dei titoli è limitata dalla CPU, le migliori prestazioni derivano dall'ottimizzazione dei sistemi di gioco a elevato utilizzo di CPU. In genere, i sistemi di intelligenza artificiale o fisica e la logica di rilevamento delle collisioni associati sono i consumer principali dei cicli della CPU nelle applicazioni Microsoft Direct3D. Qualsiasi lavoro per migliorare questi sistemi può migliorare le prestazioni complessive del gioco.
Gestione batch scarsa
Per ottenere un buon parallelismo con la GPU è necessario che i batch di disegno contengano una geometria sufficiente e che gli shader abbiano la giusta complessità, per mantenere la scheda video occupata, senza usare così tanti batch che il buffer dei comandi viene inondato. Nell'hardware di generazione corrente, è consigliabile inviare circa 300 invii batch di draw-batch per fotogramma (un minor numero di CPU a prestazioni inferiori) per impedire che l'elaborazione del buffer dei comandi del driver diventi un collo di bottiglia delle prestazioni. Alcune altre chiamate di stato API e combinazioni di driver possono comportare un'elaborazione costosa della CPU (ad esempio la compilazione del driver degli shader), quindi è consigliabile eseguire l'analisi delle prestazioni di routine.
Copia eccessiva della memoria
Durante lo sviluppo della maggior parte dei titoli pc, gli sviluppatori usano strutture di dati e stringhe utili per la gestione dei contenuti. Il lavoro della CPU necessario per il confronto tra stringhe, la copia e altre manipolazioni spesso comporta un sovraccarico misurabile, in particolare quando si prendono in considerazione i riscontri delle prestazioni associati al sottosistema cache e memoria. I piani devono essere eseguiti quando si sviluppano questi sistemi per rimuovere o ridurre al minimo la dipendenza dall'elaborazione di stringhe quando il prodotto entra nelle fasi principali di test e rilascio.
Uso eccessivo dell'invio di disegno dinamico
L'hardware video moderno funziona bene quando si gestiscono dati statici. Le schede di fascia alta hanno spesso una grande quantità di memoria video, ma questa memoria non può essere utilizzata in modo efficace dai dati dinamici.
Sebbene sia possibile implementare modelli di utilizzo ragionevolmente efficienti di buffer/buffer di indice dinamici per il contenuto dinamico, molti titoli utilizzano questo linguaggio per il contenuto altrimenti statico. Questo problema viene spesso visualizzato con alberi di partizionamento dello spazio binario (BSP) e sistemi basati sul portale che archiviano la geometria in una struttura di dati che non esegue il mapping all'hardware e devono essere elaborati in buffer per ogni fotogramma. L'inserimento del maggior contenuto in risorse statiche può ridurre notevolmente il sovraccarico di larghezza di banda del trasferimento dei dati nella scheda video, usare meglio VRAM su scheda virtuale e ridurre il sovraccarico della CPU/cache coinvolto nell'elaborazione di questo contenuto.
Sovraccarico elevato nell'elaborazione file
I giochi PC hanno ottenuto una reputazione per lunghi tempi di caricamento, particolare quando confrontati con i titoli della console con requisiti rigorosi in fase di caricamento. L'analisi del modo in cui molti titoli usano il sottosistema di file rivelano alcuni problemi comuni.
L'overhead dell'apertura di un file è in genere molto più elevato rispetto agli sviluppatori previsti. Con gli scanner antivirus su richiesta in uso diffuso e le funzionalità aggiuntive di NTFS, l'apertura di un file è un'operazione piuttosto costosa. L'apertura ripetuta di molti file o l'apertura e la chiusura dello stesso file è quindi un metodo scadente per gestire la gestione dei file. Alcuni giochi hanno tentato di attenuare questo costo delle prestazioni testando l'esistenza di un file prima di aprirlo. La realtà è che il test per l'esistenza di un file in NTFS richiede l'apertura del file, quindi il test prima dell'apertura comporta il pagamento del costo due volte.
I giochi che consentono modifiche al componente aggiuntivo, o mod, o che includono ancora lo scaffolding dello sviluppo per verificare la presenza di file di dati di override, possono avere ritardi significativi nel caricamento del gioco a causa del controllo di questi file, anche quando tali file non sono presenti. È consigliabile che i giochi controllino solo questi file quando vengono eseguiti con un'opzione della riga di comando speciale o un altro indicatore di modalità, in modo che solo gli utenti che usano questa funzionalità paghino effettivamente il costo delle prestazioni di questi controlli (spesso estesi).
Le prestazioni aggiuntive possono essere ottenute dal file system seguendo questa procedura:
- Uso appropriato degli hint del file system FILE_FLAG_RANDOM_ACCESS e FILE_FLAG_SEQUENTIAL_SCAN
- Ridimensionamento dei buffer per evitare una grande quantità di chiamate alle API di lettura/scrittura del sistema operativo
- Accesso ai file in modo asincrono
- Caricamento di thread in background
Consigliamo anche vivamente di convertire i dati offline (in fase di compilazione o installazione) invece di basarsi sulla conversione quando il gioco viene eseguito per la prima volta, in quanto impone un'imposta significativa sulle prestazioni per ogni utente.
Installazione lenta e frustrante
Un altro problema comune che abbiamo visto è tempi di installazione molto lunghi necessari per molti giochi PC moderni. I programmi di installazione richiedono più volte all'utente, talvolta semplicemente per indicare all'utente, ad esempio, "Non è necessario che DirectX sia installato". In genere, questi programmi di installazione incriminati richiedono all'utente di selezionare Avanti o OK molte volte prima dell'inizio dell'installazione del gioco. Una volta iniziato, alcuni titoli sono necessari un'ora o più prima che l'utente possa giocare al gioco. Ci sentiamo fortemente che la prima ora di esperienza di gioco non dovrebbe essere l'installazione.
È consigliabile adottare diversi approcci per gestire l'installazione. Prima di tutto, mantenere le richieste semplici e minime. In secondo luogo, progettare i dati del gioco in modo che alcuni o tutti i file di dati possano essere usati direttamente dal disco di distribuzione, dove possibile: le unità DVD moderne hanno una larghezza di banda molto elevata. In terzo luogo, è consigliabile implementare l'installazione su richiesta nei titoli per ridurre o eliminare il processo di installazione e consentire agli utenti di accedere al gioco il più rapidamente possibile. Per altre informazioni sull'installazione su richiesta, vedere Install-on-Demand for Games.
Per altre raccomandazioni sull'installazione del gioco, vedi Semplificare l'installazione del gioco.
Mancanza di considerazione della memoria fisica
A causa dell'ampia variabilità dell'hardware del PC sul mercato, i titoli in genere usano test di configurazione ad hoc per selezionare le impostazioni predefinite per il livello di dettaglio grafico. Alcuni dei titoli visti usano le dimensioni della memoria video in questi test, ma non riescono a correlarlo con le dimensioni della memoria fisica. Per gestire le situazioni di perdita del dispositivo, la maggior parte della memoria video (sia la VRAM locale nella scheda che l'apertura della memoria AGP non locale) deve essere supportata dalla memoria fisica, tramite l'uso di risorse gestite o strutture di dati personalizzate. Alcune schede video di fascia alta hanno dimensioni VRAM che rivalino con le dimensioni delle memorie CPU di fascia bassa. Nelle situazioni in cui il sistema ha memoria fisica limitata rispetto alla scheda video, la maggior parte di tale VRAM non può essere utilizzata in modo efficace e devono essere configurate impostazioni di dettaglio inferiori.
Over-Reliance alla conversione della frequenza di campionamento audio Real-Time
Un'altra fonte comune di burn del ciclo della CPU che abbiamo visto si verifica quando il sistema audio è necessario per convertire la frequenza di riproduzione durante la combinazione nel buffer hardware. Con i driver windows Driver Model (WDM), il formato del buffer hardware non è sotto il controllo diretto dell'applicazione, perché si tratta di una risorsa a livello di kernel; Il formato viene invece selezionato in base al formato di qualità più elevata di tutte le origini e alle funzionalità dell'hardware. Per impostazione predefinita, Windows XP usa una conversione della frequenza di campionamento di alta qualità per questo processo e se la maggior parte dei campioni audio richiede una conversione della frequenza, verrà utilizzata una parte significativa dei cicli della CPU.
È consigliabile creare tutti i buffer DirectSound con la stessa frequenza di campionamento. Se si usa qualsiasi funzione waveOut di Microsoft Win32, è consigliabile usare anche una frequenza di campionamento coerente con queste funzioni. Con i driver WDM, i buffer verranno tutti misti dal kernel e, se si usa una frequenza di campionamento più elevata in alcuni di essi, le frequenze di campionamento di tutti gli altri verranno convertite in modo che corrispondano. Si noti che questo implica l'uso della stessa frequenza di riproduzione per tutti i campioni audio, inclusi eventuali buffer di decompressione audio in streaming. L'impostazione della frequenza del buffer principale non ha alcun effetto a meno che non si abbia come destinazione Windows 98 o Windows Millennium Edition.
Nota
In Windows Vista e versioni successive del sistema operativo DirectSound e waveOut usano l'API Sessione audio di Windows (WASAPI) per tutti gli output audio.
Frammento di memoria virtuale
Sono stati riscontrati alcuni problemi recenti relativi al limite a 32 bit per lo spazio di memoria del processo. Anche se 2 GB di spazio indirizzi virtuale per i processi in modalità utente sono stati più che adeguati storicamente, l'aumento dell'uso di file mappati alla memoria di grandi dimensioni, allocatori di memoria personalizzati e l'aumento delle dimensioni della VRAM (che devono essere mappate nello spazio di elaborazione) ha iniziato a causare situazioni in cui le allocazioni dello spazio di memoria virtuale hanno esito negativo. Alcune DLL non Microsoft usano posizioni di avvio fisso al centro dello spazio indirizzi virtuale, causando la frammentazione che comporta allocazioni non riuscite.
Questi problemi vengono spesso visualizzati quando il gioco usa uno schema di allocazione di memoria personalizzato che tenta di allocare un grande blocco continuo di spazio di memoria virtuale. È consigliabile scrivere allocatori in modo che richiedano parti più ragionevolmente ridimensionate dello spazio indirizzi virtuale in base alle esigenze. Ad esempio, la richiesta di 64 o 256 MB alla volta, ma non di 1 GB. Tuttavia, è necessario prestare attenzione a non causare ulteriore frammentazione. L'avvento di sistemi operativi e hardware a 64 bit aiuterà notevolmente questi problemi in futuro, ma è necessario prestare attenzione ai sistemi a 32 bit di generazione corrente.
Manipolazione del controllo Floating-Point Word
Come aiuto per il debug, alcuni sviluppatori hanno abilitato le eccezioni nell'unità a virgola mobile (FPU) tramite manipolazioni della parola di controllo a virgola mobile. Questa operazione è altamente problematica e probabilmente causerà l'arresto anomalo del processo. Proprio come la convenzione di chiamata richiede che il registro ebx venga mantenuto, la maggior parte del sistema presuppone che l'FPU sia in uno stato predefinito, darà risultati ragionevoli e non genererà eccezioni. I driver e altri componenti di sistema calcolano spesso i risultati in base al presupposto che i valori di errore standard verranno visualizzati nei registri per condizioni non dannose, ma se le eccezioni sono abilitate, queste verranno annullate e causano arresti anomali.
Direct3D imposterà l'unità a virgola mobile su precisione singola, round-to-near più vicina come parte dell'inizializzazione per il thread chiamante, a meno che non venga usato il flag di D3DCREATE_FPU_PRESERVE, nel qual caso la parola di controllo a virgola mobile non viene toccata. Poiché la parola di controllo è un'impostazione per thread, assicurarsi che tutti i thread dell'applicazione siano impostati sulla modalità a precisione singola possono ottimizzare le prestazioni. Tenere presente che la chiamata _control87 non è valida per la codifica nativa x64, che usa esclusivamente la crittografia del servizio di archiviazione, ed è estremamente costosa sull'architettura basata su PowerPC della CPU Xbox 360.
Nota
Se si modifica la parola di controllo, usare _controlfp_s e tenere presente che per le piattaforme x64 non è possibile modificare la precisione a virgola mobile tramite la parola di controllo.
In tutte le librerie in cui è necessario avere regole di arrotondamento diverse o altri comportamenti, ad esempio la gestione dei vertex shader software o la compilazione, si salva e si ripristina la parola di controllo. Se un gioco deve usare eccezioni di arrotondamento non standard o FPU, deve salvare e ripristinare la parola di controllo a virgola mobile e assicurarsi che non chiami codice esterno che non sia stato dimostrato di essere al sicuro da questi problemi, incluse le API di sistema.
Installazione facoltativa del runtime DirectX
Un certo numero di giochi chiede all'utente se installare DirectX. Questo può causare problemi se l'utente presuppone che il sistema abbia installato la versione più recente di DirectX redistributable e ignora l'installazione e successivamente, l'installazione continua correttamente. Se il gioco richiede una versione specifica di D3DX o altre funzionalità aggiornate non installate, il gioco non funzionerà e l'utente si frustrarà molto.
È consigliabile che il programma di installazione del gioco installi automaticamente la ridistribuibile DirectX che il gioco è stato creato. Il processo di installazione DirectX è progettato in modo che verifichi se è necessario aggiornare qualsiasi elemento e restituisce rapidamente se non lo è. Non è quindi necessario chiedere all'utente di installare DirectX.
È possibile eseguire un'installazione invisibile all'utente di DirectX eseguendo questo comando dal pacchetto di installazione: dxsetup.exe /silent
Inoltre, le dimensioni effettive della cartella ridistribuibile possono essere configurate in modo da includere solo i file CAB (.cab) effettivamente necessari per le piattaforme e l'utilizzo di destinazione del gioco.
Nota
Prima di usare dxsetup, leggere Installazione non diretta.
Uso eccessivo della sincronizzazione dei thread
Durante la profilatura dei giochi, gli hotspot principali sono spesso correlati all'ingresso e all'uscita di sezioni critiche. Con la prevalenza delle CPU multicore, l'uso del multithreading nei giochi è aumentato notevolmente e molte implementazioni si basano sull'uso elevato della sincronizzazione dei thread. Il tempo di CPU per prendere una sezione critica anche senza conflitti è abbastanza significativo e tutte le altre forme di sincronizzazione dei thread sono ancora più costose. È quindi necessario prestare attenzione a ridurre al minimo l'uso di queste primitive.
Una fonte comune di sincronizzazione eccessiva nei giochi è l'uso di D3DCREATE_MULTITHREADED. Questo flag, rendendo thread-safe Direct3D per il rendering da più thread, adotta un approccio molto conservativo, con conseguente sovraccarico elevato di sincronizzazione. I giochi dovrebbero evitare questo flag. In alternativa, progettare il motore in modo che tutte le comunicazioni con Direct3D provenvano da un singolo thread e qualsiasi comunicazione tra thread venga gestita direttamente. Per altre informazioni sulla progettazione di giochi multithreading, vedi l'articolo Codifica per più core in Xbox 360 e Microsoft Windows.
Uso di RDTSC
L'uso dell'istruzione x86 RDTSC non è consigliato. RDTSC non riesce a calcolare correttamente i tempi in alcuni schemi di risparmio energia che modificano la frequenza della CPU in modo dinamico e su molte CPU multicore per cui il contatore del ciclo non è sincronizzato tra core. I giochi devono invece usare l'API QueryPerformanceCounter . Per altre informazioni sui problemi relativi a RDTSC e all'implementazione di tempi ad alta risoluzione con QueryPerformanceCounter, vedere l'articolo Temporizzazione del gioco e processori multicore.