Visual Leak Detector per Visual C++

Ho utilizzato questo prezioso strumento per diversi progetto durante la mia carriera e mi sono accorto di non aver mai scritto un articolo al riguardi! Gravissimo! 🙂

La pagina del progetto è questa: https://vld.codeplex.com/

Con vld è possibile riconoscere se nel nostro codice nativo (C/C++) abbiamo dei memory leak direttamente dopo un solo ciclo di utilizzo del nostro programma dalla console di Output di Visual Studio.

Sul sito del progetto la documentazione è chiara. Vi mostrerò qui ora un semplice esempio.

Per prima cosa scarichiamo l’eseguibile da https://vld.codeplex.com/ e installiamolo sul PC sul quale abbiamo il nostro Visual Studio (nel mio caso la versione 2015).

A questo punto creo un progetto Win32 Console Application con il seguente main.cpp

Se scrivete il codice prima di impostare i path per gli include di vld, la riga 10 vi darà errore. Non preoccupatevi, la sistemiamo subito.

Come vedete il nostro bel programmino è fatto apposta per sprecare memoria all’infinito. La alloca e non la rilascia mai… che bravo! 😀

La documentazione ufficiale è ben fatta e la trovate qui.

Uma volta lanciato il setup.exe di VLD quello che dovete fare è andare ad impostare sul progetto in cui lo volete utilizzare per la build di Debug che vi interessa (x86, x64 o entrambe) i path delle librerie e dei file di include di VLD.

A questo punto compiliamo in Debug e lanciamo il nostro codice. La riga 10 non darà più errore e in console vediamo l’avvenuto corretto caricamento del nostro Leak Detector prendendo i suoi parametri di configurazione dal vld.ini nella directory di installazioine del VLD.

Al termine del programma ecco quali utili informazioni vld ci offre nella cosole di output di Visual Studio!

E questo è tutto, gente!

Visual Leak Detector per Visual C++

Debug Diagnostic Tool

Oggi vedremo un caso di utilizzo del Debug Diagnostic Tool che è uno strumento molto utile per fare del debugging e del profiling sia in ambiente di Sviluppo ma sopratutto in ambiente di Produzione.

Il caso in particolare è andare ad analizzare una applicaizone ASP che in produzione, sotto stress quindi, ogni tanto manda il processore del server al 100%.

Come primo workaround si è subito messo in linea uno script di Power Shell che andasse a verificare lo stato del processore e nel caso fosse rimasto al 95% per più di 20sec, andasse a fare un IIS Reset.

Poi subito dopo seguendo questo articolo su Debuggin IIS High CPU siamo andati a impostare:

  1. Data Collection con il Performance Monitor
    In particolar modo:

    • Richieste Correnti Totali (ASP .NET)
    • Richieste in Coda (ASP .NET)
  2. Creazione di un Dump tramite Debug Diagnostic Tool 2 Collection
    In particolare:

    • Se il processore rimaneva al 90% per più di 5 secondi

E siamo rimasti ad aspettare che nuovamente succedesse lo scenario incriminato.

Abbiamo lasciato in piedi la cosa per tutta la notte: il data collection continua finchè non lo si stoppa, mentre il dump è one-time (una volta scattato, va riattivato manualmente il trigger, altrimenti si ferma).

Nella notte abbiamo avuto ben 4 casi di processore al 100% e durante il primo caso si è generato il Dump e durante tutti i casi abbiamo collezionato i dati dei contatori per le Richieste Correnti e per le richieste in Coda.

Ecco come abbiamo poi analizzato la cosa.

Per quanto riguarda i dati collezionati dal Performance Monitor si è visto che le richieste correnti schizzavano in occorrenza dell’evento incriminato:

Andando ad analizzare anche le richieste in coda:

si evince che aumentano proporzionalmente alle richieste attive.

Questo ci fa sospettare che sia effettivamente un problema di performance e non un problema di “attacco” in quanto le richieste in coda ci sono solamente durante gli eventi incriminati e quindi IIS non riesce ad evadere le richieste perchè è impegnato nell’operazione che porta il processore al 100% e questo scenario è coerente con il fatto che facendo IIS Reset la situazione ritorno normale.

Andiamo quindi ora ad analizzare il dump con il Debug Diagnosti Tool 2 Analysis.

Vediamo subito che l’analisi del Dump conferma High CPU Usage.

