My CPU usage is absurd
Gabriel Campos

I dont know how to solve this. My CPU goes to above 50% in only drawing a sprite and a background. :o:o:o
I looked and find the responsable for that...

in the line

void State_inGame::render()
{
    level.render(0); // Guilts :(
    level.render(1);

    for(std::vector<Entity *>::iterator it = v_entity.begin(); it!= v_entity.end(); it++)
    {
        Entity *e = *it;
        e->render();
    }
}

level.render(0);
level.render(1);
These are the responsable for that. If i comment these lines, no problems. So, why this two lines are making that? I am using mappy_a5.

This is the function level.render

void Level::render(int layer)
{
    MapChangeLayer(layer);
    MapDrawBG(0, 0, 0, 0, 1600, 608); EDIT: This is the responsable! Why? ???
}

Thanx

Edgar Reynaldo

Make sure all your bitmaps are video bitmaps. Drawing memory bitmaps can be very slow and cpu intensive. That may be what is happening.

Thomas Fjellstrom

What version of Allegro? I suspect those functions are from Mappy.

Edgar's advice is for Allegro 5, and don't really apply to Allegro 4

Edgar Reynaldo

He said he was using mappy_a5

Thomas Fjellstrom

He said he was using mappy_a5

You know what? Ignore that Moose guy. He's stupid.

Edgar Reynaldo

I don't see any Moose. Nothing to see here folks.

Edit
Seriously though, I don't know what MappyA5 does behind the scenes. Where did you get it from? Maybe I could look at the source code later.

Gabriel Campos

Still not working. =/

I have a character sprite (little sprite) and the tiles drawed by the mappy(allegro 5). Only this, so if even the bitmaps(png files by the way) loaded in the memory could not do so much to my CPU. The CPU gets a 60% usage.
I comment this line

MapDrawBg(0, 0, 0, 0, 1600, 608);

and voia la! No bg, only the sprite, BUT the CPU gets 1 or 2% usage. So, this is the problem. Could be a bug or my mistake loading the map? I saved in fmp format. Any ideias? :P

Thomas Fjellstrom

Make sure you stuff as many tiles and sprites into the same big texture as is possible.

Switching between textures has a lot of overhead.

Arthur Kalliokoski

If you have an older card, and your texture isn't a power of two, it could be using a software path to render it.

Audric

I'm surprised that you don't need to pass a target bitmap to MapDrawBG. So where does it draw? On the global 'screen' bitmap ? If this is the case, you get the very expensive copy of RAM to VRAM.

Thomas Fjellstrom
Audric said:

I'm surprised that you don't need to pass a target bitmap to MapDrawBG. So where does it draw? On the global 'screen' bitmap ? If this is the case, you get the very expensive copy of RAM to VRAM.

He's using A5, there's a per-thread "current target", so it draws all his loaded images to the current target.

Gabriel Campos

There is a better map tile editor for allegro 5? What do you guys uses?

Trent Gamblin

My guess is you're using D3D and drawing to a bitmap without the ALLEGRO_NO_PRESERVE_TEXTURE flag set. Or just plain using memory bitmaps.

Edgar Reynaldo

It entirely depends on what mapDrawBG is doing behind the scenes, and whether it is using memory bitmaps or not, and whether the tiles are on the same atlas, and so on....

So, again, could you let me know where you got mappyA5 from?
Edit- nevermind, I found Neil's thread.
https://www.allegro.cc/forums/thread/606962

Trent Gamblin

Even if he's not using atlases it's not going to use full cores unless it's an ancient system. It's a memory bitmap or no ALLEGRO_NO_PRESERVE_TEXTURE flag or else (unlikely) the Mappy code is really terrible.

piccolo

2013... What is your cpu spec?

Edgar Reynaldo

You could try profiling your code after building it with debugging and profiling symbols. With MinGW it is -pg. Look it up for your compiler, and then run it through a profiler. You build it with profiling symbols, then run it, then analyze the output result file with a profiler like gprof and a.out.

mingw32-g++ -Wall -g -pg -o mygame-profiler.exe src1.cpp src2.cpp mappy.c -lallegro-5.1.7-monolith-md
mygame-profiler.exe
gprof a.out

And, I briefly looked at mappy_A5 and it does not use an atlas, it uses an array of ALLEGRO_BITMAP** abmTiles;, and so it does not use held bitmap drawing either. I think that was before we had the general knowledge of that around here. The dll mappy.exe wanted was allegro 5.0.2, and I dont' have that installed so the demo doesn't run for me. :P I might try recompiling the demo later.

mappy does however respect the new bitmap flags, so if its not set to ALLEGRO_VIDEO_BITMAP if won't be a video bitmap, but video is the default, so you would have had to have changed it. :?

type568

Nobody has mentioned usage of some sleep function. Perhaps you're looping it somewhere without a rest?

Chris Katko

