Skip to content

Commit e11916c

Browse files
authored
Merge pull request #200 from sy-c/master
v2.6
2 parents 30eeed2 + b165e58 commit e11916c

File tree

4 files changed

+154
-63
lines changed

4 files changed

+154
-63
lines changed

doc/releaseNotes.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,3 +380,8 @@ This file describes the main feature changes for each readout.exe released versi
380380
## v2.5.2 - 13/09/2021
381381
- Updated configuration parameters:
382382
- equipment.TFperiod is now set to 128 by default, instead of 256 previously. This is the duration of a timeframe, in number of LHC orbits.
383+
384+
## v2.6 - 06/10/2021
385+
- Built-in memory usage reporting for o2-readout-test-fmq-memory
386+
- Added a default configuration file (/etc/o2.d/readout-defaults.cfg) to store some global settings, loaded on process startup. This is independent from the CONFIGURE time configuration file.
387+
- Process memory lock is now disabled by default (saves 2GB of unused FMQ virtual memory created for each channel).

src/ReadoutVersion.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@
99
// granted to it by virtue of its status as an Intergovernmental Organization
1010
// or submit itself to any jurisdiction.
1111

12-
#define READOUT_VERSION "2.5.2"
12+
#define READOUT_VERSION "2.6"
1313

src/mainReadout.cxx

Lines changed: 106 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ class Readout
154154
std::string cfgLogbookApiToken;
155155
int cfgLogbookUpdateInterval;
156156
std::string cfgTimeframeServerUrl;
157+
int cfgVerbose = 0;
157158

158159
// runtime entities
159160
std::vector<std::unique_ptr<Consumer>> dataConsumers;
@@ -226,6 +227,59 @@ void Readout::publishLogbookStats()
226227

