Files
DRAMSys/DRAMSys/analyzer/businessObjects/pythoncaller.cpp
Matthias Jung c0fd9de60f MAC compile flag removed.
By using the CONFIG-=app_bundle the trace analyzer
wont be build as a app package on mac anymore.
It behaves exactly like on linux now.
2016-10-24 18:04:28 +02:00

216 lines
7.6 KiB
C++

/*
* Copyright (c) 2015, University of 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
*/
#include "pythoncaller.h"
#include <exception>
#include <string>
#include <iostream>
#include <QFileInfo>
#include <QDebug>
#include <QApplication>
using namespace std;
PythonCaller::PythonCaller() :
testModuleName("tests"),
testFunctionName("runTests"),
metricModuleName("metrics"),
metricFunctionName("calculateMetrics"),
getMetricFunctionName("getMetrics"),
pathToScripts(QApplication::applicationDirPath().toStdString() + "/../../DRAMSys/analyzer/scripts/"),
plotsModuleName("plots"),
plotsFunctionName("generatePlots")
{
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() << "Test:" << testModuleName.c_str() << testFunctionName.c_str();
qDebug() << "Metric:" << metricModuleName.c_str() << metricFunctionName.c_str();
qDebug() << "Plot:" << plotsModuleName.c_str() << plotsFunctionName.c_str();
qDebug() << "Script: " << pathToScripts.c_str();
pRunTestsFunction = loadFunctionFromModule(testModuleName, testFunctionName);
pCalculateMetricsFunction = loadFunctionFromModule(metricModuleName, metricFunctionName);
pGenPlotsFunction = loadFunctionFromModule(plotsModuleName, plotsFunctionName);
pGetMetricsFunction = loadFunctionFromModule(metricModuleName, getMetricFunctionName);
}
//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(string moduleName,string functionName)
{
PyObject* pModuleName = PyUnicode_FromString(moduleName.c_str());
PyObject* pModule = PyImport_Import(pModuleName);
if(!pModule)
{
throw runtime_error(string("Could not load module "+ moduleName));
}
PyObject* pFunction = PyObject_GetAttrString(pModule, functionName.c_str());
if(!pFunction || !PyCallable_Check(pFunction))
{
throw runtime_error(string("Could not load test function " + functionName + "in module " + moduleName));
}
Py_DECREF(pModuleName);
Py_DECREF(pModule);
return pFunction;
}
PythonCaller::~PythonCaller()
{
Py_DECREF(pRunTestsFunction);
Py_DECREF(pCalculateMetricsFunction);
Py_DECREF(pGenPlotsFunction);
Py_DECREF(pGetMetricsFunction);
Py_Finalize();
}
PyObject* PythonCaller::callMetricsFunction(PyObject* function, QString argument, 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 runtime_error(string("Error in calling " + testFunctionName + " in module " + testModuleName));
}
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 runtime_error(string("Error in calling " + testFunctionName + " in module " + testModuleName));
}
return pResult;
}
TraceTestResults PythonCaller::runTestsOnTrace(QString pathToTrace)
{
TraceTestResults traceTestResult(QFileInfo(pathToTrace).baseName());
PyObject *pResult = callFunctionWithStringArgument(pRunTestsFunction, pathToTrace);
for(Py_ssize_t i= 0; i < PyList_Size(pResult); ++i)
{
PyObject* currentTestResult = PyList_GetItem(pResult,i);
QString testName(PyUnicode_AsUTF8(PyTuple_GetItem(currentTestResult,0)));
bool testPassed = (Py_True == PyTuple_GetItem(currentTestResult,1));
QString message(PyUnicode_AsUTF8(PyTuple_GetItem(currentTestResult,2)));
traceTestResult.addTestResult(TestResult(testName,testPassed,message));
}
Py_DECREF(pResult);
return traceTestResult;
}
TraceCalculatedMetrics PythonCaller::calculateMetricsOnTrace(QString pathToTrace, 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;
}
vector<string> PythonCaller::getMetrics(QString pathToTrace)
{
vector<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;
}