Yeah, I was scrolling the whole thread waiting for someone to mention it.

50%? Sounds like half of a dual-core CPU.

Add a rest(0) to your main loop and see what happens. You can be doing nothing at all and you're still going to get maximum single threaded cpu utilization unless you add a rest.

Kris Asick

To anyone who's suggested that using rest(0) or Sleep(0) will reduce CPU usage, it will not!

At least, not on Windows.

The way Sleep() works on Windows (and subsequently Allegro's rest() function) is that, if you pass it a 0, it will only give up the present timeslice to other threads of equal priority if possible. If not, it burns it itself. :P

Pass anything higher than 0 and you could lose up to 50 ms of CPU time which could seriously curtail your framerate, so don't do that. ;)

Since I've never used Mappy however I have no idea what it's doing behind the scenes or what other problems could be happening. As a thought though, try forcing Allegro into OpenGL mode if you're not already, and if you are, try not forcing it into OpenGL mode. See if that makes a difference.

Elias

Pass anything higher than 0 and you could lose up to 50 ms of CPU time which could seriously curtail your framerate, so don't do that.

I'd say that was only true a very long time ago. All the precompiled Linux kernels I've encountered in the last 10 years or so would use a 1000Hz scheduler clock, so rest(1) would sleep 1ms. Under Windows that's the default even longer (starting with XP I'd say). And I'd be very surprised if OSX will sleep more than 1ms either.

So yes, someone using Windows 98 or a self-compiled Linux might get a 10ms wait (I don't ever used a system with a 20Hz timer so 50 ms seem very unlikely) - but the chance of encountering it will be very much zero :P

Also, for Allegro 5 that should not be relevant as al_wait_for_event already will make your program not use CPU except when needed.

Kris Asick
Elias said:

I'd say that was only true a very long time ago. All the precompiled Linux kernels I've encountered in the last 10 years or so would use a 1000Hz scheduler clock, so rest(1) would sleep 1ms. Under Windows that's the default even longer (starting with XP I'd say). And I'd be very surprised if OSX will sleep more than 1ms either.
So yes, someone using Windows 98 or a self-compiled Linux might get a 10ms wait (I don't ever used a system with a 20Hz timer so 50 ms seem very unlikely) - but the chance of encountering it will be very much zero

Don't be so sure of that. On my last Windows 98 system, I was getting a granularity of about 10 ms with Sleep(). On my last Windows XP system, with much newer and better hardware, I was getting a granularity closer to 50 ms with Sleep(). I have no idea what hardware/software/driver/etc. stuff affects this but because you can't depend on the scheduler granularity to be super-low, even with a powerful system, you could end up losing a lot more time than you would want under Windows.

Besides, even if the granularity was as low as 10 ms, that still tops out at 100 FPS when there's monitors out there that can do 120. :P

I dunno about Linux but I'll take your word for it that it's a fixed 1 ms granularity. ;)

Thomas Fjellstrom

When a scheduler timer is running (on modern kernels the regular periodic timer tick can and will be turned off when the system is idle) it is usually set to 1000hz on desktops/laptops. On servers you should probably set it to 100 or 250.

Gabriel Campos

I uses a notebook pentium dual core 2.4ghz, 3Mb memory...is not a good computer, but for sprites is a pretty machine. I stopped using mappy and start to use tiled that gives me a txt files. Make my class that stores that values in a vector and draw on the map. Still burns my cpu. :o

Maybe its because of for loop?
i have two for loops: one for the background map, and one to the level map. boths for make calculations. Maybe is this?

Edgar Reynaldo

Like I said before, mappy doesn't use atlases or held drawing, both of which would speed up your drawing.

Gabriel Campos

