Exclude C++ standard library function calls from gprof output - c++

I am using the C++ standard library in some C++ code and this makefile:
CC=g++
CXXFLAGS=-Wall -Werror -ggdb3 -std=c++11 -pedantic $(OTHERFLAGS)
cpp_sort: cpp_sort.o
g++ -o $# $(CXXFLAGS) $^
clean:
rm -rf *.o cpp_sort *~
The source code:
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
void get_input(vector<int>& items, int size) {
for (int i = 0; i < size; ++i) {
int element;
cin >> element;
items.push_back(element);
}
}
void cpp_sort(vector<int>& items) {
sort(items.begin(), items.end());
}
void print_array(vector<int>& items) {
for (auto& item : items) {
cout << item << ' ';
}
cout << endl;
}
int main() {
int size;
cin >> size;
vector<int> items;
items.reserve(size);
get_input(items, size);
cpp_sort(items);
print_array(items);
}
I call make like this:
make OTHERFLAGS=-pg
run the program (where large.txt is a long list of integers):
./cpp_sort <large.txt
and view the profiling information:
grof ./cpp_sort
Which is fine and it does work, but the calling of my functions is obscured by all the C++ standard library function calls. Is there a way to exclude the standard library internal function calls?

Related

Program crashing with C++ DLL using OpenMP

