/// <summary> /// Saves this graph on a given binary stream. /// </summary> public virtual void Serialize(BuildXLWriter writer) { Contract.Requires(writer != null, "Argument writer cannot be null"); uint max = (uint)m_lastNodeId; writer.Write(max); writer.Write(m_edgeCount); for (uint node = 1; node <= max; node++) { var outEdges = GetOutEdgeListHeader(node); writer.WriteCompact(outEdges.Count); int count = 0; foreach (var edge in GetOutgoingEdges(outEdges)) { edge.Serialize(writer); count++; } Contract.Assert(outEdges.Count == count); } for (uint node = 1; node <= max; node++) { var nodeHeight = GetNodeHeight(node); writer.WriteCompact(nodeHeight); NodeEdgeListHeader inEdges = GetInEdgeListHeader(node); writer.WriteCompact(inEdges.Count); } }
private Enumerator GetOutgoingEdges(NodeEdgeListHeader edges) { return(new Enumerator(this, edges.FirstIndex, edges.Count, m_enumeratorVerificationObject, isIncoming: false)); }
/// <summary> /// Loads this graph from a given binary stream. /// </summary> private void Load(BuildXLReader reader) { m_lastNodeId = (int)reader.ReadUInt32(); m_edgeCount = reader.ReadInt32(); Contract.Assume(m_lastNodeId <= NodeId.MaxValue); // Create buffer with space for in edges and out edges m_edgeBuffer.Initialize(m_edgeCount * 2); int edgeIndex = 0; // Read the out edges { var accessor = m_edgeBuffer.GetAccessor(); // TODO: This loop takes 70% of the deserialization time; make faster. for (uint i = 1; i <= m_lastNodeId; ++i) { int outNodeCount = reader.ReadInt32Compact(); int startEdgeIndex = edgeIndex; for (int j = 0; j < outNodeCount; ++j) { var outgoingEdge = Edge.Deserialize(reader); accessor[edgeIndex] = outgoingEdge; edgeIndex++; } OutEdges[i] = new NodeEdgeListHeader(startEdgeIndex, outNodeCount); } } // Read the count of in edges // TODO: This loop takes 10% of the deserialization time; make faster. for (uint i = 1; i <= m_lastNodeId; i++) { int nodeHeight = reader.ReadInt32Compact(); NodeHeights[i] = nodeHeight; int inEdgeCount = reader.ReadInt32Compact(); // first edge index starts at end of edge span for this node and is decrements as edges // are discovered and added below. At the end the first edge index will // be at the beginning of the span edgeIndex += inEdgeCount; InEdges[i] = new NodeEdgeListHeader(edgeIndex, inEdgeCount); } // Write each out edge set to graph and compute the in edges // TODO: This parallel loop takes 20% of the (sequential) deserialization time; make faster. Parallel.For(1, m_lastNodeId + 1, (i) => { NodeId node = new NodeId((uint)i); var accessor = m_edgeBuffer.GetAccessor(); foreach (var e in GetOutgoingEdges(node)) { var inEdge = new Edge(node, e.IsLight); // Note: We access the InEdges array element directly, not via the ConcurrentDenseIndex's indexer property. // As a result, we mutate the actual array element, instead of a copy. var p = InEdges.GetBufferPointer(e.OtherNode.Value); var index = p.Buffer[p.Index].InterlockedDecrementFirstIndex(); // Set the prior index and point header at that index. The initial value // to index should be set to the index after the span. So this will always // set an index within the edge span accessor[index] = inEdge; } }); }