0

I have a method in my project which when placed into its own program takes mere seconds to run, when run inside the project where it belongs it takes 5 minutes. I have NO idea why. I have tried profiling, taking bits out, changing this and that. I'm stumped.

It populates a vector of integers to be used by another class, but this class is not currently being instantiated. I have checked as much as I can and it does seem as if there really is nothing else happening but the method magically taking longer in one project than it does in another.

The method is run at startup and takes about 5 minutes, or about 3 seconds if run on its own. What could be causing this? Strange project settings? Multithreading stuff that I'm unaware of? (as far as I know there is none in my project anyway unless it's done automatically).

There is a link to the project here. If anyone could solve this for me I would be so grateful, and as soon as I can will start a bounty for this.

The method is called PopulatePathVectors and runs in Level.cpp. Commenting out the call to the method (in the level constructor) means the program starts up in seconds. The only other class that uses the lists it generates is Agent, but currently none are being instantiated.

EDIT - As requested, here is the code. Although keep in mind that my question is not 'why is the code slow?' but 'why is it fast in one place and slow in my project?'

//parses the text path vector into the engine
void Level::PopulatePathVectors(string pathTable)
{
    // Read the file line by line.
    ifstream myFile(pathTable);

        for (unsigned int i = 0; i < nodes.size(); i++)
        {
            pathLookupVectors.push_back(vector<vector<int>>());

            for (unsigned int j = 0; j < nodes.size(); j++)
            {
                string line;

                if (getline(myFile, line)) //enter if a line is read successfully
                {
                    stringstream ss(line);
                    istream_iterator<int> begin(ss), end;
                    pathLookupVectors[i].push_back(vector<int>(begin, end));
                }
            }
        }
}

EDIT - I understand that the code is not the best it could be, but that isn't the point here. It runs quickly on it's own - about 3 seconds and that's fine for me. The problem I'm tying to solve is why it takes so much longer inside the project.

EDIT - I commented out all of the game code apart from the main game loop. I placed the method into the initialize section of the code which is run once on start up. Apart from a few methods setting up a window it's now pretty much the same as the program with ONLY the method in, only it STILL takes about 5 minutes to run. Now I know it has nothing to do with dependencies on the pathLookupVectors. Also, I know it's not a memory thing where the computer starts writing to the hard drive because while the slow program is chugging away running the method, I can open another instance of VS and run the single method program at the same time which completes in seconds. I realise that the problem might be some basic settings, but I'm not experienced so apologies if this does disappointingly end up being the reason why. I still don't have a clue why it's taking so much longer.

It would be great if this didn't take so long in debug mode as it means waiting 5 minutes every time I make a change. There MUST be a reason why this is being so slow here. These are the other included headers in the cut down project:

#include <d3d10.h>
#include <d3dx10.h>
#include "direct3D.h"
#include "game.h"
#include "Mesh.h"
#include "Camera.h"
#include "Level.h"

#include <vector>

using namespace std;

EDIT - this is a much smaller self contained project with only a tiny bit of code where the problem still happens.

this is also a very small project with the same code where it runs very fast.