Andando a vedere quindi i Topo 8 Thread scopriamo da dove parte il tutto:

Dalla pagina “RivestimentiDettagli” ed è scatenata dal metodo “.get_data()” (Tutto Codice Utente).

Andando quindi ad analizzare il codice si è scoperto che si era fatto un uso improprio di variabili statiche e quindi c’erano problemi di concorrenza che si vedevano solo in presenza di forte carico del server.

 

 

 

Debug Diagnostic Tool

NVCC compile PTX with virtual code or for specific architecture

Se compiliamo con NVCC in modo che utilizzi un Virtual Code possiamo utilizzare il programma su qualunque architettura di GPU però abbiamo un delay allo startup dell’applicazione, come descritto a pagina 25 del manuale di NVCC di CUDA 7.

CUDA_Compiler_Driver_NVCC.pdf

Che si trova nel seguente direttorio: C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v7.0\doc\pdf

“By specifying a virtual code architecture instead of a real GPU, nvcc postpones theassembly of PTX code until application runtime, at which the target GPU is exactlyknown. For instance, the command below allows generation of exactly matching GPUbinary code, when the application is launched on an sm_20 or later architecture.nvcc x.cu –gpu-architecture=compute_20 –gpu-code=compute_20The disadvantage of just in time compilation is increased application startup delay,but this can be alleviated by letting the CUDA driver use a compilation cache (refer to”Section 3.1.1.2. Just-in-Time Compilation” of CUDA C Programming Guide) which ispersistent over multiple runs of the applications.”

 

 

NVCC compile PTX with virtual code or for specific architecture

OpenCV 3.0 + openCL + First call overhead

Se siete in transizione verso le OpenCV 3.0 vi consiglio di leggere questo post:

http://answers.opencv.org/question/67592/opencv-30-vs-opencv-249-sobel-performance/

In cui anche non volendo utilizzare OpenCL se non lo setto forzatamente a “false” ho un overhead nella prima chiamata delle funzioni di image processing.

Oltre ovviamente alla guida ufficiale:

http://docs.opencv.org/master/db/dfa/tutorial_transition_guide.html

Riporto qui di seguito la citazione nel caso qualcuno chiudesso il post:

In relation to the first call overhead can you test if it helps if you add the following in your code

#include <opencv2/core/ocl.hpp>

and then

cv::ocl::setUseOpenCL(false);

at the begining.

Yes I know that you are using cv::Mat and not cv::UMat, but I observed a similar behavior in my Code even if I use cv::Mat.

By the way, another solution might be to disable the OpenCL dynamic loader by building OpenCV with

cmake -DHAVE_OPENCL_STATIC=ON -DOPENCL_LIBRARY=... -DOPENCL_INCLUDE_DIR=....

This will ensure that OpenCL is only called if you explicitly call and OpenCL function from the ocl class.

 

OpenCV 3.0 + openCL + First call overhead

Compilare le OpenCV 3.0 con CUDA 7 e VisualStudio 2013 per x64

OpenCV 3.0

Occi vi mostrerò come compilare le OpenCV con il supporto per le schede grafiche NVIDIA.

Prima di tutto scarichiamo le OpenCV 3.0 dal loro repository su GitHub: https://github.com/Itseez/opencv.

Installiamo i sorgenti dove più ci piace, per questo esempio io le metterò sul Desktop.

Poi scarichiamo CMake che al momento della stesura di questo articolo è alla versione 3.3.0. Installiamolo. Io ho utilizzato il Win32 Installer.

Scarichiamo ovviamente il CUDA toolkit dal sito della NVIDIA e installiamolo. Al momento di stesura dell’articolo siamo alla versione 7.0. Io ho installato il Windows 8.1 local installer.

Lanciamo CMake e andiamo a dare il percorso dei sorgenti delle OpenCV e della cartella dove vogliamo generare la solution di Visual Studio 2013 per la compilazione:

cmake

 

 

Spuntare “Grouped” e “Advanced”, cliccare su “Configure” e scegliere “Visual Studio 12 2013 Win64” e poi “Finished” e aspettare il termine.

cmake2

Al termine dovremmo vedere “configure done” scritto nella finestra di console di CMake ma la parte centrale probabilmente verrà evidenziata di rosso:

cmake3

 

Espandiamo il nodo BUILD nella finestra rossa ed eliminiamo la spunta da BUILD_DOCS.