i am not using mappy anymore. I created a file with intenger
level{0, 1, 2, 40, 23, 0, 0 ... and so on. Still consuming cpu. This is annoying.

Kris Asick

Could also be vsync related. If you're not vsyncing, or your GPU drivers are set to force vsync off by default, that could lead to a massive unnecessary waste of CPU power.

Thomas Fjellstrom

If you're not waiting in your main loop, its going to suck up an entire core, which shows up as 50% on a dual core system (as someone previously mentioned).

Edgar Reynaldo

i am not using mappy anymore. I created a file with intenger
level{0, 1, 2, 40, 23, 0, 0 ... and so on. Still consuming cpu. This is annoying.

Edgar said:

Like I said before, mappy doesn't use atlases or held drawing, both of which would speed up your drawing.

And are you using atlases or held drawing in your own code? I'm guessing not.

You're gonna have to show the code you're using now. We can't guess what's wrong anymore.

Gabriel Campos
#SelectExpand
1#include "LevelManager.h" 2 3LevelManager::LevelManager(void) 4{ 5 blockSize = 32; 6} 7 8LevelManager::~LevelManager(void) 9{ 10} 11 12void LevelManager::load(const char *filename) 13{ 14 int state; 15 enum loadState{TILESET, LAYER_BG, LAYER_LV}; 16 std::fstream file(filename); 17 std::vector<int>tempVector; 18 19 if(file.is_open()) 20 { 21 std::string line, value; 22 23 while(!file.eof()) 24 { 25 std::getline(file, line); 26 27 if(line.find("[tileset]") != std::string::npos) 28 { 29 state = TILESET; 30 continue; 31 } 32 33 else if(line.find("[layer_bg]") != std::string::npos) 34 { 35 state = LAYER_BG; 36 continue; 37 } 38 39 else if(line.find("[layer_lv]") != std::string::npos) 40 { 41 state = LAYER_LV; 42 continue; 43 } 44 45 switch(state) 46 { 47 case TILESET: 48 if(line.length() > 0) 49 tileset = al_load_bitmap(line.c_str()); 50 51 al_convert_mask_to_alpha(tileset, al_get_pixel(tileset, 0, 0)); 52 break; 53 54 case LAYER_BG: 55 setLayer_bg(line); 56 break; 57 58 case LAYER_LV: 59 setLayer_lv(line); 60 break; 61 } 62 63 } 64 } 65 else 66 { 67 } 68 file.close(); 69} 70 71void LevelManager::unload() 72{ 73 al_destroy_bitmap(tileset); 74} 75 76void LevelManager::render() 77{ 78 int w = al_get_bitmap_width(tileset) / blockSize; 79 int x, y; 80 81// LAYER BACKGROUND 82 for(int i = 0; i < layer_bg.size(); i++) 83 { 84 for(int j = 0; j < layer_bg[i].size(); j++) 85 { 86 x = ((layer_bg[i][j] % w) * blockSize) - blockSize; 87 y = (layer_bg[i][j] / w) * blockSize; 88 al_draw_bitmap_region(tileset, x, y, blockSize, blockSize, j * blockSize, i * blockSize, NULL); 89 } 90 } 91 92// LAYER LEVEL 93 for(int i = 0; i < layer_lv.size(); i++) 94 { 95 for(int j = 0; j < layer_lv[i].size(); j++) 96 { 97 x = ((layer_lv[i][j] % w) * blockSize) - blockSize; 98 y = (layer_lv[i][j] / w) * blockSize; 99 al_draw_bitmap_region(tileset, x, y, blockSize, blockSize, j * blockSize, i * blockSize, NULL); 100 } 101 } 102} 103 104void LevelManager::setLayer_bg(std::string line) 105{ 106 std::string value; 107 std::stringstream str(line); 108 std::vector<int>tempVector; 109 110 while(!str.eof()) 111 { 112 std::getline(str, value, ','); 113 if(value.length() > 0) 114 tempVector.push_back(atoi(value.c_str())); 115 } 116 layer_bg.push_back(tempVector); 117} 118 119void LevelManager::setLayer_lv(std::string line) 120{ 121 std::string value; 122 std::stringstream str(line); 123 std::vector<int>tempVector; 124 125 while(!str.eof()) 126 { 127 std::getline(str, value, ','); 128 if(value.length() > 0) 129 tempVector.push_back(atoi(value.c_str())); 130 } 131 layer_lv.push_back(tempVector); 132}

Its simple load the map from a txt file and the render function is called every loop to draw the map.

Werwolf696

Can you post the code that calls your level manager render routine?

Gabriel Campos
#SelectExpand
1#include "SceneGame.h" 2 3SceneGame::SceneGame() 4{ 5} 6 7SceneGame::~SceneGame() 8{ 9} 10 11void SceneGame::load() 12{ 13 player.load(); 14 levelManager.load("Data/Levels/level00.txt"); 15 //music = al_load_sample("Data/Sounds/01_level.ogg"); 16 //al_play_sample(music, 1, 0, 1, ALLEGRO_PLAYMODE_LOOP, NULL); 17} 18 19void SceneGame::unload() 20{ 21 player.unload(); 22 levelManager.unload(); 23 //al_destroy_sample(music); 24} 25 26void SceneGame::input(ALLEGRO_EVENT *event) 27{ 28 if(inputManager.isKeyPressed(event, ALLEGRO_KEY_Z)) 29 Engine::instance().changeScene(new SceneTitle()); 30 31 player.input(event); 32} 33 34void SceneGame::logic() 35{ 36 player.logic(); 37} 38 39void SceneGame::render() 40{ 41 levelManager.render(); 42 player.render(); 43}

taronĀ 

For one you're drawing the whole map completely regardless of how much of it is visible, which might be a problem if your map is really large, but I'll assume it's a small test map.

Before drawing the tilemap call al_hold_bitmap_drawing(true) and after drawing call al_hold_bitmap_drawing(false).

The manual gives a more in-depth explanation of why and when to use it.

Thread #613447. Printed from Allegro.cc