CleverRaven / Cataclysm-DDA

Cataclysm - Dark Days Ahead. A turn-based survival game set in a post-apocalyptic world.
http://cataclysmdda.org
Other
10.52k stars 4.16k forks source link

Sleeping when headlamp are turned on can lead to not responding #29451

Closed ZikoWong closed 5 years ago

ZikoWong commented 5 years ago

Describe the bug
Sleeping when headlamp are turned on can lead to not responding. When you sleep with the headlamp on.the program will recover after a period of no response. And the headlamp were not properly turned off when sleeping. The program does not report errors, but it will not respond for a period of time. If you turn off the headlight first and then go to bed. everything is normal.

111 333

To Reproduce
Steps to reproduce the behavior:

  1. Wear headlamp
  2. turn on headlamp
  3. Sleep

Versions and configuration(please complete the following information):

kevingranade commented 5 years ago

Wild guess, the prompt for turning the light off might be getting drawn incorrectly.

neitsa commented 5 years ago

I did a CPU profiling session on the portion of the sleep() code.

https://github.com/CleverRaven/Cataclysm-DDA/blob/c2068fe5a2249f5fc8595a68654205edbae721d3/src/handle_action.cpp#L720-L779

Between the time you enter the sleep() function and the moment the menu is displayed (note: it is displayed correctly) the code spend 99.56% of its time in it->is_tool_reversible()

        if( it->active && it->charges > 0 && it->is_tool_reversible() ) {

A count breakpoint indicates in my case that this line is only hit 14 times for a total of 55 secondes... (I'm on a debug build so the overhead is really sensible).

I'm going to quickly review the traversed functions (read from top to bottom):

In inventory::form_from_map, two lines takes almost 99% of the time spent here:

    items.clear();
    for( const tripoint &p : m.points_in_radius( origin, range ) ) { // 48.30%
        // can not reach this -> can not access its contents
        if( clear_path ) {
            if( origin != p && !m.clear_path( origin, p, range, 1, 100 ) ) { //49.49%
                continue;
            }
        }

On these two lines we have:

Simple Fix

A very simple change would be to keep the first two checks (they cost 0 in time) and if they are true, proceed to is_tool_reversible(). That would at least prevent the obligatory check using it->is_tool_reversible():

if( it->active && it->charges > 0) {
    if(it->is_tool_reversible() ) {
        active.push_back( it->tname() );
    }
}

I took a look at the various operators used in inventory::form_from_map but they already seem to be quite effective... It's gonna be hard to optimize :(

ZikoWong commented 5 years ago

I used task manager to check CPU usage。 Redownloaded 0.D-8769 After entering the sleep command, the CPU occupies the crazy rising program and does not respond. Return to normal after the confirmation sleep menu appears My CPU is I7 6800K,0.D8769 is a new download, all of which are default settings. I also tested the Curses version.The same problem will arise.

2

1

communistkiro commented 5 years ago

On 3 separate saves with at least one resource-draining-per-time item ON be it (heavy) flashlight, oil lamp, mp3 player, cell/smartphone 1 core of my i7 2620 goes haywire for 20-30s w/ v 0.D-1739-gc00528a (tiles) b 8776

Farseer2 commented 5 years ago

@neitsa It would only execute if the first two checks succeeded anyway

Anyway, the bug is deeper - is_tool_reversible creates an npc (item.cpp:4982), which, by default, has the position (-1, -1, 500). It then uses it as the invoker of revert item. Many calls deeper, in form_from_map, the npc's position is passed to points_in_radius, which creates a range. Because pos.z is so high, the calculations there causes minz to be larger than maxz, which causes the loop to run 0x100000000 - 499 times. I'm submitting a PR which fixes the overflow, but it is only a partial solution - the fake position should not be used at all. This is my second issue in C:DDA, so I'm not really sure how to solve it, maybe someone reading this can suggest something?