Changes

Jump to: navigation, search

DPS921/Intel Parallel Studio Inspector

8,473 bytes added, 19:44, 30 November 2020
Progress
- Hard and confusing to configurating projects
- It doesn’t support Microsoft OpenMP and TBB
- It can provide false positive and false negative
[[File:FalsePositiveEdited.png|800px]]
 
= Code for Intel Inspector =
 
== Pointer Miss Management {Memory Leak} ==
 
<syntaxhighlight lang="cpp" line='line'>
int main()
#include <iostream>
using namespace std;
 
const int maxSize = 10;
 
int main()
{
// declaring an array of pointers
int** mypointer = new int* [10];
 
// populating the array with pointers
cout << "\n Populating Array With Pointers \n" << endl;
for (int i = 0; i < maxSize; i++)
{
mypointer[i] = new int;
*mypointer[i] = i;
cout << *mypointer[i] << endl;
}
cout << "\n -----------------------------------------------" << endl;
 
 
// Switching every even numbered pointer to be pointing towards the next odd numbered pointer
cout << "\n Switching every even numbered pointer to be pointing towards the next odd numbered pointer \n" << endl;
for (int i = 0; i < maxSize; i++)
{
if (i % 2 == 0)
{
mypointer[i] = mypointer[i + 1];
}
}
cout << "\n -----------------------------------------------" << endl;
 
//Printing the results;
cout << "\n Results of the switch \n" << endl;
for (int i = 0; i < maxSize; i++)
cout << *mypointer[i] << endl;
 
cout << "\n -----------------------------------------------" << endl;
 
// deallocating memory
cout << "\n Deallocating Memory \n" << endl;
for (int i = 0; i < maxSize; i++)
{
int check = i % 2;
if (check == 0) {
delete mypointer[i];
mypointer[i] = nullptr;
}
else {
mypointer[i] = nullptr;
delete mypointer[i];
mypointer[i] = nullptr;
}
}
cout << "\n -----------------------------------------------" << endl;
 
cout << "\n Checking nullptr's" << endl;
for (int i = 0; i < maxSize; i++)
{
if (mypointer[i] == nullptr)
cout << "pointer [" << i << "] is a nullptr" << endl;
}
 
cout << "\n **There is now a memory leak with [" << (maxSize / 2) * 4 << "] bytes of data being unreachable **" << endl;
 
delete[] mypointer;
return 0;
}
</syntaxhighlight>
= How to use Intel Parallel Studio Inspector =
Once you downloaded intel Inspector application, you need to restart your Visual Studio for the feature to work.
Inside Visual Studio, there are two ways of accessing the inspector debugger. The first way is to go to the tools drop down menu and locate “Intel Inspector”, then you should be able to click on what you want to debug.
Second The first way is to locate go to the inspector icon, few directions right on tools. There will be a drop down menu that and locate “Intel Inspector”, then you should lets you choice be able to click on what choice of debugging you want to do or start a new analysisdebug.
[[File:VSInspector.png|800px]]
 
Second way is to locate the inspector icon, few directions right on tools. There will be a drop down menu that should lets you choice what choice of debugging you want to do or start a new analysis.
[[File:VSInspector2.png|800px]]
[[File:TimelineResults.png|800px]]
 
= Code for Intel Inspector =
 
== Pointer Miss Management {Memory Leak} ==
The Below code creates a dynamically allocated array of Integer pointers and allocates a new integer into each index.
In the Second For loop, the code goes onto make every even-numbered pointer point towards the next highest odd-numbered pointers memory address.
This Effectively causes a memory leak where half of the allocated memory locations no longer have any pointers pointing to them. After this, the code goes onto perform a delete operation on every pointer in an attempt to fool the Parallel Studio debugger.
 
 
<syntaxhighlight lang="cpp" line='line'>
int main()
#include <iostream>
using namespace std;
 
const int maxSize = 10;
 
