Het optimaliseren van de stapelfunctie

Momenteel gebruik ik de bibliotheek dbghelp om door de stapel van de thread van sommige processen te lopen (met GetThreadContext() en StackWalk64() ) en alleen te verzamelen de retouradressen die elk frame bevat.

De overhead om dit te doen is echter te groot voor de systeemeisen - de algehele tijd is apx. 5 msec per stapelwandeling (met 10-15 frames). Deze keer bevat de GetThreadContext() en de lus die StackWalk64() aanroept om alle frames te krijgen.

Hoe dan ook, ik moet een manier vinden om het veel sneller te doen. Iedereen heeft enig idee hoe kan ik dat doen?


Bewerk:

Weet iemand van het ETW-mechanisme (Event Tracing voor Windows)?

Zo ja, hoe traceer ik alle context-switches die in een bepaalde periode zijn gebeurd? Is er een evenementaanbieder die een evenement publiceert op elke contextswitch?

4
GMan - Het wordt gebruikt voor het profileren van een RT-systeem, niet in een debug-modus of zo, maar in de operationele modus. Daarom is het van cruciaal belang om deze informatie zeer snel te grijpen, omdat op dit moment het hele systeem is gestopt.
toegevoegd de auteur Hagay Myr, de bron
AzzA - De voorbestemde architecturen zijn beide X86 en IA64. Zal het sneller zijn dan met de StackWalk64? Doet StackWalk64 dat niet precies?
toegevoegd de auteur Hagay Myr, de bron
Het aantal platforms is beperkt (twee tot drie) dus ik denk dat het geen probleem zal zijn om het te coderen om alle mogelijke architecturen te evenaren. Moet het moeilijker/lastiger zijn om de stapel met IA64 handmatig te lopen dan met X86 ? Hoe dan ook, ik zal eerst een inschatting maken van de werkelijke hoeveelheid tijd die het kost om een ​​ StackWalk64() oproep te doen en te kijken of het eigenlijk de flessenhals is. Bedankt AzzA.
toegevoegd de auteur Hagay Myr, de bron
@AzzA: ik test het en kom terug met enkele antwoorden (hopelijk). Zie mijn bewerking van mijn vraag ...
toegevoegd de auteur Hagay Myr, de bron
@GMan: Kun je alsjeblieft een beetje uitwerken met je suggestie? Zie mijn bewerking van mijn vraag. Zou het kunnen zijn waar je voor hebt bedoeld?
toegevoegd de auteur Hagay Myr, de bron
CONTEXT structuur gevuld met GetThreadContext() heeft registers 'waarden. Omdat je de processorarchitectuur niet hebt opgegeven, zou het antwoord zijn: "Gebruik deze CONTEXT -structuur om door de stapel te lopen". Op x86-32 is EBP bijvoorbeeld de huidige frame-aanwijzer. EBP + 0 is de vorige frame-aanwijzer. EBP + 4 is retouradres.
toegevoegd de auteur lapk, de bron
StackWalk64() doet veel meer en het doet het op een draagbare manier, onafhankelijk van hoe stack wordt weergegeven, enzovoort. Dus, ik zou verwachten dat het langzamer is dan twee DWORD-waarden te laten wijzen door een aanwijzer . Ik zou echter STERK aanbevelen om StackWalk64() te gebruiken, omdat u verschillende platforms target, juist omdat het draagbaar is.
toegevoegd de auteur lapk, de bron
Ik stond op het punt te suggereren dat je zelf StackWalk64() timmerde. Weet u zeker dat uw langzame tijden niet veel te maken hebben met het schakelen tussen threads? In principe, als u alleen het retouradres voor elk stapelframe nodig heeft, moet dit niet moeilijk zijn. Op x86-32 is het net zo eenvoudig als het verkrijgen van een DWORD waarde.
toegevoegd de auteur lapk, de bron
Het is niet precies bedoeld om op prestatie-kritische wijze te worden gebruikt.
toegevoegd de auteur GManNickG, de bron
@HagayMyr: Misschien heb je meer geluk met iets dat bedoeld is om te worden gebruikt voor profilering, om de overhead te verlagen. (Gebruik ook @name om te antwoorden.)
toegevoegd de auteur GManNickG, de bron

