eeschema: Connectivity threading
This threads the first step (update item) in the connectivity routine. Also eliminates the duplicate call for multiple copies of the same sheet.
This commit is contained in:
parent
e90452d0e2
commit
1a031e771f
|
@ -58,6 +58,13 @@ namespace AC_KEYS
|
|||
*/
|
||||
static const wxChar EnableSvgImport[] = wxT( "EnableSvgImport" );
|
||||
|
||||
/**
|
||||
* Testing mode for new connectivity algorithm. Setting this to on will cause all modifications
|
||||
* to the netlist to be recalculated on the fly. This may be slower than the standard process
|
||||
* at the moment
|
||||
*/
|
||||
static const wxChar RealtimeConnectivity[] = wxT( "RealtimeConnectivity" );
|
||||
|
||||
/**
|
||||
* Allow legacy canvas to be shown in GTK3. Legacy canvas is generally pretty
|
||||
* broken, but this avoids code in an ifdef where it could become broken
|
||||
|
@ -183,6 +190,9 @@ void ADVANCED_CFG::loadSettings( wxConfigBase& aCfg )
|
|||
configParams.push_back( new PARAM_CFG_BOOL(
|
||||
true, AC_KEYS::AllowLegacyCanvasInGtk3, &m_allowLegacyCanvasInGtk3, false ) );
|
||||
|
||||
configParams.push_back(
|
||||
new PARAM_CFG_BOOL( true, AC_KEYS::RealtimeConnectivity, &m_realTimeConnectivity, false ) );
|
||||
|
||||
wxConfigLoadSetups( &aCfg, configParams );
|
||||
|
||||
dumpCfg( configParams );
|
||||
|
@ -200,4 +210,4 @@ bool ADVANCED_CFG::AllowLegacyCanvas() const
|
|||
#endif
|
||||
|
||||
return allow;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <unordered_map>
|
||||
#include <profile.h>
|
||||
|
||||
#include <advanced_config.h>
|
||||
#include <common.h>
|
||||
#include <erc.h>
|
||||
#include <sch_edit_frame.h>
|
||||
|
@ -308,23 +309,56 @@ void CONNECTION_GRAPH::Recalculate( SCH_SHEET_LIST aSheetList, bool aUncondition
|
|||
if( aUnconditional )
|
||||
Reset();
|
||||
|
||||
for( const auto& sheet : aSheetList )
|
||||
{
|
||||
std::vector<SCH_ITEM*> items;
|
||||
std::map<SCH_ITEM*, std::vector<SCH_SHEET_PATH>> sheets;
|
||||
|
||||
for( auto item = sheet.LastScreen()->GetDrawItems();
|
||||
item; item = item->Next() )
|
||||
for( auto sheet : aSheetList )
|
||||
{
|
||||
if( auto list = sheet.LastDrawList() )
|
||||
sheets[list].push_back( sheet );
|
||||
}
|
||||
|
||||
size_t parallelThreadCount = std::min<size_t>( std::thread::hardware_concurrency(),
|
||||
( sheets.size() + 1 ) / 2 );
|
||||
std::atomic<size_t> nextSheet( 0 );
|
||||
std::vector<std::future<size_t>> returns( parallelThreadCount );
|
||||
|
||||
auto update_connectivity = [&]() -> size_t
|
||||
{
|
||||
for( size_t sheetId = nextSheet++; sheetId < sheets.size(); sheetId = nextSheet++ )
|
||||
{
|
||||
if( item->IsConnectable() &&
|
||||
( aUnconditional || item->IsConnectivityDirty() ) )
|
||||
auto sheet = sheets.begin();
|
||||
std::advance( sheet, sheetId );
|
||||
std::vector<SCH_ITEM*> items;
|
||||
|
||||
for( auto item = sheet->first; item; item = item->Next() )
|
||||
{
|
||||
items.push_back( item );
|
||||
if( item->IsConnectable() && ( aUnconditional || item->IsConnectivityDirty() ) )
|
||||
items.push_back( item );
|
||||
}
|
||||
|
||||
auto it = sheet->second.begin();
|
||||
updateItemConnectivity( *it, items );
|
||||
|
||||
for( ++it; it != sheet->second.end(); ++it )
|
||||
initializeSheetConnections( *it, items );
|
||||
}
|
||||
|
||||
updateItemConnectivity( sheet, items );
|
||||
return 1;
|
||||
};
|
||||
|
||||
if( parallelThreadCount == 1 )
|
||||
update_connectivity();
|
||||
else
|
||||
{
|
||||
for( size_t ii = 0; ii < parallelThreadCount; ++ii )
|
||||
returns[ii] = std::async( std::launch::async, update_connectivity );
|
||||
|
||||
// Finalize the threads
|
||||
for( size_t ii = 0; ii < parallelThreadCount; ++ii )
|
||||
returns[ii].wait();
|
||||
}
|
||||
|
||||
|
||||
phase1.Stop();
|
||||
wxLogTrace( "CONN_PROFILE", "UpdateItemConnectivity() %0.4f ms", phase1.msecs() );
|
||||
|
||||
|
@ -341,10 +375,50 @@ void CONNECTION_GRAPH::Recalculate( SCH_SHEET_LIST aSheetList, bool aUncondition
|
|||
}
|
||||
|
||||
|
||||
void CONNECTION_GRAPH::updateItemConnectivity( SCH_SHEET_PATH aSheet,
|
||||
std::vector<SCH_ITEM*> aItemList )
|
||||
void CONNECTION_GRAPH::initializeSheetConnections( SCH_SHEET_PATH aSheet,
|
||||
std::vector<SCH_ITEM*>& aItemList )
|
||||
{
|
||||
std::unordered_map< wxPoint, std::vector<SCH_ITEM*> > connection_map;
|
||||
for( auto item : aItemList )
|
||||
{
|
||||
if( item->Type() == SCH_SHEET_T )
|
||||
{
|
||||
for( auto& pin : static_cast<SCH_SHEET*>( item )->GetPins() )
|
||||
pin.InitializeConnection( aSheet );
|
||||
}
|
||||
else if( item->Type() != SCH_COMPONENT_T )
|
||||
{
|
||||
auto conn = item->InitializeConnection( aSheet );
|
||||
|
||||
// Set bus/net property here so that the propagation code uses it
|
||||
switch( item->Type() )
|
||||
{
|
||||
case SCH_LINE_T:
|
||||
conn->SetType( ( item->GetLayer() == LAYER_BUS ) ?
|
||||
CONNECTION_BUS : CONNECTION_NET );
|
||||
break;
|
||||
|
||||
case SCH_BUS_BUS_ENTRY_T:
|
||||
conn->SetType( CONNECTION_BUS );
|
||||
break;
|
||||
|
||||
case SCH_PIN_T:
|
||||
case SCH_BUS_WIRE_ENTRY_T:
|
||||
conn->SetType( CONNECTION_NET );
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CONNECTION_GRAPH::updateItemConnectivity( SCH_SHEET_PATH aSheet,
|
||||
std::vector<SCH_ITEM*>& aItemList )
|
||||
{
|
||||
std::unordered_multimap< wxPoint, SCH_ITEM* > connection_map;
|
||||
|
||||
for( auto item : aItemList )
|
||||
{
|
||||
|
@ -356,24 +430,17 @@ void CONNECTION_GRAPH::updateItemConnectivity( SCH_SHEET_PATH aSheet,
|
|||
{
|
||||
for( auto& pin : static_cast<SCH_SHEET*>( item )->GetPins() )
|
||||
{
|
||||
if( !pin.Connection( aSheet ) )
|
||||
{
|
||||
pin.InitializeConnection( aSheet );
|
||||
}
|
||||
|
||||
pin.InitializeConnection( aSheet );
|
||||
pin.ConnectedItems().clear();
|
||||
pin.Connection( aSheet )->Reset();
|
||||
|
||||
connection_map[ pin.GetTextPos() ].push_back( &pin );
|
||||
m_items.insert( &pin );
|
||||
connection_map.emplace( pin.GetTextPos(), &pin );
|
||||
InsertItem( &pin );
|
||||
}
|
||||
}
|
||||
else if( item->Type() == SCH_COMPONENT_T )
|
||||
{
|
||||
auto component = static_cast<SCH_COMPONENT*>( item );
|
||||
|
||||
component->UpdatePins( &aSheet );
|
||||
|
||||
for( auto& it : component->GetPinMap() )
|
||||
{
|
||||
SCH_PIN* pin = &it.second;
|
||||
|
@ -388,15 +455,15 @@ void CONNECTION_GRAPH::updateItemConnectivity( SCH_SHEET_PATH aSheet,
|
|||
// Invisible power pins need to be post-processed later
|
||||
|
||||
if( pin->IsPowerConnection() && !pin->IsVisible() )
|
||||
m_invisible_power_pins.push_back( pin );
|
||||
InsertPin( pin );
|
||||
|
||||
connection_map[ pos ].push_back( pin );
|
||||
m_items.insert( pin );
|
||||
connection_map.emplace( pos, pin );
|
||||
InsertItem( pin );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_items.insert( item );
|
||||
InsertItem( item );
|
||||
auto conn = item->InitializeConnection( aSheet );
|
||||
|
||||
// Set bus/net property here so that the propagation code uses it
|
||||
|
@ -421,22 +488,23 @@ void CONNECTION_GRAPH::updateItemConnectivity( SCH_SHEET_PATH aSheet,
|
|||
}
|
||||
|
||||
for( auto point : points )
|
||||
{
|
||||
connection_map[ point ].push_back( item );
|
||||
}
|
||||
connection_map.emplace( point, item );
|
||||
}
|
||||
|
||||
item->SetConnectivityDirty( false );
|
||||
}
|
||||
|
||||
for( const auto& it : connection_map )
|
||||
auto primary_it = connection_map.begin();
|
||||
for( auto it = connection_map.begin(); it != connection_map.end(); it = primary_it )
|
||||
{
|
||||
auto connection_vec = it.second;
|
||||
auto range = connection_map.equal_range( it->first );
|
||||
auto count = std::distance( range.first, range.second );
|
||||
primary_it = range.second;
|
||||
SCH_ITEM* junction = nullptr;
|
||||
|
||||
for( auto primary_it = connection_vec.begin(); primary_it != connection_vec.end(); primary_it++ )
|
||||
for( primary_it = range.first; primary_it != range.second; ++primary_it )
|
||||
{
|
||||
auto connected_item = *primary_it;
|
||||
auto connected_item = primary_it->second;
|
||||
|
||||
// Look for junctions. For points that have a junction, we want all
|
||||
// items to connect to the junction but not to each other.
|
||||
|
@ -458,10 +526,10 @@ void CONNECTION_GRAPH::updateItemConnectivity( SCH_SHEET_PATH aSheet,
|
|||
// entry itself, this means that either the bus entry is not
|
||||
// connected to anything graphically, or that it is connected to
|
||||
// a segment at some point other than at one of the endpoints.
|
||||
if( connection_vec.size() == 1 )
|
||||
if( count == 1 )
|
||||
{
|
||||
auto screen = aSheet.LastScreen();
|
||||
auto bus = screen->GetBus( it.first );
|
||||
auto bus = screen->GetBus( primary_it->first );
|
||||
|
||||
if( bus )
|
||||
{
|
||||
|
@ -474,42 +542,41 @@ void CONNECTION_GRAPH::updateItemConnectivity( SCH_SHEET_PATH aSheet,
|
|||
// Bus-to-bus entries are treated just like bus wires
|
||||
if( connected_item->Type() == SCH_BUS_BUS_ENTRY_T )
|
||||
{
|
||||
if( connection_vec.size() < 2 )
|
||||
if( count < 2 )
|
||||
{
|
||||
auto screen = aSheet.LastScreen();
|
||||
auto bus = screen->GetBus( it.first );
|
||||
auto bus = screen->GetBus( primary_it->first );
|
||||
|
||||
if( bus )
|
||||
{
|
||||
auto bus_entry = static_cast<SCH_BUS_BUS_ENTRY*>( connected_item );
|
||||
|
||||
if( it.first == bus_entry->GetPosition() )
|
||||
if( primary_it->first == bus_entry->GetPosition() )
|
||||
bus_entry->m_connected_bus_items[0] = bus;
|
||||
else
|
||||
bus_entry->m_connected_bus_items[1] = bus;
|
||||
|
||||
bus_entry->ConnectedItems().insert( bus );
|
||||
bus->ConnectedItems().insert( bus_entry );
|
||||
bus_entry->AddConnectionTo( bus );
|
||||
bus->AddConnectionTo( bus_entry );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for( auto test_it = primary_it + 1; test_it != connection_vec.end(); test_it++ )
|
||||
for( auto test_it = std::next( primary_it ); test_it != range.second; ++test_it )
|
||||
{
|
||||
auto test_item = *test_it;
|
||||
auto test_item = test_it->second;
|
||||
|
||||
if( !junction && test_item->Type() == SCH_JUNCTION_T )
|
||||
{
|
||||
junction = test_item;
|
||||
}
|
||||
|
||||
if( connected_item != test_item &&
|
||||
connected_item != junction &&
|
||||
if( connected_item != junction &&
|
||||
connected_item->ConnectionPropagatesTo( test_item ) &&
|
||||
test_item->ConnectionPropagatesTo( connected_item ) )
|
||||
{
|
||||
connected_item->ConnectedItems().insert( test_item );
|
||||
test_item->ConnectedItems().insert( connected_item );
|
||||
connected_item->AddConnectionTo( test_item );
|
||||
test_item->AddConnectionTo( connected_item );
|
||||
}
|
||||
|
||||
// Set up the link between the bus entry net and the bus
|
||||
|
@ -646,7 +713,7 @@ void CONNECTION_GRAPH::buildConnectionGraph()
|
|||
|
||||
// Resolve drivers for subgraphs and propagate connectivity info
|
||||
|
||||
// We don't want to spin up a new thread for fewer than 8 nets (overhead costs)
|
||||
// We don't want to spin up a new thread for fewer than 4 nets (overhead costs)
|
||||
size_t parallelThreadCount = std::min<size_t>( std::thread::hardware_concurrency(),
|
||||
( m_subgraphs.size() + 3 ) / 4 );
|
||||
|
||||
|
|
|
@ -35,10 +35,6 @@
|
|||
// #define CONNECTIVITY_DEBUG
|
||||
#endif
|
||||
|
||||
// Uncomment this line to enable real-time connectivity updates
|
||||
// TODO(JE) re-enable this once performance concerns are sorted out
|
||||
// #define CONNECTIVITY_REAL_TIME
|
||||
|
||||
class SCH_PIN;
|
||||
|
||||
class SCH_EDIT_FRAME;
|
||||
|
@ -198,12 +194,29 @@ public:
|
|||
// TODO(JE) firm up API and move to private
|
||||
std::map<int, std::vector<CONNECTION_SUBGRAPH*> > m_net_code_to_subgraphs_map;
|
||||
|
||||
inline void InsertItem( SCH_ITEM* aItem )
|
||||
{
|
||||
std::lock_guard<std::mutex> lock( m_item_mutex );
|
||||
m_items.insert( aItem );
|
||||
}
|
||||
|
||||
inline void InsertPin( SCH_PIN* aPin )
|
||||
{
|
||||
std::lock_guard<std::mutex> lock( m_power_pin_mutex );
|
||||
m_invisible_power_pins.push_back( aPin );
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
std::mutex m_item_mutex;
|
||||
|
||||
std::unordered_set<SCH_ITEM*> m_items;
|
||||
|
||||
std::vector<CONNECTION_SUBGRAPH*> m_subgraphs;
|
||||
|
||||
std::mutex m_power_pin_mutex;
|
||||
|
||||
std::vector<SCH_PIN*> m_invisible_power_pins;
|
||||
|
||||
std::unordered_map<wxString, std::shared_ptr<BUS_ALIAS>> m_bus_alias_cache;
|
||||
|
@ -223,8 +236,6 @@ private:
|
|||
|
||||
int m_last_subgraph_code;
|
||||
|
||||
std::mutex m_item_mutex;
|
||||
|
||||
// Needed for m_UserUnits for now; maybe refactor later
|
||||
SCH_EDIT_FRAME* m_frame;
|
||||
|
||||
|
@ -256,7 +267,20 @@ private:
|
|||
* @param aItemList is a list of items to consider
|
||||
*/
|
||||
void updateItemConnectivity( SCH_SHEET_PATH aSheet,
|
||||
std::vector<SCH_ITEM*> aItemList );
|
||||
std::vector<SCH_ITEM*>& aItemList );
|
||||
|
||||
/**
|
||||
* This is a shortcut function to only update the connections for duplicate sheets
|
||||
* Since shared sheets have the same layout, we don't need to re-create the connection
|
||||
* map, only add the sheet path to the item connection.
|
||||
*
|
||||
* N.B. This must be run sequentially after the first shared sheet
|
||||
*
|
||||
* @param aSheet path to the sheet with item list
|
||||
* @param aItemList vector of items
|
||||
*/
|
||||
void initializeSheetConnections( SCH_SHEET_PATH aSheet,
|
||||
std::vector<SCH_ITEM*>& aItemList );
|
||||
|
||||
/**
|
||||
* Generates the connection graph (after all item connectivity has been updated)
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <boost/regex.hpp>
|
||||
#include <wx/tokenzr.h>
|
||||
|
||||
#include <advanced_config.h>
|
||||
#include <connection_graph.h>
|
||||
#include <sch_screen.h>
|
||||
|
||||
|
@ -281,7 +282,8 @@ wxString SCH_CONNECTION::Name( bool aIgnoreSheet ) const
|
|||
|
||||
void SCH_CONNECTION::AppendInfoToMsgPanel( MSG_PANEL_ITEMS& aList ) const
|
||||
{
|
||||
#ifdef CONNECTIVITY_REAL_TIME
|
||||
if( !ADVANCED_CFG::GetCfg().m_realTimeConnectivity )
|
||||
return;
|
||||
|
||||
wxString msg, group_name;
|
||||
std::vector<wxString> group_members;
|
||||
|
@ -319,14 +321,14 @@ void SCH_CONNECTION::AppendInfoToMsgPanel( MSG_PANEL_ITEMS& aList ) const
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void SCH_CONNECTION::AppendDebugInfoToMsgPanel( MSG_PANEL_ITEMS& aList ) const
|
||||
{
|
||||
#ifdef CONNECTIVITY_REAL_TIME
|
||||
if( !ADVANCED_CFG::GetCfg().m_realTimeConnectivity )
|
||||
return;
|
||||
|
||||
wxString msg;
|
||||
|
||||
AppendInfoToMsgPanel( aList );
|
||||
|
@ -345,7 +347,6 @@ void SCH_CONNECTION::AppendDebugInfoToMsgPanel( MSG_PANEL_ITEMS& aList ) const
|
|||
|
||||
msg.Printf( "%s at %p", Parent()->GetSelectMenuText( MILLIMETRES ), Parent() );
|
||||
aList.push_back( MSG_PANEL_ITEM( _( "Attached To" ), msg, RED ) );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include <executable_names.h>
|
||||
#include <eda_dockart.h>
|
||||
|
||||
#include <advanced_config.h>
|
||||
#include <general.h>
|
||||
#include <eeschema_id.h>
|
||||
#include <netlist.h>
|
||||
|
@ -794,9 +795,9 @@ void SCH_EDIT_FRAME::OnModify()
|
|||
|
||||
m_foundItems.SetForceSearch();
|
||||
|
||||
#ifdef CONNECTIVITY_REAL_TIME
|
||||
RecalculateConnections();
|
||||
#endif
|
||||
|
||||
if( ADVANCED_CFG::GetCfg().m_realTimeConnectivity )
|
||||
RecalculateConnections();
|
||||
|
||||
m_canvas->Refresh();
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include <kicad_device_context.h>
|
||||
#include <hotkeys_basic.h>
|
||||
|
||||
#include <advanced_config.h>
|
||||
#include <general.h>
|
||||
#include <eeschema_id.h>
|
||||
#include <list_operations.h>
|
||||
|
@ -563,9 +564,8 @@ void SCH_EDIT_FRAME::OnSelectTool( wxCommandEvent& aEvent )
|
|||
|
||||
case ID_HIGHLIGHT:
|
||||
// TODO(JE) remove once real-time connectivity is a given
|
||||
#ifndef CONNECTIVITY_REAL_TIME
|
||||
RecalculateConnections();
|
||||
#endif
|
||||
if( ADVANCED_CFG::GetCfg().m_realTimeConnectivity )
|
||||
RecalculateConnections();
|
||||
|
||||
SetToolID( ID_HIGHLIGHT, wxCURSOR_HAND, _("Highlight specific net") );
|
||||
break;
|
||||
|
|
|
@ -73,6 +73,11 @@ public:
|
|||
*/
|
||||
bool m_enableSvgImport;
|
||||
|
||||
/**
|
||||
* Do real-time connectivity
|
||||
*/
|
||||
bool m_realTimeConnectivity;
|
||||
|
||||
/**
|
||||
* Helper to determine if legacy canvas is allowed (according to platform
|
||||
* and config)
|
||||
|
|
Loading…
Reference in New Issue