int main()
{
// declaring an array of pointers
int** mypointer = new int* [10];
 
// populating the array with pointers
cout << "\n Populating Array With Pointers \n" << endl;
for (int i = 0; i < maxSize; i++)
{
mypointer[i] = new int;
*mypointer[i] = i;
cout << *mypointer[i] << endl;
}
cout << "\n -----------------------------------------------" << endl;
 
 
// Switching every even numbered pointer to be pointing towards the next odd numbered pointer
cout << "\n Switching every even numbered pointer to be pointing towards the next odd numbered pointer \n" << endl;
for (int i = 0; i < maxSize; i++)
{
if (i % 2 == 0)
{
mypointer[i] = mypointer[i + 1];
}
}
cout << "\n -----------------------------------------------" << endl;
 
//Printing the results;
cout << "\n Results of the switch \n" << endl;
for (int i = 0; i < maxSize; i++)
cout << *mypointer[i] << endl;
 
cout << "\n -----------------------------------------------" << endl;
 
// deallocating memory
cout << "\n Deallocating Memory \n" << endl;
for (int i = 0; i < maxSize; i++)
{
int check = i % 2;
if (check == 0) {
delete mypointer[i];
mypointer[i] = nullptr;
}
else {
mypointer[i] = nullptr;
delete mypointer[i];
mypointer[i] = nullptr;
}
}
cout << "\n -----------------------------------------------" << endl;
 
cout << "\n Checking nullptr's" << endl;
for (int i = 0; i < maxSize; i++)
{
if (mypointer[i] == nullptr)
cout << "pointer [" << i << "] is a nullptr" << endl;
}
 
cout << "\n **There is now a memory leak with [" << (maxSize / 2) * 4 << "] bytes of data being unreachable **" << endl;
 
 
 
delete[] mypointer;
return 0;
}
</syntaxhighlight>
 
As can be seen Below the Intel Parallel Inspector debugging tool was not fooled by the attempt to misguide it and effectively detected the leak. However it should also be pointed out that it did not detect where the leak occurs, but instead, where the pointer which is leaking is instantiated, furthermore, the debugging tool seems to be misdiagnosing memory errors having to do with improper instantiation, where none exist. This can be caused by the nature of the array having the same signature as a 2D array but being treated as a one dimensional array.
 
[[File:FalsePositive.png]]
 
== False Positive ==
The code below attempts to fool the Intel Parallel Inspector into assuming that the pointer allocated pointers have not been deleted when they have. The pointers address' are copied into a temporary pointer called deletor, which then is used to delete the allocated memory without directly calling the delete operation on the raw pointers themselves. The intel parallel studio does not fall for this attempt either. It accurately does not find a memory leak. However, it still shows a false positive for an uninitialized access error due to the nature of the array.
 
<syntaxhighlight lang="cpp" line='line'>
#include <iostream>
using namespace std;
 
const int maxSize = 10;
 
int main()
{
// declaring an array of pointers
int** mypointer = new int* [10];
 
// populating the array with pointers
cout << "\n Populating Array With Pointers \n" << endl;
for (int i = 0; i < maxSize; i++)
{
mypointer[i] = new int;
*mypointer[i] = i;
cout << *mypointer[i] << endl;
}
cout << "\n -----------------------------------------------" << endl;
 
 
// Switching every even numbered pointer to be pointing towards the next odd numbered pointer
cout << "\n deleting pointers \n" << endl;
 
int* deletor;
for (int i = 0; i < maxSize; i++)
{
deletor = mypointer[i];
cout << "Deleting [" << *deletor << "]" << endl;
delete deletor;
 
}
cout << "\n -----------------------------------------------" << endl;
 
//Printing the results;
cout << "\n Making everything a nullptr \n" << endl;
for (int i = 0; i < maxSize; i++)
mypointer[i] = nullptr;
 
 
 
cout << "\n Checking nullptr's" << endl;
for (int i = 0; i < maxSize; i++)
{
if (mypointer[i] == nullptr)
cout << "pointer [" << i << "] is a nullptr" << endl;
}
 
 
delete[] mypointer;
cout << "\n **There should be no memory leak**" << endl;
 
 
 
 
return 0;
}
</syntaxhighlight>
 
 
The image below showcases how The intel Parallel Inspector can show false positives. If you into the yellow highlighted section you will see that the error occurs on line 18 when we try to access *mypointer, which the inspector falsely claims not to have been initialized, however if we look at line 17 we can see that the pointer was properly initialized.
 
[[File:FalsePositiveCode.jpg]]
 
== Thread Race Conditions ==
 
The below code does three things. The fisrt is to define a class counter. This class has three functions and one member variable. the Variable is the counter which is meant to be iterated. The three functions are the constructor, which sets the counter to 0. The getter which returns the value of the counter and lastly the increment function add(), which when called increments the counter by the specified amount. Secondly the code defines the function runCounter() which is responsible for creating a counter type object, creating ten threads and assigning them all to increment the counter by 1,000 simultaneously. This creates the optimal conditions for a race condition to occur within the add() member function of the counter object. And lastly the main() function is responsible for running the runcounterFunction 10,000 times.
 
