252 lines
8.8 KiB
C++
252 lines
8.8 KiB
C++
/*
|
|
* Copyright (c) 2015, Technische Universität Kaiserslautern
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are
|
|
* met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright notice,
|
|
* this list of conditions and the following disclaimer.
|
|
*
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* 3. Neither the name of the copyright holder nor the names of its
|
|
* contributors may be used to endorse or promote products derived from
|
|
* this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
|
|
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
* Authors:
|
|
* Janik Schlemminger
|
|
* Robert Gernhardt
|
|
* Matthias Jung
|
|
* Felipe S. Prado
|
|
* Derek Christ
|
|
*/
|
|
|
|
#include "pythoncaller.h"
|
|
#include <exception>
|
|
#include <string>
|
|
#include <iostream>
|
|
#include <QFileInfo>
|
|
#include <QDebug>
|
|
#include <QApplication>
|
|
|
|
PythonCaller &PythonCaller::instance()
|
|
{
|
|
static PythonCaller instance;
|
|
return instance;
|
|
}
|
|
|
|
PythonCaller::PythonCaller() :
|
|
metricModuleName("metrics"),
|
|
metricFunctionName("calculateMetrics"),
|
|
getMetricFunctionName("getMetrics"),
|
|
|
|
pathToScripts(QApplication::applicationDirPath().toStdString() +
|
|
"/../../DRAMSys/traceAnalyzer/scripts/"),
|
|
plotsModuleName("plots"),
|
|
plotsFunctionName("generatePlots"),
|
|
checkDependenciesModuleName("checkDependencies"),
|
|
vcdExportModuleName("vcdExport"),
|
|
vcdExportFunctionName("dumpVcd"),
|
|
vcdExportDependenciesFunctionName("checkVcdExport")
|
|
{
|
|
Py_Initialize();
|
|
PyObject *sysPath = PySys_GetObject((char *)"path");
|
|
PyObject *path = PyUnicode_FromString(this->pathToScripts.c_str());
|
|
PyList_Insert(sysPath, 0, path);
|
|
Py_DECREF(path);
|
|
|
|
qDebug() << "Metric:" << metricModuleName.c_str() << metricFunctionName.c_str();
|
|
qDebug() << "Plot:" << plotsModuleName.c_str() << plotsFunctionName.c_str();
|
|
qDebug() << "VcdExport:" << vcdExportModuleName.c_str() << vcdExportFunctionName.c_str();
|
|
qDebug() << "Script: " << pathToScripts.c_str();
|
|
|
|
pCalculateMetricsFunction = loadFunctionFromModule(metricModuleName,
|
|
metricFunctionName);
|
|
pGenPlotsFunction = loadFunctionFromModule(plotsModuleName, plotsFunctionName);
|
|
pGetMetricsFunction = loadFunctionFromModule(metricModuleName,
|
|
getMetricFunctionName);
|
|
|
|
pVcdExportDependenciesFunction = loadFunctionFromModule(checkDependenciesModuleName, vcdExportDependenciesFunctionName);
|
|
|
|
if (vcdExportDependenciesAvailable())
|
|
pVcdExportFunction = loadFunctionFromModule(vcdExportModuleName, vcdExportFunctionName);
|
|
else
|
|
std::cerr << "Warning: Python module pyvcd or tqdm not installed! Exporting as VCD not possible." << std::endl;
|
|
}
|
|
|
|
|
|
//returns new reference to the function (see: http://edcjones.tripod.com/refcount.html for the difference between "new reference" and "borrowed reference")
|
|
PyObject *PythonCaller::loadFunctionFromModule(std::string moduleName, std::string functionName)
|
|
{
|
|
PyObject *pModuleName = PyUnicode_FromString(moduleName.c_str());
|
|
PyObject *pModule = PyImport_Import(pModuleName);
|
|
|
|
if (!pModule) {
|
|
throw std::runtime_error(std::string("Could not load module " + moduleName));
|
|
}
|
|
|
|
PyObject *pFunction = PyObject_GetAttrString(pModule, functionName.c_str());
|
|
|
|
if (!pFunction || !PyCallable_Check(pFunction)) {
|
|
throw std::runtime_error(
|
|
std::string("Could not load test function " + functionName + "in module " + moduleName));
|
|
}
|
|
|
|
Py_DECREF(pModuleName);
|
|
Py_DECREF(pModule);
|
|
return pFunction;
|
|
}
|
|
|
|
PythonCaller::~PythonCaller()
|
|
{
|
|
Py_DECREF(pCalculateMetricsFunction);
|
|
Py_DECREF(pGenPlotsFunction);
|
|
Py_DECREF(pGetMetricsFunction);
|
|
|
|
if (pVcdExportFunction)
|
|
Py_DECREF(pVcdExportFunction);
|
|
|
|
Py_DECREF(pVcdExportDependenciesFunction);
|
|
Py_Finalize();
|
|
}
|
|
|
|
PyObject *PythonCaller::callMetricsFunction(PyObject *function, QString argument, std::vector<long> list)
|
|
{
|
|
assert(PyCallable_Check(function));
|
|
|
|
PyObject *pArgs = PyTuple_New(2);
|
|
PyObject *pArgumentString = PyUnicode_FromString(
|
|
argument.toStdString().c_str());
|
|
PyObject *pArgumentList = PyList_New(list.size());
|
|
for (size_t i = 0; i < list.size(); i++) {
|
|
PyList_SetItem(pArgumentList, i, PyBool_FromLong(list[i]));
|
|
}
|
|
PyTuple_SetItem(pArgs, 0, pArgumentString);
|
|
PyTuple_SetItem(pArgs, 1, pArgumentList);
|
|
PyObject *pResult = PyObject_CallObject(function, pArgs);
|
|
Py_DECREF(pArgs);
|
|
|
|
if (!pResult) {
|
|
PyErr_Print();
|
|
throw std::runtime_error(
|
|
std::string("Error in calling " + metricFunctionName + " in module " + metricModuleName));
|
|
}
|
|
|
|
return pResult;
|
|
}
|
|
|
|
//returns a new reference to result of function call
|
|
PyObject *PythonCaller::callFunctionWithStringArgument(PyObject *function,
|
|
QString argument)
|
|
{
|
|
assert(PyCallable_Check(function));
|
|
|
|
PyObject *pArgs = PyTuple_New(1);
|
|
PyObject *pArgument = PyUnicode_FromString(argument.toStdString().c_str());
|
|
PyTuple_SetItem(pArgs, 0, pArgument);
|
|
PyObject *pResult = PyObject_CallObject(function, pArgs);
|
|
Py_DECREF(pArgument);
|
|
|
|
if (!pResult) {
|
|
PyErr_Print();
|
|
throw std::runtime_error(std::string("Error in calling function with string argument"));
|
|
}
|
|
|
|
return pResult;
|
|
}
|
|
|
|
PyObject *PythonCaller::callFunctionWithoutArguments(PyObject *function)
|
|
{
|
|
assert(PyCallable_Check(function));
|
|
PyObject *pResult = PyObject_CallObject(function, NULL);
|
|
|
|
if (!pResult) {
|
|
PyErr_Print();
|
|
throw std::runtime_error(std::string("Error in calling python function"));
|
|
}
|
|
|
|
return pResult;
|
|
}
|
|
|
|
TraceCalculatedMetrics PythonCaller::calculateMetricsOnTrace(QString pathToTrace, std::vector<long> list)
|
|
{
|
|
TraceCalculatedMetrics result(QFileInfo(pathToTrace).baseName());
|
|
PyObject *pResult = callMetricsFunction(pCalculateMetricsFunction, pathToTrace,
|
|
list);
|
|
|
|
for (Py_ssize_t i = 0; i < PyList_Size(pResult); ++i) {
|
|
PyObject *calculatedMetric = PyList_GetItem(pResult, i);
|
|
QString metricName(PyUnicode_AsUTF8(PyTuple_GetItem(calculatedMetric, 0)));
|
|
double value = PyFloat_AsDouble(PyTuple_GetItem(calculatedMetric, 1));
|
|
result.addCalculatedMetric(CalculatedMetric(metricName, value));
|
|
}
|
|
|
|
Py_DECREF(pResult);
|
|
return result;
|
|
}
|
|
|
|
std::vector<std::string> PythonCaller::getMetrics(QString pathToTrace)
|
|
{
|
|
std::vector<std::string> result;
|
|
PyObject *pResult = callFunctionWithStringArgument(pGetMetricsFunction,
|
|
pathToTrace);
|
|
|
|
for (Py_ssize_t i = 0; i < PyList_Size(pResult); ++i) {
|
|
PyObject *metric = PyList_GetItem(pResult, i);
|
|
QString metricName(PyUnicode_AsUTF8(metric));
|
|
result.push_back(metricName.toStdString().c_str());
|
|
}
|
|
|
|
Py_DECREF(pResult);
|
|
return result;
|
|
}
|
|
|
|
QString PythonCaller::generatePlotsOnTrace(QString pathToTrace)
|
|
{
|
|
assert(PyCallable_Check(pGenPlotsFunction));
|
|
|
|
PyObject *pResult = callFunctionWithStringArgument(pGenPlotsFunction,
|
|
pathToTrace);
|
|
QString outputFiles (PyUnicode_AsUTF8(pResult));
|
|
Py_DECREF(pResult);
|
|
return outputFiles;
|
|
|
|
}
|
|
|
|
QString PythonCaller::exportAsVcd(QString pathToTrace)
|
|
{
|
|
if (!pVcdExportFunction)
|
|
return QString();
|
|
|
|
PyObject *pResult = callFunctionWithStringArgument(pVcdExportFunction, pathToTrace);
|
|
|
|
QString dump(PyUnicode_AsUTF8(pResult));
|
|
Py_DECREF(pResult);
|
|
return dump;
|
|
}
|
|
|
|
bool PythonCaller::vcdExportDependenciesAvailable()
|
|
{
|
|
PyObject *result = callFunctionWithoutArguments(pVcdExportDependenciesFunction);
|
|
bool available = PyObject_IsTrue(result);
|
|
Py_DECREF(result);
|
|
|
|
return available;
|
|
}
|