Skip to content

Commit

Permalink
embed python into Application module
Browse files Browse the repository at this point in the history
  • Loading branch information
zigen committed Jun 16, 2022
1 parent 687cf30 commit f57f5ba
Show file tree
Hide file tree
Showing 19 changed files with 175 additions and 47 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
compile_commands.json
*.plan
results
.oppfeaturestate

### coverage files
quisp/coverage*
Expand Down
Empty file added .nedexclusions
Empty file.
12 changes: 12 additions & 0 deletions .oppfeatures
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<features cppSourceRoots = "src" definesFile = "quisp/features.h">
<feature
id = "EmbeddedPython"
name = "Embedded Python"
description = "this allows user to run python code in a simulation"
initiallyEnabled = "false"
extraSourceFolders = ""
compileFlags = "-DENABLE_PYTHON"
linkerFlags = ""
/>

</features>
11 changes: 8 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
QUISP_MAKEFILE = "./quisp/Makefile"
QUISP_SRC_DIR = "./quisp"
QUISP_MAKEFILE = "$(QUISP_SRC_DIR)/Makefile
QUISP_FEATURE = "$(QUISP_SRC_DIR)/feature_defines.h"

.PHONY: all tidy format ci makefile-exe makefile-lib checkmakefile googletest clean test coverage coverage-report help quispr

Expand Down Expand Up @@ -47,12 +49,15 @@ eigen/CMakeLists.txt:

eigen: eigen/CMakeLists.txt

makefile-exe: eigen
makefile-exe: eigen $(QUISP_FEATURE)
cd quisp && opp_makemake -f --deep -O out -i ./makefrag

makefile-lib: eigen
makefile-lib: eigen $(QUISP_FEATURE)
cd quisp && opp_makemake -f --deep -O out -i ./makefrag -M debug --make-so

$(QUISP_FEATURE): $(wildcard .oppfeaturestate) .oppfeatures
opp_featuretool defines > $(QUISP_SRC_DIR)/feature_defines.h

clean:
@if [ -f "$(QUISP_MAKEFILE)" ]; then \
$(MAKE) -C quisp clean; \
Expand Down
1 change: 1 addition & 0 deletions quisp/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ out/
.oppfeaturestate
quisp.dSYM/
Test*
feature_defines.h

PhotonicQubit_m.cc
PhotonicQubit_m.h
Expand Down
6 changes: 3 additions & 3 deletions quisp/.nedfolders
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.
./channels
./modules
./networks
channels
modules
networks
16 changes: 16 additions & 0 deletions quisp/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import opp
import application

def init_app_module(app):
num_resources = app.par("distant_measure_count").int()
pattern = app.par("TrafficPattern").int()
initiator_addr = app.par("LoneInitiatorAddress").int()

if pattern == 1 and app.my_address == initiator_addr:
dest_addr = app.get_one_random_endnode_addr()
pk = app.create_conn_setup_req(dest_addr,num_resources)
app.schedule_at(opp.sim_time(), pk)
if pattern == 2:
dest_addr = app.get_one_random_endnode_addr()
pk = app.create_conn_setup_req(dest_addr,num_resources)
app.schedule_at(opp.sim_time() + 0.00001 * app.my_address, pk)
35 changes: 28 additions & 7 deletions quisp/modules/Application/Application.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,31 @@
*/
#include "Application.h"
#include <omnetpp.h>
#include <pybind11/detail/common.h>
#include <pybind11/pybind11.h>
#include <functional>
#include <memory>
#include <vector>
#include "messages/base_messages_m.h"
#include "messages/connection_setup_messages_m.h"
#include "modules/Application/IApplication.h"
#include "utils/ComponentProvider.h"

using namespace omnetpp;
using namespace quisp::messages;
namespace py = pybind11;