I have a program using OpenMP on C++ and I need it to port into Dll so I can call it from Python. It returns an array of double values, which calculated using a lot of for loops with openmp pragma. I was doubtful if it is going to work, so I started from a little test program that calculates Pi value in a loop with different precision values, then I would measure performance and ensure that OpenMP works properly that way. Plain (w/o Omp) implementation works fine from Python and C++, however Omp variant gives a runtime error in Python (exception: access violation writing 0x000000000000A6C8) and crashes without an error in C++. Also Omp variant works fine if it is not a Dll and just a regular executable. The Dll is made with a makefile. App that uses the Dll built into an executable with g++ with no flags (source code is in UnitMain.cpp). All the relevant code and a Makefile below (I didn't include some files and functions for brevity).
UPD: I tried Microsoft compiler and it works, also I tested a linux dynamic library on WSL/g++ and it also works. Looks like it is Windows gcc specific, I'll try another version of gcc (btw my current version is this):
Thread model: posix gcc version 8.1.0 (x86_64-posix-seh-rev0, Built by MinGW-W64 project)
UnitFunctions.cpp
#include "UnitFunctions.h"
#include <omp.h>
#include <stdio.h>
#include <string.h>
typedef long long int64_t;
double pi(int64_t n) {
double sum = 0.0;
int64_t sign = 1;
for (int64_t i = 0; i < n; ++i) {
sum += sign/(2.0*i+1.0);
sign *= -1;
}
return 4.0*sum;
}
void calcPiOmp(double* arr, int N) {
int64_t base = 10e5;
#pragma omp parallel for
for(int i = 0; i < N; ++i) {
arr[i] = pi(base+i);
}
}
UnitMain.cpp
#include <windows.h>
#include <iostream>
using namespace std;
struct DllHandle
{
DllHandle(const char * const filename)
: h(LoadLibrary(filename)) {}
~DllHandle() { if (h) FreeLibrary(h); }
const HINSTANCE Get() const { return h; }
private:
HINSTANCE h;
};
int main()
{
const DllHandle h("Functions.DLL");
if (!h.Get())
{
MessageBox(0,"Could not load DLL","UnitCallDll",MB_OK);
return 1;
}
typedef const void (*calcPiOmp_t) (double*, int);
const auto calcPiOmp = reinterpret_cast<calcPiOmp_t>(GetProcAddress(h.Get(), "calcPiOmp"));
double arr[80];
calcPiOmp(arr, 80);
cout << arr[0] << endl;
return 0;
}
Makefile
all: UnitEntryPoint.o UnitFunctions.o
g++ -m64 -fopenmp -s -o Functions.dll UnitEntryPoint.o UnitFunctions.o
UnitEntryPoint.o: UnitEntryPoint.cpp
g++ -m64 -fopenmp -c UnitEntryPoint.cpp
UnitFunctions.o: UnitFunctions.cpp
g++ -m64 -fopenmp -c UnitFunctions.cpp
A Python script
import numpy as np
import ctypes as ct
cpp_fun = ct.CDLL('./Functions.dll')
cpp_fun.calcPiNaive.argtypes = [np.ctypeslib.ndpointer(), ct.c_int]
cpp_fun.calcPiOmp.argtypes = [np.ctypeslib.ndpointer(), ct.c_int]
arrOmp = np.zeros(N).astype('float64')
cpp_fun.calcPiOmp(arrOmp, N)

C++ Multiple definition of helper function

EDIT: Answered -- the issue was that because the functions had the same signature, despite them being in separate files, C++ saw both versions and got confused.
I have three classes: Table and Bed both inherit from Furniture.
Table and Bed each have a helper function GetLowerCase(std::string) defined in each class individually. When make is run (Makefile shown below), I get an error saying that GetLowerCase in Bed.cpp was first defined in Table.cpp
Makefile:
main: main.o Furniture.o Table.o Bed.o
g++ main.o Furniture.o Table.o Bed.o -o main
main.o: main.cpp
g++ -c main.cpp
Furniture.o: Furniture.cpp Furniture.h
g++ -c Furniture.cpp
Table.o: Furniture.cpp Table.cpp Table.h
g++ -c Table.cpp
Bed.o: Furniture.cpp Bed.cpp Bed.h
g++ -c Bed.cpp
clean:
rm *.o main
Table.cpp:
#include "Table.h"
#include <iostream>
#include <string>
std::string GetLowerCase(std::string str)
{
std::string out;
for (int i=0; i<str.length(); i++)
{
out[i] = tolower(str[i]);
}
return out;
}
Table::Table(const std::string n, std::string wt) : Furniture(n)
{
wood_type = GetLowerCase(wt);
if (wood_type != "pine" && wood_type != "oak")
{
std::cerr << "Wood type must be OAK or PINE.";
}
}
void Table::Print()
{
Furniture::Print();
std::cout << "Wood Type: " << wood_type << std::endl;
}
Bed.cpp:
#include "Bed.h"
#include <iostream>
#include <string>
std::string GetLowerCase(std::string str)
{
std::string out;
for (int i=0; i<str.length(); i++)
{
out[i] = tolower(str[i]);
}
return out;
}
Bed::Bed(const std::string n, std::string sz) : Furniture(n)
{
size = GetLowerCase(sz);
if (size != "twin" && size != "full" && size != "queen" && size != "king")
{
std::cerr << "Bed size must be TWIN, FULL, QUEEN, or KING.";
}
}
void Bed::Print()
{
Furniture::Print();
std::cout << "Size: " << size << std::endl;
}
I would have thought that GetLowerCase would be entirely contained within the .cpp file it was defined in and wouldn't be "seen" by any other files.
It's not in any header or source files besides the two listed above. Very confused, and would love some help!
Either declare your function static or wrap it in an anonymous namespace:
namespace {
// duplicated names here.
}
Your options:
Move all your helper functions into a helper class (like CommomUtils) as static member functions. I recommend this way, it's more C++, and you can avoid duplicate code.
Declare your function as static. So its scope would be in file that defines it, rather than global.
Warp your function with namespace.
Defines your function only once, and in file you want to use it, use extern std::string GetLowerCase(std::string str) to declare it, then you can call it.

CodeBlocks compiler issue, C++

I'm using CodeBlocks for C++ and it's probably a compiler issue. I am learning using vector pointer and tried to create function that return vector pointer. Below is my code. It has compiled and executed before without using pointer. Now I try to have a function that returns pointer, but somehow it doesn't work and I couldn't figure out the errors. Please help.
error:
main.cpp|8|undefined reference to `RandomNum::RandomNum(int, int, int, int)
main.cpp|9|undefined reference to `RandomNum::getVecPointer()
main.cpp
#include <iostream>
#include "RandomNum.h"
using namespace std;
int main()
{
RandomNum rand(5, 5, 100, 1000); <----error
vector<float>* p = rand.getVecPointer();
cout << (*p)[0] << endl;
return 0;
}
RandomNum.h
#include <vector>
#ifndef RANDOMNUM_H
#define RANDOMNUM_H
class RandomNum
{
private:
int M, x, y, z; //M is the number of cells
std::vector <float> aVector;
public:
//constructor
RandomNum(int, int, int, int);
//generate random float between 0 and 1;
float unif();
//build a vector of random points
std::vector<float>* getVecPointer();
};
#endif
RandomNum.cpp
#include "RandomNum.h"
#include <cmath> //for trunc()
RandomNum::RandomNum( int MM,int xx, int yy, int zz )
{
//x, y, z are seeds, M is the number of random numbers to be generated [0,1]
M = MM;
x = xx;
y = yy;
z = zz;
}
float RandomNum::unif()
{
float tmp;
...
return(tmp - trunc(tmp));
}
std::vector<float>* RandomNum::getVecPointer()
{
int i ;
for (i = 0 ; i < M; i++)
{
float x = unif();
aVector.push_back(x);
}
return &aVector;
}
I'm unable to reproduce your problem. I downloaded your files and I created a Makefile:
OLIST += rand.o RandomNum.o
CFLAGS += -Wall -Werror
all: rand
%.o: %.cpp
c++ $(CFLAGS) -c $<
rand: $(OLIST)
c++ -o rand $(OLIST)
clean:
rm -f *.o rand
Here's the output of the make:
c++ -Wall -Werror -c rand.cpp
c++ -Wall -Werror -c RandomNum.cpp
c++ -o rand rand.o RandomNum.o
Note that because you were having a compile issue, I nop'ed the trunc call so things would be simpler (i.e. it wasn't germane to the problem you were having). Also, I renamed main.cpp to rand.cpp [again, should make no difference]
If you use the public member vector::at function, which returns an element at position i in the vector, your code will work...
int main()
{
RandomNum rand(5, 5, 100, 1000); // <----error
vector<float>* p = rand.getVecPointer();
for (int i = 0; i < p->size(); i++) {
cout << (p)->at(i);
}
return 0;
}
Although this is a valid program, there are few reasons to use pointer to vector. Vectors are built to use Resource Acquisition Is Initialization (RAII), a method of managing their own memory. When you use pointer to vector, you defeat the purpose of RAII. You may have to deal with memory allocation/cleanup, null pointers, etc, which is what RAII is supposed to spare you from.
Your getVecPointer() function can return the vector::data public member function which returns a pointer to the first element in the array used internally by the vector...
int* p = myvector.data();

