Files
DRAMSys/extensions/apps/traceAnalyzer/businessObjects/dramTimeDependencies/phasedependenciestracker.cpp

348 lines
12 KiB
C++

/*
* Copyright (c) 2025 Fraunhofer IESE. All rights reserved.
*
* Authors:
* Iron Prando da Silva
*/
#include "phasedependenciestracker.h"
#include <chrono>
#include <iostream>
void PhaseDependenciesTracker::calculateDependencies(TraceDB& tdb, std::vector<QString>& commands)
{
using std::chrono::duration;
using std::chrono::duration_cast;
using std::chrono::high_resolution_clock;
using std::chrono::microseconds;
auto deviceInstantiationTimeStart = high_resolution_clock::now();
auto deviceConfig = ConfigurationFactory::make(tdb);
auto deviceInstantiationTimeEnd = high_resolution_clock::now();
auto deviceInstantiationTimeDuration =
duration_cast<microseconds>(deviceInstantiationTimeEnd - deviceInstantiationTimeStart);
mBeginTransaction(tdb);
mDropTable(tdb);
if (commands.size() > 0)
{
auto phasesLoadingTimeStart = high_resolution_clock::now();
auto& phases = mGetFilteredPhases(deviceConfig, tdb, commands);
auto phasesLoadingTimeEnd = high_resolution_clock::now();
auto phasesLoadingTimeDuration =
duration_cast<microseconds>(phasesLoadingTimeEnd - phasesLoadingTimeStart);
if (phases.size() != 0)
{
auto dependenciesCalcTimeStart = high_resolution_clock::now();
auto& entries = mCalculateDependencies(deviceConfig, phases, commands);
auto dependenciesCalcTimeEnd = high_resolution_clock::now();
auto dependenciesCalcTimeDuration =
duration_cast<microseconds>(dependenciesCalcTimeEnd - dependenciesCalcTimeStart);
if (entries.size() > 0)
{
mCreateTable(tdb);
}
auto tableInsertionTimeStart = high_resolution_clock::now();
mInsertIntoTable(tdb, entries);
auto tableInsertionTimeEnd = high_resolution_clock::now();
auto tableInsertionTimeDuration =
duration_cast<microseconds>(tableInsertionTimeEnd - tableInsertionTimeStart);
auto totalTime = deviceInstantiationTimeDuration + phasesLoadingTimeDuration +
dependenciesCalcTimeDuration + tableInsertionTimeDuration;
std::cout << "PhaseDependenciesTracker times (us):" << std::endl
<< "\tDevice instantiation: " << deviceInstantiationTimeDuration.count()
<< std::endl
<< "\tPhase loading: " << phasesLoadingTimeDuration.count() << std::endl
<< "\tDependencies calculation: " << dependenciesCalcTimeDuration.count()
<< std::endl
<< "\tDB table population: " << tableInsertionTimeDuration.count()
<< std::endl
<< " - Total time: " << totalTime.count() << std::endl;
}
else
{
// TODO - not sure if necessary. Still, a possibility
// mRollbackChanges(tdb);
// return;
}
}
mCommitTransaction(tdb);
}
void PhaseDependenciesTracker::mDropTable(TraceDB& tdb)
{
QString command = "DROP TABLE IF EXISTS DirectDependencies; ";
auto query = mExecuteQuery(tdb, command);
query.finish();
}
void PhaseDependenciesTracker::mCreateTable(TraceDB& tdb)
{
QString command =
"CREATE TABLE DirectDependencies( DelayedPhaseID INT, DelayedPhaseName, DependencyType, "
"TimeDependency, DependencyPhaseID INT, DependencyPhaseName ); ";
auto query = mExecuteQuery(tdb, command);
query.finish();
}
void PhaseDependenciesTracker::mInsertIntoTable(TraceDB& tdb,
const std::vector<DBDependencyEntry>& entries)
{
static const size_t bulkInsertionSize = 30;
QString command;
size_t counter = 0;
for (const auto& entry : entries)
{
if (counter == 0)
{
// Reset command string and add first entry
command =
"INSERT INTO 'DirectDependencies' ('DelayedPhaseID', 'DelayedPhaseName', "
"'DependencyType', 'TimeDependency', 'DependencyPhaseID', 'DependencyPhaseName') ";
mAddFirstEntryCommandString(command, entry);
counter++;
}
else if (counter == bulkInsertionSize - 1)
{
// Write last entry and submit
mAddEntryCommandString(command, entry);
auto query = mExecuteQuery(tdb, command);
query.finish();
counter = 0;
}
else
{
// Write entry
mAddEntryCommandString(command, entry);
counter++;
}
}
if (counter != 0)
{
auto query = mExecuteQuery(tdb, command);
query.finish();
}
}
const std::vector<std::shared_ptr<DBPhaseEntryBase>>
PhaseDependenciesTracker::mGetFilteredPhases(const std::shared_ptr<ConfigurationBase> deviceConfig,
TraceDB& tdb,
const std::vector<QString>& commands)
{
std::vector<std::shared_ptr<DBPhaseEntryBase>> phases;
QString queryStr = deviceConfig->getQueryStr(commands);
auto query = mExecuteQuery(tdb, queryStr);
if (!query.next())
return phases;
if (!query.last())
{
throw sqlException(("Query:\n " + tdb.queryToString(query) +
"\n failed. Error: \n"
"Could not retrieve number of rows\n")
.toStdString(),
tdb.pathToDB.toStdString());
}
size_t nrows = query.at() + 1;
if (!query.first())
{
throw sqlException(("Query:\n " + tdb.queryToString(query) +
"\n failed. Error: \n"
"Could not retrieve number of rows safely\n")
.toStdString(),
tdb.pathToDB.toStdString());
}
phases.resize(nrows);
size_t rowIt = 0;
do
{
phases[rowIt] = deviceConfig->makePhaseEntry(query);
++rowIt;
} while (query.next());
if (rowIt != nrows)
{
throw std::runtime_error("An error occurred while fetching phases in "
"'PhaseDependenciesTracker::mGetFilteredPhases': expected " +
std::to_string(nrows) + " rows, but found " +
std::to_string(rowIt) + "\n");
}
query.finish();
return phases;
}
const std::vector<DBDependencyEntry> PhaseDependenciesTracker::mCalculateDependencies(
const std::shared_ptr<ConfigurationBase> deviceConfig,
const std::vector<std::shared_ptr<DBPhaseEntryBase>>& phases,
std::vector<QString>& commands)
{
std::vector<DBDependencyEntry> entries;
entries.reserve((size_t)(0.4 * phases.size()));
// Get dependencies for device
const DependencyMap deviceDependencies = deviceConfig->getDependencies(commands);
// Tries to find all timing dependencies for each phase on the trace
PoolControllerMap poolController = deviceConfig->getPools();
for (size_t i = 1; i < phases.size(); i++)
{
// Pool dependencies variables reset
poolController.clear();
// Auxiliary variables
const auto phase = phases[i];
if (phase == nullptr)
continue;
// Get time dependency descriptions for the current phase
const auto& deps = deviceDependencies.at(phase->phaseName);
// Loop all previous phases until there cannot be any more time dependencies
for (int j = i - 1; j >= 0; j--)
{
// Get next phase to analyse
const auto& otherPhase = phases[j];
// Calculates the time difference in nanoseconds
const auto timeDiff = phase->phaseBegin - otherPhase->phaseBegin;
// Time difference begin greater than the maximum possible dependency time ends the
// internal loop
if (timeDiff > deps.maxTime)
break;
// For each possible dependency for the current phase,
// checks if otherPhase would match as a dependency
for (const auto& dep : deps.dependencies)
{
bool isPoolDep = dep.phaseDep.isPool();
if (!isPoolDep && dep.phaseDep != otherPhase->phaseName)
continue;
if (!phase->potentialDependency(dep, otherPhase))
{
continue;
}
if (isPoolDep)
{
// Captures activate window and command bus dependencies
auto busyTime = poolController.getBusyTime(dep.phaseDep, otherPhase->phaseName);
if (busyTime > 0 && timeDiff <= busyTime)
{
if (timeDiff == busyTime)
{
// Captures only the first (exactly matching time) phase in
// the pool window as a dependency
poolController.push(
dep.phaseDep,
DBDependencyEntry{phase->id,
phase->phaseName.getIDStr(),
PhaseDependency::dependencyTypeName(dep.depType),
dep.timeDepName,
otherPhase->id,
otherPhase->phaseName.getIDStr()});
}
if (timeDiff < busyTime)
{
poolController.increment(dep.phaseDep);
}
}
continue;
}
if (timeDiff == dep.timeValue)
{
entries.emplace_back(
DBDependencyEntry{phase->id,
phase->phaseName.getIDStr(),
PhaseDependency::dependencyTypeName(dep.depType),
dep.timeDepName,
otherPhase->id,
otherPhase->phaseName.getIDStr()});
}
}
}
poolController.merge(entries);
}
return entries;
}
QSqlQuery PhaseDependenciesTracker::mExecuteQuery(TraceDB& tdb, const QString queryStr)
{
QSqlQuery query(tdb.database);
query.prepare(queryStr);
tdb.executeQuery(query);
return query;
}
void PhaseDependenciesTracker::mBeginTransaction(TraceDB& tdb)
{
const QString queryStr = "BEGIN TRANSACTION;";
auto query = mExecuteQuery(tdb, queryStr);
query.finish();
}
void PhaseDependenciesTracker::mRollbackChanges(TraceDB& tdb)
{
const QString queryStr = "ROLLBACK;";
auto query = mExecuteQuery(tdb, queryStr);
query.finish();
}
void PhaseDependenciesTracker::mCommitTransaction(TraceDB& tdb)
{
const QString queryStr = "COMMIT;";
auto query = mExecuteQuery(tdb, queryStr);
query.finish();
}
void PhaseDependenciesTracker::mAddFirstEntryCommandString(QString& command,
const DBDependencyEntry& entry)
{
command = command + " SELECT '" + QString::number(entry.delayedPhaseID) +
"' AS 'DelayedPhaseID', '" + entry.delayedPhaseName + "' AS 'DelayedPhaseName', '" +
entry.dependencyType + "' AS 'DependencyType', '" + entry.timeDependency +
"' AS 'TimeDependency', '" + QString::number(entry.dependencyPhaseID) +
"' AS 'DependencyPhaseID', '" + entry.dependencyPhaseName +
"' AS 'DependencyPhaseName' ";
}
void PhaseDependenciesTracker::mAddEntryCommandString(QString& command,
const DBDependencyEntry& entry)
{
command = command + " UNION ALL SELECT '" + QString::number(entry.delayedPhaseID) + "', '" +
entry.delayedPhaseName + "', '" + entry.dependencyType + "', '" +
entry.timeDependency + "', '" + QString::number(entry.dependencyPhaseID) + "', '" +
entry.dependencyPhaseName + "' ";
}