namespace quisp {
namespace modules {

PYBIND11_EMBEDDED_MODULE(application, m) {
py::class_<Application, std::unique_ptr<Application, pybind11::nodelete>, cSimpleModule> QuispApplication(m, "Application");
QuispApplication.def("create_conn_setup_req", &Application::createConnectionSetupRequest);
QuispApplication.def_readonly("my_address", &Application::my_address);
QuispApplication.def("get_one_random_endnode_addr", &Application::getOneRandomEndNodeAddress);
py::class_<ConnectionSetupRequest, std::unique_ptr<ConnectionSetupRequest, py::nodelete>, omnetpp::cMessage>(m, "ConnectionSetupRequest");
}

Application::Application() : provider(utils::ComponentProvider{this}) {}

/**
Expand All @@ -30,22 +46,26 @@ void Application::initialize() {
return;
}

my_address = provider.getQNode()->par("address");
is_e2e_connection = par("EndToEndConnection");
num_measure = par("distant_measure_count");
WATCH_VECTOR(other_end_node_addresses);
storeEndNodeAddresses();

#ifdef ENABLE_PYTHON
const char *app_py_path = par("app_py_path").stringValue();
compile_code(app_py_path);
auto obj = py::cast(this);
execute_python("init_app_module", obj);

WATCH_VECTOR(other_end_node_addresses);
storeEndNodeAddresses();
#else

my_address = provider.getQNode()->par("address");
is_e2e_connection = par("EndToEndConnection");
num_measure = par("distant_measure_count");
traffic_pattern = par("TrafficPattern");

if (!is_e2e_connection) {
return;
}

traffic_pattern = par("TrafficPattern");

if (traffic_pattern == 0) {
EV_INFO << "EndToEndConnection is set true. but no traffic pattern specified; proceeding with no traffic\n";
return;
Expand Down Expand Up @@ -76,6 +96,7 @@ void Application::initialize() {
}

error("Invalid TrafficPattern specified.");
#endif
}

/**
Expand Down
1 change: 0 additions & 1 deletion quisp/modules/Application/Application.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ class Application : public IApplication, python_embeddable::PythonEmbeddable {
Application();
~Application() {}

protected:
int my_address;

std::vector<int> other_end_node_addresses;
Expand Down
1 change: 1 addition & 0 deletions quisp/modules/Application/Application.ned
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ simple Application
{
parameters:
@display("i=block/app");
string app_py_path = default("app");
int address;
volatile double sendIaTime @unit(s) = default(exponential(1s)); // time between generating packets
string Other_endnodes_table = "";
Expand Down
2 changes: 1 addition & 1 deletion quisp/modules/Application/Application_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class AppTestTarget : public quisp::modules::Application {
explicit AppTestTarget(TestQNode *parent_qnode) : Application(), toRouterGate(new TestGate(this, "toRouter")) {
this->provider.setStrategy(std::make_unique<Strategy>(parent_qnode));
setComponentType(new TestModuleType("test qnode"));
setParStr(this, "app_py_path", "app.py");
setParStr(this, "app_py_path", "app");
}
virtual ~AppTestTarget() { EVCB.gateDeleted(toRouterGate); }
std::vector<int> getOtherEndNodeAdresses() { return this->other_end_node_addresses; }
Expand Down
7 changes: 6 additions & 1 deletion quisp/modules/Backend/Backend.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@

namespace quisp::modules::backend {

BackendContainer::BackendContainer() : interpreter(pybind11::scoped_interpreter{}) {}
BackendContainer::BackendContainer()
#ifdef ENABLE_PYTHON
: interpreter(pybind11::scoped_interpreter{})
#endif
{
}

BackendContainer::~BackendContainer() {}

Expand Down
8 changes: 8 additions & 0 deletions quisp/modules/Backend/Backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <pybind11/embed.h>
#include <memory>
#include "RNG.h"
#include "feature_defines.h"

namespace quisp::modules::backend {
using quisp::modules::common::ErrorTrackingBackend;
Expand All @@ -16,6 +17,10 @@ class BackendContainer : public omnetpp::cSimpleModule {
~BackendContainer();

void initialize() override {
#ifdef ENABLE_PYTHON
python_enabled = true;
#endif
WATCH(python_enabled);
auto backend_type = std::string(par("backendType").stringValue());
if (backend_type == "ErrorTrackingBackend") {
backend = std::make_unique<ErrorTrackingBackend>(std::make_unique<RNG>(this));
Expand All @@ -36,7 +41,10 @@ class BackendContainer : public omnetpp::cSimpleModule {
protected:
void configureErrorTrackingBackend();
std::unique_ptr<IQuantumBackend> backend = nullptr;
bool python_enabled = false;
#ifdef ENABLE_PYTHON
pybind11::scoped_interpreter interpreter;
#endif
};

Define_Module(BackendContainer);
Expand Down
5 changes: 4 additions & 1 deletion quisp/modules/Backend/Backend_test.cc
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "Backend.h"
#include <Python.h>
#include <gtest/gtest.h>
#include <test_utils/TestUtils.h>
#include "modules/common_types.h"
Expand Down Expand Up @@ -29,6 +30,7 @@ TEST(BackendContainer, callInitialize) {
}

TEST(BackendContainer, callInitializeWithInvalidBackend) {
Py_Finalize();
auto *sim = utils::prepareSimulation();
BackendContainer *backend = new BackendContainer();
sim->registerComponent(backend);
Expand All @@ -37,7 +39,8 @@ TEST(BackendContainer, callInitializeWithInvalidBackend) {
EXPECT_THROW(backend->callInitialize(), omnetpp::cRuntimeError);
}

TEST(BackendContainer, getQuantumBackend) {
TEST(BackendConpainer, getQuantumBackend) {
Py_Finalize();
auto *sim = utils::prepareSimulation();
BackendContainer *backend = new BackendContainer();
sim->registerComponent(backend);
Expand Down
50 changes: 50 additions & 0 deletions quisp/modules/Common/PythonEmbeddedable.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#include "PythonEmbeddedable.h"
#include <omnetpp.h>
#include <pybind11/detail/common.h>
#include <pybind11/embed.h>
#include <pybind11/operators.h>
#include <pybind11/pybind11.h>
#include <filesystem>
#include <memory>
#include "feature_defines.h"

namespace py = pybind11;
namespace opp = omnetpp;
namespace fs = std::filesystem;
namespace quisp::modules::python_embeddable {

#ifdef ENABLE_PYTHON
PYBIND11_EMBEDDED_MODULE(opp, m) {
py::class_<opp::cPar, std::unique_ptr<opp::cPar, py::nodelete>> OppPar(m, "Par");
OppPar.def("str", &omnetpp::cPar::str);
OppPar.def("int", &omnetpp::cPar::intValue);

py::class_<opp::cSimpleModule, std::unique_ptr<opp::cSimpleModule, py::nodelete>> OppSimpleModule(m, "SimpleModule");
OppSimpleModule.def("par", py::overload_cast<const char*>(&opp::cSimpleModule::par), py::return_value_policy::reference);
OppSimpleModule.def("schedule_at", &opp::cSimpleModule::scheduleAt);
m.def("sim_time", &opp::simTime, py::return_value_policy::reference);

py::class_<opp::SimTime> OppSimTime(m, "SimTime");
OppSimTime.def(py::self + float());
OppSimTime.def(py::self += float());
OppSimTime.def(float() + py::self);

py::class_<opp::cMessage, std::unique_ptr<opp::cMessage, py::nodelete>> OppCMessage(m, "Message");
}
#endif

void PythonEmbeddable::compile_code(const char* file_name) {
auto* env = omnetpp::getEnvir();
auto* config = env->getConfigEx();
fs::path exe_path(env->getArgVector()[0]);
fs::path conf_path(env->resolveResourcePath(config->getFileName()));
py::module sys = py::module::import("sys");
py::cast<py::list>(sys.attr("path")).append(fs::absolute(exe_path.parent_path()).string());
py::cast<py::list>(sys.attr("path")).append(fs::absolute(conf_path.parent_path()).string());
py::print(sys.attr("path"));
module = pybind11::module_::import(file_name);
}

void PythonEmbeddable::execute_python(const char* func_name, py::object& arg1) { py::object ret = module.attr(func_name)(arg1); }

} // namespace quisp::modules::python_embeddable
33 changes: 6 additions & 27 deletions quisp/modules/Common/PythonEmbeddedable.h
Original file line number Diff line number Diff line change
@@ -1,37 +1,16 @@
#pragma once
#include <Python.h>
#include <cstdio>
#include <fstream>
#include <iostream>
#include <string>
#include "pybind11/pybind11.h"
#include <pybind11/pybind11.h>

namespace quisp::modules::python_embeddable {
namespace py = pybind11;

class PythonEmbeddable {
public:
PythonEmbeddable() {}
~PythonEmbeddable() {}
void compile_code(const char* file_name) {
FILE* file = std::fopen(file_name, "rt");
if (file == NULL) {
std::cout << file_name << " not found" << std::endl;
return;
}
std::fseek(file, 0L, SEEK_END);
auto length = std::ftell(file);
std::rewind(file);
char* source = (char*)malloc(length + 1);
std::fread(source, sizeof(char), length, file);
fclose(file);
source[length] = '\0';
std::cout << source << std::endl;
code_object = Py_CompileString(source, file_name, Py_file_input);
globals = pybind11::globals().ptr();
}

void execute_python() { PyEval_EvalCode(code_object, globals, pybind11::dict().ptr()); }
void compile_code(const char* file_name);
void execute_python(const char* func_name, py::object& arg1);

PyObject* globals;
PyObject* code_object = nullptr;
pybind11::module_ module;
};
} // namespace quisp::modules::python_embeddable
31 changes: 28 additions & 3 deletions quisp/test_utils/Configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,19 @@

#include <omnetpp.h>
#include "KeyValue.h"
#include "omnetpp/cconfiguration.h"

namespace quisp_test {
namespace configuration {

using key_value::TestKeyValue;

class Configuration : public omnetpp::cConfiguration {
class Configuration : public omnetpp::cConfigurationEx {
private:
std::vector<TestKeyValue> kvs;

public:
Configuration() {
Configuration() : omnetpp::cConfigurationEx() {
kvs = std::vector<TestKeyValue>();
auto kv = TestKeyValue{};
kvs.push_back(kv);
Expand All @@ -23,7 +24,31 @@ class Configuration : public omnetpp::cConfiguration {
virtual const char *getPerObjectConfigValue(const char *objectFullPath, const char *keySuffix) const override { return nullptr; };
virtual const KeyValue &getPerObjectConfigEntry(const char *objectFullPath, const char *keySuffix) const override { return kvs.at(0); };
virtual const char *substituteVariables(const char *value) const override { return nullptr; };
virtual void initializeFrom(cConfiguration *bootConfig) override{};
virtual const char *getFileName() const override { return "test-file-name"; };
virtual void validate(const char *ignorableConfigKeys = nullptr) const override{};
virtual std::vector<std::string> getConfigNames() override { return {}; };
virtual void activateConfig(const char *configName, int runNumber = 0) override{};
virtual std::string getConfigDescription(const char *configName) const override {}
virtual std::vector<std::string> getBaseConfigs(const char *configName) const override {}
virtual std::vector<std::string> getConfigChain(const char *configName) const override {}
virtual int getNumRunsInConfig(const char *configName) const override {}
virtual std::vector<RunInfo> unrollConfig(const char *configName) const override {}
virtual const char *getActiveConfigName() const override {}
virtual int getActiveRunNumber() const override {}
virtual const char *getVariable(const char *varname) const override {}
virtual std::vector<const char *> getIterationVariableNames() const override {}
virtual std::vector<const char *> getPredefinedVariableNames() const override {}
virtual const char *getVariableDescription(const char *varname) const override {}
virtual void dump() const override {}
virtual std::vector<const char *> getMatchingConfigKeys(const char *pattern) const override {}
virtual const char *getParameterValue(const char *moduleFullPath, const char *paramName, bool hasDefaultValue) const override {}
virtual const KeyValue &getParameterEntry(const char *moduleFullPath, const char *paramName, bool hasDefaultValue) const override {}
virtual std::vector<const char *> getKeyValuePairs() const override {}
virtual std::vector<const char *> getParameterKeyValuePairs() const override {}
virtual std::vector<const char *> getMatchingPerObjectConfigKeys(const char *objectFullPath, const char *keySuffixPattern) const override {}
virtual std::vector<const char *> getMatchingPerObjectConfigKeySuffixes(const char *objectFullPath, const char *keySuffixPattern) const override {}
};

} // namespace configuration
} // namespace quisp_test
} // namespace quisp_test
Loading

0 comments on commit f57f5ba

Please sign in to comment.