What is wrong with vectors of Armadillo library

Previously I posted a question which was a bit complicated in some sense. In this question, I made a simple example to generate the same problem with Armadillo library which is supposed to be very fast.
Considering the following code with two main functions only one is activated at each time:
#include <armadillo>
const int runmax=50000000;
arma::vec::fixed<3u> x,y;
double a,b;
void init()
{
x<<0.2<<arma::endr<<-0.3<<arma::endr<<0.1;
y<<1<<arma::endr<<1<<arma::endr<<1;
a=0.3;
b=a*a;
}
template<unsigned N>
void scaledsum(double a,arma::vec::fixed<N> &x,double b,arma::vec::fixed<N> &y)
{
for(int i=0;i<N;i++)
{
y(i)=a*x(i)+b*y(i);
}
}
void main1()
{
for(int i=0;i<runmax;i++)
{
y=a*x+b*y;
}
}
void main2()
{
for(int i=0;i<runmax;i++)
{
scaledsum(a,x,b,y);
}
}
int main()
{
init();
//main1();
main2();
y.print();
return 0;
}
perf stat ./main1
perf stat ./main2
I expect main1 runs faster than main2. or at least very close to it. But main1 runs slower.
I do not understand such profiling:
main1
0.209682235 seconds time elapsed
main2
0.121644777 seconds time elapsed
PS
Compilation command: g++ -std=c++11 -O3 -s -DNDEBUG test.cpp

Getting a Dwarf Error Version '4'

