You are here:

C++/GCC vs MSVC++ compilation


QUESTION: Hi, I am about to lose my mind and hoping you can prevent it. Background: As part of a much-too-low budget science project I am stuck with the horrifying task of porting a home-made computing cluster (made by the undersigned, who has no formal programming background and is a complete amateur) from Excel VBA via C++ to CUDA (for obvious reasons). What is basically going on is that a 50 000 rows by 1 000 columns 2d array (5-digit integers) is loaded into memory from a text file, then an algorithm is run using a given set of input variables. Currently, this is taking place on some 30-50 cpu cores, each running their own excel/vba instance w. all the data inside. As results come out, each instance delivers them to a text file and receives a new set of inputs and starts over, and like so it goes on for infinity, although painstakingly slow, partly due to the code (which could surely have been more efficient), and partly, of course, due to the software. Can't wait to see those GPUs hammer this to pieces!

The first step was to create a c++ console app that was able to actually load all the data into a 2d array and perform some symbolic calculations (not the entire routine that I am planning to port). This I have done, and before I ran into the problem that this post is all about, I had also made good progress in figuring out how to distribute the work between CUDA kernels (the problem is NOT CUDA-related). My little cpp app has been created using CODE::BLOCKS for various reasons. However, the CUDA part of the project will need MSVC++ (I am using 2008 express), so I am compiling it there, too. In C::B, it runs beatifully, both debug and release. And it runs fine in MSVC++ too, EXCEPT: There are two loops, and one of them, it seems, needs 5 to 10 times more time to execute. Can you believe that? Identical code! Now here is my code, and it's the first loop that's killing me (reading the data into memory). On my quad XEON x5472 3ghz w 8gb ram, the C::B release needs 8-10 seconds to get it done, whereas the MSVC++ compilation needs 40-70 secs to get it done, so obviously somethin aint right. I should mention that although my OS is 64 bit, both compilers are 32, and I have compiled the MSVC++ version on a 32 bit machine too in order to eliminate that as a possible cause, getting the exact same difference there.

This is the entire code. In C::B there is only one file, containing only this code; in MSVC there are also stdfafx.h, targetver.h and stdafx.cpp, which are there by default. References to them have been removed from the MSVC++ code in order to have it identical (adding or removing the default #include "stdafx.h" and the int _tmain(int argc, _TCHAR* argv[]) doesn't matter).

Please save me from going mad. And talk to me like a child; remember, I only barely understand what is going on in there and have only been able to put it together using bits and pieces from here and there on the internet (took me almost a week).

#include <iostream>
#include <fstream>
#include <vector>
using namespace std;
#define COLUMNS 809
#define ROWS 34199
int main()
short unsigned int sek, secs, dag, dager; long double snittsum; float snitt;
vector<vector<int> > rundata(ROWS, vector<int>(COLUMNS));
fstream myfile ("Rundata.txt", ios::in);
 if (myfile.is_open())
   for(unsigned int i = 0;i < rundata.size();++i)
       {for(unsigned int j = 0;j < rundata[i].size();++j) {myfile >> rundata[i][j];}
myfile.clear(); myfile.close();
sek = 1; dag = 0; snittsum = 0;

cout<< "Sett inn antall koler du vil ha snittet av: "; cin>> dager;
cout<< "\n"; cout<< "Sett inn antall rader som skal være med: "; cin>> secs;
   for(int d =0; d<dager;d++)
       {dag++; for(int s=0;s<secs;s++)    {snittsum = snittsum + rundata[sek][dag]; sek++;}
   sek = 1;}
   cout<< "\n";cout<< "\n";cout<<"Snittsum var :"<<snittsum;
   cout<< "\n"; cout<< "\n"; snitt = ((snittsum/10.0)/(secs*dager));  cout<<"..og snitt var: "<<snitt;cout<< "\n";
   cout<< "\n";cout<< "\n"; cout<< "Vil du avslutte? \n"; cin>>dager;    cout<< "\n";

ANSWER: Hello Leonard.

Hang on to your mind. When you're dealing with this quantity of data, you should stay away from the friendly and convenient library functions and go to a lower level.

Using the QueryPerformanceCounter() function, you can see what sections of your code are taking the longest to run. That function returns CPU clock ticks.

I tested 4 Release versions of your file reading code.

1) Original version, text file read into vector: 65,877,075 ticks
2) Text File read into array: 63,614,807 ticks

My original idea that the vector was the cause of the problem was incorrect!

3) Binary file read into array, one number at a time: 2,556,770 ticks
Wow, that shows that fstream >> int is a very time consuming process.

4) Bulk read of binary file into array: 564,670 ticks.

In case you're wondering, the minimum time to initialize the array memory without reading from the file was 233,231 ticks.