3 antwoord

De snelste manier die ik kan bedenken is om uw eigen versie van GetThreadContext en StackWalk64 te maken door een kerneldriver te maken die het kernelStack -veld van ETHREAD -structuur van de thread die u probeert te controleren. Here is een goed artikel over dit onderwerp.

3
toegevoegd
Ik heb het artikel gelezen dat je hebt gelinkt. Ik begreep heel goed wat je voorstelde. Heeft een willekeurige thread een ETHREAD-structuur? Het is mijn bedoeling om een ​​procesrun te doorbreken en alle threads (die ik hun ID's nog niet ken) opnieuw te doorlopen om hun stapels te pakken. Hoe kan ik een kerneldriver gebruiken/bouwen om deze taak te vervullen?
toegevoegd de auteur Hagay Myr, de bron
Ik heb vrijwel geen ervaring met het schrijven van kernel-stuurprogramma's in Windows. Als u zegt dat het ook riskant is, dan gebruik ik uw advies en houd ik me aan de gebruikersmoduscode. Zie alstublieft mijn bewerking van mijn vraag, misschien kunt u daarmee helpen ...
toegevoegd de auteur Hagay Myr, de bron
Ja, ze hebben allemaal ETHREAD-structuur. U moet eerst beginnen met het ophalen van de lijst met threads van een bepaald proces. Echter als je het niet prettig vindt om een ​​kernel-driver te schrijven (als je toegang tot ETHREAD zelf vrij gevaarlijk vindt, omdat de structuur verschilt tussen OS-versies), houd ik me liever gewoon aan de code van de gebruikersmodus omdat je iets in de hand hebt tussen prestaties en stabiliteit. Schrijf anders de ring-0 code zo veel als je kunt, want hoe meer code je in de kernel schrijft, des te betere prestaties je krijgt.
toegevoegd de auteur JosephH, de bron

Als u Windows Vista of hoger gebruikt, moet u de ETW-periode gebruiken. Je kunt alles activeren waar je het over hebt, inclusief contextschakelaars en voorbeeldprofielgebeurtenissen, en het is behoorlijk efficiënt. Voor X86 loopt het in feite de EBP-registerketen, wat een gelinkte lijst van adressen is die het moet herhalen. In 64-bits land moet de stapelwandelaar de stapel afwikkelen, en dus is het iets minder efficiënt, maar ik kan je vertellen of je redelijk veel werk in je toepassing doet, de effecten van stapelen worden niet weergegeven up. Het is zeker niet in het milliseconde bereik.

2
toegevoegd

Het ETW-deel is eigenlijk een onafhankelijke vraag. Windows-hulpprogramma's voor analyse van prestaties kunnen alle context-switches vastleggen, evenals Visual Studio Profiler in de modus "Contourcollitie Concurrency Profilering". Je kunt ook alle gebeurtenissen handmatig in het bestand dumpen met behulp van logman, zie de instructies hier .

1
toegevoegd
Mee eens, maar het kwam in dezelfde context (mijn vraag) die probeert een efficiënte (en goedkope) oplossing te vinden om een ​​programma te profileren op een reeds geïmplementeerd systeem (niet in onze handen en niet in de debug-modus). Ik heb het artikel gelezen dat je hebt gelinkt over de ETW. Ik vraag me af hoe kan men deze context-switches tracings programmatisch doen? Voor de duidelijkheid, ik moet een programma schrijven (niet in een .NET env.) Dat de call-stacks van de schakeldraden verzamelt op alle context-switchmomenten (in een bepaalde periode, zeg de laatste 3 minuten) . Waar zal ik beginnen?
toegevoegd de auteur Hagay Myr, de bron
Ik zou de tools gebruiken die ik je gaf om de gegevens te verzamelen en deze vervolgens verwerken met behulp van aangepaste code. Zelf 'verzamelen' is gewoon niet rendabel. Gebruik dus logman of Xperf of VS profiler om een ​​traceerbestand te maken en gebruik code om het in batch te ontleden (er zijn verschillende indelingen beschikbaar).
toegevoegd de auteur Uri Cohen, de bron