Nel mio caso l’errore deo Config era il fatto che non trova Doxygen. Semplicemente così dovremmo risolvere il conflitto.

Però io ho eliminato anche la generazione degli esempi per velocizzare un po’ la compilazione togliendo la spunta da BUILD_EXAMPLES

cmake_build

Controlliamo che nel nodo CMAKE il valore di CMAKE_LINKER sia il linker di Visual Studio 2013 (v12).

cmake_linker

Controlliamo che nel nodo CUDA non sia selezionato (eventualmente togliamo la sputa da) CUDA_ATTACH_VS_BUILD_RULE_TO_CUDA_FILE.

Questo flag server se si eseguono Build in parallelo.

cmake_cuda

Nel nodo WITH controlliamo che siano selezionati (altrimnenti mettiamo la spunta anche in)  WITH_CUBLAS, WITH_CUDA, WITH_OPENGL.

Intanto che compiliamo con CUDA compiliamo anche le CUDA Basic Linear Algebra Subroutines (cuBLAS) e il supporto per le OPEN_GL.

cmake_with

Ripremiamo “Configure” per fare il refresh e per vedere che questa volta la finestra centrale sia “bianca”.

Vi ricordo che ora è bianca perchè abbiamo tolto la spunta da BUILD_DOCS che cercava Doxygen e non per le altre configurazioni fatte.

cmake_ok

Se la finestra centrale è bianca e abbiamo “Configure done” allora è tutto Ok e possiamo cliccare su “Generate” per creare la soluzione Visual Studio.

cmake_generate

A questo punto dopo “Generating done” possiamo chiudere CMake e andare ad aprire la solution nella cartella dove abbiamo detto di crearla che nel mio caso è: C:\Users\fabio\Desktop\buildCuda

cmake_build_dir

Aprite la solutione, lanciate ALL_BUILD in Debug o Release e andate a prendere un caffè 🙂

Non vi è bastato vero il caffè? Sul mio PC impiega circa un’ora a Build (i7, 12GB ram, SSD HD).

vs13_cv3_debug

Una volta finito di Compilare lanciate la INSTALL.

Lanciate INSTALL che trovate in (CMakeTargets) per avere nella directory “install” le dll e librerie appena compilate

vs13_cv3_debug_install

vs13_cv3_debug_install_end

Ecco dove troverete le vostre DLL e LIB delle OpenCV compilate con CUDA

vs13_cv3_debug_install_end_dir

Io ora ho compilato in Debug.

Lanciando anche la compilazione in Release vedrete insieme le librerie di debug (*d.dll, *d.lib) assieme a quelle di release (*.dll, *.lib).

OpenCV 2.4.9

Per le OpenCV 2.4.9 il procedimento è praticamente identico, però ho dovuto impostare il CUDA_GENERATION dicendo esplicitamente la mia architettura ‘Kepler

cmake_cuda_generation

 

Altrimenti avevo l’errore di compilazione: Unsupported gpu architecture ‘compute_11’

Ho letto comunque che se si setta l’architettura specifica anche con le OpenCV 3.0 la compilazione è molto più veloce perchè non vengono compilati i file .cu per le altre architatture.

Senza specificarlo invece vengono compilati i .cu per tutte le architatture (GPU): Kepler, Fermi, etc…

E ho dovuto modificare il file NCV.cu (opencv-2.4.9\modules\gpu\src\nvidia\core\NCV.cu), andando ad includere il package “algorithm”:

#include <algorithm>

ncv.cu

Altrimenti mi dava l’errore: ‘max’ undefined error.

Compilare le OpenCV 3.0 con CUDA 7 e VisualStudio 2013 per x64

Debugging native applications with WinDBG

Configurare windows perchè tramite (WER – Windows Error Reporting) crei un user-mode minidump quando un’applicazione va in crash:

https://msdn.microsoft.com/en-us/library/windows/desktop/bb787181(v=vs.85).aspx


