implement multi-threaded stage1 analysis using an internal nng pipeline
This commit is contained in:
parent
4dcaf2ee47
commit
24542b4a6d
5 changed files with 263 additions and 174 deletions
|
@ -221,6 +221,26 @@ class ManaSinkPerfProxy: public IManaSink
|
||||||
Perf perf_;
|
Perf perf_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline std::string to_string(const ManaSinkPerfProxy::Perf &perf)
|
||||||
|
{
|
||||||
|
auto totalBytes = std::accumulate(std::begin(perf.eventBytes), std::end(perf.eventBytes),
|
||||||
|
static_cast<size_t>(0));
|
||||||
|
auto totalHits = std::accumulate(std::begin(perf.eventHits), std::end(perf.eventHits),
|
||||||
|
static_cast<size_t>(0));
|
||||||
|
double elapsed_ms =
|
||||||
|
std::chrono::duration_cast<std::chrono::milliseconds>(perf.t_endRun - perf.t_beginRun)
|
||||||
|
.count();
|
||||||
|
double elapsed_s = elapsed_ms / 1000.0;
|
||||||
|
|
||||||
|
double MiB = totalBytes / (1024.0 * 1024);
|
||||||
|
double MiB_s = MiB / elapsed_s;
|
||||||
|
double hit_s = totalHits / elapsed_s;
|
||||||
|
|
||||||
|
return fmt::format("events={}, bytes={:.2f} MiB, elapsed={:.2f} s, "
|
||||||
|
"event_rate={:.2f} event/s, data_rate={:.2f} MiB/s",
|
||||||
|
totalHits, MiB, elapsed_s, hit_s, MiB_s);
|
||||||
|
}
|
||||||
|
|
||||||
// wraps a mana_api.h mana_sink_plugin_t instance
|
// wraps a mana_api.h mana_sink_plugin_t instance
|
||||||
struct ManaCSink: public IManaSink
|
struct ManaCSink: public IManaSink
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,9 +2,9 @@
|
||||||
#define CF5E5AFF_F218_4A25_95DF_8097D7C5685B
|
#define CF5E5AFF_F218_4A25_95DF_8097D7C5685B
|
||||||
|
|
||||||
#include "mana_api.hpp"
|
#include "mana_api.hpp"
|
||||||
|
#include "mnode_spdlog.hpp"
|
||||||
#include <mesytec-mnode/mnode_cpp_types.h>
|
#include <mesytec-mnode/mnode_cpp_types.h>
|
||||||
#include <mesytec-mnode/mnode_nng.h>
|
#include <mesytec-mnode/mnode_nng.h>
|
||||||
#include <spdlog/spdlog.h>
|
|
||||||
|
|
||||||
namespace mesytec::mnode::mana
|
namespace mesytec::mnode::mana
|
||||||
{
|
{
|
||||||
|
@ -15,8 +15,8 @@ struct MessageHeader
|
||||||
{
|
{
|
||||||
Invalid = 0,
|
Invalid = 0,
|
||||||
BeginRun = 42,
|
BeginRun = 42,
|
||||||
EndRun,
|
EndRun = 43,
|
||||||
EventData,
|
EventData = 44,
|
||||||
};
|
};
|
||||||
|
|
||||||
u32 messageType;
|
u32 messageType;
|
||||||
|
@ -37,6 +37,7 @@ class NngServerSink: public IManaSink
|
||||||
explicit NngServerSink(nng_socket socket)
|
explicit NngServerSink(nng_socket socket)
|
||||||
: socket_(socket)
|
: socket_(socket)
|
||||||
, msg_(nng::make_unique_msg())
|
, msg_(nng::make_unique_msg())
|
||||||
|
, logger_(get_spdlog_logger("mana::NngServerSink"))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,7 +58,8 @@ class NngServerSink: public IManaSink
|
||||||
nng_msg_append(msg.get(), &header, sizeof(header));
|
nng_msg_append(msg.get(), &header, sizeof(header));
|
||||||
nng_msg_append(msg.get(), descriptor_json, len + 1);
|
nng_msg_append(msg.get(), descriptor_json, len + 1);
|
||||||
|
|
||||||
spdlog::info("Sending BeginRun message (size={})", nng_msg_len(msg.get()));
|
logger_->info("Sending BeginRun message (size={})", nng_msg_len(msg.get()));
|
||||||
|
|
||||||
int res = 0;
|
int res = 0;
|
||||||
|
|
||||||
do
|
do
|
||||||
|
@ -66,14 +68,14 @@ class NngServerSink: public IManaSink
|
||||||
{
|
{
|
||||||
if (res != NNG_ETIMEDOUT)
|
if (res != NNG_ETIMEDOUT)
|
||||||
{
|
{
|
||||||
nng::mnode_nng_error("nng_sendmsg", res);
|
logger_->error("Error sending BeginRun message: {}", nng_strerror(res));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (res == NNG_ETIMEDOUT);
|
while (res == NNG_ETIMEDOUT);
|
||||||
|
|
||||||
spdlog::info("Waiting for response from client");
|
logger_->debug("Waiting for response from client");
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
|
@ -81,12 +83,13 @@ class NngServerSink: public IManaSink
|
||||||
|
|
||||||
if (res && res != NNG_ETIMEDOUT)
|
if (res && res != NNG_ETIMEDOUT)
|
||||||
{
|
{
|
||||||
nng::mnode_nng_error("nng_recvmsg", res);
|
logger_->error("Error receiving response from client: {}", nng_strerror(res));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (!res)
|
else if (!res)
|
||||||
{
|
{
|
||||||
spdlog::info("begin_run: Received response from client");
|
logger_->info("Received response to BeginRun from client (size={})",
|
||||||
|
nng_msg_len(msg.get()));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -106,7 +109,7 @@ class NngServerSink: public IManaSink
|
||||||
MessageHeader header{MessageHeader::EndRun};
|
MessageHeader header{MessageHeader::EndRun};
|
||||||
nng_msg_append(msg.get(), &header, sizeof(header));
|
nng_msg_append(msg.get(), &header, sizeof(header));
|
||||||
nng_msg_append(msg.get(), descriptor_json, len + 1);
|
nng_msg_append(msg.get(), descriptor_json, len + 1);
|
||||||
spdlog::info("Sending EndRun message (size={})", nng_msg_len(msg.get()));
|
logger_->info("Sending EndRun message (size={})", nng_msg_len(msg.get()));
|
||||||
int res = 0;
|
int res = 0;
|
||||||
|
|
||||||
do
|
do
|
||||||
|
@ -115,12 +118,14 @@ class NngServerSink: public IManaSink
|
||||||
{
|
{
|
||||||
if (res != NNG_ETIMEDOUT)
|
if (res != NNG_ETIMEDOUT)
|
||||||
{
|
{
|
||||||
nng::mnode_nng_error("nng_sendmsg", res);
|
logger_->error("Error sending EndRun message: {}", nng_strerror(res));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (res == NNG_ETIMEDOUT);
|
while (res == NNG_ETIMEDOUT);
|
||||||
|
|
||||||
|
logger_->info("Sent EndRun message");
|
||||||
}
|
}
|
||||||
|
|
||||||
void process_event(uint16_t eventIndex, mana_offset_array_t *arrays, size_t arrayCount,
|
void process_event(uint16_t eventIndex, mana_offset_array_t *arrays, size_t arrayCount,
|
||||||
|
@ -174,7 +179,7 @@ class NngServerSink: public IManaSink
|
||||||
if (!msg_)
|
if (!msg_)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
spdlog::debug("Sending EventData message of size {}", nng_msg_len(msg_.get()));
|
logger_->trace("Sending EventData message of size {}", nng_msg_len(msg_.get()));
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
|
@ -182,7 +187,7 @@ class NngServerSink: public IManaSink
|
||||||
{
|
{
|
||||||
if (res != NNG_ETIMEDOUT)
|
if (res != NNG_ETIMEDOUT)
|
||||||
{
|
{
|
||||||
nng::mnode_nng_error("nng_sendmsg", res);
|
logger_->error("Error sending EventData message: {}", nng_strerror(res));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -196,8 +201,156 @@ class NngServerSink: public IManaSink
|
||||||
static constexpr size_t InitialMessageReserve = 2 * 1024 * 1024;
|
static constexpr size_t InitialMessageReserve = 2 * 1024 * 1024;
|
||||||
nng_socket socket_;
|
nng_socket socket_;
|
||||||
nng::unique_msg msg_;
|
nng::unique_msg msg_;
|
||||||
|
std::shared_ptr<spdlog::logger> logger_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline void nng_client_run(nng_socket socket_, mana::IManaSink *sink, std::atomic<bool> &quit)
|
||||||
|
{
|
||||||
|
auto receive_message = [socket_, &quit]()
|
||||||
|
{
|
||||||
|
auto rp = [&quit](int res) { return !quit && res == NNG_ETIMEDOUT; };
|
||||||
|
return nng::receive_message_retry(socket_, 0, rp);
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class State
|
||||||
|
{
|
||||||
|
BeginRun,
|
||||||
|
Run,
|
||||||
|
};
|
||||||
|
|
||||||
|
auto logger = get_spdlog_logger("mana::nng_client");
|
||||||
|
|
||||||
|
auto process_event_data = [&logger](nng_msg *msg, mana::IManaSink *sink)
|
||||||
|
{
|
||||||
|
while (nng_msg_len(msg) >= sizeof(mana::EventDataHeader))
|
||||||
|
{
|
||||||
|
auto header = nng::msg_trim_read<mana::EventDataHeader>(msg);
|
||||||
|
assert(header);
|
||||||
|
|
||||||
|
if (nng_msg_len(msg) < header->sizeBytes)
|
||||||
|
{
|
||||||
|
logger->error("Error reading event data: expected {} bytes, got {}",
|
||||||
|
header->sizeBytes, nng_msg_len(msg));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto arrays = reinterpret_cast<mana_offset_array_t *>(nng_msg_body(msg));
|
||||||
|
sink->process_event(header->eventIndex, arrays, header->arrayCount, header->sizeBytes);
|
||||||
|
nng_msg_trim(msg, header->sizeBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
return nng_msg_len(msg) == 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto state = State::BeginRun;
|
||||||
|
|
||||||
|
while (!quit)
|
||||||
|
{
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case State::BeginRun:
|
||||||
|
{
|
||||||
|
logger->info("Waiting for BeginRun from server");
|
||||||
|
|
||||||
|
auto [msg, res] = receive_message();
|
||||||
|
|
||||||
|
if (res)
|
||||||
|
{
|
||||||
|
logger->error("Error receiving BeginRun message: {}", nng_strerror(res));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t msgSize = nng_msg_len(msg.get());
|
||||||
|
logger->info("State::BeginRun: Received message of size {}", msgSize);
|
||||||
|
|
||||||
|
auto header = nng::msg_trim_read<mana::MessageHeader>(msg.get());
|
||||||
|
|
||||||
|
if (!header)
|
||||||
|
{
|
||||||
|
logger->error("Error reading message header");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger->info("State::BeginRun: messageType={}", static_cast<int>(header->messageType));
|
||||||
|
|
||||||
|
if (header->messageType == mana::MessageHeader::BeginRun)
|
||||||
|
{
|
||||||
|
logger->info("Received BeginRun message (size={})", msgSize);
|
||||||
|
std::string descriptor_json;
|
||||||
|
std::copy(reinterpret_cast<const char *>(nng_msg_body(msg.get())),
|
||||||
|
reinterpret_cast<const char *>(nng_msg_body(msg.get())) + msgSize,
|
||||||
|
std::back_inserter(descriptor_json));
|
||||||
|
|
||||||
|
sink->begin_run(descriptor_json.c_str());
|
||||||
|
|
||||||
|
if (auto res = nng::send_empty_message(socket_))
|
||||||
|
{
|
||||||
|
logger->error("Error sending response to BeginRun message: {}",
|
||||||
|
nng_strerror(res));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
logger->info("Receiving Data...");
|
||||||
|
state = State::Run;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logger->error("Error reading BeginRun header: messageType={}",
|
||||||
|
static_cast<int>(header->messageType));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case State::Run:
|
||||||
|
{
|
||||||
|
auto [msg, res] = receive_message();
|
||||||
|
|
||||||
|
if (res)
|
||||||
|
{
|
||||||
|
logger->error("State::Run: Error receiving message: {}", nng_strerror(res));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t msgSize = nng_msg_len(msg.get());
|
||||||
|
logger->trace("State::Run: Received message of size {}", msgSize);
|
||||||
|
|
||||||
|
auto header = nng::msg_trim_read<mana::MessageHeader>(msg.get());
|
||||||
|
|
||||||
|
if (!header)
|
||||||
|
{
|
||||||
|
logger->error("State::Run: Error reading message header, message too short");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger->trace("State::Run: received message: messageType={}",
|
||||||
|
static_cast<int>(header->messageType));
|
||||||
|
|
||||||
|
if (header->messageType == mana::MessageHeader::EndRun)
|
||||||
|
{
|
||||||
|
logger->info("State::Run: Received EndRun message");
|
||||||
|
std::string descriptor_json;
|
||||||
|
std::copy(reinterpret_cast<const char *>(nng_msg_body(msg.get())),
|
||||||
|
reinterpret_cast<const char *>(nng_msg_body(msg.get())) + msgSize,
|
||||||
|
std::back_inserter(descriptor_json));
|
||||||
|
sink->end_run(descriptor_json.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (header->messageType == mana::MessageHeader::EventData)
|
||||||
|
{
|
||||||
|
if (!process_event_data(msg.get(), sink))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logger->error("State::Run: Received unknown message type: {}",
|
||||||
|
static_cast<int>(header->messageType));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace mesytec::mnode::mana
|
} // namespace mesytec::mnode::mana
|
||||||
|
|
||||||
#endif /* CF5E5AFF_F218_4A25_95DF_8097D7C5685B */
|
#endif /* CF5E5AFF_F218_4A25_95DF_8097D7C5685B */
|
||||||
|
|
|
@ -126,6 +126,8 @@ inline std::string histo_info(const std::vector<std::vector<TH1 *>> &histos)
|
||||||
|
|
||||||
MANA_DEFINE_PLUGIN_BEGIN_RUN(begin_run)
|
MANA_DEFINE_PLUGIN_BEGIN_RUN(begin_run)
|
||||||
{
|
{
|
||||||
|
assert(context);
|
||||||
|
assert(context == g_ctx);
|
||||||
log_debug("begin_run: context=%p, descriptor_json=%s", context, descriptor_json);
|
log_debug("begin_run: context=%p, descriptor_json=%s", context, descriptor_json);
|
||||||
auto jRun = nlohmann::json::parse(descriptor_json);
|
auto jRun = nlohmann::json::parse(descriptor_json);
|
||||||
std::filesystem::path rp(jRun["name"].get<std::string>());
|
std::filesystem::path rp(jRun["name"].get<std::string>());
|
||||||
|
@ -142,6 +144,8 @@ MANA_DEFINE_PLUGIN_BEGIN_RUN(begin_run)
|
||||||
|
|
||||||
MANA_DEFINE_PLUGIN_END_RUN(end_run)
|
MANA_DEFINE_PLUGIN_END_RUN(end_run)
|
||||||
{
|
{
|
||||||
|
assert(context);
|
||||||
|
assert(context == g_ctx);
|
||||||
log_debug("end: context=%p, descriptor_json=%s", context, descriptor_json);
|
log_debug("end: context=%p, descriptor_json=%s", context, descriptor_json);
|
||||||
auto ctx = reinterpret_cast<Context *>(context);
|
auto ctx = reinterpret_cast<Context *>(context);
|
||||||
ctx->outputFile->Write();
|
ctx->outputFile->Write();
|
||||||
|
@ -150,6 +154,8 @@ MANA_DEFINE_PLUGIN_END_RUN(end_run)
|
||||||
|
|
||||||
MANA_DEFINE_PLUGIN_EVENT_DATA(process_event)
|
MANA_DEFINE_PLUGIN_EVENT_DATA(process_event)
|
||||||
{
|
{
|
||||||
|
assert(context);
|
||||||
|
assert(context == g_ctx);
|
||||||
log_trace("event: ctx=%p, eventIndex=%d, arrayCount=%zu, totalBytes=%zu", context, eventIndex,
|
log_trace("event: ctx=%p, eventIndex=%d, arrayCount=%zu, totalBytes=%zu", context, eventIndex,
|
||||||
arrayCount, totalBytes);
|
arrayCount, totalBytes);
|
||||||
auto ctx = reinterpret_cast<Context *>(context);
|
auto ctx = reinterpret_cast<Context *>(context);
|
||||||
|
|
|
@ -47,6 +47,7 @@
|
||||||
#include "internal/mana_analysis.h"
|
#include "internal/mana_analysis.h"
|
||||||
#include "internal/mana_arena.h"
|
#include "internal/mana_arena.h"
|
||||||
#include "internal/mana_lib.hpp"
|
#include "internal/mana_lib.hpp"
|
||||||
|
#include "internal/mana_nng.hpp"
|
||||||
|
|
||||||
CMRC_DECLARE(mnode::resources);
|
CMRC_DECLARE(mnode::resources);
|
||||||
|
|
||||||
|
@ -377,10 +378,16 @@ void usage(const char *self)
|
||||||
std::cout << fmt::format(
|
std::cout << fmt::format(
|
||||||
"usage: {} [--plugin=<plugin.so>] [--replay-strategy=<name>] <zipfile>\n", self);
|
"usage: {} [--plugin=<plugin.so>] [--replay-strategy=<name>] <zipfile>\n", self);
|
||||||
std::cout
|
std::cout
|
||||||
|
|
||||||
<< " --plugin=<plugin.so> Load a plugin to process the data. Default is a "
|
<< " --plugin=<plugin.so> Load a plugin to process the data. Default is a "
|
||||||
"simple counting plugin.\n"
|
"simple counting plugin.\n"
|
||||||
|
|
||||||
<< " --replay-strategy=<name> Use a specific replay strategy. "
|
<< " --replay-strategy=<name> Use a specific replay strategy. "
|
||||||
"Available: 'single-threaded', 'multi-threaded'. Default: 'multi-threaded'\n"
|
"Available: 'single-threaded', 'multi-threaded'. Default: 'multi-threaded'\n"
|
||||||
|
|
||||||
|
<< " --analysis-strategy=<name> Use a specific analysis strategy. "
|
||||||
|
"Available: 'single-threaded', 'multi-threaded'. Default: 'multi-threaded'\n"
|
||||||
|
|
||||||
<< " --log-level=<level> One of 'trace', 'debug', 'info', 'warn', 'error', "
|
<< " --log-level=<level> One of 'trace', 'debug', 'info', 'warn', 'error', "
|
||||||
"'off'.\n";
|
"'off'.\n";
|
||||||
}
|
}
|
||||||
|
@ -391,7 +398,8 @@ int main(int argc, char *argv[])
|
||||||
const auto jModuleDataSources = nlohmann::json::parse(f.begin(), f.end());
|
const auto jModuleDataSources = nlohmann::json::parse(f.begin(), f.end());
|
||||||
|
|
||||||
argh::parser parser(
|
argh::parser parser(
|
||||||
{"-h", "--help", "--plugin", "--replay-strategy", "--no-buffering ", "--log-level"});
|
{"-h", "--help", "--plugin", "--replay-strategy", "--analysis-strategy", "--log-level"});
|
||||||
|
|
||||||
parser.parse(argc, argv);
|
parser.parse(argc, argv);
|
||||||
|
|
||||||
auto filename = parser[1];
|
auto filename = parser[1];
|
||||||
|
@ -460,8 +468,6 @@ int main(int argc, char *argv[])
|
||||||
destSink = std::make_unique<mana::ManaCountingSink>();
|
destSink = std::make_unique<mana::ManaCountingSink>();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto manaSink = std::make_unique<mana::ManaSinkPerfProxy>(destSink.get());
|
|
||||||
|
|
||||||
std::string strategyName = "multi-threaded";
|
std::string strategyName = "multi-threaded";
|
||||||
|
|
||||||
if (parser("--replay-strategy"))
|
if (parser("--replay-strategy"))
|
||||||
|
@ -507,42 +513,75 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
// make the analysis instance available to the parser callbacks
|
// make the analysis instance available to the parser callbacks
|
||||||
parserContext->parser.userContext = &mana;
|
parserContext->parser.userContext = &mana;
|
||||||
|
auto perfSink = std::make_unique<mana::ManaSinkPerfProxy>(destSink.get());
|
||||||
|
mana.sink = perfSink.get();
|
||||||
|
|
||||||
auto run_replay = [&]
|
auto run_replay = [&]
|
||||||
{
|
{
|
||||||
manaSink->init(0, nullptr);
|
mana.sink->init(0, nullptr);
|
||||||
manaSink->begin_run(mana.runDescriptor.dump().c_str());
|
mana.sink->begin_run(mana.runDescriptor.dump().c_str());
|
||||||
|
|
||||||
replayStrategy->run(*listfileContext, *parserContext);
|
replayStrategy->run(*listfileContext, *parserContext);
|
||||||
|
|
||||||
manaSink->end_run(mana.runDescriptor.dump().c_str());
|
mana.sink->end_run(mana.runDescriptor.dump().c_str());
|
||||||
manaSink->shutdown();
|
mana.sink->shutdown();
|
||||||
};
|
};
|
||||||
|
|
||||||
// if (parser["--no-buffering"])
|
strategyName = "multi-threaded";
|
||||||
|
|
||||||
|
if (parser("--analysis-strategy"))
|
||||||
|
strategyName = parser("--analysis-strategy").str();
|
||||||
|
|
||||||
|
if (strategyName == "single-threaded")
|
||||||
{
|
{
|
||||||
mana.sink = manaSink.get();
|
// replay strategy handles threading of the file io.
|
||||||
|
// the target mana.sink is called in the main thread.
|
||||||
run_replay();
|
run_replay();
|
||||||
}
|
}
|
||||||
|
else if (strategyName == "multi-threaded")
|
||||||
auto perf = manaSink->perf();
|
|
||||||
{
|
{
|
||||||
auto totalBytes = std::accumulate(std::begin(perf.eventBytes), std::end(perf.eventBytes),
|
// Create a NngServerSink and use it as the destination sink of the parsing stage.
|
||||||
static_cast<size_t>(0));
|
// In the main thread run a mana nng client, reading from the server
|
||||||
auto totalHits = std::accumulate(std::begin(perf.eventHits), std::end(perf.eventHits),
|
// socket, feeding the destination sink.
|
||||||
static_cast<size_t>(0));
|
static const char *url = "inproc://mana_analysis_stage1";
|
||||||
double elapsed_ms =
|
nng_socket serverSocket = nng::make_pair_socket();
|
||||||
std::chrono::duration_cast<std::chrono::milliseconds>(perf.t_endRun - perf.t_beginRun)
|
if (int res = nng_listen(serverSocket, url, nullptr, 0))
|
||||||
.count();
|
{
|
||||||
double elapsed_s = elapsed_ms / 1000.0;
|
spdlog::error("Error listening on '{}': {}", url, nng_strerror(res));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
nng_socket clientSocket = nng::make_pair_socket();
|
||||||
|
if (int res = nng_dial(clientSocket, url, nullptr, 0))
|
||||||
|
{
|
||||||
|
spdlog::error("Error connecting to '{}': {}", url, nng_strerror(res));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
// create the server sink and set it as the destination sink for the module data stage
|
||||||
|
auto serverSink = std::make_unique<mana::NngServerSink>(serverSocket);
|
||||||
|
auto serverPerfSink = std::make_unique<mana::ManaSinkPerfProxy>(serverSink.get());
|
||||||
|
auto destSink = mana.sink;
|
||||||
|
mana.sink = serverPerfSink.get();
|
||||||
|
|
||||||
double MiB = totalBytes / (1024.0 * 1024);
|
std::thread replayThread(run_replay);
|
||||||
double MiB_s = MiB / elapsed_s;
|
// FIXME: this is useless when running the client loop blocking like this
|
||||||
double hit_s = totalHits / elapsed_s;
|
std::atomic<bool> clientQuit = false;
|
||||||
|
destSink->init(0, nullptr);
|
||||||
|
mana::nng_client_run(clientSocket, destSink, clientQuit);
|
||||||
|
destSink->shutdown();
|
||||||
|
if (replayThread.joinable())
|
||||||
|
replayThread.join();
|
||||||
|
fmt::print("Internal NngServerSink: {}\n", to_string(serverPerfSink->perf()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::cerr << fmt::format("Error: unknown analysis strategy '{}'\n", strategyName);
|
||||||
|
usage(argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
fmt::print("Data Sink Performance: events={}, bytes={:.2f} MiB, elapsed={:.2f} s, "
|
if (auto perfProxy = dynamic_cast<mana::ManaSinkPerfProxy *>(perfSink.get()))
|
||||||
"event_rate={:.2f} event/s, data_rate={:.2f} MiB/s\n",
|
{
|
||||||
totalHits, MiB, elapsed_s, hit_s, MiB_s);
|
fmt::print("Destination Sink: {}\n", to_string(perfProxy->perf()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -15,151 +15,17 @@ void usage(const char *self)
|
||||||
{
|
{
|
||||||
std::cout << fmt::format("usage: {} [--plugin=<plugin.so>] <url>\n", self);
|
std::cout << fmt::format("usage: {} [--plugin=<plugin.so>] <url>\n", self);
|
||||||
std::cout
|
std::cout
|
||||||
|
|
||||||
<< " --plugin=<plugin.so> Load a plugin to process the data. Default is a "
|
<< " --plugin=<plugin.so> Load a plugin to process the data. Default is a "
|
||||||
"simple counting plugin.\n"
|
"simple counting plugin.\n"
|
||||||
<< " --processing-strategy=<name> Use a specific processing strategy. "
|
|
||||||
"Available: 'single-threaded', 'nng-pair'. Default: 'nng-pair'\n"
|
|
||||||
<< " --log-level=<level> One of 'trace', 'debug', 'info', 'warn', 'error', "
|
<< " --log-level=<level> One of 'trace', 'debug', 'info', 'warn', 'error', "
|
||||||
"'off'.\n";
|
"'off'.\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
bool process_event_data(nng_msg *msg, mana::IManaSink *sink)
|
|
||||||
{
|
|
||||||
while (nng_msg_len(msg) >= sizeof(mana::EventDataHeader))
|
|
||||||
{
|
|
||||||
auto header = nng::msg_trim_read<mana::EventDataHeader>(msg);
|
|
||||||
assert(header);
|
|
||||||
|
|
||||||
if (nng_msg_len(msg) < header->sizeBytes)
|
|
||||||
{
|
|
||||||
spdlog::error("Error reading event data: expected {} bytes, got {}", header->sizeBytes,
|
|
||||||
nng_msg_len(msg));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto arrays = reinterpret_cast<mana_offset_array_t *>(nng_msg_body(msg));
|
|
||||||
sink->process_event(header->eventIndex, arrays, header->arrayCount, header->sizeBytes);
|
|
||||||
nng_msg_trim(msg, header->sizeBytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
return nng_msg_len(msg) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void run(nng_socket socket_, mana::IManaSink *sink, std::atomic<bool> &quit)
|
void run(nng_socket socket_, mana::IManaSink *sink, std::atomic<bool> &quit)
|
||||||
{
|
{
|
||||||
auto receive_message = [socket_, &quit]()
|
mana::nng_client_run(socket_, sink, quit);
|
||||||
{
|
|
||||||
auto rp = [&quit](int res) { return !quit && res == NNG_ETIMEDOUT; };
|
|
||||||
return nng::receive_message_retry(socket_, 0, rp);
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class State
|
|
||||||
{
|
|
||||||
BeginRun,
|
|
||||||
Run,
|
|
||||||
};
|
|
||||||
|
|
||||||
auto state = State::BeginRun;
|
|
||||||
|
|
||||||
while (!quit)
|
|
||||||
{
|
|
||||||
switch (state)
|
|
||||||
{
|
|
||||||
case State::BeginRun:
|
|
||||||
{
|
|
||||||
spdlog::info("Waiting for BeginRun from server");
|
|
||||||
|
|
||||||
auto [msg, res] = receive_message();
|
|
||||||
|
|
||||||
if (res)
|
|
||||||
{
|
|
||||||
nng::mnode_nng_error("nng_recvmsg", res);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const size_t msgSize = nng_msg_len(msg.get());
|
|
||||||
spdlog::info("State::BeginRun: Received message of size {}", msgSize);
|
|
||||||
|
|
||||||
auto header = nng::msg_trim_read<mana::MessageHeader>(msg.get());
|
|
||||||
|
|
||||||
if (!header)
|
|
||||||
{
|
|
||||||
spdlog::error("Error reading message header");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
spdlog::info("State::BeginRun: messageType={}", static_cast<int>(header->messageType));
|
|
||||||
|
|
||||||
if (header->messageType == mana::MessageHeader::BeginRun)
|
|
||||||
{
|
|
||||||
spdlog::info("Received BeginRun message (size={})", msgSize);
|
|
||||||
std::string descriptor_json;
|
|
||||||
std::copy(reinterpret_cast<const char *>(nng_msg_body(msg.get())),
|
|
||||||
reinterpret_cast<const char *>(nng_msg_body(msg.get())) + msgSize,
|
|
||||||
std::back_inserter(descriptor_json));
|
|
||||||
sink->begin_run(descriptor_json.c_str());
|
|
||||||
if (auto res = nng::send_empty_message(socket_))
|
|
||||||
{
|
|
||||||
nng::mnode_nng_error("nng_sendmsg", res);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
spdlog::info("Receiving Data");
|
|
||||||
state = State::Run;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
spdlog::error("Error reading BeginRun header");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case State::Run:
|
|
||||||
{
|
|
||||||
auto [msg, res] = receive_message();
|
|
||||||
|
|
||||||
if (res)
|
|
||||||
{
|
|
||||||
nng::mnode_nng_error("nng_recvmsg", res);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const size_t msgSize = nng_msg_len(msg.get());
|
|
||||||
spdlog::debug("State::Run: Received message of size {}", msgSize);
|
|
||||||
|
|
||||||
auto header = nng::msg_trim_read<mana::MessageHeader>(msg.get());
|
|
||||||
|
|
||||||
if (!header)
|
|
||||||
{
|
|
||||||
spdlog::error("Error reading message header");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
spdlog::debug("State::Run: messageType={}", static_cast<int>(header->messageType));
|
|
||||||
|
|
||||||
if (header->messageType == mana::MessageHeader::EndRun)
|
|
||||||
{
|
|
||||||
spdlog::info("Received EndRun message");
|
|
||||||
std::string descriptor_json;
|
|
||||||
std::copy(reinterpret_cast<const char *>(nng_msg_body(msg.get())),
|
|
||||||
reinterpret_cast<const char *>(nng_msg_body(msg.get())) + msgSize,
|
|
||||||
std::back_inserter(descriptor_json));
|
|
||||||
sink->end_run(descriptor_json.c_str());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (header->messageType == mana::MessageHeader::EventData)
|
|
||||||
{
|
|
||||||
if (!process_event_data(msg.get(), sink))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
spdlog::error("Unknown message type: {}", static_cast<int>(header->messageType));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
|
@ -177,6 +43,11 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
spdlog::set_level(spdlog::level::info);
|
spdlog::set_level(spdlog::level::info);
|
||||||
|
|
||||||
|
if (parser("--log-level"))
|
||||||
|
{
|
||||||
|
spdlog::set_level(spdlog::level::from_str(parser("--log-level").str()));
|
||||||
|
}
|
||||||
|
|
||||||
boost::dll::shared_library pluginHandle;
|
boost::dll::shared_library pluginHandle;
|
||||||
std::unique_ptr<mana::IManaPlugin> manaCppPlugin;
|
std::unique_ptr<mana::IManaPlugin> manaCppPlugin;
|
||||||
std::unique_ptr<mana::IManaSink> destSink;
|
std::unique_ptr<mana::IManaSink> destSink;
|
||||||
|
|
Loading…
Reference in a new issue