void BuildBlock::onTimestamp(const notification::Path& path, const value::Value* value) { if (_stats) return; auto ts = value->AsULong(); _executionsBuilder.SetTimestamp(ts); _stacksBuilder.SetTimestamp(ts); _criticalGraph.SetTimestamp(ts); _stateHistory.SetTimestamp(ts); _diskRequests.SetTimestamp(ts); if (_saveTs == 0) { _saveTs = ts; } else if (ts > _saveTs + kSaveInterval) { SaveExecutions(); // Clean everything that is |kSaveInterval| old. tbinfo() << "Cleaning the history." << tbendl(); _stacksBuilder.Cleanup(_saveTs); _criticalGraph.Cleanup(_saveTs); _stateHistory.Cleanup(_saveTs); _diskRequests.Cleanup(_saveTs); tbinfo() << "Continuing to read the trace." << tbendl(); _lastCleanupTs = _saveTs; _saveTs = ts; } }
void BuildBlock::onEnd(const notification::Path& path, const value::Value* value) { if (_stats) return; tbinfo() << "Completed reading the trace." << tbendl(); SaveExecutions(); tbinfo() << "A total of " << _numExecutions << " executions were added to the database." << tbendl(); }
void BuildBlock::SaveExecutions() { tbinfo() << "Saving current executions to the database." << tbendl(); // Notify the executions and stacks builder that we reached // the end of the trace. _executionsBuilder.Terminate(); _stacksBuilder.Terminate(); // Save all executions in the database. for (auto& execution : _executionsBuilder) { if (execution->startTs() < _lastCleanupTs) { tberror() << "Skipping an execution because it starts before the last cleanup ts." << tbendl(); tberror() << " Execution start ts: " << execution->startTs() << tbendl(); continue; } // Compute the critical path of the execution. critical::CriticalPath criticalPath; critical::ComputeCriticalPath( _criticalGraph, execution->startTs(), execution->endTs(), execution->startThread(), &criticalPath); // Extract the stacks that belong to the execution. execution::ExtractStacks( criticalPath, _stacksBuilder, _criticalGraph, _stateHistory, _diskRequests, _currentState, &_db, execution.get()); // Extract execution metrics. execution::ExtractMetrics( criticalPath, _stateHistory, _currentState, _quarks, execution.get()); // Add the execution to the database. _db.AddExecution(*execution); ++_numExecutions; } // Flush saved executions. _executionsBuilder.Flush(); }
bool CriticalGraph::ComputeCriticalPath( const CriticalNode* from, const CriticalNode* to, const std::unordered_set<uint32_t>& tids, CriticalPath* path) const { assert(from != nullptr); assert(to != nullptr); assert(path != nullptr); // Topological sort. std::vector<const CriticalNode*> topological; if (!TopologicalSort(from, to, &topological)) { tberror() << "Destination node wasn't found in topological sort." << tbendl(); return false; } // Compute maximum distance from destination for each node. std::unordered_map<const CriticalNode*, NodeDistance> distances; for (auto it = topological.rbegin(); it != topological.rend(); ++it) { // If the node is the destination, the distance is zero. if (*it == to) { distances[*it] = NodeDistance(0, kInvalidCriticalEdgeId); continue; } // Compute the 2 possible distances. size_t horizontal_distance = kHugeDistance; CriticalEdgeId horizontal_edge_id = (*it)->edge(kCriticalEdgeOutHorizontal); if (horizontal_edge_id != kInvalidCriticalEdgeId) { const auto& edge = GetEdge(horizontal_edge_id); auto distance_look = distances.find(edge.to()); if (distance_look != distances.end()) { horizontal_distance = distance_look->second.distance; if (horizontal_distance != kHugeDistance) { if (tids.find((*it)->tid()) == tids.end()) { // Reduce the cost of edges that are on other threads. horizontal_distance = std::min(horizontal_distance, static_cast<size_t>(1)); } horizontal_distance += edge.Cost(); } } } size_t vertical_distance = kHugeDistance; CriticalEdgeId vertical_edge_id = (*it)->edge(kCriticalEdgeOutVertical); if (vertical_edge_id != kInvalidCriticalEdgeId) { const auto& edge = GetEdge(vertical_edge_id); auto distance_look = distances.find(edge.to()); if (distance_look != distances.end()) { vertical_distance = distance_look->second.distance; if (vertical_distance != kHugeDistance) vertical_distance += edge.Cost(); } } // Keep the maximum distance which is not invalid. if (horizontal_distance != kHugeDistance && (vertical_distance == kHugeDistance || horizontal_distance >= vertical_distance)) { distances[*it] = NodeDistance(horizontal_distance, horizontal_edge_id); } else if (vertical_distance != kHugeDistance && (horizontal_distance == kHugeDistance || vertical_distance >= horizontal_distance)) { distances[*it] = NodeDistance(vertical_distance, vertical_edge_id); } } // Retrieve the critical path. const CriticalNode* cur = from; while (cur != to) { const NodeDistance& distance = distances[cur]; const CriticalEdge& edge = GetEdge(distance.edge); if (edge.type() != CriticalEdgeType::kVertical) { path->Push(CriticalPathSegment( edge.from()->ts(), edge.from()->tid(), edge.type())); } cur = GetEdge(distance.edge).to(); } // Restrict the critical path to the autorized threads. path->RestrictToThreads(tids); return true; }