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();
}
Esempio n. 2
0
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;
}