From dc3475c7b9b81e8305161a661cc7e36dd0179e16 Mon Sep 17 00:00:00 2001 From: Kevin Granade Date: Sun, 23 Jun 2019 02:17:08 -0700 Subject: [PATCH] Field enumeration perf (#31686) * Templatize shift_bitset_cache * Establish and use a bitset cache for which submaps contain active fields --- src/map.cpp | 46 +++++++++++++++++++++++++++++--------------- src/map.h | 6 +++--- src/map_field.cpp | 23 ++++++++++++++++++---- tests/map_memory.cpp | 16 +++++++-------- 4 files changed, 61 insertions(+), 30 deletions(-) diff --git a/src/map.cpp b/src/map.cpp index 2c523a0bfe91d..5d7b32e620cd0 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -2705,6 +2705,7 @@ void map::decay_fields_and_scent( const time_duration &amount ) << abs_sub.x + smx << "," << abs_sub.y + smy << "," << abs_sub.z << "has " << to_proc << " field_count"; } + get_cache( smz ).field_cache.reset( smx + ( smy * MAPSIZE ) ); // This submap has no fields continue; } @@ -5411,7 +5412,10 @@ bool map::add_field( const tripoint &p, const field_id type, int intensity, if( current_submap->fld[l.x][l.y].add_field( type, intensity, age ) ) { //Only adding it to the count if it doesn't exist. - current_submap->field_count++; + if( ! current_submap->field_count++ ) { + get_cache( p.z ).field_cache.set( static_cast( p.x / SEEX + ( ( + p.y / SEEX ) * MAPSIZE ) ) ); + } } if( g != nullptr && this == &g->m && p == g->u.pos() ) { @@ -5446,7 +5450,10 @@ void map::remove_field( const tripoint &p, const field_id field_to_remove ) if( current_submap->fld[l.x][l.y].remove_field( field_to_remove ) ) { // Only adjust the count if the field actually existed. - current_submap->field_count--; + if( ! --current_submap->field_count ) { + get_cache( p.z ).field_cache.reset( static_cast( p.x / SEEX + ( ( + p.y / SEEX ) * MAPSIZE ) ) ); + } const auto &fdata = all_field_types_enum_list[ field_to_remove ]; for( bool i : fdata.transparent ) { if( !i ) { @@ -6478,31 +6485,36 @@ void map::shift_traps( const tripoint &shift ) } } -void shift_map_memory_seen_cache( - std::bitset &map_memory_seen_cache, - const int sx, const int sy ) +template +void shift_bitset_cache( std::bitset &cache, const int sx, const int sy ) { - // sx shifts by SEEX rows, sy shifts by SEEX columns. - int shift_amount = ( sx * SEEX ) + ( sy * MAPSIZE_Y * SEEX ); + // sx shifts by MULTIPLIER rows, sy shifts by MULTIPLIER columns. + int shift_amount = ( sx * MULTIPLIER ) + ( sy * SIZE * MULTIPLIER ); if( shift_amount > 0 ) { - map_memory_seen_cache >>= static_cast( shift_amount ); + cache >>= static_cast( shift_amount ); } else if( shift_amount < 0 ) { - map_memory_seen_cache <<= static_cast( -shift_amount ); + cache <<= static_cast( -shift_amount ); } // Shifting in the y direction shifted in 0 values, no no additional clearing is necessary, but // a shift in the x direction makes values "wrap" to the next row, and they need to be zeroed. if( sx == 0 ) { return; } - const size_t x_offset = ( sx > 0 ) ? MAPSIZE_X - SEEX : 0; - for( size_t y = 0; y < MAPSIZE_X; ++y ) { - size_t y_offset = y * MAPSIZE_X; - for( size_t x = 0; x < SEEX; ++x ) { - map_memory_seen_cache.reset( y_offset + x_offset + x ); + const size_t x_offset = ( sx > 0 ) ? SIZE - MULTIPLIER : 0; + for( size_t y = 0; y < SIZE; ++y ) { + size_t y_offset = y * SIZE; + for( size_t x = 0; x < MULTIPLIER; ++x ) { + cache.reset( y_offset + x_offset + x ); } } } +template void +shift_bitset_cache( std::bitset &cache, + const int sx, const int sy ); +template void +shift_bitset_cache( std::bitset &cache, const int sx, const int sy ); + void map::shift( const int sx, const int sy ) { // Special case of 0-shift; refresh the map @@ -6540,7 +6552,8 @@ void map::shift( const int sx, const int sy ) // Clear vehicle list and rebuild after shift clear_vehicle_cache( gridz ); clear_vehicle_list( gridz ); - shift_map_memory_seen_cache( get_cache( gridz ).map_memory_seen_cache, sx, sy ); + shift_bitset_cache( get_cache( gridz ).map_memory_seen_cache, sx, sy ); + shift_bitset_cache( get_cache( gridz ).field_cache, sx, sy ); if( sx >= 0 ) { for( int gridx = 0; gridx < my_MAPSIZE; gridx++ ) { if( sy >= 0 ) { @@ -6781,6 +6794,9 @@ void map::loadn( const int gridx, const int gridy, const int gridz, const bool u if( !tmpsub->active_items.empty() ) { submaps_with_active_items.emplace( absx, absy, gridz ); } + if( tmpsub->field_count > 0 ) { + get_cache( gridz ).field_cache.set( gridx + ( gridy * MAPSIZE ) ); + } // Destroy bugged no-part vehicles auto &veh_vec = tmpsub->vehicles; for( auto iter = veh_vec.begin(); iter != veh_vec.end(); ) { diff --git a/src/map.h b/src/map.h index b3346c96ef60e..dc5f64448a3a0 100644 --- a/src/map.h +++ b/src/map.h @@ -163,6 +163,7 @@ struct level_cache { float camera_cache[MAPSIZE_X][MAPSIZE_Y]; lit_level visibility_cache[MAPSIZE_X][MAPSIZE_Y]; std::bitset map_memory_seen_cache; + std::bitset field_cache; bool veh_in_active_range; bool veh_exists_at[MAPSIZE_X][MAPSIZE_Y]; @@ -1692,9 +1693,8 @@ class map bool need_draw_lower_floor( const tripoint &p ); }; -void shift_map_memory_seen_cache( - std::bitset &map_memory_seen_cache, - const int sx, const int sy ); +template +void shift_bitset_cache( std::bitset &cache, const int sx, const int sy ); std::vector closest_points_first( int radius, point p ); std::vector closest_points_first( int radius, int x, int y ); diff --git a/src/map_field.cpp b/src/map_field.cpp index 9029fab300bf1..eb684d87364fd 100644 --- a/src/map_field.cpp +++ b/src/map_field.cpp @@ -107,10 +107,11 @@ bool map::process_fields() const int maxz = zlevels ? OVERMAP_HEIGHT : abs_sub.z; for( int z = minz; z <= maxz; z++ ) { bool zlev_dirty = false; + auto &field_cache = get_cache( z ).field_cache; for( int x = 0; x < my_MAPSIZE; x++ ) { for( int y = 0; y < my_MAPSIZE; y++ ) { - submap *const current_submap = get_submap_at_grid( { x, y, z } ); - if( current_submap->field_count > 0 ) { + if( field_cache[ x + ( y * MAPSIZE ) ] ) { + submap *const current_submap = get_submap_at_grid( { x, y, z } ); const bool cur_dirty = process_fields_in_submap( current_submap, x, y, z ); zlev_dirty |= cur_dirty; } @@ -369,7 +370,7 @@ bool map::process_fields_in_submap( submap *const current_submap, if( !all_field_types_enum_list[cur.get_field_type()].transparent[cur.get_field_intensity() - 1] ) { dirty_transparency_cache = true; } - current_submap->field_count--; + --current_submap->field_count; curfield.remove_field( it++ ); continue; } @@ -1358,7 +1359,7 @@ bool map::process_fields_in_submap( submap *const current_submap, cur.set_field_intensity( cur.get_field_intensity() - 1 ); } if( !cur.is_field_alive() ) { - current_submap->field_count--; + --current_submap->field_count; curfield.remove_field( it++ ); } else { ++it; @@ -1366,6 +1367,20 @@ bool map::process_fields_in_submap( submap *const current_submap, } } } + const int minz = zlevels ? -OVERMAP_DEPTH : abs_sub.z; + const int maxz = zlevels ? OVERMAP_HEIGHT : abs_sub.z; + for( int z = std::max( submap_z - 1, minz ); z <= std::min( submap_z + 1, maxz ); ++z ) { + auto &field_cache = get_cache( z ).field_cache; + for( int y = std::max( submap_y - 1, 0 ); y <= std::min( submap_y + 1, MAPSIZE - 1 ); ++y ) { + for( int x = std::max( submap_x - 1, 0 ); x <= std::min( submap_x + 1, MAPSIZE - 1 ); ++x ) { + if( get_submap_at_grid( { x, y, z } )->field_count > 0 ) { + field_cache.set( x + ( y * MAPSIZE ) ); + } else { + field_cache.reset( x + ( y * MAPSIZE ) ); + } + } + } + } return dirty_transparency_cache; } diff --git a/tests/map_memory.cpp b/tests/map_memory.cpp index e8ad59d21d7a1..afb2d186d1ea8 100644 --- a/tests/map_memory.cpp +++ b/tests/map_memory.cpp @@ -167,56 +167,56 @@ TEST_CASE( "shift_map_memory_seen_cache" ) GIVEN( "all bits are set" ) { test_cache.set(); WHEN( "positive x shift" ) { - shift_map_memory_seen_cache( test_cache, 1, 0 ); + shift_bitset_cache( test_cache, 1, 0 ); THEN( "last 12 columns are 0, rest are 1" ) { check_quadrants( test_cache, last_twelve, 0, true, false, true, false ); } } WHEN( "negative x shift" ) { - shift_map_memory_seen_cache( test_cache, -1, 0 ); + shift_bitset_cache( test_cache, -1, 0 ); THEN( "first 12 columns are 0, rest are 1" ) { check_quadrants( test_cache, first_twelve, 0, false, true, false, true ); } } WHEN( "positive y shift" ) { - shift_map_memory_seen_cache( test_cache, 0, 1 ); + shift_bitset_cache( test_cache, 0, 1 ); THEN( "last 12 rows are 0, rest are 1" ) { check_quadrants( test_cache, 0, last_twelve, true, true, false, false ); } } WHEN( "negative y shift" ) { - shift_map_memory_seen_cache( test_cache, 0, -1 ); + shift_bitset_cache( test_cache, 0, -1 ); THEN( "first 12 rows are 0, rest are 1" ) { check_quadrants( test_cache, 0, first_twelve, false, false, true, true ); } } WHEN( "positive x, positive y shift" ) { - shift_map_memory_seen_cache( test_cache, 1, 1 ); + shift_bitset_cache( test_cache, 1, 1 ); THEN( "last 12 columns and rows are 0, rest are 1" ) { check_quadrants( test_cache, last_twelve, last_twelve, true, false, false, false ); } } WHEN( "positive x, negative y shift" ) { - shift_map_memory_seen_cache( test_cache, 1, -1 ); + shift_bitset_cache( test_cache, 1, -1 ); THEN( "last 12 columns and first 12 rows are 0, rest are 1" ) { check_quadrants( test_cache, last_twelve, first_twelve, false, false, true, false ); } } WHEN( "negative x, positive y shift" ) { - shift_map_memory_seen_cache( test_cache, -1, 1 ); + shift_bitset_cache( test_cache, -1, 1 ); THEN( "first 12 columns and last 12 rows are 0, rest are 1" ) { check_quadrants( test_cache, first_twelve, last_twelve, false, true, false, false ); } } WHEN( "negative x, negative y shift" ) { - shift_map_memory_seen_cache( test_cache, -1, -1 ); + shift_bitset_cache( test_cache, -1, -1 ); THEN( "first 12 columns and rows are 0, rest are 1" ) { check_quadrants( test_cache, first_twelve, first_twelve, false, false, false, true );