I am having some trouble with my school project. I think that it may be an error with my use of pointers but I am not sure why I am getting this error. This code is incomplete but I am trying to test it along the way. Do you have any idea why I am getting this error and what does it mean? Thanks!
Error from Cygwin Terminal
-bash-3.2$ make clean
rm -rf *.o simulate
-bash-3.2$ make simulate
g++ -c -g Main.cpp
g++ -c -g Maze.cpp
g++ Main.o Maze.o -o simulate
/usr/bin/ld: Dwarf Error: found dwarf version '4', this reader only handles version 2 information.
Maze.o: In function `Maze::createMaze(char*)':
Maze.cpp:(.text+0x49): undefined reference to `Node::Node(char)'
collect2: error: ld returned 1 exit status
make: *** [simulate] Error 1
Main.cpp
#include <iostream>
#include <fstream>
#include <string>
#include "Maze.h"
using namespace std;
int main()
{
int array_size = 1024;
char * mazeArray = new char[array_size];
int position = 0;
string mazeName;
Maze Maze1;
cout << "Enter the name of the maze file: ";
getline(cin, mazeName);
ifstream fin(mazeName.c_str());
//File opened successfully
if(fin.is_open())
{
while(!fin.eof() && position < array_size)
{
fin.get(mazeArray[position]); //reading one character from file to mazeArray
position++;
}
mazeArray[position-1] = '\0'; //placing character mazeArray terminating character
for(int i = 0; mazeArray[i] != '\0'; i++){
if(isspace(mazeArray[i]))
mazeArray[i] = mazeArray[i+1];
}
cout << "Displaying mazeArray..." << endl << endl;
//this loop display all the charaters in mazeArray till \0
for(int i = 0; mazeArray[i] != '\0'; i++)
{
cout << mazeArray[i];
}
cout << endl;
Maze1.createMaze(mazeArray);
}
else //file could not be opened
{
cout << "File could not be opened." << endl;
}
return 0;
}
Maze.h
#ifndef MAZE_H
#define MAZE_H
#include <string>
#include <sstream>
#include <vector>
#include "Node.h"
using namespace std;
class Maze
{
public:
void createMaze(char*);
void availablePaths();
void displayPath();
void moveNorth();
void moveSouth();
void moveEast();
void moveWest();
int getroomCount();
char getpathHistory();
char getcurrentRoom();
private:
int roomCount;
char pathHistory[];
Node* currentRoom;
Node* nodeArray[12];
struct isPath;
vector<Node*> nodeVector;
};
#endif
Maze.cpp
#include <iostream>
#include <string>
#include "Maze.h"
using namespace std;
Node* Node1;
void Maze::createMaze(char *inFile){
int count = 0;
//Creates Nodes for Maze
for(int ii = 0; ii <= 12; ii++){
Node1 = new Node(inFile[count]);
nodeVector.push_back(Node1);
count = count + 5;
//If there is not another node break out of the for loop.
if(inFile[count] == '\0'){
break;
}
}
}
void Maze::availablePaths(){
}
void Maze::displayPath(){
}
void Maze::moveNorth(){
}
void Maze::moveSouth(){
}
void Maze::moveEast(){
}
void Maze::moveWest(){
}
int Maze::getroomCount(){
}
char Maze::getpathHistory(){
}
char Maze::getcurrentRoom(){
}
Node.h
#ifndef NODE_H
#define NODE_H
#include <string>
#include <map>
#include <sstream>
using namespace std;
class Node
{
public:
Node(char);
void setNodeName(char);
void attachNewNode(Node, int);
Node *getAttachedNode(int);
private:
char name; // Title that is displayed above the menu.
Node *attachedNodes[4];
};
#endif
Node.cpp
#include <iostream>
#include <string>
#include <vector>
#include "Node.h"
using namespace std;
Node::Node(char name) : name(name) {
}
void Node::setNodeName(char tempName){
name = tempName;
}
void Node::attachNewNode(Node temp, int direction){
attachedNodes[direction] = temp;
}
Node Node::getAttachedNode(int direction){
return attachedNodes[direction];
}
makefile
#!/bin/bash
#file:makefile
CC = g++
CFLAGS = -c -g
simulate: Main.o Maze.o
$(CC) Main.o Maze.o -o simulate
Main.o: Main.cpp Maze.h
$(CC) $(CFLAGS) Main.cpp
Maze.o: Maze.cpp Menu.h Node.h
$(CC) $(CFLAGS) Maze.cpp
Node.o: Node.cpp Node.h
$(CC) $(CFLAGS) Node.cpp
clean:
rm -rf *.o simulate
The problem is not in your code, per se.
One problem is that your linking command is failing because you are not linking all your object files. You need to link Main.o, Maze.o and Node.o to create the executable:
g++ Main.o Maze.o Node.o -o simulate
Another problem is that your compiler is newer than your linker. The compiler is generating debugging information using Dwarf version 4, but your linker (/usr/bin/ld) only understands Dwarf version 2.
/usr/bin/ld: Dwarf Error: found dwarf version '4', this reader only handles
version 2 information.
You need to update your linker to a newer version compatible with the compiler you are using.
Or, as janneb suggests in a comment, you can use -gdwarf-2 in both the compilation and link lines. In the makefile:
CFLAGS = -c -gdwarf-2
FILES.cpp = Main.cpp Maze.cpp Node.cpp
FILES.o = $(FILES.cpp:.cpp=.o}
simulate: $(FILES.o)
$(CC) $(CFLAGS) $(FILES.o) -o $#
(There should be few parts of command lines in a makefile that are not macro invocations; then you can change everything more easily.)
You will need to remove the Dwarf-4 object files and recompile to avoid the error/warning.
You can simply fix this by:
export CFLAGS='-gdwarf-2 -gstrict-dwarf'
Then, remake your project.