Why was GCC was so much faster ? I don't know. Perhaps it has a more efficient implementation of the C++ library.

Generally, if you know the size of your data, you don't need to use a vector. It's more efficient to declare or allocate one large chunk of memory and use that as an array of any dimension you like.

You should use a binary file for your data, not ascii text.


My test code is below. Remember that when reading binary data, you must open the file as a binary file. That is what the "rb" parameter does in fopen. Otherwise your file read will stop on the first byte that looks like an end of file marker.

Also, notice that such a large array cannot be on the stack. That is why it was moved from inside main into the file scope.

#include <iostream>
#include <fstream>
#include <vector>

#include <Windows.h>
#include <stdio.h>

using namespace std;

#define COLUMNS 809
#define ROWS 34199

static int rundata[ROWS][COLUMNS];

int main(void)
   LARGE_INTEGER afterReading;

   FILE* fd = fopen("Rundata.bin", "rb");
   if (fd != NULL)
#if 1
       int readCount = (int)fread(rundata, sizeof(int), ROWS * COLUMNS, fd);
       for(unsigned int i = 0;i < ROWS/*rundata.size()*/;++i)
         for(unsigned int j = 0;j < COLUMNS/*rundata[i].size()*/;++j)
         int readCount = (int)fread(&rundata[i][j], sizeof(int), 1, fd);
         //if (readCount == 0) cout << "Read error eof " << feof(fd) << " error " << ferror(fd) << endl;
       cout << "Reading " << (afterReading.QuadPart - afterMakingVector.QuadPart) << endl;
       cout << "Cannot open file\n";
       return 0;

   return 0;

---------- FOLLOW-UP ----------

QUESTION: Hello again, Zlatko. First, let me just say that I am SO VERY grateful to receive such competent guidance. I have been working every minute now since you sent your answer, and I have almost managed get your code to work, but only almost. A couple of follow-up questions: 1. When you say "it was moved from inside main into the file scope" I assume you mean that I should put the file-reading code in a header file, i.e. "load.h" and put #include "load.h" among the other includes at the top of my main.cpp. Is that correct? If not, how, precisely, should it be incorporated? 2. You say I should use a binary file for data. I would have done that, but I haven't been able to figure out how to get my data into a file like that. The originating Excel 2007 .xlsb binary format file is only a third the size of the .txt that I am using, so no doubt it's better. I have actually been able to create a binary file using code snippets I've found, but it's twice as big as the .xlsb file and I haven’t been able to verify that my data have found their way in there correctly or to make the file work with your code. How can I safely transport my data from the cute little 70 MB .xlsb file to a .bin file like you're suggesting? 3. As a first time user of any forum on the internet, I am completely astounded by the fact that an expert like yourself is actually helping ME, and it feels like a miracle. Given the huge tasks that I am facing compared to my relatively low level of knowledge, I could easily keep you going night and day with all sorts of silly questions. Could you give me a guideline with regard to how much I may bother you, (or the other experts here, for that matter)? Don't know if questions make you happy or they bother you or how this whole thing works,really.

Hello Leonard.

I'm glad I could help. I'll address your questions.

1) File scope:
The vector rundata was originally in main. I suggested that you turn rundata into a two dimensional array. Variables declared in a function are created on the stack. An array the size of rundata cannot be created on the stack so I moved rundata out of main and into the global storage area. You can see it above the main function in the code I posted. I added the static keyword to the rundata declaration so that it would be visible only in the file that its in.

You should not put code or variables into header files. Header files should contain function declarations, macro definitions, extern variables, class definitions, and a few other things. Of course, class definitions can have short code in the class but generally code goes int .c and cpp files.

2) Getting code into binary format:
If the code in excel has to be extracted only once, then get it into the text format, and write a simple tool to read the text format and write out binary. After that you have the binary file to work with. I assume that once you have the binary file the spreadsheets could be thrown away. Is that correct? Do you need help with that?

It might be useful to have the first few integers in your binary file contain special information about the file. For example, you might store the dimensions of the array that the binary data represents. Then, when reading the file, you could create an array of those dimensions dynamically.

3) Silly questions:
Your project sounds interesting, and you seem keen to do much work yourself, so I don't mind helping. I get a little tired of people begging me to do their school work for them when they are not willing to do anything themselves, but you don't seem that way. Generally, I like people to go through the expert web site because I can set limits on number of questions per day. You can reach me at my special invitation only e-mail address at . I will let you know when I need a break.

Sorry for the errors in the code I posted. As a rule I run everything through a compiler before posting, but this time I was careless. The variable declaration of afterMakingVector was lost. Actually that variable is not even needed.


All Answers

Answers by Expert:

Ask Experts




No longer taking questions.


No longer taking questions.

No longer taking questions.

©2017 All rights reserved.