/** * Is graphA isomorphic to graphB? * * If this function returns true, then Perm will contain the permutation * required to transform graphB into graphA. * We also use the degree of each Node, that is the number of connections it has, to * speed up rejection of non-isomorphic graphs (if there is a Node in graphA with n * connections, there must be at least one unmatched in graphB with n connections). * * @param[in] Node the discovered Node which we are trying to match * with a permutation the topology * @param[in,out] State our global state, degree and adjacency matrix, * output a permutation if successful * @retval TRUE the graphs are isomorphic * @retval FALSE the graphs are not isomorphic * */ BOOLEAN STATIC IsIsomorphic ( IN UINT8 Node, IN OUT STATE_DATA *State ) { UINT8 j; UINT8 k; UINT8 Nodecnt; // We have only been called if Nodecnt == pSelected->size ! Nodecnt = State->NodesDiscovered + 1; if (Node != Nodecnt) { // Keep building the permutation for (j = 0; j < Nodecnt; j++) { // Make sure the degree matches if (State->Fabric->SysDegree[Node] != State->Fabric->DbDegree[j]) { continue; } // Make sure that j hasn't been used yet (ought to use a "used" // array instead, might be faster) for (k = 0; k < Node; k++) { if (State->Fabric->Perm[k] == j) { break; } } if (k != Node) { continue; } State->Fabric->Perm[Node] = j; if (IsIsomorphic (Node + 1, State)) { return TRUE; } } return FALSE; } else { // Test to see if the permutation is isomorphic for (j = 0; j < Nodecnt; j++) { for (k = 0; k < Nodecnt; k++) { if (State->Fabric->SysMatrix[j][k] != State->Fabric->DbMatrix[State->Fabric->Perm[j]][State->Fabric->Perm[k]] ) { return FALSE; } } } return TRUE; } }
static int IsDual(int mj, MatRep_t *rep_m, int nj) { MatRep_t *rep_n; /* Generators of constituent of N */ int result; CfInfo *minfo = InfoM.Cf + mj; /* First check: Dimensions and splitting field must match ------------------------------------------------------ */ if (InfoN.Cf[nj].dim != minfo->dim || InfoN.Cf[nj].spl != minfo->spl) return 0; /* Read the (contragrediate) generators and compare ------------------------------------------------ */ MESSAGE(2,(" (%s%s)",InfoN.BaseName,Lat_CfName(&InfoN,nj))); rep_n = Lat_ReadCfGens(&InfoN,nj,LAT_RG_INVERT|LAT_RG_TRANSPOSE | (InfoN.Cf[nj].peakword >= 0 ? LAT_RG_STD : 0)); result = IsIsomorphic(rep_m,minfo,rep_n,Trans + TKInfo.NCf, minfo->peakword >= 0); MrFree(rep_n); return result; }
static int AddConstituent(MatRep_t *cf, CfInfo *info, int modno, int cfno) { int i, m; for (i = 0; i < NumCf; ++i) { int rc; rc = IsIsomorphic(CfList[i].Gen,CfList[i].Info,cf,NULL,0); if (rc < 0) return -1; if (rc) break; } if (i < NumCf) /* Constituent was already in the list */ { int m = CfList[i].Mult; MrFree(cf); CfList[i].CfMap[m][0] = modno; } else /* It's a new constituent */ { CfList[i].Gen = cf; CfList[i].Info = info; CfList[i].Wg = WgAlloc(cf); CfList[i].Mod = &ModList[modno].Info; CfList[i].Mult = 0; ++NumCf; } m = CfList[i].Mult; CfList[i].CfMap[m][0] = modno; CfList[i].CfMap[m][1] = cfno; CfList[i].Mult++; MESSAGE(1,("%s%s is constituent %d\n",ModList[modno].Info.BaseName, Lat_CfName(&ModList[modno].Info,cfno),i)); return i; }
/** * Using the description of the fabric topology we discovered, try to find a match * among the supported topologies. * * @HtFeatMethod{::F_LOOKUP_COMPUTE_AND_LOAD_ROUTING_TABLES} * * A supported topology description matches the discovered fabric if the Nodes can be * matched in such a way that all the Nodes connected in one set are exactly the * Nodes connected in the other (formally, that the graphs are isomorphic). Which * Links are used is not really important to matching. If the graphs match, then * there is a permutation of one that translates the Node positions and Linkages to * the other. * * In order to make the isomorphism test efficient, we test for matched number of Nodes * (a 4 Node fabric is not isomorphic to a 2 Node topology), and provide degrees of Nodes * to the isomorphism test. * * The generic routing table solution for any topology is predetermined and represented * as part of the topology. The permutation we computed tells us how to interpret the * routing onto the fabric we discovered. We do this working backward from the last * Node discovered to the BSP, writing the routing tables as we go. * * @param[in,out] State the discovered fabric, degree matrix, permutation * */ VOID LookupComputeAndLoadRoutingTables ( IN OUT STATE_DATA *State ) { TOPOLOGY_CONTEXT TopologyContextHandle; UINT8 *Selected; UINT8 Size; UINT8 PairCounter; UINT8 ReqTargetLink; UINT8 RspTargetLink; UINT8 ReqTargetNode; UINT8 RspTargetNode; UINT8 AbstractBcTargetNodes; UINT32 BcTargetLinks; UINT8 NodeCounter; UINT8 NodeBeingRouted; UINT8 NodeRoutedTo; UINT8 BroadcastSourceNode; Size = State->NodesDiscovered + 1; BeginTopologies (&TopologyContextHandle, &Selected, State); while (Selected != NULL) { if (GraphHowManyNodes (Selected) == Size) { // Build Degree vector and Adjacency Matrix for this entry for (NodeCounter = 0; NodeCounter < Size; NodeCounter++) { State->Fabric->DbDegree[NodeCounter] = 0; for (PairCounter = 0; PairCounter < Size; PairCounter++) { if (GraphIsAdjacent (Selected, NodeCounter, PairCounter)) { State->Fabric->DbMatrix[NodeCounter][PairCounter] = TRUE; State->Fabric->DbDegree[NodeCounter]++; } else { State->Fabric->DbMatrix[NodeCounter][PairCounter] = FALSE; } } } if (IsIsomorphic (0, State)) { break; // A matching topology was found } } GetNextTopology (&TopologyContextHandle, &Selected); } if (Selected != NULL) { // Compute the reverse Permutation for (NodeCounter = 0; NodeCounter < Size; NodeCounter++) { State->Fabric->ReversePerm[State->Fabric->Perm[NodeCounter]] = NodeCounter; } // Start with the last discovered Node, and move towards the BSP for (NodeCounter = 0; NodeCounter < Size; NodeCounter++) { NodeBeingRouted = ((Size - 1) - NodeCounter); for (NodeRoutedTo = 0; NodeRoutedTo < Size; NodeRoutedTo++) { BcTargetLinks = 0; AbstractBcTargetNodes = GraphGetBc (Selected, State->Fabric->Perm[NodeBeingRouted], State->Fabric->Perm[NodeRoutedTo]); for (BroadcastSourceNode = 0; BroadcastSourceNode < MAX_NODES; BroadcastSourceNode++) { if ((AbstractBcTargetNodes & ((UINT32)1 << BroadcastSourceNode)) != 0) { // Accepting broadcast from yourself is handled in Nb, so in the topology graph it is an error. ASSERT (NodeBeingRouted != State->Fabric->ReversePerm[BroadcastSourceNode]); BcTargetLinks |= (UINT32)1 << FindLinkToNode (NodeBeingRouted, State->Fabric->ReversePerm[BroadcastSourceNode], State); } } if (NodeBeingRouted == NodeRoutedTo) { ReqTargetLink = ROUTE_TO_SELF; RspTargetLink = ROUTE_TO_SELF; } else { ReqTargetNode = GraphGetReq (Selected, State->Fabric->Perm[NodeBeingRouted], State->Fabric->Perm[NodeRoutedTo]); ReqTargetLink = FindLinkToNode (NodeBeingRouted, State->Fabric->ReversePerm[ReqTargetNode], State); RspTargetNode = GraphGetRsp (Selected, State->Fabric->Perm[NodeBeingRouted], State->Fabric->Perm[NodeRoutedTo]); RspTargetLink = FindLinkToNode (NodeBeingRouted, State->Fabric->ReversePerm[RspTargetNode], State); } State->Nb->WriteFullRoutingTable (NodeBeingRouted, NodeRoutedTo, ReqTargetLink, RspTargetLink, BcTargetLinks, State->Nb); } // Clean up discovery 'footprint' that otherwise remains in the routing table. It didn't hurt // anything, but might cause confusion during debug and validation. Do this by setting the // route back to all self routes. Since it's the Node that would be one more than actually installed, // this only applies if less than MaxNodes were found. // if (Size < MAX_NODES) { State->Nb->WriteFullRoutingTable (NodeBeingRouted, Size, ROUTE_TO_SELF, ROUTE_TO_SELF, 0, State->Nb); } } } else { // // No Matching Topology was found // Error Strategy: // Auto recovery doesn't seem likely, Force boot as 1P. // For reporting, logging, provide number of Nodes // If not implemented or returns, boot as BSP uniprocessor. // // This can be caused by not supplying an additional topology list, if your board is not one of the built-in topologies. // NotifyErrorCohNoTopology (State->NodesDiscovered, State); IDS_ERROR_TRAP; // Force 1P State->NodesDiscovered = 0; State->TotalLinks = 0; State->Nb->EnableRoutingTables (0, State->Nb); State->HtInterface->CleanMapsAfterError (State); } // Save the topology pointer, or NULL, for other features State->Fabric->MatchedTopology = Selected; IDS_HDT_CONSOLE ( HT_TRACE, "System routed as %s.\n", ((TopologyContextHandle.IsCustomList) ? "custom topology" : (((Selected == amdHtTopologySingleNode) || (Selected == NULL)) ? "single node" : ((Selected == amdHtTopologyDualNode) ? "dual node" : ((Selected == amdHtTopologyFourSquare) ? "four node box" : ((Selected == amdHtTopologyFourKite) ? "four node kite" : ((Selected == amdHtTopologyFourFully) ? "fully connected four-way" : ((Selected == amdHtTopologyEightDoubloon) ? "MCM max performance" : ((Selected == amdHtTopologyEightTwinFullyFourWays) ? "MCM max I/O" : "AMD builtin topology")))))))) ); }