227228
int Readout::init(int argc, char* argv[])
228229
{
230+
int doMemLock = 0; // when set, ensure all allocated memory is locked in ram
231+
std::string readoutExe = ""; // when set, use specified executable
232+
std::string readoutConfig = ""; // when set, use specified executable
233+
234+
// cache of logs - delay startup messages
235+
std::vector<std::pair<AliceO2::InfoLogger::InfoLogger::InfoLoggerMessageOption, std::string>> initLogs;
236+
237+
// load configuration defaults
238+
ConfigFile cfgDefaults;
239+
const std::string cfgDefaultsPath = "file:/etc/o2.d/readout-defaults.cfg"; // path to default configuration file
240+
const std::string cfgDefaultsEntryPoint = "readout"; // entry point for default configuration variables (e.g. section named [readout])
241+
try {
242+
cfgDefaults.load(cfgDefaultsPath.c_str());
243+
initLogs.push_back({LogInfoDevel, "Defaults loaded from " + cfgDefaultsPath});
244+
cfgDefaults.getOptionalValue<int>(cfgDefaultsEntryPoint + ".memLock", doMemLock, doMemLock);
245+
cfgDefaults.getOptionalValue<std::string>(cfgDefaultsEntryPoint + ".readoutExe", readoutExe, readoutExe);
246+
cfgDefaults.getOptionalValue<std::string>(cfgDefaultsEntryPoint + ".readoutConfig", readoutConfig, readoutConfig);
247+
cfgDefaults.getOptionalValue<int>(cfgDefaultsEntryPoint + ".verbose", cfgVerbose, cfgVerbose);
248+
}
249+
catch(...) {
250+
//initLogs.push_back({LogWarningSupport_(3100), std::string("Error loading defaults")});
251+
}
252+
253+
// redirect executable (if different from self!)
254+
if (readoutExe.length() && readoutExe!=argv[0]) {
255+
std::vector<char*> argv2;
256+
argv2.push_back((char *)readoutExe.c_str());
257+
if (readoutConfig.length()) {
258+
argv2.push_back((char *)readoutConfig.c_str());
259+
}
260+
for (int i=argv2.size(); i<argc; i++) {
261+
argv2.push_back(argv[i]);
262+
}
263+
printf("Launching ");
264+
for (auto const &a : argv2) {
265+
printf("%s ",a);
266+
}
267+
printf("\n");
268+
argv2.push_back(NULL);
269+
execv(readoutExe.c_str(), &argv2[0]);
270+
printf("Failed to execute : %s\n",strerror(errno));
271+
exit(1);
272+
}
273+
274+
// before anything, ensure all memory used by readout is kept in RAM
275+
if (doMemLock) {
276+
if (mlockall(MCL_CURRENT | MCL_FUTURE) == 0) {
277+
initLogs.push_back({LogInfoDevel, "Memory locked"});
278+
} else {
279+
initLogs.push_back({LogWarningSupport_(3230), "Failed to lock memory"});
280+
}
281+
}
282+
229283
if (argc < 2) {
230284
printf("Please provide path to configuration file\n");
231285
return -1;
@@ -245,49 +299,56 @@ int Readout::init(int argc, char* argv[])
245299

246300
// log startup and options
247301
theLog.log(LogInfoSupport_(3001), "Readout " READOUT_VERSION " - process starting, pid %d", getpid());
248-
theLog.log(LogInfoDevel, "Optional built features enabled:");
249-
#ifdef WITH_READOUTCARD
250-
theLog.log(LogInfoDevel, "READOUTCARD : yes");
251-
#else
252-
theLog.log(LogInfoDevel, "READOUTCARD : no");
253-
#endif
254-
#ifdef WITH_CONFIG
255-
theLog.log(LogInfoDevel, "CONFIG : yes");
256-
#else
257-
theLog.log(LogInfoDevel, "CONFIG : no");
258-
#endif
259-
#ifdef WITH_FAIRMQ
260-
theLog.log(LogInfoDevel, "FAIRMQ : yes");
261-
// redirect FMQ logs to infologger
262-
setFMQLogsToInfoLogger(&theLog);
263-
#else
264-
theLog.log(LogInfoDevel, "FAIRMQ : no");
265-
#endif
266-
#ifdef WITH_NUMA
267-
theLog.log(LogInfoDevel, "NUMA : yes");
268-
#else
269-
theLog.log(LogInfoDevel, "NUMA : no");
270-
#endif
271-
#ifdef WITH_RDMA
272-
theLog.log(LogInfoDevel, "RDMA : yes");
273-
#else
274-
theLog.log(LogInfoDevel, "RDMA : no");
275-
#endif
276-
#ifdef WITH_OCC
277-
theLog.log(LogInfoDevel, "OCC : yes");
278-
#else
279-
theLog.log(LogInfoDevel, "OCC : no");
280-
#endif
281-
#ifdef WITH_LOGBOOK
282-
theLog.log(LogInfoDevel, "LOGBOOK : yes");
283-
#else
284-
theLog.log(LogInfoDevel, "LOGBOOK : no");
285-
#endif
286-
#ifdef WITH_ZMQ
287-
theLog.log(LogInfoDevel, "ZMQ : yes");
288-
#else
289-
theLog.log(LogInfoDevel, "ZMQ : no");
290-
#endif
302+
if (cfgVerbose) {
303+
theLog.log(LogInfoDevel, "Optional built features enabled:");
304+
#ifdef WITH_READOUTCARD
305+
theLog.log(LogInfoDevel, "READOUTCARD : yes");
306+
#else
307+
theLog.log(LogInfoDevel, "READOUTCARD : no");
308+
#endif
309+
#ifdef WITH_CONFIG
310+
theLog.log(LogInfoDevel, "CONFIG : yes");
311+
#else
312+
theLog.log(LogInfoDevel, "CONFIG : no");
313+
#endif
314+
#ifdef WITH_FAIRMQ
315+
theLog.log(LogInfoDevel, "FAIRMQ : yes");
316+
// redirect FMQ logs to infologger
317+
setFMQLogsToInfoLogger(&theLog);
318+
#else
319+
theLog.log(LogInfoDevel, "FAIRMQ : no");
320+
#endif
321+
#ifdef WITH_NUMA
322+
theLog.log(LogInfoDevel, "NUMA : yes");
323+
#else
324+
theLog.log(LogInfoDevel, "NUMA : no");
325+
#endif
326+
#ifdef WITH_RDMA
327+
theLog.log(LogInfoDevel, "RDMA : yes");
328+
#else
329+
theLog.log(LogInfoDevel, "RDMA : no");
330+
#endif
331+
#ifdef WITH_OCC
332+
theLog.log(LogInfoDevel, "OCC : yes");
333+
#else
334+
theLog.log(LogInfoDevel, "OCC : no");
335+
#endif
336+
#ifdef WITH_LOGBOOK
337+
theLog.log(LogInfoDevel, "LOGBOOK : yes");
338+
#else
339+
theLog.log(LogInfoDevel, "LOGBOOK : no");
340+
#endif
341+
#ifdef WITH_ZMQ
342+
theLog.log(LogInfoDevel, "ZMQ : yes");
343+
#else
344+
theLog.log(LogInfoDevel, "ZMQ : no");
345+
#endif
346+
}
347+
348+
// report cached logs
349+
for(auto const &l : initLogs) {
350+
theLog.log(l.first, "%s", l.second.c_str());
351+
}
291352

292353
return 0;
293354
}
@@ -1250,12 +1311,8 @@ class ReadoutOCCStateMachine : public RuntimeControlledObject
12501311
// the main program loop
12511312
int main(int argc, char* argv[])
12521313
{
1253-
// before anything, ensure all memory used by readout is kept in RAM
1254-
bool memLockSuccess = false;
1255-
if (mlockall(MCL_CURRENT | MCL_FUTURE) == 0) {
1256-
memLockSuccess = true;
1257-
}
1258-
1314+
//printf("Starting %s - %d\n",argv[0], (int)getpid());
1315+
12591316
// check environment settings
12601317

12611318
// OCC control port. If set, use OCClib to handle Readout states.
@@ -1285,11 +1342,6 @@ int main(int argc, char* argv[])
12851342
return err;
12861343
}
12871344

1288-
// report memlock status
1289-
if (!memLockSuccess) {
1290-
theLog.log(LogWarningSupport_(3230), "Failed to lock readout memory");
1291-
}
1292-
12931345
if (occMode) {
12941346
#ifdef WITH_OCC
12951347
theLog.log(LogInfoDevel, "Readout entering OCC state machine");

src/testFmqMemory.cxx

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,41 @@
1414
#include <string.h>
1515
#include <chrono>
1616
#include <sys/types.h>
17+
#include <sys/mman.h>
18+
#include <unistd.h>
1719

1820
#include <fairmq/FairMQDevice.h>
1921
#include <fairmq/FairMQTransportFactory.h>
2022
//#include <fairmq/tools/Unique.h>
2123

24+
void logMemoryUsage() {
25+
double memPageSize = getpagesize() / (1024.0*1024.0);
26+
const int maxpath = 256;
27+
char fn[maxpath];
28+
snprintf(fn, maxpath, "/proc/%d/statm", getpid());
29+
FILE *fp=fopen(fn,"r");
30+
const int maxline = 256;
31+
char buf[maxline];
32+
if (fgets(buf, maxline, fp) != NULL) {
33+
int vsize, vresident, vshared, vtext, vlib, vdata, vdt;
34+
if (sscanf(buf, "%d %d %d %d %d %d %d", &vsize, &vresident, &vshared, &vtext, &vlib, &vdata, &vdt) == 7) {
35+
printf("Memory stats: size = %6.2f MB\tresident = %6.2f MB\tshared = %6.2f MB\n", vsize * memPageSize, vresident * memPageSize, vshared * memPageSize);
36+
}
37+
}
38+
fclose(fp);
39+
}
40+
41+
2242
#define GB *1073741824LLU
2343
#define SLEEPTIME 3
24-
#define WAITHERE printf("Waiting %ds ",SLEEPTIME); for(int k=0; k<SLEEPTIME; k++) {printf(".");fflush(stdout);usleep(1000000);} printf("\n");
44+
//#define WAITHERE printf("Waiting %ds ",SLEEPTIME); for(int k=0; k<SLEEPTIME; k++) {printf(".");fflush(stdout);usleep(1000000);} printf("\n");
45+
#define WAITHERE logMemoryUsage();
46+
47+
48+
// memory settings
49+
const bool memlock = false; // lock the whole process memory
50+
const bool fmqMemLock = true; // lock FMQ region
51+
const bool fmqMemZero = false; // zero FMQ region
2552

2653

2754
int main(int argc, const char* argv[]) {
@@ -34,7 +61,14 @@ int main(int argc, const char* argv[]) {
3461
return -1;
3562
}
3663

37-
printf("Startup %d\n",(int)getpid());
64+
printf("Locking process memory: %s\n", memlock ? "yes" : "no");
65+
if (memlock) {
66+
if (mlockall(MCL_CURRENT | MCL_FUTURE) != 0) {
67+
printf("failed to lock memory\n");
68+
}
69+
}
70+
71+
printf("Startup pid %d\n",(int)getpid());
3872
WAITHERE;
3973

4074
std::unique_ptr<FairMQChannel> sendingChannel;
@@ -48,13 +82,13 @@ int main(int argc, const char* argv[]) {
4882
sendingChannel = std::make_unique<FairMQChannel>("readout-test", "pair", transportFactory);
4983
WAITHERE;
5084

51-
printf("Get unmanaged memory\n");
85+
printf("Get unmanaged memory (lock=%s, zero=%s)\n", fmqMemLock ? "yes" : "no", fmqMemZero ? "yes" : "no");
5286
long long mMemorySize = ngb GB;
5387
auto t00 = std::chrono::steady_clock::now();
5488
try {
5589
// memoryBuffer = sendingChannel->Transport()->CreateUnmanagedRegion(mMemorySize, [](void* /*data*/, size_t /*size*/, void* /*hint*/) {});
5690
memoryBuffer = sendingChannel->Transport()->CreateUnmanagedRegion(mMemorySize, [](void* /*data*/, size_t /*size*/, void* /*hint*/) {},
57-
"",0,fair::mq::RegionConfig{true, false}); // lock / zero
91+
"",0,fair::mq::RegionConfig{fmqMemLock, fmqMemZero}); // lock / zero
5892
}
5993
catch(...) {
6094
printf("Failed to get buffer (exception)\n"); return 1;
@@ -66,6 +100,7 @@ int main(int argc, const char* argv[]) {
66100
WAITHERE;
67101

68102
printf("Write to memory, by chunks of 1GB\n");
103+
t00 = std::chrono::steady_clock::now();
69104
for (unsigned int i=0; i<ngb; i++) {
70105
auto t0 = std::chrono::steady_clock::now();
71106
char *ptr=(char *)memoryBuffer->GetData();
@@ -82,11 +117,10 @@ int main(int argc, const char* argv[]) {
82117
std::chrono::duration<double> tdiff = std::chrono::steady_clock::now() - t0;
83118
printf(" %.2lf GB/s\n", 1.0/tdiff.count());
84119
}
120+
std::chrono::duration<double> tdiff1 = std::chrono::steady_clock::now() - t00;
85121
printf("Done writing\n");
86-
87-
tdiff0 = std::chrono::steady_clock::now() - t00;
88-
printf("Average: %.2lf GB/s (including alloc)\n", ngb * 1.0/(tdiff0.count()-SLEEPTIME));
89-
122+
printf("Average: %.2lf GB/s (writing)\n", ngb * 1.0/tdiff1.count());
123+
printf("Average: %.2lf GB/s (writing + malloc)\n", ngb * 1.0/(tdiff0.count() + tdiff1.count()));
90124
WAITHERE;
91125

92126
printf("Cleanup FMQ unmanaged region\n");

0 commit comments

Comments
 (0)