“Starting with Windows Server 2008 and Windows Vista with Service Pack 1 (SP1), Windows Error Reporting (WER) can be configured so that full user-mode dumps are collected and stored locally after a user-mode application crashes. Applications that do their own custom crash reporting, including .NET applications, are not supported by this feature (for those see http://www.codeproject.com/Articles/1934/Post-Mortem-Debugging-Your-Application-with-Minidu).

This feature is not enabled by default. Enabling the feature requires administrator privileges. To enable and configure the feature, use the following registry values under the

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps

key.

Value Description Type Default value
DumpFolder The path where the dump files are to be stored. If you do not use the default path, then make sure that the folder contains ACLs that allow the crashing process to write data to the folder.For service crashes, the dump is written to service specific profile folders depending on the service account used.For example, the profile folder for System services is %WINDIR%\System32\Config\SystemProfile.
For Network and Local Services, the folder is %WINDIR%\ServiceProfiles.
REG_EXPAND_SZ %LOCALAPPDATA%\CrashDumps
DumpCount The maximum number of dump files in the folder. When the maximum value is exceeded, the oldest dump file in the folder will be replaced with the new dump file. REG_DWORD 10
DumpType Specify one of the following dump types:

  • 0: Custom dump
  • 1: Mini dump
  • 2: Full dump
REG_DWORD 1
CustomDumpFlags The custom dump options to be used. This value is used only when DumpType is set to 0.The options are a bitwise combination of the MINIDUMP_TYPE enumeration values. REG_DWORD MiniDumpWithDataSegs | MiniDumpWithUnloadedModules | MiniDumpWithProcessThreadData.

These registry values represent the global settings.

You can also provide per-application settings that override the global settings.

To create a per-application setting, create a new key for your application under

HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\Windows Error Reporting\LocalDumps 
(for example,HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\Windows Error Reporting\LocalDumps\MyApplication.exe).

Add your dump settings under the MyApplication.exe key.

If your application crashes, WER will first read the global settings, and then will override any of the settings with your application-specific settings.

After an application crashes and prior to its termination, the system will check the registry settings to determine whether a local dump is to be collected.

After the dump collection has completed, the application will be allowed to terminate normally.

If the application supports recovery, the local dump is collected before the recovery callback is called.

These dumps are configured and controlled independently of the rest of the WER infrastructure.

You can make use of the local dump collection even if WER is disabled or if the user cancels WER reporting.

The local dump can be different than the dump sent to Microsoft.”


Testiamo quindi il tutto:

Creiamo un’applicazione nativa che vada in crash e chiamiamola WinDbgMinidumpTestCrash.exe (ecco il codice che utilizzerò per questo esempio)

#include <iostream>

using namespace std;

void main() {
	cout << "Hello, World!\n";
	cout << "Type a key\n";

	char c = 'a';
	cin >> c;

	// Crash!
	char *p;
	p[1] = 'b';
}

Abilitiamo quindi la generazione dei minidump per questa applicazione:

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps\WinDbgMinidumpTestCrash.exe]
"DumpType"=dword:00000001
"DumpFolder"=hex(2):43,00,3a,00,5c,00,74,00,65,00,6d,00,70,00,00,00

La cartella DumpFolder è “C:\temp”, il tipo di Dump è 1 (minidump).

Lanciamo quindi l’applicazione che andrà in crash e genererà a questo punto il suo minidump all’interno di C:\temp
windbg_crash1

windbg_crash2
A questo punto dobbiamo andare a lanciare WinDBG e caricare il file di dump appena creato:

Solo caricando il file… ci ammonisce che abbiamo un’eccezione…
windbg_crash3

Configuriamo la cartella dove mettere i simboli delle classi di Microsoft

*** configure symbols to be downloaded from Microsoft
.symfix c:\symbols

Ricarichiamo il tutto (lasciamo il tempo al download dei simboli)

*** Reload anything which has been loaded so far
.reload

windbg_crash4
Poi andiamo ad eseguire il comando che WinDbg ci diceva di lanciare per accedere alle informazioni sulla nostra eccezione

.excr

E boom! Ecco la riga incriminata! 😀
windbg_crash5
Se andiamo a lanciare anche il comando

!analyze -v

Ecco che WinDBG ci mostra esattamente il punto anche nella finestra di comando:

windbg_crash_analyze_v

 

Nel caso in cui il progetto con cui è stato compilato l’eseguibile non si trovi più nello stesso percorso (il modulo da errore di caricamento symboli):

crash_windbg7
occrre andare a dire a WinDBG dove trovare il .pdb e i sorgenti con gli appositi menu:
crash_windbg8
E richiamare nuovamente .ecxr

crash_windbg9

Ed ecco riapparire il nostro codice incriminato!

Ecco perchè a volte è bene tenere sotto versioning anche i file compilati e i file con i simboli di debug 😉
crash_windbg10

 

Debugging native applications with WinDBG