01/08/2025
Få styr på mobilspillets performance med Arm Mobile Studio
I en verden hvor mobile spil konstant bliver mere komplekse og krævende, er det afgørende for udviklere at sikre en problemfri og flydende spiloplevelse på tværs af et bredt spektrum af enheder. Fra de nyeste high-end smartphones til ældre, mere almindelige modeller, skal billedhastigheden (frame rate) forblive stabil, og strømforbruget holdes nede. Dette er præcis, hvor avancerede analyseværktøjer kommer ind i billedet. I dette blogindlæg dykker vi ned i, hvordan den nye samling af værktøjer fra Arm Mobile Studio kan hjælpe dig med Android performanceanalyse, og hvordan de fungerer i synergi med spilmotorer som Unity for at opnå en endnu mere dybdegående forståelse af dit spils performance.

Vi fokuserer specifikt på Streamline, Arm Mobile Studio's mest alsidige og detaljerede performanceanalysekomponent. Vi vil beskrive, hvordan Streamline kan integreres med Unity for at give dig et klart billede af, hvordan forskellige aspekter af dit spil udnytter ressourcerne i Arm Cortex-A CPU'en eller Arm Mali GPU'en på en mobil enhed. Arm Mobile Studio's Starter Edition er gratis, og kildekoden til det projekt, vi bruger her, kan findes på GitHub.
Hvad er Streamline?
Streamline er et kraftfuldt værktøj, der indsamler sample-baserede og event-baserede performance-data fra en række kilder på en Android-enhed. Disse aggregerede resultater vises i forskellige visninger, hvoraf vi vil koncentrere os om Timeline-visningen. Den øverste halvdel af skærmen viser indsamlede systemperformance-tællere, mens den nederste halvdel kan vise en række forskellige informationstyper på den samme tidslinje. Her ser vi for eksempel Heat Map-visningen, som indikerer, hvordan beregningsaktiviteten er fordelt på tværs af trådene i den profilerede applikation.
Analyse af et Unity-eksempel
Til denne demonstration analyserer vi et simpelt Unity-indhold: en gennemflyvning af et procedurelt genereret terræn. Kameraet drejer og vender sig, mens nye terrænfliser genereres 'on-the-fly', efterhånden som de bliver nødvendige. Fliser, der kommer for langt væk fra kameraet, slettes, så scenens kompleksitet forbliver nogenlunde konstant over tid, når scenen er fyldt ud. Nogle gange bevæger kameraet sig langsomt, hvilket resulterer i en langsom rate for ny terrængenerering, mens det andre gange accelererer, hvilket kræver en højere rate for terrængenerering. Kanterne på hver flise er gengivet i en mørkere farve, så du tydeligt kan se størrelsen på hver flise.
Fordi genereringen af en terrænflise er beregningsmæssigt intensiv, benytter vi Unity Job Scheduler. Dette giver os mulighed for at afsende baggrundstråde, der ikke blokerer hoved-Unity-tråden. Dette sikrer, at brugeren oplever en stabil billedhastighed snarere end et hakkende stop, hver gang nyt terræn genereres.
Demoen er konfigureret til at køre gennem fire forskellige scener, der ser identiske ud, men genererer terrænfliserne forskelligt. Som det følgende diagram viser, består terrænet af mange terrænblokke, hvor hver blok har en fast størrelse. Hver blok består af flere meshes (én til det grønne terræn, én til det gule terræn og én til vandet) med en fast opløsning. Render Distance kontrollerer antallet af fliser omkring spilleren, der genereres.
| Scene | Render Distance | Terrain Tile Size | Terrain Resolution | Number of parallel terrain generations |
|---|---|---|---|---|
| 1 | 3 | 20x20 | 32x32 | 8 |
| 2 | 3 | 20x20 | 32x32 | 1 |
| 3 | 6 | 10x10 | 16x16 | 8 |
| 4 | 6 | 10x10 | 16x16 | 1 |
Vi udfører profileringen på en Huawei P10-telefon, udgivet i 2017. Den indeholder en HiSilicon Kirin 960-chip, som består af fire højtydende Arm Cortex-A73 CPU-kerner, fire højeffektive Arm Cortex-A53 CPU-kerner og Arm Mali-G71 MP8 GPU'en.
Profilering i Unity – og hvor Streamline kommer ind
Unity indeholder sin egen profiler, som fungerer glimrende på Android-enheder. Unity's profiler er fremragende til at vise os, hvornår jobs er planlagt, men den viser ikke detaljer om enhedens fysiske ressourcer (CPU'er og GPU'er) og hvordan de bliver brugt. Vi rammer måske vores 60 FPS, men udnytter vi alle vores CPU-kerner til det yderste og dræner batteriet for at opnå det? Det er her, Streamline kommer ind.
I resten af dette blogindlæg vil vi vise, hvilke data Streamline indsamler og præsenterer, og hvordan vi kan bruge Streamline's annotationsfunktioner til at sende kontekst fra Unity-spillet ned til Streamline, hvilket gør dataene lettere at fortolke.
Streamline's annotationsfunktioner til Unity
Før vi taler om, hvordan annotations kan indsættes i dit Unity-spil, lad os se på slutresultatet for vores eksempelindhold, når vi har modificeret spillet til at udnytte tre af Streamline's annotationsfunktioner:
- Markers er den simpleste form for annotation – et enkelt tidspunkt med en label, der vises øverst i Streamline's Timeline-visning.
- Channels giver lidt mere struktur ved at tilbyde en separat informationsrække ved siden af hver tråd. Annotations kan placeres i en kanal, og i modsætning til en marker dækker hver annotation et tidsinterval.
- Custom Activity Maps er den mest avancerede form for annotation og en mekanisme til at vise globale (tværgående) aktiviteter, der kan have komplekse afhængigheder. Hvert Custom Activity Map vises som sin egen visning i den nederste halvdel af Streamline UI'en.
Analyse af Timeline og Heat Map
Når vi har indsamlet en profil, åbner den i Streamline, og vi kan begynde at afdække, hvad der foregår. Når vi undersøger vores indhold, er det første, der fanger vores opmærksomhed, Markers (i grønt øverst på tidslinjen), som her indikerer, hvor hver frame starter. Vi kan se, at billedhastigheden ikke er så jævn, som vi ønsker, og der er betydelig sporadisk aktivitet på tværs af alle CPU-kerner. Billedhastigheden starter langsomt og ser derefter ud til at accelerere med lejlighedsvise pauser. Dette stemmer ret godt overens med, hvad vi kan forvente af terrængenerering – kan vi se dybere?
Timeline-visningen i Streamline er opdelt i to dele – den øverste visning viser metrikkerne, og den nederste halvdel kan vise forskellige ting, herunder Heat Map. Heat Map viser os, hvordan arbejdet blev fordelt på tværs af systemet, og giver os mulighed for at filtrere den øverste tidslinje for kun at vise det arbejde, der er tilskrevet specifikke processer eller tråde. Ved at undersøge Heat Map og vælge først UnityMain-tråden og derefter alle Worker Thread-trådene, kan vi se, hvordan CPU-aktiviteten blev fordelt mellem hoved-Unity-tråden og trådene i job-scheduleren.
CPU-profil for UnityMain-tråden: Viser store udbrud af aktivitet på Cortex-A73 CPU'erne.
CPU-profil for alle Worker Thread-tråde: Viser mindre udbrud af aktivitet på tværs af både Cortex-A73 og Cortex-A53 CPU'erne.
Dyk ned i UnityMain-tråden med Channels
Lad os tage et kig på hovedtråden. Hvis du kigger nærmere på skærmbilledet til venstre, vil du se en "A"-marker ved siden af UnityMain-tråden, som vi undersøger. Dette betyder, at Streamline Annotation Channels er til stede. Vi zoomer lidt ind på tidslinjen og udvider UnityMain-tråden for at se, hvad der sker. Scene- og TerrainController-rækkerne er Streamline-kanaler, genereret af annotations, der er placeret i spillet. Scene-kanalen viser os, hvilken scene der kører – vi kan se, at dette er 20x20, 32x32-versionen med en render distance på 3 og 8 tråde kørende parallelt. TerrainController-kanalen bruges til at indikere, hvornår særligt interessante kodestykker kører på hoved-Unity-tråden. De blå blokke markerer den kode, der kører, når et Terrain-job afsluttes. De grønne blokke markerer, hvor nye Terrains planlægges til generering. Vi kan her se, at al hovedtrådsaktivitet primært skyldes det arbejde, der skal udføres, når et job er afsluttet, og det endelige mesh skal genereres og indsættes i scenen.
Brug af Calipers til tidsintervalanalyse
Ud over at fokusere på bestemte tråde kan vi også begrænse vores analyse til bestemte tidsperioder. Streamline's calipers giver os mulighed for at markere et bestemt tidsinterval til analyse – her har vi valgt starten og slutningen af den intense aktivitetsperiode relateret til Terrain-afslutning (calipers er sat øverst på Timeline-visningen). Hvis vi skifter til Call Paths-visningen, kan vi få en god idé om, hvor tiden bliver brugt i den tidsperiode, der er valgt af calipers. Fordi vi brugte IL2CPP scripting backend til Unity, får vi meget mere information, end hvis vi havde brugt den standard Mono runtime. Jeg vil ikke gå i detaljer om, hvad der foregår her, men der er tydeligvis meget, der kræver en dybere undersøgelse.
Worker-trådene og deres aktivitet
Når vi filtrerer for kun at vise Worker Thread-trådene, er der ingen overraskelser, da vi har bedt om maksimalt otte jobs, der skal køre parallelt. I dette skærmbillede har vi udvidet Cortex-A53-klyngen, så vi kan se udnyttelsen af de enkelte kerner. Vi ser nogle grønne blokke i TerrainController-kanalen, der indikerer nye Terrains, der planlægges, derefter intens aktivitet på tværs af alle kerner, og derefter blå aktivitet i TerrainController for at behandle disse Terrains i hovedtråden, når de er genereret (vi ser ikke denne hovedtrådsaktivitet i graferne, fordi vi ikke har UnityMain-tråden valgt).
Sammenligning af scener
Det er interessant at sammenligne dette med aktiviteten i den anden scene, hvor terrænfliserne har samme kompleksitet, men vi kun tillader én at blive planlagt ad gangen. Der er et par ting at bemærke her: CPU-aktiviteten er langt mindre intens – de fleste kerner er inaktive eller tæt på inaktive det meste af tiden. Billedhastigheden er ikke perfekt, men den er meget jævnere. Fordi vi kun har én frame, der afsluttes ad gangen, reducerer vi de store udbrud af aktivitet på hovedtråden, der holdt os tilbage.
Vi kan også sammenligne profilen med den tredje scene, som bruger mindre fliser. Som du kan se, er CPU-aktiviteten mindre intens, og de blå blokke med afsluttende arbejde i hovedtråden er kortere, hvilket resulterer i en jævnere billedhastighed sammenlignet med den første scene (men der er naturligvis flere jobs i alt, så vi skal sikre os, at terrængenereringen stadig holder trit med den hastighed, hvormed kameraet flyver hen over terrænet).
Den fjerde scene, med små fliser og kun én terrængenerering kørende ad gangen, viser den jævneste billedhastighed overordnet set, men vi skal være meget opmærksomme på at sikre, at terrængenereringen sker med tilstrækkelig hastighed til at følge med kameraet. Du vil i den originale video se, at dette ikke altid er tilfældet, når kameraet bevæger sig hurtigt over den fjerde scene.
Custom Activity Maps for dybere indsigt
Endelig kan vi bruge et Custom Activity Map for at få endnu mere indsigt i, hvordan worker-trådene udfører terrængenerering. Hvert Custom Activity Map vises som en mulighed i menuen nederst til venstre, som vi indtil nu har brugt til at vise Heat Map. Når vi vælger Terrain Generation-visningen, ser vi en farvet boks for hver Terrain generation-aktivitet, der viser, hvornår den startede og stoppede. En mouseover viser terrænflisens verdenskoordinater, hvornår den blev initieret, og hvor lang tid det tog at fuldføre. I dette skærmbillede grafer vi også den beregningsmæssige arbejdsbyrde, der fandt sted på Mali GPU'en – som forventet er der en jævn stigning i GPU-aktivitet, efterhånden som terrænet bliver fyldt ud. Dette skærmbillede blev taget under fokus på begyndelsen af den første scene, hvor vi genererer store fliser, op til 8 samtidigt. Pauserne, mens hovedtråden forbereder al den nye geometri, får GPU'en til at være inaktiv i lange perioder.
Når vi bevæger os til den fjerde scene, hvor vi genererer mindre fliser serielt, ser vi en meget jævnere stigning i GPU-aktivitet, og vi kan tydeligt se, at kun ét Terrain-job kørte ad gangen (og hvert job er kortere på grund af den mindre flisestørrelse).
Sådan bruger du Streamline Annotations i Unity
Streamline annotations bruger en specifik protokol, og en open-source C-implementering leveres som en del af Arm Mobile Studio. For at gøre det nemt at generere Streamline annotations fra Unity-indhold, har du brug for nogle C#-wrappers omkring C-implementeringen. De wrappers, der bruges i denne gennemgang, sammen med den nødvendige C-implementering, er tilgængelige som en Unity Asset Package. Download den og importer den til dit projekt som en brugerdefineret Asset-pakke. Pakken tilføjer nye metoder i et Arm-namespace, der giver dig mulighed for nemt at bruge Streamline annotations i dit eget projekt. API-dokumentation kan findes i README.md-filen inde i pakken.
Opsætning af dit Unity-projekt
Hvis du ønsker at opnå de hurtigste og nemmest analysérbare Android builds fra Unity, er der nogle specifikke Android Player-indstillinger, du bør konfigurere:
- Sørg for, at du bruger IL2CPP som Scripting Backend, og indstil C++ Compiler Configuration til Debug. Dette kompilerer ikke kun dine scripts til native kode for bedre performance, men det betyder også, at Streamline kan se debug-informationen for at mappe performance-data tilbage til dine funktioner i Call Path-visningen.
- Indstil Target Architecture til ARM64 (ARMv7 er standard). De fleste mobile enheder i dag er 64-bit, og du vil opnå kodegenerering af højere kvalitet som resultat.
Tilføjelse af Markers
Markers er den nemmeste annotation at bruge. Den medfølgende metode tager en streng og en valgfri farve. For eksempel blev følgende kode brugt til at udsende de grønne per-frame markers i en af GameObjects (hvis du ikke er bekendt med Unity-arkitektur, kaldes Update()-metoden automatisk én gang per frame):
void Update () { Arm.Annotations.marker("Frame " + Time.frameCount, Color.green); }
Tilføjelse af Channels
Brug af channels er ikke meget sværere. Først skal du oprette en kanal, der angiver dens navn. Du kan derefter logge annotations ind i kanalen ved hjælp af metoder på Channel-objektet, for eksempel:
channel = new Arm.Annotations.Channel("Scene"); channel.annotate(sceneDescription, color);
Husk, at annotations i channels vil dække et tidsinterval. Hvis du vil afslutte annotationen, før du starter den næste, kan du bruge end()-metoden. For eksempel er den del af TerrainController, der udfører Terrain-afslutning i hovedtråden, indkapslet som følger:
// Begin annotation channel.annotate("Completing", Color.blue); Mesh mesh = obj.GetComponent
Brug af Custom Activity Maps
Custom Activity Maps (CAMs) kan betragtes som endnu et lag oven på channels. Du skal først navngive CAM'en, før du opretter spor inden i den. Du kan derefter tilføje annotations til disse spor, ligesom du ville gøre det til channels. I eksemplet blev Terrain Generation CAM oprettet som følger:
terrainCAM = new Arm.Annotations.CustomActivityMap("Terrain Generation"); terrainTracks = new Arm.Annotations.CustomActivityMap.Track[16]; for (int i = 0; i < 16; i++) { terrainTracks[i] = terrainCAM.createTrack("TerrainJob " + i); }
Der er dog en komplikation for vores brugssituation: når et job kører i Unity Job System, kan det stort set ikke interagere med resten af dit spils objektmodel (hvilket hjælper med at holde tingene trådsikre). Alt, hvad vi kan gøre i jobbet, er at gemme start- og stoptidspunktet, og når hovedtråden rydder op i jobbet, er det der, vi kan registrere jobets aktivitet i CAM'en. C#-wrappersne leverer en funktion, der sikkert kan kaldes fra jobs, som returnerer den aktuelle tid i det format, Streamline annotations behøver.
UInt64 startTime = Arm.Annotations.getTime();
Når vi er tilbage i hovedtråden, vælger vi et spor at bruge (vi administrerer dem i en pulje for at sikre, at der ikke er overlap, da det er visuelt hjælpsomt) og registrerer jobbet på det pågældende spor. Her er job.timings et to-elementers array, der er udfyldt af jobbet og indeholder jobbets start- og stoptidspunkt.
track.registerJob(obj.name, Color.grey, job.timings[0], job.timings[1]);
Og det er det! Vi forventer at forfine denne Unity Package over tid for at tilføje mere funktionalitet; din feedback er altid velkommen!
Indsamling af en grundlæggende profil i Streamline
Der er et par trin, du skal igennem for at indsamle din første profil i Streamline, men når du først er sat op, er tingene ret ligetil. Først skal du downloade og installere den gratis Windows, Mac eller Linux-version af Arm Mobile Studio Starter Edition. Husk fra den tidligere beskrivelse af Streamline's arkitektur, at der er et par ting, du skal have på plads:
- Du skal have gator kørende på din mobile enhed på en måde, der giver den adgang til din applikation.
- Du skal have en måde at få data af din enhed og ind i værktøjerne.
Streamline giver dig et par måder at opnå dette på, men vi har fundet, at den simpleste metode, der er robust på tværs af en række enheder, er først at sikre, at du kender et par vigtige oplysninger:
- Om din applikation er 32- eller 64-bit. Dette vil være 64-bit, hvis du fulgte instruktionerne ovenfor og byggede dit Unity-spil med ARM64-mulighederne.
- Pakkenavnet på din applikation (som du angav i Unity's Android Player-indstillinger). For vores eksempelapplikation er dette
com.Arm.InfiniteTerrain. - Hvor gator-binaries findes: du finder dem i
streamline/bin/arm(32-bit) ellerstreamline/bin/arm64(64-bit) mapperne i din Arm Mobile Studio-installation.
Når du kender disse oplysninger, er trinnene til at udføre analyse som følger:
- Sørg for, at applikationen er installeret på din enhed.
- Brug Android adb-værktøjet til at videresende en netværksport fra din mobile enhed til en lokal port på det system, hvor du kører Arm Mobile Studio.
- Brug adb til at pushe gator (enten 32- eller 64-bit versionen afhængigt af din applikation) til din enhed og start den med samme pakkenavn som din applikation.
- Start Streamline og forbind den til den lokale port, du brugte adb til at videresende trafik til. Dette er punktet, hvor du kan vælge, hvilke performance-tællere du er interesseret i at indsamle.
- Start din applikation på din mobile enhed. Streamline vil begynde at indsamle analysedataene, efterhånden som de kommer ind.
Når gator kører, kan du installere nye versioner af din applikation, starte og stoppe Streamline og udføre flere analyser uden at skulle genstarte gator. For at gøre processen lettere kan du downloade gatorme-scriptet, som du kan bruge til at konfigurere og køre gator og adb for dig; alt, hvad du behøver at angive, er stien til den gator-binary, du vil køre, pakkenavnet på din applikation, og hvilken Mali GPU du har i din enhed (Dette hjælper, hvis gator ikke kan finde ud af, hvilken GPU du har ved at undersøge enheden). Det udfører også flere andre trin for at sikre, at denne metode fungerer godt på det bredeste udvalg af mobile enheder og sikrer, at gator lukkes korrekt ned, når du er færdig med din profileringsaktivitet. (Ja, vi vil integrere gatorme-funktionaliteten direkte i Streamline i den nærmeste fremtid!).
gatorme-dokumentationen forklarer detaljerne, men som et arbejdeksempel er her, hvordan InfiniteTerrain-indholdet kunne profileres, efter at APK'en er installeret på din enhed.
Først kører du gatorme fra kommandolinjen:
$ ./gatorme.sh com.Arm.InfiniteTerrain G71 ./mobilestudio-macosx/streamline/bin/arm64/gatord
Du kan nu starte Streamline og gøre dig klar til at fange. Der er et par indstillinger, du vil sikre dig, at du får rigtigt:
- Connection: Sørg for, at den er sat til TCP og den korrekte port (f.eks. 8080).
- Capture Configuration: Vælg de ønskede CPU- og GPU-tællere.
Når du har dette sat op, er gentagne deploy/analyse/fix-trin nemme – du kan lade gatorme køre, mens du lukker din applikation, Build-and-Run direkte fra Unity og fanger mere Streamline-information.
Konklusion
Vi har gennemgået nogle af de yderligere indsigter, vi kan få i Streamline, hvis vi bruger annotations fra selve spillet til at give os en mere overordnet kontekst. Vi brugte:
- Markers til at vise os, hvornår en ny frame startede.
- Channels til at vise os, hvilken scene der kørte, og hvilke aktiviteter hovedtråden udførte.
- Custom Activity Maps til at vise os adfærden af asynkront planlagte terrængenereringsjobs.
Streamline, som en del af Arm Mobile Studio, tilbyder en dybdegående og detaljeret tilgang til performanceanalyse af Android-applikationer, især spil udviklet med Unity. Ved at integrere Streamline's kraftfulde annotationsfunktioner kan udviklere opnå en hidtil uset forståelse af deres spils performance, identificere flaskehalse og foretage præcise optimeringer. Den gratis Starter Edition gør det tilgængeligt for alle, og med den medfølgende Unity Asset Package er det nemmere end nogensinde at komme i gang.
Hvis du har spørgsmål om Arm Mobile Studio eller Arm inden for grafik og gaming generelt, så deltag i vores Graphics and Multimedia Forum eller læs mere om vores værktøjer på Arm Mobile Studio developer-siden.
Hvis du vil læse andre artikler, der ligner Optimering af mobilspil med Arm Mobile Studio, kan du besøge kategorien Software.