Dollarslice
  • 9,917
  • 22
  • 59
  • 87
  • Have you compared the assembly generated in and out of your project? – Rup Nov 14 '11 at 10:54
  • could be either project settings or memory hog (is it taking more memory than the RAM you have?) – CharlesB Nov 14 '11 at 10:55
  • 10
    Please, show us the relevant code here. You can't really expect people to download unknown files off the internet, and then browse through your entire project's code, just to be able to help you – jalf Nov 14 '11 at 10:55
  • Is one in debug and the other release? Difference in memory managers? You mention populating vectors, are you hitting std collection debug checking? – ssube Nov 14 '11 at 10:56
  • 3
    I'm not sure a lot of people will download that zip file. Try to create a minimal test case that reproduces the problem and post it inline here. – Mat Nov 14 '11 at 10:56
  • 2
    Can't you create a [Short, Self Contained, Correct (Compilable), Example](http://sscce.org/) instead of asking people do download a 30MB archive? – Some programmer dude Nov 14 '11 at 10:57
  • I haven't looked at the code, but from what I read the function looks like it is called multiple times; try to add breakpoints and see the backtrace every time you have a hit to know where the unwanted calls comes from. – wormsparty Nov 14 '11 at 11:03
  • Well, if you comment out/remove from build everything else except your class/method then you DO have a 'project which when placed into its own program takes mere seconds to run'. Somewhere, removing something will reduce your run time. You do, at least, have a way of repoducing the problem, (do a full build), and a way of removing it, (place the class/call in a project of its own). Given that, you should be able to debug it on your own. – Martin James Nov 14 '11 at 11:16
  • @wormsparty i tried this, it's only called once. – Dollarslice Nov 14 '11 at 12:27
  • @JoachimPileborg I have specifically said that the problem is not the code, but why it runs slowly in this particular project. I also said that I created a stand alone project for the function, and it runs quite fast, therefore doing what you ask would not be of help. Thank you for your advice anyway. – Dollarslice Nov 14 '11 at 13:16
  • possible exact duplicate to [this question](http://stackoverflow.com/q/7809473/1025391)? – moooeeeep Nov 14 '11 at 19:30
  • @fmaas yeah I know, but they did start off differently. The other question was about optimisation, but since I realised (through this question) that the problem wasn't really about that, I updated the info on the other one anyway. – Dollarslice Nov 14 '11 at 20:25
  • Have you measured the actual performance of just the method in question with something like `QueryPerformanceCounter`? http://stackoverflow.com/questions/1739259/how-to-use-queryperformancecounter – Michael Price Nov 22 '11 at 15:26
  • @MichaelPrice: I measured his projects. The same code in one project runs in 6.31s on (about 9000 faults/sec). The same code in his main project only has ~300 faults/sec, taking 178.31 to run. The project settings are the same as far as I can tell, both single threaded. – Mooing Duck Nov 22 '11 at 18:43
  • By doing various optimizations I was able to bring them down to 4.00s and 74.40s respectively, but cannot explain why they are different, other than in the big project, there's several other heap allocations first. – Mooing Duck Nov 22 '11 at 18:53
  • @MooingDuck - Cache line problems? Does the changing the size of the input file change the relative run times? What happens if you preallocate with `reserve`? – Michael Price Nov 22 '11 at 18:59
  • @MichaelPrice: Preallocating with reserve brought it down to 74.40. But I've just observed that MSVC9 runs it in 15.88s. Curiouser and curiouser. – Mooing Duck Nov 22 '11 at 19:14
  • @MichaelPrice: You're brilliant. The "fast" project wasn't loading the file at all. – Mooing Duck Nov 22 '11 at 20:00
  • @MooingDuck - Thus the case of the finicky function has been resolved. – Michael Price Nov 22 '11 at 20:05

3 Answers3

6

I ran this code in MSVC10 (same compiler you are using) and duplicated your results with the projects you provided. However I was unable to profile with this compiler due to using the express version.

I ran this code in the MSVC9 compiler, and it ran 5 times faster! I also profiled it, and got these results:

Initialize (97.43%)
    std::vector::_Assign (29.82%) 
        std::vector::erase (12.86%)
            std::vector::_Make_iter (3.71%)
            std::_Vector_const_iterator (3.14%)
        std::_Iterator_base (3.71%)
        std::~_Ranit (3.64%)
    std::getline (27.74%)
        std::basic_string::append (12.16%)
            std::basic_string::_Grow (3.66%)
            std::basic_string::_Eos (3.43%)
        std::basic_streambuf::snextc (5.61%)
    std::operator<<(std::string) (13.04%)
        std::basic_streambuf::sputc(5.84%)
    std::vector::push_back (11.84%)
        std::_Uninit_move::?? (3.32%)
    std::basic_istream::operator>>(int) (7.77%)
        std::num_get::get (4.6%)
            std::num_get::do_get (4.55%)

The "fast" version got these results: (scaled to match other times):

Initialize (97.42%)
    std::_Uninit_copy (31.72%)
        std::_Construct (18.58%)
        std::_Vector_const_iterator::operator++ (6.34%)
        std::_Vector_const_iterator::operator!= (3.62%)
    std::getline (25.37%)
        std::getline (13.14%)
        std::basic_ios::widen (12.23%)
    std::_Construct (18.58%)
        std::vector::vector (14.05%)
    std::_Destroy (14.95%)
        std::vector::~vector (11.33%)
    std::vector::_Tidy (23.46%)
        std::_Destroy (19.89%)
            std::vector::~vector (12.23%)
        [ntdll.dll] (3.62%)

After studying these results and considering Michael Price's comments many times, it dawned on me to make sure the input files were the same size. When this dawned on me, I realized the profile for the "fast" version, does not show std::operator<<(std::string) or std::vector::push_back at all, which seems suspicious. I checked the MethodTest project, and found that it did not have a WepTestLevelPathTable.txt, causing the getline to fail, and the entire function to do almost nothing at all, except allocate a bunch of empty vectors. When I copied the WepTestLevelPathTable.txt to the MethodTest project, it is exactly the same speed as the "slow" verison. Case solved. Use a smaller file for debug builds.

Mooing Duck
  • 64,318
  • 19
  • 100
  • 158
2

Here're a few methods I believe could slow down the start-up process:

  1. Level::GenerateGridNodes():

    void Level::GenerateGridNodes()
    {
        int gridHeight = gridSize;
        int gridWidth = gridSize;
    
        // ADD THIS STATEMENT:
        nodes.reserve(gridHeight*gridWidth);
    
        for (int h = 2; h <= gridHeight; h++)
        {
            for (int w = 2; w <= gridWidth; w++)
            {
                nodes.push_back(Node(D3DXVECTOR3((float)w, (float)h, 0)));
            }
        }
    }//end GenerateGridNodes()
    
  2. Level::CullInvalidNodes(): For std::vectors, use remove-erase idiom to make erasing elements faster. You also need to re-think of how this function should work because it seems to have lots of redudant erasing and adding of nodes. Would it make sense in the code that instead of erasing you could simply assign the value you push_back() right after deletion to the value you're erasing? So instead of v.erase(itr) followed by v.push_back(new_element), you could simply do *itr = new_element;? DISCLAIMER: I haven't looked at actually what the functions does. Honestly, I don't have the time for that. I'm just pointing you to a possiblity.

  3. In Level::LinkNodes():

    void Level::LinkNodes()
    {
        //generates a vector for every node
        // ADD THIS BEFORE THE FOR LOOP
        nodeAdjacencyVectors.reserve(nodes.size());
        for (unsigned int i = 0; ....)
        //... Rest of the code
    }//end LinkNodes()
    

In short, you still have got room for a lot of improvement. I believe the main hog is the Level class functions. You should have another look through it and probably rethink how each function should be implemented. Especially those invoked within the constructor of Level class.

Vite Falcon
  • 6,575
  • 3
  • 30
  • 48
  • I will do those things, and yes I have a lot to improve. However this doesn't explain why it would be running slowly in my project but very fast somewhere else. – Dollarslice Nov 14 '11 at 12:29
  • @SirYakalot: That would most probably be because Visual Studio will attach its 'Debugger' when running an application from VS. You should: (a) Run the application on its own (b) Compile your application in 'Release' mode to see its actual performance. This is because in 'Debug' mode the code gets extra validation checks and does not get optimized to help you debug your application in the event that you find a bug. In 'Release' mode, these checks and extra code are taken off. In addition to that your code will get optimized to run in the fastest possible manner. – Vite Falcon Nov 14 '11 at 12:56
  • Thanks for the info. Does this explain why it would run faster in another vs project? or would this apply to both? – Dollarslice Nov 14 '11 at 13:14
  • @SirYakalot: When you say another VS project is it that you've added your files to a new project and see that there's a performance boost? If so, was that project running in 'Release' mode? I see that you've only compiled your 'exe' in 'Debug' mode, hence my question. – Vite Falcon Nov 14 '11 at 13:21
  • No it was in debug mode also. I simply put the function into the main of an empty project and it runs quite fast. – Dollarslice Nov 14 '11 at 13:29
  • @SirYakalot: Sorry, frankly I am a bit lost. Are you trying to say that you ran ONLY this function in your original project, the same way you ran it in another project? Meaning, ONLY this function runs in both projects? – Vite Falcon Nov 14 '11 at 13:34
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/4974/discussion-between-vite-falcon-and-siryakalot) – Vite Falcon Nov 14 '11 at 13:35
  • I replied in chat also, but in case anyone else is confused about this; one program runs just the method, and is fast, while the other more complex program takes far longer to execute the same method. I'm very willing to accept the fact that this may be due to something basic I'm not understanding. I am fairly new to programming. – Dollarslice Nov 14 '11 at 18:25
0

It contained a loop withing a loop, each inner loop reads each line of an over 30MB data file. Of course it's going to be slow. I would say it's slow by design.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621