02. [40p] CPU Monitoring

For this task we will use CPUUsage.sln inside the CPUUsage folder and EvenimenteProcMon.sln inside the Task-02 folder.

:!: First of all, monitor the CPU usage of the CPUUsage process, using both Task Manager and Windows Performance Recorder.

Going further, we want to analyze EvenimenteProcMon program, which has the purpose of integrating your messages with Process Monitor, so these can be viewed as the process unfolds. It is necessary to understand any code, not perfectly, but at least to get the big picture of what is going on.

A ProcessMonitor class with 5 functions was created:

The code below highlights that it was declared globally:

MyProcMon __procMon;

This means that at the start of the process, before executing the main function, when the global variables are initialized, our class instance will be constructed along with the implicit handle for the Process Monitor message interface. The handle is closed when the object is destroyed, after the program's execution ends.

Another class was declared, ProcMonLogFunc, with the purpose of highlighting when entering and leaving a function. This led to defining the following macro, which declares a ProcMonLogFunc object and passes it the name of the current function as a parameter.

#define DBGTRACE_FN_ () ProcMonLogFunc __my_log __ (__ FUNCTIONW__)

:!: Start Process Monitor and change the filter to ProcessName contains EvenimenteProcMon. Select the profiling button as shown below:

After running the program, the Process Monitor tool will generate a capture containing multiple details. We should notice messages such as Output: =⇒ Func1 and Output: ⇐= Func1, with the associated timestamps for these events in the Time of Day column. The difference between these times indicates how long the execution took for Func1, expressed in hundreds of nanoseconds.

As it is inefficient to calculate by hand the times for each function, we can save the output in a .csv format, by going to File → Save and choosing the “Comma-Separated Values” option. The generated file will look like this:

"4:42:07.1846936 PM","EvenimenteProcMon.exe","6352","Debug Output Profiling","","","Output: ==>main"
"4:42:07.1848812 PM","EvenimenteProcMon.exe","6352","Debug Output Profiling","","","Output: Acesta e logul meu 1"
"4:42:07.1848883 PM","EvenimenteProcMon.exe","6352","Debug Output Profiling","","","Output: ==>Func1"
"4:42:07.1848955 PM","EvenimenteProcMon.exe","6352","Debug Output Profiling","","","Output: <==Func1"
"4:42:07.1848990 PM","EvenimenteProcMon.exe","6352","Debug Output Profiling","","","Output: ==>Func2"
"4:42:07.1849038 PM","EvenimenteProcMon.exe","6352","Debug Output Profiling","","","Output: <==Func2"
"4:42:07.1849069 PM","EvenimenteProcMon.exe","6352","Debug Output Profiling","","","Output: ==>Func3"
"4:42:07.1849105 PM","EvenimenteProcMon.exe","6352","Debug Output Profiling","","","Output: <==Func3"
"4:42:07.1849148 PM","EvenimenteProcMon.exe","6352","Debug Output Profiling","","","Output: Acesta e logul meu 2"
"4:42:07.1849184 PM","EvenimenteProcMon.exe","6352","Debug Output Profiling","","","Output: <==main"

:!: Create a simple parser in Python to find out easier the total time spent in every function. If you only want to take into account the CPU usage, you need to have logging messages before and after every I/O operation, in order to not count in their time.