<syntaxhighlight lang="cpp" line='line'>
 
#include <iostream>
#include <thread>
#include <vector>
 
// Counter Object
class Counter;
int runCounter();
 
int main()
{
 
int val = 0;
 
// Runs the counter 1000 times and has 10 threads iterate it by 1000 each, needs to reach 10000 in total
for (int k = 0; k < 1000; k++)
{
if ((val = runCounter()) != 10000)
{
std::cout << "Error at count number = " << k << " Counter Value = " << val << std::endl;
}
}
return 0;
}
 
 
 
class Counter
{
//counter
int count;
public:
Counter() {
count = 0;
}
int getCounter() {
return count;
}
void add(int num) {
for (int i = 0; i < num; ++i)
{
// lock should be applied here
count++;
}
}
};
 
int runCounter()
{
Counter counter;
//creates a vector of threads
//Creates 10 threads gives it a reference to the counter object, resulting in 1000 count++ calss from each thread
std::vector<std::thread> threads;
for (int i = 0; i < 10; ++i) {
threads.push_back(std::thread(&Counter::add, &counter, 1000));
}
 
//joins threads
for (int i = 0; i < threads.size(); i++)
{
threads.at(i).join();
}
return counter.getCounter();
}
</syntaxhighlight>
 
As the image below shows, the Intel Parallel Inspector manages to accurately detect the race condition, and properly highlight it in the showcase window. It should be noted that this view creates the perfect perspective to guide a programmer to implement either a lock or a mutex on this particular segment of code.
 
[[File:ThreadRC.jpg]]
 
== OMP Race Conditions ==
 
The code below attempts to create a race condition using the OMP parallel construct. The race codnition is created by the variable temp, which is supposed to be a local variable for the specific thread which is used to collect the total sum for the calculations done by the thread. however if the variable is put outside the OMP parallel construct it becomes accessible by all the threads and is no longer a local variable. This causes a race condition.
 
<syntaxhighlight lang="cpp" line='line'>
 
#include <iostream>
#include <iomanip>
#include <omp.h>
 
 
// Race Condition
int main() {
int numThreads = 6;
int numSteps = 1000000;
omp_set_num_threads(numThreads);
double* sum = new double[numThreads];
double pi, totalSum = 0.0;
const double stepSize = 1.0 / numSteps;
 
// Creates The Race Condition, Place within the OMP Parallel to undo race condition
double temp = 0.0;
#pragma omp parallel
{
int ID = omp_get_thread_num();
int incriment = ID;
double x;
for (int i = ID; i < numSteps; i = i + numThreads) {
x = ((double)i + 0.5) * stepSize;
temp += 1.0 / (1.0 + x * x);
}
 
sum[ID] = temp;
}
 
for (int i = 0; i < numThreads; i++)
{
totalSum = totalSum + sum[i];
}
 
pi = (4.0) * totalSum * stepSize;
delete[] sum;
 
std::cout << "Expexted Number : 3.14___" << std::endl;
std::cout << "REceived Number : " << pi << std::endl;
 
}
</syntaxhighlight>
 
 
 
There are two images below, One is an image of the results of an analysis of the above code by the Intel Parallel Inspector which as can be seen has flagged race conditions in the file, however, upon closer examination it becomes apparent that the details about the race conditions are nonsensical and cannot be interpreted (this can be seen by looking at the highlighted portion of the code view). This can be explained by the second image below. Highlighted in that image in the red box a warning message can be seen warning the user that Microsoft OMP is not supported by the Intel Parallel Inspector which might cause false positives or inaccurate diagnostics
 
[[File:OMPRC.jpg]]
 
OMP Error Message Below
 
 
[[File:OMPError.jpg]]
 
 
 
However, it should also be mentioned that should the code be fixed and analysis is re-run the number of positives goes down from 4 to 2. This means that there is internal code generated by the OMP addon that results in the Inspector flagging false positives, but also that the Inspector is capable of detecting race-conditions in OMP code (MS Version), it's just not able to effectively pinpoint their location and communicate it to the programmer. (Image of analysis on fixed code below)
 
[[File:OMPFixed.jpg]]
= Reference =
Update 3: Sunday November 29th 2020 - Adding all the information for the report
 
Update 4: Monday November 30th 2020 - Made final edits to the Wiki
150
edits

Navigation menu