...
 
Commits (1)
......@@ -214,7 +214,7 @@ endif ()
if (NOT WIN32)
# cl.exe has a different set of flags
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -Wall -Werror -Wno-unused-variable -Wno-unused-function -Wextra -Wno-unused-parameter")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -Wall -Wno-unused-variable -Wno-unused-function -Wextra -Wno-unused-parameter")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0 -DDEBUG")
FIND_PACKAGE(MPI REQUIRED)
......
......@@ -53,7 +53,7 @@ void fatal(const char* fmt, ...) __attribute__ ((__noreturn__));
#endif
#ifdef DEBUG
void debug(const char* fmt, ...);
#define debug(fmt, ...) do{}while(0)
#else
//use do{}while(0) construct to consume the semicolon the user puts after debug();
#define debug(fmt, ...) do{}while(0)
......
......@@ -37,6 +37,10 @@ namespace fmitcp {
fmi2_status_t getDirectionalDerivatives(
const fmitcp_proto::fmi2_import_get_directional_derivative_req& r,
fmitcp_proto::fmi2_import_get_directional_derivative_res& response);
//this gets reserve()d appropriately as we go along
vector<char> responseBuffer;
protected:
string m_fmuPath;
......@@ -80,9 +84,15 @@ namespace fmitcp {
/// To be implemented in subclass
virtual void onError(string message){};
#define CLIENTDATA_NEW //{121.8M, 59.7M} -> {130M, 47.9M} ...
#ifndef CLIENTDATA_NEW
//returns reply as std::string
//if the string is empty then there was some kind of problem
std::string clientData(const char *data, size_t size);
#else
//if the char vector is empty then there was some kind of problem
const vector<char>& clientData(const char *data, size_t size);
#endif
/// Set to true to start ignoring the local FMU and just send back dummy responses. Good for debugging the protocol.
void sendDummyResponses(bool);
......
......@@ -33,6 +33,26 @@ namespace fmitcp {
oss << szStr << s;
}
static void packIntoCharVector(std::vector<char>& vec, const std::string& s) {
size_t sz = s.size();
if (sz > 0xFFFFFFFF) {
fprintf(stderr, "sz = %lu\n", sz);
exit(1);
}
vec.reserve(vec.size() + 4 + s.length());
//size of packet, including type
char szStr[4];
szStr[0] = (uint8_t)sz;
szStr[1] = (uint8_t)(sz>>8);
szStr[2] = (uint8_t)(sz>>16);
szStr[3] = (uint8_t)(sz>>24);
vec.insert(vec.end(), szStr, &szStr[4]);
vec.insert(vec.end(), s.c_str(), s.c_str() + s.length());
}
static size_t parseSize(const char *data, size_t size) {
if (size < 4) {
fprintf(stderr, "parseSize(): not enough data\n");
......
......@@ -51,7 +51,7 @@ void warning(const char*fmt,...){
}
#ifdef DEBUG
void debug(const char*fmt,...){
/*void debug(const char*fmt,...){
if (fmigo_loglevel >= ::jm_log_level_debug) {
va_list argptr;
va_start(argptr, fmt);
......@@ -60,7 +60,7 @@ void debug(const char*fmt,...){
fprintf(stderr,ANSI_COLOR_RESET);
va_end(argptr);
}
}
}*/
#endif
namespace common {
......
......@@ -329,6 +329,7 @@ fmi2_status_t Server::getDirectionalDerivatives(
return status;
}
#ifndef CLIENTDATA_NEW
string Server::clientData(const char *data, size_t size) {
//split up packets
//each one starts with a 4-byte length
......@@ -355,6 +356,34 @@ string Server::clientData(const char *data, size_t size) {
return oss.str();
}
#else
const vector<char>& Server::clientData(const char *data, size_t size) {
//split up packets
//each one starts with a 4-byte length
responseBuffer.resize(0);
while (size > 0) {
//size of packet, including type
size_t packetSize = fmitcp::serialize::parseSize(data, size);
data += 4;
size -= 4;
if (packetSize > size) {
fatal("packetSize > size\n");
}
string s = clientDataInner(data, packetSize);
fmitcp::serialize::packIntoCharVector(responseBuffer, s);
data += packetSize;
size -= packetSize;
}
return responseBuffer;
}
#endif
string Server::clientDataInner(const char *data, size_t size) {
std::pair<fmitcp_proto::fmitcp_message_Type,std::string> ret;
......@@ -1130,21 +1159,36 @@ string Server::clientDataInner(const char *data, size_t size) {
break; } case fmitcp_proto::type_fmi2_import_do_step_req: {
// Unpack message
fmitcp_proto::fmi2_import_do_step_req r; r.ParseFromArray(data, size);
bool newStep = r.newstep();
debug("fmi2_import_do_step_req(commPoint=%g,stepSize=%g,newStep=%d)\n",r.currentcommunicationpoint(),r.communicationstepsize(),newStep?1:0);
/*#if sizeof(double) != 8
#error sizeof(double) != 8
#endif
#if sizeof(bool) != 1
#error sizeof(bool) != 1
#endif*/
if (size != 2*sizeof(double) + sizeof(bool)) {
fatal("wrong size for type_fmi2_import_do_step_req - interfacing 32-bit and 64-bit machines?\n");
}
double *ddata = (double*)data;
bool *bdata = (bool*)&ddata[2];
double currentcommunicationpoint = ddata[0];
double communicationstepsize = ddata[1];
bool newStep = bdata[0];
debug("fmi2_import_do_step_req(commPoint=%g,stepSize=%g,newStep=%d)\n", currentcommunicationpoint, communicationstepsize, newStep?1:0);
if (newStep) {
//keep track of what the next communication point will be
//this may not work correctly if multiple steps with newStep=false are taken
//fmigo never does this, so this works
//a better solution would be to tie these two values to the current FMUstate
this->currentCommunicationPoint = r.currentcommunicationpoint() + r.communicationstepsize();
this->currentCommunicationPoint = currentcommunicationpoint + communicationstepsize;
}
//this step size is really just a guess - it could be variable
//but it should be good enough for computeNumericalDirectionalDerivative()
this->communicationStepSize = r.communicationstepsize();
this->communicationStepSize = communicationstepsize;
if (hdf5Filename.length()) {
//log outputs before doing anything
......@@ -1156,7 +1200,7 @@ string Server::clientDataInner(const char *data, size_t size) {
fmi2_status_t status = fmi2_status_ok;
if (!m_sendDummyResponses) {
// Step the FMU
status = fmi2_import_do_step(m_fmi2Instance, r.currentcommunicationpoint(), r.communicationstepsize(), newStep);
status = fmi2_import_do_step(m_fmi2Instance, currentcommunicationpoint, communicationstepsize, newStep);
if (newStep) {
m_timer.rotate("do_step");
} else {
......
......@@ -69,12 +69,16 @@ FMU_VOID_REQ_IMPL(fmi2_import_cancel_step)
std::string fmitcp::serialize::fmi2_import_do_step(double currentCommunicationPoint,
double communicationStepSize,
bool newStep){
fmi2_import_do_step_req req;
req.set_currentcommunicationpoint(currentCommunicationPoint);
req.set_communicationstepsize(communicationStepSize);
req.set_newstep(newStep);
return pack(type_fmi2_import_do_step_req, req);
std::string str(2 + 2*sizeof(double)+sizeof(bool), 0);
str[0] = type_fmi2_import_do_step_req;
str[1] = type_fmi2_import_do_step_req >> 8;
double *d = (double*)&str[2];
d[0] = currentCommunicationPoint;
d[1] = communicationStepSize;
bool *b = (bool*)&d[2];
b[0] = newStep;
return str;
}
std::string fmitcp::serialize::fmi2_import_get_status(fmitcp_proto::fmi2_status_kind_t s){
......
......@@ -726,12 +726,21 @@ static void run_server(string fmuPath, string hdf5Filename) {
}
//let Server handle packet, send reply back to master
#ifndef CLIENTDATA_NEW
std::string str = server.clientData(recv_str.c_str(), recv_str.length());
if (str.length() > 0) {
server.m_timer.rotate("pre_send");
MPI_Send((void*)str.c_str(), str.length(), MPI_CHAR, rank, tag, MPI_COMM_WORLD);
server.m_timer.rotate("send");
}
#else
const vector<char>& str = server.clientData(recv_str.c_str(), recv_str.length());
if (str.size() > 0) {
server.m_timer.rotate("pre_send");
MPI_Send((void*)&str[0], str.size(), MPI_CHAR, rank, tag, MPI_COMM_WORLD);
server.m_timer.rotate("send");
}
#endif
}
MPI_Finalize();
......@@ -752,6 +761,13 @@ int main(int argc, char *argv[] ) {
fmigo::globals::timer.dont_rotate = true;
FILE *outfile = stdout;
//check endianness
int e = 1;
if (*(char*)&e != 1) {
//workaround: use protobuf for get_real/set_real/do_step
fatal("Big-endian machines not supported\n");
}
#ifdef USE_MPI
MPI_Init(NULL, NULL);
......
......@@ -47,6 +47,7 @@ static void handleMessage(zmq::socket_t& socket, FMIServer& server, int port) {
fatal("Port %i: !socket.recv(&msg)\n", port);
}
server.m_timer.rotate("recv");
#ifndef CLIENTDATA_NEW
string str = server.clientData(static_cast<char*>(msg.data()), msg.size());
if (str.length() > 0) {
......@@ -56,6 +57,17 @@ static void handleMessage(zmq::socket_t& socket, FMIServer& server, int port) {
socket.send(rep, ZMQ_DONTWAIT);
server.m_timer.rotate("send");
}
#else
const vector<char>& str = server.clientData(static_cast<char*>(msg.data()), msg.size());
if (str.size() > 0) {
zmq::message_t rep(str.size());
memcpy(rep.data(), &str[0], str.size());
server.m_timer.rotate("pre_send");
socket.send(rep, ZMQ_DONTWAIT);
server.m_timer.rotate("send");
}
#endif
}
int main(int argc, char *argv[]) {
......
set -e
pushd ../../../..
source boilerplate.sh
popd
# Designed not to oversubscribe on 8-core machine (ThinkPad W540)
N=7
FMU=${FMUS_DIR}/gsl/clutch/clutch.fmu
FMUS=
CONNS=
for i in $(seq 0 $(python <<< "print($N - 1)"))
do
for j in $(seq 0 $(python <<< "print($N - 1)"))
do
CONNS="$CONNS -c $i,x_e,$j,x_in_e -c $i,v_e,$j,v_in_e -c $i,a_e,$j,force_in_e -c $i,force_e,$j,force_in_ex"
CONNS="$CONNS -c $i,x_s,$j,x_in_s -c $i,v_s,$j,v_in_s -c $i,a_s,$j,force_in_s -c $i,force_s,$j,force_in_sx"
done
FMUS="$FMUS $FMU"
done
#echo $CONNS
#echo $FMUS
echo $(python <<< "print($N * $N * 8)") connections
for method in jacobi #gs
do
#echo ---------------------
#echo "MPI, method=$method"
#time mpiexec -np $(python <<< "print($N + 1)") fmigo-mpi -m $method -t 10 -d 0.0005 -a - $FMUS <<< "$CONNS"|sha1sum
URIS=
for j in $(seq 1 $N)
do
PORT=$(python <<< "print(1023 + $j)")
if [ $j -eq 1 ]
then
valgrind --tool=callgrind --callgrind-out-file=fmigo-server.callgrind fmigo-server -p $PORT $EXTRA -l 4 $FMU &
else
fmigo-server -p $PORT $EXTRA $FMU &
fi
URIS="$URIS tcp://localhost:$PORT"
done
#echo ---------------------
echo "ZMQ, method=$method"
time valgrind --tool=callgrind --callgrind-out-file=fmigo-master.callgrind fmigo-master -l 4 -m $method -t 1 -d 0.0005 -f none -a - $URIS <<< "$CONNS"
done