libadc-cxx 1.0.0
Structured logging for scientific computing
Loading...
Searching...
No Matches
builder.ipp
Go to the documentation of this file.
1#include <pwd.h>
2#include <unistd.h>
3#include <time.h>
4#include <sys/time.h>
5#include <sys/utsname.h>
6#include <sstream>
7#include <fstream>
8#include <array>
9#include <ostream>
10#include <utility>
11#include <string>
12#include <cstdio>
13#include <boost/algorithm/string.hpp>
14#include <uuid/uuid.h>
15
18
19/* implementation note:
20 * do not use language features beyond c++17.
21 */
22
23namespace adc {
24
25
26
27std::string tolower_s(std::string s)
28{
29 std::transform(s.begin(), s.end(), s.begin(),
30 [](unsigned char c){ return std::tolower(c); }
31 );
32 return s;
33}
34
35std::string get_exe(size_t bufsize)
36{
37 ssize_t ret;
38 auto buffer = std::make_unique<char[]>(bufsize);
39 ret = readlink("/proc/self/exe", buffer.get(), bufsize - 1);
40 if (ret < 0)
41 sprintf(buffer.get(),"(nullexe)");
42 else
43 buffer.get()[ret] = '\0';
44 return buffer.get();
45}
46
47// std date and formatters are still unstable; use c.
48// fixme strftime isn't 8601 tz format compliant (no xx:yy) adc::format_timespec_8601
49// fixme consider using nanoseconds instead of milli. adc::format_timespec_8601
50std::string format_timespec_8601(struct timespec& ts)
51{
52 struct tm tm;
53 char prefix[40] = "YYYY-MM-ddTHH:mm:ss";
54 char suffix[40] = "0000 ";
55 char millis[20];
56 localtime_r(&ts.tv_sec, &tm);
57 sprintf(millis, "%03ld", ts.tv_nsec / 1000000);
58 strftime(prefix, sizeof(prefix), "%Y-%m-%dT%H:%M:%S.", &tm);
59 strftime(suffix, sizeof(suffix), "%z", &tm);
60 std::string buf = std::string(prefix) + std::string(millis) + std::string(suffix);
61 return buf;
62
63}
64
65std::string format_timespec_utc_ns(struct timespec& ts)
66{
67 char str[40];
68 snprintf(str, sizeof(str), "%ld.%09ld",(long)ts.tv_sec, (long)ts.tv_nsec);
69 return std::string(str);
70}
71
72std::string get_lscpu(){
73 pipe_data lscpu = out_pipe::run("lscpu -J");
74 if (lscpu.rc) {
75 return "{}";
76 }
77 return lscpu.output;
78}
79
80#define CPUINFO_FILE "/proc/cpuinfo"
82{
83 static std::string affinity_all;
84 if (affinity_all.size() < 2) {
85 std::ifstream in(CPUINFO_FILE);
86 std::string line;
87 uint32_t pmax = 0;
88 while (std::getline(in, line)) {
89 size_t cp = line.find(' ');
90 std::string name = line.substr(0, cp);
91 if (name == "processor") {
92 cp = line.find(':');
93 std::istringstream iss(line.substr(cp+1));
94 uint32_t val;
95 iss >> val;
96 if (iss.fail()) {
97 return 0;
98 } else {
99 pmax = (val > pmax ? val : pmax);
100 }
101 }
102 }
103 if (pmax == 0) {
104 affinity_all = "0-1024";
105 } else {
106 std::ostringstream oss;
107 oss << "0-" << pmax;
108 affinity_all = oss.str();
109 }
110 }
111 return affinity_all;
112}
113
114
115std::vector< std::string> get_libs(std::string_view )
116{
117 pid_t pid = getpid();
118 std::ostringstream cmd;
119 cmd << "/usr/bin/grep r-xp /proc/" << pid << "/maps | /usr/bin/grep '\\.so' | /usr/bin/sed -e 's%.* /%/%g'";
120 pipe_data proclibs = out_pipe::run(cmd.str());
121 std::vector< std::string> libs;
122 if (proclibs.rc) {
123 return libs;
124 }
125 std::istringstream nss(proclibs.output);
126 std::string line;
127 while (std::getline(nss, line)) {
128 libs.push_back(line);
129 }
130 return libs;
131}
132
133boost::json::object get_numa_hardware()
134{
135 static bool shell_done;
136 static boost::json::object numa_json;
137 if (!shell_done) {
138 shell_done = 1;
139 pipe_data numactl = out_pipe::run("numactl -H");
140 size_t numa_node_count = 0;
141 if (! numactl.rc) {
142 std::vector<std::string> cpulist;
143 std::vector<int64_t> sizes;
144 std::vector<std::string> numa_node;
145 shell_done = 1;
146 adc::pipe_data numactl = adc::out_pipe::run("numactl -H");
147 std::string line;
148 std::istringstream nss(numactl.output);
149 while (std::getline(nss, line)) {
150 size_t cp = line.find(':');
151 std::string name = line.substr(0, cp);
152 if (name == "available") {
153 std::istringstream iss(line.substr(cp+1));
154 iss >> numa_node_count;
155 continue;
156 }
157 if (name.substr(name.length()-4) == "cpus" ) {
158 cpulist.push_back(line.substr(cp+2));
159 continue;
160 }
161 if (name.substr(name.length()-4) == "size" ) {
162 std::istringstream iss(line.substr(cp+1));
163 int64_t mb;
164 iss >> mb;
165 sizes.push_back(mb);
166 continue;
167 }
168 if (name.substr(name.length()-4) == "nces" )
169 break; // stop on "node distances:"
170 }
171 if (! numa_node_count || sizes.size() != numa_node_count || cpulist.size() != numa_node_count)
172 return numa_json; // inconsistent data
173#if 0 // FLAT lists
174 numa_json["numa_node_count"] = numa_node_count;
175 numa_json["numa_cpu_list"] = boost::json::value_from(cpulist);
176 numa_json["numa_node_megabyte"] = boost::json::value_from(sizes);
177#endif
178 boost::json::array na;
179 for (size_t i = 0; i < numa_node_count; i++) {
180 boost::json::object o = {
181 {"node_number", i},
182 {"node_megabytes", sizes[i]},
183 {"cpu_list", cpulist[i]}
184 };
185 na.emplace_back(o);
186 }
187 numa_json["node_list"] = na;
188 }
189 }
190 return numa_json;
191}
192
193boost::json::object get_gpu_data()
194{
195 static bool shell_done;
196 static boost::json::object gpu_json;
197 if (!shell_done) {
198#ifdef ADC_GPU_DEBUG
199 std::cerr << "add_host_section: doing gpu" <<std::endl;
200#endif
201 size_t gpu_count = 0;
202 shell_done = 1;
203 pipe_data lspci = out_pipe::run("lspci -vmm |grep -B1 -A 6 -i '3d controller'");
204 if (! lspci.rc) {
205#ifdef ADC_GPU_DEBUG
206 std::cerr << "add_host_section: parsing gpu" <<std::endl;
207#endif
208 std::vector<std::string> vendor;
209 std::vector<std::string> device;
210 std::vector<std::string> rev;
211 std::vector<int32_t> numa_node;
212 shell_done = 1;
213 std::string line;
214 std::istringstream nss(lspci.output);
215 while (std::getline(nss, line)) {
216 if (line.substr(0,1) == "-")
217 continue;
218 size_t cp = line.find(':');
219 std::string name = line.substr(0, cp);
220 if (name == "Class") {
221 std::string cname = boost::algorithm::trim_copy(line.substr(cp+1));
222 if (cname == "3D controller") {
223 // std::cerr << "add_host_section: found gpu " << gpu_count <<std::endl;
224 gpu_count++;
225 } else {
226 // std::cerr << "add_host_section: found non-gpu " << cname <<std::endl;
227 }
228 continue;
229 }
230 if (name == "Vendor" ) {
231 vendor.push_back(boost::algorithm::trim_copy(line.substr(cp+1)));
232 continue;
233 }
234 if (name == "Device" ) {
235 device.push_back(boost::algorithm::trim_copy(line.substr(cp+1)));
236 continue;
237 }
238 if (name == "Rev" ) {
239 rev.push_back(boost::algorithm::trim_copy(line.substr(cp+1)));
240 continue;
241 }
242 if (name == "NUMANode" ) {
243 std::istringstream iss(line.substr(cp+1));
244 int32_t nn;
245 iss >> nn;
246 numa_node.push_back(nn);
247 continue;
248 }
249 }
250 if (vendor.size() != gpu_count ||
251 device.size() != gpu_count ||
252 rev.size() != gpu_count ||
253 numa_node.size() != gpu_count) {
254 std::cerr << "add_host_section: size mismatch " <<
255 gpu_count <<
256 vendor.size() <<
257 device.size() <<
258 rev.size() <<
259 numa_node.size() <<
260 std::endl;
261 return gpu_json; // inconsistent data
262 }
263 gpu_json["gpu_count"] = gpu_count;
264 boost::json::array ga;
265 for (size_t i = 0; i < gpu_count; i++) {
266 boost::json::object o = {
267 {"gpu_number", i},
268 {"numa_node", numa_node[i]},
269 {"vendor", vendor[i]},
270 {"device", device[i]},
271 {"rev", rev[i]}
272 };
273 ga.emplace_back(o);
274 }
275 gpu_json["gpulist"] = ga;
276 }
277#ifdef ADC_GPU_DEBUG
278 else {
279 std::cerr << "add_host_section: lspci fail " << lspci.rc <<std::endl;
280 }
281#endif
282 }
283 return gpu_json;
284}
285
286#define MEMINFO_FILE "/proc/meminfo"
287
288struct item {
289 std::string name;
290 uint64_t value;
291};
292
293// data read from MEMINFO_FILE or computed therewith
294// direct read fields are not documented.
295static std::map<std::string, uint64_t> midata = {
296 {"MemTotal", 0 },
297 {"MemUsed", 0 }, // total - free
298 {"MemFree", 0 },
299 {"Shmem", 0 },
300 {"SReclaimable", 0 },
301 {"Buffers", 0 },
302 {"Cached", 0 },
303 {"CachedAll", 0 }, // Cached + SReclaimable,
304 {"MemAvailable", 0 },
305 {"SwapTotal", 0 },
306 {"SwapUsed", 0 }, // SwapTotal - SwapFree
307 {"SwapFree", 0},
308 {"valid", 0} // is the full map populated
309};
310
311// the number of undocumented members of midata (those read directly)
312const size_t meminfo_raw = 9;
313
314// get MemTotal off top of /proc/meminfo
315uint64_t get_memtotal()
316{
317 std::ifstream in(MEMINFO_FILE);
318 std::string line;
319 while (std::getline(in, line)) {
320 size_t cp = line.find(':');
321 std::string name = line.substr(0, cp);
322 if (name == "MemTotal") {
323 std::istringstream iss(line.substr(cp+1));
324 uint64_t val;
325 iss >> val;
326 if (iss.fail()) {
327 return 0;
328 } else {
329 return val;
330 }
331 }
332 }
333 return 0;
334}
335
336// on return, midata["valid"] is 1 if successful or 0 if a problem reading all
337// expected values.
338// produce data equivalent to free -k -w
340{
341 std::ifstream in(MEMINFO_FILE);
342
343 std::string line;
344 size_t count = 0;
345 while (std::getline(in, line)) {
346 size_t cp = line.find(':');
347 std::string name = line.substr(0, cp);
348 auto it = midata.find(name);
349 if (it != midata.end()) {
350 std::istringstream iss(line.substr(cp+1));
351 uint64_t val;
352 iss >> val;
353 if (iss.fail()) {
354 std::cerr << "error reading value for " << it->first << std::endl;
355 continue;
356 }
357 it->second = val;
358 count++;
359#ifdef ADC_MEMINFO_DEBUG
360 std::cerr << "parsed meminfo." << name << std::endl;
361#endif
362 }
363 }
364 if (count == meminfo_raw) {
365 midata["valid"] = 1;
366 midata["MemUsed"] = midata["MemTotal"] - midata["MemFree"];
367 midata["SwapUsed"] = midata["SwapTotal"] - midata["SwapFree"];
368 midata["CachedAll"] = midata["Cached"] + midata["SReclaimable"];
369 if (midata["MemAvailable"] > midata["MemTotal"]) {
370 midata["MemAvailable"] = midata["MemFree"];
371 // work around container misreporting
372 // documented in procps utility 'free'
373 }
374 midata["valid"] = 1;
375 } else {
376 midata["valid"] = 0;
377 std::cerr << "read meminfo failed" << std::endl;
378 std::cerr << "count = " << count << std::endl;
379 std::cerr << "mdsize = " << midata.size() << std::endl;
380 }
381}
382
383builder::builder(void *mpi_communicator_p) : mpi_comm_p(mpi_communicator_p) {
384}
385
386// auto-populate the header section with application name
387void builder::add_header_section(std::string_view application_name)
388{
389 uid_t uid = geteuid();
390 struct passwd pw;
391 struct passwd *pwp = NULL;
392 int bsize = sysconf(_SC_GETPW_R_SIZE_MAX);
393 if (bsize < 0)
394 bsize = 16384;
395 char buf[bsize];
396 getpwuid_r(uid, &pw, buf, bsize, &pwp);
397 const char *uname;
398 if (pwp) {
399 uname = pw.pw_name;
400 } else {
401 uname = "<unknown_user>";
402 }
403 struct timespec ts;
404 clock_gettime(CLOCK_REALTIME, &ts);
405 std::string ts_8601 = format_timespec_8601(ts);
406 std::string ts_ns = format_timespec_utc_ns(ts);
407
408 boost::json::object vv = {
409 { "version", adc::enum_version.name}
410 };
411 vv["tags"] = boost::json::value_from(adc::enum_version.tags);
412 uuid_t uuid;
413 uuid_generate_random(uuid);
414 char uuidbuf[40];
415 uuid_unparse_lower(uuid, uuidbuf);
416 boost::json::value jv = {
417 {"adc_api_version", vv },
418 {"timestamp", ts_ns },
419 {"datestamp", ts_8601 },
420 {"user", uname },
421 {"uid", std::to_string(uid) },
422 {"application", application_name},
423 {"uuid", uuidbuf }
424 };
425 d["header"] = jv;
426}
427
428std::vector<std::string> split_string(const std::string& s, char delimiter)
429{
430 std::vector<std::string> tokens;
431 std::stringstream ss(s);
432 std::string token;
433 while (std::getline(ss, token, delimiter)) {
434 if (token.length() > 0) {
435 tokens.push_back(token);
436 }
437 }
438 return tokens;
439}
440
441std::vector<std::string> builder::get_host_env_vars()
442{
443 const char *env = getenv("ADC_HOST_SECTION_ENV");
444 if (env) {
445 return split_string(std::string(env), ':');
446 }
447 std::vector<std::string> s;
448 return s;
449}
450
451#define ADC_HS_BAD ~(ADC_HS_ALL)
452// auto-populate the host section
453void builder::add_host_section(int32_t subsections)
454{
455
456 if (ADC_HS_BAD & subsections) {
457 std::cerr << "bad arg to add_host_section: " << subsections <<std::endl;
458 return;
459 }
460 struct utsname ubuf;
461 int uerr = uname(&ubuf);
462 if (uerr < 0) {
463 std::cerr << "uname failed in add_host_section" <<std::endl;
464 return;
465 }
466 boost::json::object jv = {
467 {"name", std::string(ubuf.nodename) }
468 };
469 if ( subsections & ADC_HS_OS ) {
470 jv["os_family"] = std::string(ubuf.sysname);
471 jv["os_version"] = std::string(ubuf.release);
472 jv["os_arch"] = std::string(ubuf.machine);
473 jv["os_build"] = std::string(ubuf.version);
474 }
475 if (subsections & ADC_HS_ENV) {
476 std::vector<std::string> env_vars = get_host_env_vars();
477 for (auto it = env_vars.begin();
478 it != env_vars.end(); it++) {
479 const char *s = getenv(it->c_str());
480 if (!s)
481 s = "";
482 jv[*it] = std::string(s);
483 }
484 }
485 if (subsections & ADC_HS_RAMSIZE) {
486 if (midata["valid"] == 1) {
487 jv["mem_total"] = midata["MemTotal"];
488 } else {
490 if (midata["valid"] == 1)
491 jv["mem_total"] = midata["MemTotal"];
492 else
493 jv["mem_total"] = 0;
494 }
495 }
496 if (subsections & ADC_HS_CPU) {
497 boost::system::error_code ec;
498 std::string lscpu = get_lscpu();
499 auto cv = boost::json::parse(lscpu, ec);
500 if (ec) {
501 std::cerr << "unable to parse ("<< ec <<") lscpu output: " << lscpu << std::endl;
502 }
503 jv["cpu"] = cv;
504 }
505 if (subsections & ADC_HS_GPU) {
506 jv["gpu"] = get_gpu_data();
507 }
508 if (subsections & ADC_HS_NUMA) {
509 jv["numa_hardware"] = get_numa_hardware();
510 }
511
512 d["host"] = jv;
513}
514
515// populate application run-time data to app_data section.
516// any relationship to previous jobs/higher level workflows goes in app_data
517// somehow.
518void builder::add_app_data_section(std::shared_ptr< builder_api > app_data)
519{
520 auto app_data_derived = std::dynamic_pointer_cast<builder>(app_data);
521 d["app_data"] = app_data_derived->flatten();
522}
523
526 if (midata["valid"] == 0) {
527 boost::json::object jv;
528 d["memory_usage"] = jv;
529 return;
530 }
531
532 boost::json::value jv = {
533 {"mem_total", midata["MemTotal"]},
534 {"mem_used", midata["MemUsed"]},
535 {"mem_free", midata["MemFree"]},
536 {"mem_shared", midata["Shmem"]},
537 {"mem_buffers", midata["Buffers"]},
538 {"mem_cache", midata["CachedAll"]},
539 {"mem_available", midata["MemAvailable"]},
540 {"swap_total", midata["SwapTotal"]},
541 {"swap_used", midata["SwapUsed"]},
542 {"swap_free", midata["SwapFree"]}
543 };
544 d["memory_usage"] = jv;
545}
546
547// populate application run-time physics (re)configuration/result to model_data section.
548// e.g. changes in mesh/particle decomp go here.
549void builder::add_model_data_section(std::shared_ptr< builder_api > model_data)
550{
551 auto model_data_derived = std::dynamic_pointer_cast<builder>(model_data);
552 d["model_data"] = model_data_derived->flatten();
553}
554
555// auto-populate code section with os-derived info at time of call,
556// tag, version, and code_details blob.
557void builder::add_code_section(std::string tag, std::shared_ptr< builder_api > version, std::shared_ptr< builder_api > code_details)
558{
559 std::string fullpath = get_exe(4096);
560 const char *basename = strrchr(fullpath.c_str(), '/');
561 if (!basename)
562 basename = fullpath.c_str();
563 else
564 basename++;
565 std::vector< std::string> libs = get_libs(fullpath);
566 auto code_details_derived = std::dynamic_pointer_cast<builder>(code_details);
567 auto version_derived = std::dynamic_pointer_cast<builder>(version);
568 boost::json::value jv = {
569 {"name", tag },
570 {"program", basename},
571 {"path", fullpath},
572 {"version", version_derived->d},
573 {"libs", boost::json::value_from(libs) },
574 {"details", code_details_derived->flatten()}
575 };
576 d["code"] = jv;
577}
578
579// populate build/install configuration information like options enabled
580void builder::add_code_configuration_section(std::shared_ptr< builder_api > build_details)
581{
582 auto build_details_derived = std::dynamic_pointer_cast<builder>(build_details);
583 d["code_configuration"] = build_details_derived->flatten();
584}
585
586// populate exit_data section
587void builder::add_exit_data_section(int return_code, std::string status, std::shared_ptr< builder_api > status_details)
588{
589 auto status_details_derived = std::dynamic_pointer_cast<builder>(status_details);
590 boost::json::value jv = {
591 { "return_code", std::to_string(return_code)},
592 { "status", status},
593 { "details", status_details_derived->flatten()}
594 };
595 d["exit_data"] = jv;
596}
597
598
599void builder::add_section(std::string_view name, std::shared_ptr< builder_api > section)
600{
601
602 auto nk = kind(name);
603 if (nk == k_none) {
604 auto section_derived = std::dynamic_pointer_cast<builder>(section);
605 sections[std::string(name)] = std::move(section_derived);
606 }
607}
608
609std::shared_ptr< builder_api > builder::get_section(std::string_view name)
610{
611 auto nk = kind(name);
612 if (nk == k_section)
613 return sections[std::string(name)];
614 // should we throw here instead? probably not, for optional sections
615 return std::shared_ptr< builder_api >(NULL);
616}
617
618std::vector< std::string > builder::get_section_names()
619{
620 std::vector< std::string > result;
621 for (auto const& element : sections) {
622 result.push_back(element.first);
623 }
624 return result;
625}
626
627std::vector< std::string > builder::get_field_names()
628{
629// iterate d keys
630// can we return an interator here instead?
631 std::vector< std::string > result;
632 for (auto const& element : d) {
633 result.push_back(element.key());
634 }
635 return result;
636}
637
638static void get_scalar(field& f, scalar_type st, boost::json::value *v)
639{
640 boost::json::string *s;
641 switch (st) {
642 case cp_bool:
643 f.data = variant(*(v->if_bool()));
644 f.vp = &std::get< bool >(f.data);
645 f.count = 1;
646 return;
647 case cp_char:
648 f.data = variant(static_cast<char>(*(v->if_int64())));
649 f.vp = &std::get< char >(f.data);
650 f.count = 1;
651 return;
652 case cp_char16:
653 f.data = variant(static_cast<char16_t>(*(v->if_uint64())));
654 f.vp = &std::get< char16_t >(f.data);
655 f.count = 1;
656 return;
657 case cp_char32:
658 f.data = variant(static_cast<char32_t>(*(v->if_uint64())));
659 f.vp = &std::get< char32_t >(f.data);
660 f.count = 1;
661 return;
662 case cp_uint8:
663 f.data = variant(static_cast<uint8_t>(*(v->if_uint64())));
664 f.vp = &std::get< uint8_t >(f.data);
665 f.count = 1;
666 return;
667 case cp_uint16:
668 f.data = variant(static_cast<uint16_t>(*(v->if_uint64())));
669 f.vp = &std::get< uint16_t >(f.data);
670 f.count = 1;
671 return;
672 case cp_uint32:
673 f.data = variant(static_cast<uint32_t>(*(v->if_uint64())));
674 f.vp = &std::get< uint32_t >(f.data);
675 f.count = 1;
676 return;
677 case cp_uint64:
678 s = v->if_string();
679 if (s) {
680 uint64_t u64;
681 std::string ss(*s);
682 std::istringstream iss(ss);
683 iss >> u64;
684 f.data = variant(u64);
685 f.vp = &std::get< uint64_t >(f.data);
686 f.count = 1;
687 }
688 return;
689 case cp_int8:
690 f.data = variant(static_cast<int8_t>(*(v->if_int64())));
691 f.vp = &std::get< int8_t >(f.data);
692 f.count = 1;
693 return;
694 case cp_int16:
695 f.data = variant(static_cast<int16_t>(*(v->if_int64())));
696 f.vp = &std::get< int16_t >(f.data);
697 f.count = 1;
698 return;
699 case cp_int32:
700 f.data = variant(static_cast<int32_t>(*(v->if_int64())));
701 f.vp = &std::get< int32_t >(f.data);
702 f.count = 1;
703 return;
704 case cp_int64:
705 f.data = variant(*(v->if_int64()));
706 f.vp = &std::get< int64_t >(f.data);
707 f.count = 1;
708 return;
709 case cp_epoch:
710 f.data = variant(*(v->if_int64()));
711 f.vp = &std::get< int64_t >(f.data);
712 f.count = 1;
713 return;
714 // char *
715 // fallthrough block for all string variants
716 case cp_cstr:
717 case cp_json_str:
718 case cp_yaml_str:
719 case cp_xml_str:
720 case cp_json:
721 case cp_path:
722 case cp_number_str:
723 s = v->if_string();
724 if (s) {
725#ifdef ADC_GV_STR_DEBUG
726 std::cerr << "s c ptr " << (void*)(s->c_str()) << std::endl;
727#endif
728 std::string ss(*s);
729#ifdef ADC_GV_STR_DEBUG
730 std::cerr << "ss c ptr " << (void*)(ss.c_str()) << std::endl;
731#endif
732 //f.data = variant(ss);
733 f.data = ss;
734 //f.vp = (&std::get< std::string >(f.data))->data();
735#ifdef ADC_GV_STR_DEBUG
736 std::cerr << "f ptr " << (void*)&f.kt << std::endl;
737 std::cerr << "f.data " << (void*)&std::get< std::string >(f.data) << std::endl;
738 std::cerr << "f.data>data " << (void*)std::get< std::string >(f.data).data() << std::endl;
739#endif
740 f.vp = (&std::get< std::string >(f.data))->data();
741#ifdef ADC_GV_STR_DEBUG
742 std::cerr << "f.vp " << f.vp << std::endl;
743#endif
744 f.count = s->size();
745 }
746 return;
747 case cp_f32:
748 f.data = variant( static_cast<float>(*(v->if_double())));
749 f.vp = &std::get< float >(f.data);
750 f.count = 1;
751 return;
752 case cp_f64:
753 f.data = variant( *(v->if_double()));
754 f.vp = &std::get< double >(f.data);
755 f.count = 1;
756 return;
757#if ADC_SUPPORT_EXTENDED_FLOATS
758 case cp_f80:
759 // prec fixme cp_F80 get_value
760 return;
761#endif
762#if ADC_SUPPORT_QUAD_FLOATS
763 case cp_f128:
764 // prec fixme cp_F128 get_value
765 return;
766#endif
767#if ADC_SUPPORT_GPU_FLOATS
768 // prec fixme cp_Fx gpufloats get_value
769 case cp_f8_e4m3:
770 case cp_f8_e5m2:
771 case cp_f16_e5m10:
772 case cp_f16_e8m7:
773 return;
774#endif
775 case cp_c_f32: {
776 std::complex<float> cv(0,0);
777 if (v->is_array()) {
778 float re = 0, im = 0;
779 auto a = v->as_array();
780 if (a.size() == 2 &&
781 a[0].is_double() && a[1].is_double() ) {
782 re = static_cast<float>(a[0].as_double());
783 im = static_cast<float>(a[1].as_double());
784 cv = { re, im};
785 }
786 }
787 f.data = variant(cv) ;
788 f.vp = &std::get< std::complex<float> >(f.data);
789 f.count = 1;
790 }
791 return;
792 case cp_c_f64: {
793 std::complex<double> cv(0,0);
794 if (v->is_array()) {
795 double re = 0, im = 0;
796 auto a = v->as_array();
797 if (a.size() == 2 &&
798 a[0].is_double() &&
799 a[1].is_double() ) {
800 re = a[0].as_double();
801 im = a[1].as_double();
802 cv = { re, im};
803 }
804 }
805 f.data = variant(cv) ;
806 f.vp = &std::get< std::complex<double> >(f.data);
807 f.count = 1;
808 }
809 return;
810#if ADC_SUPPORT_EXTENDED_FLOATS
811 case cp_c_f80:
812 // prec fixme cp_c_F80 get_value
813#endif
814#if ADC_SUPPORT_QUAD_FLOATS
815 case cp_c_f128:
816 // prec fixme cp_c_F128 get_value
817#endif
818 case cp_timespec:
819 // fallthrough
820 case cp_timeval: {
821 std::array<int64_t, 2> av = {0,0};
822 if (v->is_array()) {
823 int64_t sec = 0, subsec = 0;
824 auto a = v->as_array();
825 if (a.size() == 2 &&
826 a[0].is_int64() &&
827 a[1].is_int64() ) {
828 sec = a[0].as_int64();
829 subsec = a[1].as_int64();
830 av = { sec, subsec};
831 }
832 }
833 f.data = variant(av);
834 f.vp = &std::get< std::array<int64_t,2> >(f.data);
835 f.count = 1;
836 }
837 return;
838 default:
839 return;
840 }
841}
842
843/* copy all elements of a matching type st into matching positions
844 * of a shared array. type mismatches are silently ignored, their
845 * values being converted to 0.
846 *
847 * As we are querying arrays we built, there should never be a mismatch.
848 */
849template<typename T>
850static void fill_array(field& f, scalar_type st, boost::json::array& a) {
851 auto a_len = a.size();
852 //c++20 std::shared_ptr<T[]> sa = std::make_shared<T[]>(a_len);
853 std::shared_ptr<T[]> sa(new T[a_len]);
854 size_t i;
855 auto json_type = scalar_type_representation(st);
856 for (i = 0; i < a_len; i++) {
857 if ( a[i].kind() == json_type) {
858 boost::system::error_code ec;
859 T x = a[i].to_number<T>(ec);
860 if (!ec.failed()) {
861 sa[i] = x;
862 } else {
863 sa[i] = 0;
864 }
865 } else {
866 sa[i] = 0;
867 }
868 }
869 f.data = variant( sa ) ;
870 f.vp = (std::get< std::shared_ptr<T[]> >(f.data)).get();
871 f.count = a_len;
872};
873
874static void fill_array_u64(field& f, boost::json::array& a) {
875 auto a_len = a.size();
876 //c++20 std::shared_ptr<uint64_t[]> sa = std::make_shared<uint64_t[]>(a_len);
877 std::shared_ptr<uint64_t[]> sa(new uint64_t[a_len]);
878 size_t i;
879 for (i = 0; i < a_len; i++) {
880 boost::json::string *s = a[i].if_string();
881 if ( s ) {
882 std::string ss (*s);
883 std::istringstream iss(ss);
884 uint64_t x;
885 iss >> x;
886 if (!iss.fail()) {
887 sa[i] = x;
888 } else {
889 sa[i] = 0;
890 }
891 } else {
892 sa[i] = 0;
893 }
894 }
895 f.data = variant( sa ) ;
896 f.vp = (std::get< std::shared_ptr<uint64_t[]> >(f.data)).get();
897 f.count = a_len;
898};
899
900/* copy pairs of a matching type st into matching positions
901 * of a shared array of complex. type mismatches are silently ignored, their
902 * values being converted to 0.
903 *
904 * As we are querying arrays we built, there should never be a mismatch.
905 */
906template<typename T>
907static void fill_array_complex(field& f, boost::json::array& a) {
908 auto a_len = a.size();
909 // c++20: std::shared_ptr<std::complex<T>[]> sa = std::make_shared<std::complex<T>[]>(a_len);
910 std::shared_ptr<std::complex<T>[]> sa(new std::complex<T>[a_len]);
911 size_t i;
912 for (i = 0; i < a_len; i++) {
913 if ( a[i].kind() == boost::json::kind::array) {
914 auto pair = a[i];
915 if (pair.as_array().size() != 2) {
916 sa[i] = { 0, 0 };
917 continue;
918 }
919 boost::system::error_code ecr;
920 boost::system::error_code eci;
921 T re = pair.as_array()[0].to_number<T>(ecr);
922 T im = pair.as_array()[1].to_number<T>(eci);
923 if (!(ecr.failed() || eci.failed())) {
924 sa[i] = { re, im };
925 } else {
926 sa[i] = { 0, 0 };
927 }
928 } else {
929 sa[i] = { 0, 0 };
930 }
931 }
932 f.data = variant( sa ) ;
933 f.vp = (std::get< std::shared_ptr<std::complex<T>[]> >(f.data)).get();
934 f.count = a_len;
935};
936
937/* expects a json array of boolean values. any non-boolean value is
938 * mapped to false in the output array.
939 */
940void fill_array_bool(field& f, boost::json::array& a) {
941 auto a_len = a.size();
942 //c++20 std::shared_ptr<T[]> sa = std::make_shared<T[]>(a_len);
943 std::shared_ptr<bool[]> sa(new bool[a_len]);
944 size_t i;
945 for (i = 0; i < a_len; i++) {
946 bool* bptr = a[i].if_bool();
947 if (bptr) {
948 sa[i] = *bptr;
949 } else {
950 sa[i] = false;
951 }
952 }
953 f.data = variant( sa ) ;
954 f.vp = (std::get< std::shared_ptr<bool[]> >(f.data)).get();
955 f.count = a_len;
956}
957
958void fill_array_string(field& f, boost::json::array& a) {
959 auto a_len = a.size();
960 //c++20 std::shared_ptr<T[]> sa = std::make_shared<T[]>(a_len);
961 std::shared_ptr<std::string[]> sa(new std::string[a_len]);
962 size_t i;
963 for (i = 0; i < a_len; i++) {
964 boost::json::string* sptr = a[i].if_string();
965 if (sptr) {
966 sa[i] = std::string(sptr->c_str());
967 } else {
968 sa[i] = std::string("");
969 }
970 }
971 f.data = variant( sa ) ;
972 f.vp = (std::get< std::shared_ptr<std::string[]> >(f.data)).get();
973 f.count = a_len;
974}
975
976static void get_array(field& f, scalar_type st, boost::json::value *v)
977{
978 if (!v->is_array()) {
979 return;
980 }
981
982 auto a = v->as_array();
983 switch (st) {
984 case cp_bool:
985 fill_array_bool(f, a);
986 return;
987 case cp_char:
988 fill_array<char>(f, st, a);
989 return;
990 case cp_char16:
991 fill_array<char16_t>(f, st, a);
992 return;
993 case cp_char32:
994 fill_array<char32_t>(f, st, a);
995 return;
996 case cp_uint8:
997 fill_array<uint8_t>(f, st, a);
998 return;
999 case cp_uint16:
1000 fill_array<uint16_t>(f, st, a);
1001 return;
1002 case cp_uint32:
1003 fill_array<uint32_t>(f, st, a);
1004 return;
1005 case cp_uint64:
1006 fill_array_u64(f, a);
1007 return;
1008 case cp_int8:
1009 fill_array<int8_t>(f, st, a);
1010 return;
1011 case cp_int16:
1012 fill_array<int16_t>(f, st, a);
1013 return;
1014 case cp_int32:
1015 fill_array<int32_t>(f, st, a);
1016 return;
1017 case cp_int64:
1018 fill_array<int64_t>(f, st, a);
1019 return;
1020 // fallthrough block for all string variants
1021 case cp_cstr:
1022 case cp_json_str:
1023 case cp_yaml_str:
1024 case cp_xml_str:
1025 case cp_json:
1026 case cp_path:
1027 case cp_number_str:
1028 fill_array_string(f, a);
1029 return;
1030 case cp_f32:
1031 fill_array<float>(f, st, a);
1032 return;
1033 case cp_f64:
1034 fill_array<double>(f, st, a);
1035 return;
1036#if ADC_SUPPORT_EXTENDED_FLOATS
1037 case cp_f80:
1038 // prec fixme cp_F80 get_value
1039 return;
1040#endif
1041#if ADC_SUPPORT_QUAD_FLOATS
1042 case cp_f128:
1043 // prec fixme cp_F128 get_value
1044 return;
1045#endif
1046#if ADC_SUPPORT_GPU_FLOATS
1047 // prec fixme cp_Fx gpufloats get_value
1048 case cp_f8_e4m3:
1049 case cp_f8_e5m2:
1050 case cp_f16_e5m10:
1051 case cp_f16_e8m7:
1052 return;
1053#endif
1054 case cp_c_f32:
1055 fill_array_complex<float>(f, a);
1056 return;
1057 case cp_c_f64:
1058 fill_array_complex<double>(f, a);
1059 return;
1060#if ADC_SUPPORT_EXTENDED_FLOATS
1061 case cp_c_f80:
1062 // prec fixme cp_c_F80 get_value
1063#endif
1064#if ADC_SUPPORT_QUAD_FLOATS
1065 case cp_c_f128:
1066 // prec fixme cp_c_F128 get_value
1067#endif
1068 default:
1069 return;
1070 }
1071}
1072
1073const field builder::get_value(std::string_view name)
1074{
1075 field f = { k_none, cp_none, NULL, 0, "", variant() };
1076 f.kt = kind(name);
1077 if (f.kt != k_value)
1078 return f;
1079 auto jit = d[name]; // see also at() and at_pointer()
1080 if (jit.kind() == boost::json::kind::object) {
1081 auto obj = jit.as_object();
1082 auto v = obj.if_contains("value");
1083 auto type_name_v = obj.if_contains("type");
1084 std::string type_name;
1085 if (type_name_v) {
1086 type_name = *(type_name_v->if_string());
1087 }
1088 if (v && type_name.size()) {
1089 auto c = obj.if_contains("container_type");
1090 auto st = scalar_type_from_name(type_name);
1091 if (!c) {
1092 f.st = st;
1093 get_scalar(f, st, v);
1094 return f;
1095 } else {
1096 f.st = st;
1097 f.container = *(c->if_string());
1098 get_array(f, st, v);
1099 return f;
1100 }
1101 }
1102 }
1103 if (jit.kind() == boost::json::kind::array) {
1104 // untyped json arrays in get_value make no sense
1105 return f;
1106 }
1107 if (jit.kind() == boost::json::kind::object) {
1108 // object in get_value make no sense
1109 return f;
1110 }
1111 if (jit.kind() == boost::json::kind::string) {
1112 // bare strings default to cp_cstr
1113 f.st = cp_cstr;
1114 f.vp = jit.if_string()->c_str();
1115 f.count = jit.if_string()->size();
1116 return f;
1117 }
1118 if (jit.kind() == boost::json::kind::bool_) {
1119 f.st = cp_bool;
1120 f.vp = jit.if_bool();
1121 f.count = 1;
1122 return f;
1123 }
1124 if (jit.kind() == boost::json::kind::int64) {
1125 f.st = cp_int64;
1126 f.vp = jit.if_int64();
1127 f.count = 1;
1128 return f;
1129 }
1130 if (jit.kind() == boost::json::kind::uint64) {
1131 f.st = cp_uint64;
1132 f.vp = jit.if_uint64();
1133 f.count = 1;
1134 return f;
1135 }
1136 if (jit.kind() == boost::json::kind::double_) {
1137 f.st = cp_f64;
1138 f.vp = jit.if_double();
1139 f.count = 1;
1140 return f;
1141 }
1142 return f;
1143}
1144
1145#if 0
1146// fixme implement json-path lookup of boost.json items, maybe; builder::get_boost_json_value
1147// accept paths of /a/b/c
1148// split to vector walk down sections for prefix
1149// of a, b, c
1150// assemble remaining path and call at_pointer.
1151void *builder::get_boost_json_value(std::string_view path)
1152{
1153 auto sit = sections.find(name);
1154 if (sit != sections.end())
1155 return k_section;
1156 auto jit = d.find(name);
1157 if (jit != d.end())
1158 return k_value;
1159 boost::json::value jv = d.at_pointer(path);
1160}
1161#endif
1162
1163void builder::add_mpi_section(std::string_view name, void *mpi_comm_p, adc_mpi_field_flags bitflags)
1164{
1165 if (!mpi_comm_p || bitflags == ADC_MPI_NONE)
1166 return;
1167 std::string commname = std::string("mpi_comm_") += name;
1168#ifdef ADC_HAVE_MPI
1169 if (*(MPI_Comm *)mpi_comm_p == MPI_COMM_NULL)
1170 return;
1171 MPI_Comm *comm = (MPI_Comm *)mpi_comm_p;
1172 boost::json::object jv;
1173 int err;
1174 int rank = -1;
1175 if ( bitflags & ADC_MPI_RANK) {
1176 err = MPI_Comm_rank(*comm, &rank);
1177 if (!err) {
1178 jv["mpi_rank"] = rank;
1179 }
1180 }
1181
1182 int size = -1;
1183 if ( bitflags & ADC_MPI_SIZE) {
1184 err = MPI_Comm_size(*comm, &size);
1185 if (!err) {
1186 jv["mpi_size"] = size;
1187 }
1188 }
1189
1190 if ( bitflags & ADC_MPI_NAME) {
1191 char name[MPI_MAX_OBJECT_NAME];
1192 int len = 0;
1193 err = MPI_Comm_get_name(*comm, name, &len);
1194 if (!err) {
1195 jv["mpi_name"] = name;
1196 }
1197 }
1198
1199 int major=0, minor=0;
1200 if ( bitflags & ADC_MPI_VER) {
1201 err = MPI_Get_version(&major, &minor);
1202 std::ostringstream mversion;
1203 mversion << MPI_VERSION << "." << MPI_SUBVERSION;
1204 if (!err) {
1205 jv["mpi_version"] = mversion.str();
1206 }
1207 }
1208
1209 err = 0;
1210 if ( bitflags & ADC_MPI_LIB_VER) {
1211 std::ostringstream lversion;
1212#ifdef OMPI_VERSION
1213#define USE_set_lib_version
1214 lversion << "OpenMPI " << OMPI_MAJOR_VERSION << "." <<
1215 OMPI_MINOR_VERSION << "." << OMPI_RELEASE_VERSION;
1216 goto set_lib_version;
1217#else
1218#ifdef MVAPICH2_VERSION
1219#define USE_set_lib_version
1220 lversion << MVAPICH2_VERSION;
1221 goto set_lib_version;
1222#else
1223#ifdef MPICH_VERSION
1224#define USE_set_lib_version
1225 lversion << MPICH_VERSION;
1226 goto set_lib_version;
1227#endif
1228#endif
1229#endif
1230 char lv[MPI_MAX_LIBRARY_VERSION_STRING];
1231 int sz = 0;
1232 err = MPI_Get_library_version(lv, &sz);
1233 lversion << lv;
1234#ifdef USE_set_lib_version
1235set_lib_version:
1236#endif
1237 if (!err) {
1238 jv["mpi_library_version"] = lversion.str();
1239 }
1240 }
1241
1242 if (bitflags & (ADC_MPI_HOSTLIST | ADC_MPI_RANK_HOST)) {
1243 if (rank < 0) {
1244 err = MPI_Comm_rank(*comm, &rank);
1245 if (err)
1246 goto mpi_out;
1247 }
1248 if (size < 0) {
1249 err = MPI_Comm_size(*comm, &size);
1250 if (err)
1251 goto mpi_out;
1252 }
1253 char *hostnames = (char *)calloc(size*MPI_MAX_PROCESSOR_NAME, 1);
1254 int nlen;
1255 MPI_Get_processor_name(hostnames + rank * MPI_MAX_PROCESSOR_NAME, &nlen);
1256 MPI_Allgather(hostnames + rank * MPI_MAX_PROCESSOR_NAME,
1257 MPI_MAX_PROCESSOR_NAME,
1258 MPI_CHAR,
1259 hostnames,
1260 MPI_MAX_PROCESSOR_NAME,
1261 MPI_CHAR,
1262 *comm);
1263
1264 std::vector<std::string> rh;
1265 for (auto i = 0; i < size; i++)
1266 rh.push_back(std::string(hostnames + rank * MPI_MAX_PROCESSOR_NAME));
1267
1268 if (bitflags & ADC_MPI_RANK_HOST) {
1269 boost::json::array av(rh.begin(), rh.end());
1270 jv["mpi_rank_host"] = av;
1271 }
1272
1273 if (bitflags & ADC_MPI_HOSTLIST ) {
1274 std::vector<std::string> hl;
1275 std::set<std::string> hm;
1276 for (auto i = 0; i < size; i++)
1277 hm.insert(std::string(hostnames + rank * MPI_MAX_PROCESSOR_NAME));
1278 for (auto i = 0; i < size; i++) {
1279 std::string stmp(hostnames + rank * MPI_MAX_PROCESSOR_NAME);
1280 if (hm.count(stmp)) {
1281 hl.push_back(stmp);
1282 hm.erase(stmp);
1283 }
1284 }
1285 boost::json::array hv(hl.begin(), hl.end());
1286 jv["mpi_hostlist"] = hv;
1287 }
1288
1289 free(hostnames);
1290 }
1291
1292mpi_out:
1293
1294#else
1295 // add fake rank 0, size 1, versions and names "none" per bitflags
1296 boost::json::object jv;
1297 int rank = 0;
1298 if ( bitflags & ADC_MPI_RANK) {
1299 jv["mpi_rank"] = rank;
1300 }
1301
1302 int size = 1;
1303 if ( bitflags & ADC_MPI_SIZE) {
1304 jv["mpi_size"] = size;
1305 }
1306
1307 if ( bitflags & ADC_MPI_NAME) {
1308 jv["mpi_name"] = "none";
1309 }
1310
1311 if ( bitflags & ADC_MPI_VER) {
1312 jv["mpi_version"] = "none";
1313 }
1314
1315 if ( bitflags & ADC_MPI_LIB_VER) {
1316 jv["mpi_library_version"] = "none";
1317 }
1318
1319 if (bitflags & (ADC_MPI_HOSTLIST | ADC_MPI_RANK_HOST)) {
1320 char myhost[HOST_NAME_MAX];
1321 int herr = gethostname(myhost, HOST_NAME_MAX);
1322 if (herr < 0)
1323 sprintf(myhost, "name_unavailable");
1324
1325 std::vector<std::string> rh;
1326 rh.push_back(myhost);
1327 boost::json::array av(rh.begin(), rh.end());
1328
1329 if (bitflags & ADC_MPI_RANK_HOST) {
1330 jv["mpi_rank_host"] = av;
1331 }
1332
1333 if (bitflags & ADC_MPI_HOSTLIST ) {
1334 jv["mpi_hostlist"] = av;
1335 }
1336 }
1337#endif // ADC_HAVE_MPI
1338 d[commname] = jv;
1339}
1340
1342{
1343 std::vector< std::string >slurmvars;
1344 add_slurm_section(slurmvars);
1345}
1346
1347void builder::add_slurm_section(const std::vector< std::string >& slurmvars)
1348{
1349 static std::vector< std::pair<const char *, const char *> > slurm_names =
1350 {
1351 { "cluster", "SLURM_CLUSTER_NAME"},
1352 { "job_id", "SLURM_JOB_ID"},
1353 { "num_nodes", "SLURM_JOB_NUM_NODES"},
1354 { "dependency", "SLURM_JOB_DEPENDENCY"},
1355 };
1356
1357 boost::json::object jv;
1358 for (const auto& i : slurm_names) {
1359 const char *val = getenv(i.second);
1360 if (val)
1361 jv[i.first] = val;
1362 else
1363 jv[i.first] = "";
1364 }
1365 for (const auto& i : slurmvars) {
1366 const char *val = getenv(i.c_str());
1367 if (val)
1368 jv[i] = val;
1369 else
1370 jv[i] = "";
1371 }
1372 d["slurm"] = jv;
1373}
1374
1376{
1377 static std::vector< std::pair<const char *, const char *> > names =
1378 {
1379 { "wfid", "ADC_WFID"},
1380 { "wfid_parent", "ADC_WFID_PARENT"},
1381 { "wfid_path", "ADC_WFID_PATH"}
1382 };
1383
1384 boost::json::object jv;
1385 for (const auto& i : names) {
1386 const char *val = getenv(i.second);
1387 if (val)
1388 jv[i.first] = val;
1389 else
1390 jv[i.first] = "";
1391 }
1392 boost::json::array av;
1393 const char *cenv = getenv("ADC_WFID_CHILDREN");
1394 if (cenv) {
1395 // split and append to wfid_children
1396 std::stringstream ss(cenv);
1397 string elt;
1398 char pathsep = ':';
1399 while (getline(ss, elt, pathsep)) {
1400 if (elt.size() > 0) {
1401#ifdef ADC_WORKFLOW_DEBUG
1402 std::cerr << __func__ << ": add child " << elt << std::endl;
1403#endif
1404 av.emplace_back(elt);
1405 }
1406 }
1407 }
1408 jv["wfid_children"] = av;
1409 d["adc_workflow"] = jv;
1410}
1411
1412bool array_contains_string( boost::json::array& av, string_view uuid)
1413{
1414 for (const auto& v : av) {
1415 if (v.is_string() && v.as_string() == uuid) {
1416 return true;
1417 }
1418 }
1419 return false;
1420}
1421
1422void builder::add_workflow_children(std::vector< std::string >& child_uuids)
1423{
1424 auto wsection = d.if_contains("adc_workflow");
1425 if (! wsection) {
1426 std::cerr << __func__ << ": called before add_workflow_section" << std::endl;
1427 return;
1428 }
1429 if (! wsection->is_object()) {
1430 std::cerr << __func__ << ": adc_workflow is not an object. (?!)" << std::endl;
1431 return;
1432 }
1433 auto haschildren = wsection->as_object().if_contains("wfid_children");
1434 if (!haschildren) {
1435 std::cerr << __func__ << ": called before successful add_workflow_section" << std::endl;
1436 return;
1437 }
1438 auto children = wsection->as_object()["wfid_children"];
1439 if (!children.is_array()) {
1440 std::cerr << __func__ << ": wfid_children is not an array. (?!)" << std::endl;
1441 return;
1442 }
1443 for (auto const& uuid : child_uuids) {
1444 if (array_contains_string(wsection->as_object()["wfid_children"].as_array(), uuid)) {
1445 continue;
1446 }
1447 wsection->as_object()["wfid_children"].as_array().emplace_back(uuid);
1448 }
1449}
1450
1451
1453{
1454 static const std::vector<std::string > gitlab_ci_names = {
1455 "CI_RUNNER_ID",
1456 "CI_RUNNER_VERSION",
1457 "CI_PROJECT_ID",
1458 "CI_PROJECT_NAME",
1459 "CI_SERVER_FQDN",
1460 "CI_SERVER_VERSION",
1461 "CI_JOB_ID",
1462 "CI_JOB_STARTED_AT",
1463 "CI_PIPELINE_ID",
1464 "CI_PIPELINE_SOURCE",
1465 "CI_COMMIT_SHA",
1466 "GITLAB_USER_LOGIN"
1467 };
1468 boost::json::object jv;
1469 for (const auto& i : gitlab_ci_names) {
1470 const char *val = getenv(i.c_str());
1471 if (val)
1472 jv[tolower_s(i)] = val;
1473 else
1474 jv[tolower_s(i)] = "";
1475 }
1476 d["gitlab_ci"] = jv;
1477}
1478
1479void builder::add(std::string_view name, bool value) {
1480 boost::json::value jv = {
1481 {"type", adc::to_string(cp_bool)},
1482 {"value", value}
1483 };
1484 d[name] = jv;
1485}
1486
1487void builder::add(std::string_view name, char value) {
1488 boost::json::value jv = {
1489 {"type", adc::to_string(cp_char)},
1490 {"value", value }
1491 };
1492 d[name] = jv;
1493}
1494
1495void builder::add(std::string_view name, char16_t value) {
1496 uint64_t ivalue = value;
1497 boost::json::value jv = {
1498 {"type", adc::to_string(cp_char16)},
1499 {"value", ivalue}
1500 };
1501 d[name] = jv;
1502}
1503
1504void builder::add(std::string_view name, char32_t value) {
1505 uint64_t ivalue = value;
1506 boost::json::value jv = {
1507 {"type", adc::to_string(cp_char32)},
1508 {"value", ivalue}
1509 };
1510 d[name] = jv;
1511}
1512
1513// builder::add null-terminated string
1514void builder::add(std::string_view name, char* value) {
1515 boost::json::value jv = {
1516 {"type", adc::to_string(cp_cstr)},
1517 {"value", value}
1518 };
1519 d[name] = jv;
1520}
1521void builder::add(std::string_view name, const char* value) {
1522 boost::json::value jv = {
1523 {"type", adc::to_string(cp_cstr)},
1524 {"value", value}
1525 };
1526 d[name] = jv;
1527}
1528void builder::add(std::string_view name, std::string_view value) {
1529 boost::json::value jv = {
1530 {"type", adc::to_string(cp_cstr)},
1531 {"value", value}
1532 };
1533 d[name] = jv;
1534}
1535void builder::add(std::string_view name, std::string& value) {
1536 boost::json::value jv = {
1537 {"type", adc::to_string(cp_cstr)},
1538 {"value", value}
1539 };
1540 d[name] = jv;
1541}
1542
1543// builder::add null-terminated string file path
1544void builder::add_path(std::string_view name, char* value) {
1545 boost::json::value jv = {
1546 {"type", adc::to_string(cp_path)},
1547 {"value", value}
1548 };
1549 d[name] = jv;
1550}
1551void builder::add_path(std::string_view name, const char* value) {
1552 boost::json::value jv = {
1553 {"type", adc::to_string(cp_path)},
1554 {"value", value}
1555 };
1556 d[name] = jv;
1557}
1558void builder::add_path(std::string_view name, std::string_view value) {
1559 boost::json::value jv = {
1560 {"type", adc::to_string(cp_path)},
1561 {"value", value}
1562 };
1563 d[name] = jv;
1564}
1565void builder::add_path(std::string_view name, std::string& value) {
1566 boost::json::value jv = {
1567 {"type", adc::to_string(cp_path)},
1568 {"value", value}
1569 };
1570 d[name] = jv;
1571}
1572
1573// builder::add string which is serialized json.
1574void builder::add_json_string(std::string_view name, std::string_view value) {
1575 boost::json::value jv = {
1576 {"type", adc::to_string(cp_json_str)},
1577 {"value", value}
1578 };
1579 d[name] = jv;
1580}
1581
1582void builder::add_yaml_string(std::string_view name, std::string_view value) {
1583 boost::json::value jv = {
1584 {"type", adc::to_string(cp_yaml_str)},
1585 {"value", value}
1586 };
1587 d[name] = jv;
1588}
1589
1590void builder::add_xml_string(std::string_view name, std::string_view value) {
1591 boost::json::value jv = {
1592 {"type", adc::to_string(cp_xml_str)},
1593 {"value", value}
1594 };
1595 d[name] = jv;
1596}
1597
1598void builder::add_number_string(std::string_view name, std::string_view value) {
1599 boost::json::value jv = {
1600 {"type", adc::to_string(cp_number_str)},
1601 {"value", value}
1602 };
1603 d[name] = jv;
1604}
1605
1606#if ADC_BOOST_JSON_PUBLIC
1607void builder::add(std::string_view name, boost::json::value value) {
1608 boost::json::value jv = {
1609 {"type", adc::to_string(cp_json)},
1610 {"value", value}
1611 };
1612 d[name] = jv;
1613}
1614#endif
1615
1616
1617void builder::add(std::string_view name, uint8_t value) {
1618 boost::json::value jv = {
1619 {"type", adc::to_string(cp_uint8)},
1620 {"value", value}
1621 };
1622 d[name] = jv;
1623}
1624void builder::add(std::string_view name, uint16_t value) {
1625 boost::json::value jv = {
1626 {"type", adc::to_string(cp_uint16)},
1627 {"value", value}
1628 };
1629 d[name] = jv;
1630}
1631void builder::add(std::string_view name, uint32_t value) {
1632 boost::json::value jv = {
1633 {"type", adc::to_string(cp_uint32)},
1634 {"value", value}
1635 };
1636 d[name] = jv;
1637}
1638void builder::add(std::string_view name, uint64_t value) {
1639 boost::json::value jv = {
1640 {"type", adc::to_string(cp_uint64)},
1641 {"value", std::to_string(value)}
1642 };
1643 d[name] = jv;
1644}
1645void builder::add(std::string_view name, int8_t value) {
1646 boost::json::value jv = {
1647 {"type", adc::to_string(cp_int8)},
1648 {"value", value}
1649 };
1650 d[name] = jv;
1651}
1652void builder::add(std::string_view name, int16_t value) {
1653 boost::json::value jv = {
1654 {"type", adc::to_string(cp_int16)},
1655 {"value", value}
1656 };
1657 d[name] = jv;
1658}
1659void builder::add(std::string_view name, int32_t value) {
1660 boost::json::value jv = {
1661 {"type", adc::to_string(cp_int32)},
1662 {"value", value }
1663 };
1664 d[name] = jv;
1665}
1666void builder::add(std::string_view name, int64_t value) {
1667 boost::json::value jv = {
1668 {"type", adc::to_string(cp_int64)},
1669 {"value", value}
1670 };
1671 d[name] = jv;
1672}
1673void builder::add(std::string_view name, float value) {
1674 boost::json::value jv = {
1675 {"type", adc::to_string(cp_f32)},
1676 {"value", value }
1677 };
1678 d[name] = jv;
1679}
1680void builder::add(std::string_view name, const std::complex<float>& value) {
1681 boost::json::value jv = {
1682 {"type", adc::to_string(cp_c_f32)},
1683 {"value", { value.real(), value.imag() }}
1684 };
1685 d[name] = jv;
1686}
1687void builder::add(std::string_view name, double value) {
1688 boost::json::value jv = {
1689 {"type", adc::to_string(cp_f64)},
1690 {"value", value }
1691 };
1692 d[name] = jv;
1693}
1694void builder::add(std::string_view name, const std::complex<double>& value) {
1695 boost::json::value jv = {
1696 {"type" , adc::to_string(cp_c_f64)},
1697 {"value", { value.real(), value.imag() }}
1698 };
1699 d[name] = jv;
1700}
1701
1702
1703void builder::add(std::string_view name, const struct timeval& tv) {
1704 boost::json::value jv = {
1705 {"type" , adc::to_string(cp_timeval)},
1706 {"value", { (int64_t)tv.tv_sec, (int64_t)tv.tv_usec }}
1707 };
1708 d[name] = jv;
1709}
1710
1711void builder::add(std::string_view name, const struct timespec& ts) {
1712 boost::json::value jv = {
1713 {"type" , adc::to_string(cp_timespec)},
1714 {"value", { (int64_t)ts.tv_sec, (int64_t)ts.tv_nsec }}
1715 };
1716 d[name] = jv;
1717}
1718
1719void builder::add_epoch(std::string_view name, int64_t epoch) {
1720 boost::json::value jv = {
1721 {"type", adc::to_string(cp_epoch)},
1722 {"value", epoch }
1723 };
1724 d[name] = jv;
1725}
1726
1727
1728void builder::add_from_pointer_type(std::string_view name, void* p, enum scalar_type t)
1729{
1730 switch (t) {
1731 case cp_bool:
1732 {
1733 bool *v = (bool *)p;
1734 add(name, *v);
1735 }
1736 break;
1737 case cp_char:
1738 {
1739 char *v = (char *)p;
1740 add(name, *v);
1741 }
1742 break;
1743 case cp_char16:
1744 {
1745 char16_t *v = (char16_t *)p;
1746 add(name, *v);
1747 }
1748 break;
1749 case cp_char32:
1750 {
1751 char32_t *v = (char32_t *)p;
1752 add(name, *v);
1753 }
1754 break;
1755 case cp_cstr:
1756 {
1757 char *v = (char *)p;
1758 add(name, v);
1759 }
1760 break;
1761 case cp_json_str:
1762 {
1763 char *v = (char *)p;
1764 add_json_string(name, v);
1765 }
1766 break;
1767 case cp_yaml_str:
1768 {
1769 char *v = (char *)p;
1770 add_yaml_string(name, v);
1771 }
1772 break;
1773 case cp_xml_str:
1774 {
1775 char *v = (char *)p;
1776 add_xml_string(name, v);
1777 }
1778 break;
1779#if ADC_BOOST_JSON_PUBLIC
1780 case cp_json:
1781 return; // pointers to json objects are ignored. fixme? ADC_BOOST_JSON_PUBLIC in builder::add_from_pointer_type
1782#endif
1783 case cp_path:
1784 {
1785 char *v = (char *)p;
1786 add_path(name, v);
1787 }
1788 break;
1789 case cp_number_str:
1790 {
1791 char *v = (char *)p;
1792 add_number_string(name, v);
1793 }
1794 break;
1795 case cp_uint8:
1796 {
1797 uint8_t *v = (uint8_t *)p;
1798 add(name, *v);
1799 }
1800 break;
1801 case cp_uint16:
1802 {
1803 uint16_t *v = (uint16_t *)p;
1804 add(name, *v);
1805 }
1806 break;
1807 case cp_uint32:
1808 {
1809 uint32_t *v = (uint32_t *)p;
1810 add(name, *v);
1811 }
1812 break;
1813 case cp_uint64:
1814 {
1815 uint64_t *v = (uint64_t *)p;
1816 add(name, *v);
1817 }
1818 break;
1819 case cp_int8:
1820 {
1821 int8_t *v = (int8_t *)p;
1822 add(name, *v);
1823 }
1824 break;
1825 case cp_int16:
1826 {
1827 int16_t *v = (int16_t *)p;
1828 add(name, *v);
1829 }
1830 break;
1831 case cp_int32:
1832 {
1833 int32_t *v = (int32_t *)p;
1834 add(name, *v);
1835 }
1836 break;
1837 case cp_int64:
1838 {
1839 int64_t *v = (int64_t *)p;
1840 add(name, *v);
1841 }
1842 break;
1843 case cp_f32:
1844 {
1845 float *v = (float *)p;
1846 add(name, *v);
1847 }
1848 break;
1849 case cp_f64:
1850 {
1851 double *v = (double *)p;
1852 add(name, *v);
1853 }
1854 break;
1855#if ADC_SUPPORT_EXTENDED_FLOATS
1856 case cp_f80:
1857 {
1858 // prec fixme? verify cp_f80 in supporting compiler builder::add_from_pointer_type
1859 __float80 *v = (__float80 *)p;
1860 add(name, *v);
1861 }
1862 break;
1863#endif
1864#if ADC_SUPPORT_QUAD_FLOATS
1865 case cp_f128:
1866 {
1867 __float128 *v = (__float128 *)p;
1868 add(name, *v);
1869 }
1870 break;
1871#endif
1872#if ADC_SUPPORT_GPU_FLOATS
1873 case cp_f8_e4m3:
1874 {
1875 // prec fixme verify cp_f8_e4m3 in supporting compiler ; builder::add_from_pointer_type
1876 }
1877 break;
1878 case cp_f8_e5m2:
1879 {
1880 // prec fixme verify cp_f8_e5m2 in supporting compiler ; builder::add_from_pointer_type
1881 }
1882 break;
1883 case cp_f16_e5m10:
1884 {
1885 // prec fixme verify cp_f16_e5m10 in supporting compiler ; builder::add_from_pointer_type
1886 }
1887 break;
1888 case cp_f16_e8m7:
1889 {
1890 // prec fixme verify cp_f16_e8m7 in supporting compiler ; builder::add_from_pointer_type
1891 }
1892 break;
1893#endif
1894 case cp_c_f32:
1895 {
1896 float *v = (float *)p;
1897 std::complex<float> c(v[0], v[1]);
1898 add(name, c);
1899 }
1900 break;
1901 case cp_c_f64:
1902 {
1903 double *v = (double *)p;
1904 std::complex<double> c(v[0], v[1]);
1905 add(name, c);
1906 }
1907 break;
1908#if ADC_SUPPORT_QUAD_FLOATS
1909 case cp_c_f128:
1910 {
1911 __float128 *v = (__float128 *)p;
1912 std::complex<__float128> c(v[0], v[1]);
1913 add(name, c);
1914 }
1915 break;
1916#endif
1917#if ADC_SUPPORT_EXTENDED_FLOATS
1918 case cp_c_f80:
1919 {
1920 // prec fixme? cp_c_f80 ; builder::add_from_pointer_type
1921 __float80 *v = (__float80 *)p;
1922 std::complex<__float80> c(v[0], v[1]);
1923 add(name, c);
1924 }
1925 break;
1926#endif
1927 case cp_timespec:
1928 {
1929 struct timespec *v = (struct timespec *)p;
1930 add(name, *v);
1931 }
1932 break;
1933 case cp_timeval:
1934 {
1935 struct timeval *v = (struct timeval *)p;
1936 add(name, *v);
1937 }
1938 break;
1939 case cp_epoch:
1940 {
1941 int64_t *v = (int64_t *)p;
1942 add_epoch(name, *v);
1943 }
1944 break;
1945 default:
1946 break;
1947 }
1948}
1949
1950void builder::add_array(std::string_view name, bool value[], size_t len, std::string_view c) {
1951 boost::json::array av(value, value+len);
1952 boost::json::value jv = {
1953 {"type", "array_" + adc::to_string(cp_bool)},
1954 {"container_type", c},
1955 {"value", av}
1956 };
1957 d[name] = jv;
1958}
1959
1960void builder::add_array(std::string_view name, const char *value, size_t len, std::string_view c) {
1961 boost::json::array av(value, value+len);
1962 boost::json::value jv = {
1963 {"type", "array_" + adc::to_string(cp_char)},
1964 {"container_type", c},
1965 {"value", av}
1966 };
1967 d[name] = jv;
1968}
1969
1970void builder::add_array(std::string_view name, char16_t value[], size_t len, std::string_view c) {
1971 boost::json::array av(value, value+len);
1972 boost::json::value jv = {
1973 {"type", "array_" + adc::to_string(cp_char16)},
1974 {"container_type", c},
1975 {"value", av}
1976 };
1977 d[name] = jv;
1978}
1979
1980void builder::add_array(std::string_view name, char32_t value[], size_t len, std::string_view c) {
1981 boost::json::array av(value, value+len);
1982 boost::json::value jv = {
1983 {"type", "array_" + adc::to_string(cp_char32)},
1984 {"container_type", c},
1985 {"value", av}
1986 };
1987 d[name] = jv;
1988}
1989
1990void builder::add_array(std::string_view name, uint8_t value[], size_t len, std::string_view c) {
1991 boost::json::array av(value, value+len);
1992 boost::json::value jv = {
1993 {"type", "array_" + adc::to_string(cp_uint8)},
1994 {"container_type", c},
1995 {"value", av}
1996 };
1997 d[name] = jv;
1998}
1999void builder::add_array(std::string_view name, uint16_t value[], size_t len, std::string_view c) {
2000 boost::json::array av(value, value+len);
2001 boost::json::value jv = {
2002 {"type", "array_" + adc::to_string(cp_uint16)},
2003 {"container_type", c},
2004 {"value", av}
2005 };
2006 d[name] = jv;
2007}
2008void builder::add_array(std::string_view name, uint32_t value[], size_t len, std::string_view c) {
2009 boost::json::array av(value, value+len);
2010 boost::json::value jv = {
2011 {"type", "array_" + adc::to_string(cp_uint32)},
2012 {"container_type", c},
2013 {"value", av}
2014 };
2015 d[name] = jv;
2016}
2017void builder::add_array(std::string_view name, uint64_t value[], size_t len, std::string_view c) {
2018 std::vector<std::string> sv(len);
2019 for (size_t i = 0; i < len; i++)
2020 sv[i] = std::to_string(value[i]);
2021 boost::json::array av(sv.begin(), sv.end());
2022 boost::json::value jv = {
2023 {"type", "array_" + adc::to_string(cp_uint64)},
2024 {"container_type", c},
2025 {"value", av}
2026 };
2027 d[name] = jv;
2028}
2029void builder::add_array(std::string_view name, int8_t value[], size_t len, std::string_view c) {
2030 boost::json::array av(value, value+len);
2031 boost::json::value jv = {
2032 {"type", "array_" + adc::to_string(cp_int8)},
2033 {"container_type", c},
2034 {"value", av}
2035 };
2036 d[name] = jv;
2037}
2038void builder::add_array(std::string_view name, int16_t value[], size_t len, std::string_view c) {
2039 boost::json::array av(value, value+len);
2040 boost::json::value jv = {
2041 {"type", "array_" + adc::to_string(cp_int16)},
2042 {"container_type", c},
2043 {"value", av}
2044 };
2045 d[name] = jv;
2046}
2047void builder::add_array(std::string_view name, int32_t value[], size_t len, std::string_view c) {
2048 boost::json::array av(value, value+len);
2049 boost::json::value jv = {
2050 {"type", "array_" + adc::to_string(cp_int32)},
2051 {"container_type", c},
2052 {"value", av}
2053 };
2054 d[name] = jv;
2055}
2056void builder::add_array(std::string_view name, int64_t value[], size_t len, std::string_view c) {
2057 boost::json::array av(value, value+len);
2058 boost::json::value jv = {
2059 {"type", "array_" + adc::to_string(cp_int64)},
2060 {"container_type", c},
2061 {"value", av}
2062 };
2063 d[name] = jv;
2064}
2065void builder::add_array(std::string_view name, float value[], size_t len, std::string_view c) {
2066 boost::json::array av(value, value+len);
2067 boost::json::value jv = {
2068 {"type", "array_" + adc::to_string(cp_f32)},
2069 {"container_type", c},
2070 {"value", av}
2071 };
2072 d[name] = jv;
2073}
2074#if 0
2075void builder::add_array(std::string_view name, const std::complex<float> value[], size_t len, std::string_view c) {
2076 boost::json::array av(value, value+len);
2077 boost::json::value jv = {
2078 {"type", "array_" + adc::to_string(cp_c_f32)},
2079 {"container_type", c},
2080 {"value", { value.real(), value.imag() }}
2081 };
2082 d[name] = jv;
2083}
2084#endif
2085void builder::add_array(std::string_view name, double value[], size_t len, std::string_view c) {
2086 boost::json::array av(value, value+len);
2087 boost::json::value jv = {
2088 {"type", "array_" + adc::to_string(cp_f64)},
2089 {"container_type", c},
2090 {"value", av}
2091 };
2092 d[name] = jv;
2093}
2094#if 0
2095void builder::add_array(std::string_view name, const std::complex<double> value[], size_t len, std::string_view c) {
2096 boost::json::array av(value, value+len);
2097 boost::json::value jv = {
2098 {"type" , "array_" + adc::to_string(cp_c_f64)},
2099 {"container_type", c},
2100 {"value", { value.real(), value.imag() }}
2101 };
2102 d[name] = jv;
2103}
2104#endif
2105
2106void builder::add_array(std::string_view name, char* value[], size_t len, std::string_view c) {
2107 boost::json::array av(value, value+len);
2108 boost::json::value jv = {
2109 {"type", "array_" + adc::to_string(cp_cstr)},
2110 {"container_type", c},
2111 {"value", av}
2112 };
2113 d[name] = jv;
2114}
2115void builder::add_array(std::string_view name, const char* value[], size_t len, std::string_view c) {
2116 boost::json::array av(value, value+len);
2117 boost::json::value jv = {
2118 {"type", "array_" + adc::to_string(cp_cstr)},
2119 {"container_type", c},
2120 {"value", av}
2121 };
2122 d[name] = jv;
2123}
2124void builder::add_array(std::string_view name, std::string value[], size_t len, std::string_view c) {
2125 boost::json::array av(value, value+len);
2126 boost::json::value jv = {
2127 {"type", "array_" + adc::to_string(cp_cstr)},
2128 {"container_type", c},
2129 {"value", av}
2130 };
2131 d[name] = jv;
2132}
2133void builder::add_array(std::string_view name, const std::string value[], size_t len, std::string_view c) {
2134 boost::json::array av(value, value+len);
2135 boost::json::value jv = {
2136 {"type", "array_" + adc::to_string(cp_cstr)},
2137 {"container_type", c},
2138 {"value", av}
2139 };
2140 d[name] = jv;
2141}
2142void builder::add_array(std::string_view name, const std::vector<std::string> value, std::string_view c) {
2143 boost::json::value jv = {
2144 {"type", "array_" + adc::to_string(cp_cstr)},
2145 {"container_type", c},
2146 {"value", boost::json::value_from(value)}
2147 };
2148 d[name] = jv;
2149}
2150void builder::add_array(std::string_view name, const std::set<std::string> value, std::string_view c) {
2151 boost::json::value jv = {
2152 {"type", "array_" + adc::to_string(cp_cstr)},
2153 {"container_type", c},
2154 {"value", boost::json::value_from(value)}
2155 };
2156 d[name] = jv;
2157}
2158void builder::add_array(std::string_view name, const std::list<std::string> value, std::string_view c) {
2159 boost::json::value jv = {
2160 {"type", "array_" + adc::to_string(cp_cstr)},
2161 {"container_type", c},
2162 {"value", boost::json::value_from(value)}
2163 };
2164 d[name] = jv;
2165}
2166// Array of strings which are serialized json.
2167void builder::add_array_json_string(std::string_view name, const std::string value[], size_t len, std::string_view c) {
2168 boost::json::array av(value, value+len);
2169 boost::json::value jv = {
2170 {"type", "array_" + adc::to_string(cp_json_str)},
2171 {"container_type", c},
2172 {"value", av}
2173 };
2174 d[name] = jv;
2175}
2176
2177
2178/*
2179 * recursively merge sections into a single json tree
2180 */
2181boost::json::object builder::flatten()
2182{
2183 boost::json::object tot(d); // copy
2184 for (auto it = sections.begin(); it != sections.end(); it++) {
2185 tot[it->first] = it->second->flatten();
2186 }
2187 return tot;
2188}
2189
2190BOOST_SYMBOL_VISIBLE std::string builder::serialize() {
2191 boost::json::object total;
2192 total = flatten();
2193 return boost::json::serialize(total);
2194}
2195
2196key_type builder::kind(std::string_view name) {
2197 auto sit = sections.find(std::string(name));
2198 if (sit != sections.end())
2199 return k_section;
2200 auto jit = d.find(name);
2201 if (jit != d.end())
2202 return k_value;
2203 return k_none;
2204}
2205
2206} // end namespace adc
#define CPUINFO_FILE
Definition builder.ipp:80
#define ADC_HS_BAD
Definition builder.ipp:451
#define MEMINFO_FILE
Definition builder.ipp:286
std::shared_ptr< builder_api > get_section(std::string_view name)
get the existing named section
Definition builder.ipp:609
std::vector< std::string > get_section_names()
get the names of sections
Definition builder.ipp:618
builder(void *mpi_communicator_p=NULL)
Definition builder.ipp:383
void add_json_string(std::string_view name, std::string_view value)
add string which is serialized json.
Definition builder.ipp:1574
void add_mpi_section(std::string_view name, void *mpi_comm_p, adc_mpi_field_flags bitflags)
add data about a named mpi communicator. In most applications, "mpi_comm_world" is the recommended na...
Definition builder.ipp:1163
void add_code_configuration_section(std::shared_ptr< builder_api > build_details)
Populate build/install "configuration" information such as options enabled.
Definition builder.ipp:580
void add_model_data_section(std::shared_ptr< builder_api > model_data)
populate application run-time physics (re)configuration/result to "model_data" section....
Definition builder.ipp:549
void add_array_json_string(std::string_view name, const std::string value[], size_t len, std::string_view c)
Add Array of strings which are serialized json.
Definition builder.ipp:2167
void add_xml_string(std::string_view name, std::string_view value)
add string which is xml.
Definition builder.ipp:1590
void add_yaml_string(std::string_view name, std::string_view value)
add string which is yaml.
Definition builder.ipp:1582
void add(std::string_view name, bool value)
add a named boolean
Definition builder.ipp:1479
void add_host_section(int32_t subsections)
auto-populate the "host" section based on bitflags. There are many optional subsections covering cpus...
Definition builder.ipp:453
const field get_value(std::string_view name)
get the existing named field in the section.
Definition builder.ipp:1073
void add_workflow_section()
add data from adc_wfid_ environment variables. The section name is "adc_workflow".
Definition builder.ipp:1375
void add_array(std::string_view name, bool value[], size_t len, std::string_view c)
Fixed length arrays of scalar members.
Definition builder.ipp:1950
void add_from_pointer_type(std::string_view name, void *, enum scalar_type t)
add data from a c pointer
Definition builder.ipp:1728
void add_number_string(std::string_view name, std::string_view value)
add string which is an arbitrary precision decimal number
Definition builder.ipp:1598
void add_gitlab_ci_section()
add gitlab_ci environment variable dictionary. The section added is named "gitlab_ci".
Definition builder.ipp:1452
void add_section(std::string_view name, std::shared_ptr< builder_api > section)
copy populated generic section into the builder under specified name.
Definition builder.ipp:599
void add_memory_usage_section()
populate "memory_usage" section with current host /proc/meminfo data in the style of free(1).
Definition builder.ipp:524
void add_code_section(std::string tag, std::shared_ptr< builder_api > version, std::shared_ptr< builder_api > code_details)
Definition builder.ipp:557
std::vector< std::string > get_field_names()
get the names of non-section fields in the section
Definition builder.ipp:627
void add_slurm_section()
add slurm output environment variable dictionary elements. The section added is named "slurm".
Definition builder.ipp:1341
void add_exit_data_section(int return_code, std::string status, std::shared_ptr< builder_api > status_details)
populate "exit_data" section with code and status stream and user provided details.
Definition builder.ipp:587
void add_epoch(std::string_view name, int64_t epoch)
add unix epoch seconds (gettimeofday)
Definition builder.ipp:1719
void add_app_data_section(std::shared_ptr< builder_api > app_data)
create the "app_data" section with data defined by the application writer.
Definition builder.ipp:518
void add_path(std::string_view name, char *value)
add null-terminated string filepath
Definition builder.ipp:1544
std::string serialize()
convert object to a json string reflecting the section hierarchy.
Definition builder.ipp:2190
void add_workflow_children(std::vector< std::string > &child_uuids)
add list of child uuids to "adc_workflow" section after add_workflow_section has been called....
Definition builder.ipp:1422
void add_header_section(std::string_view application_name)
auto-populate the "header" section with application name and required local data
Definition builder.ipp:387
static pipe_data run(const std::string &proc)
Definition outpipe.ipp:29
std::string get_default_affinity()
Definition builder.ipp:81
std::string format_timespec_utc_ns(struct timespec &ts)
Definition builder.ipp:65
key_type
when expanding scalar_type, always update enum.ipp to match.
Definition types.hpp:106
scalar_type scalar_type_from_name(const std::string &name)
get the enum representation of a scalar_type string
Definition enums.ipp:100
version enum_version("1.0.0", {"none"})
the version number of enum scalar_type and object_type
std::variant< bool, char, char16_t, char32_t, int8_t, int16_t, int32_t, int64_t, uint8_t, uint16_t, uint32_t, uint64_t, float, double, std::complex< float >, std::complex< double >, std::array< int64_t, 2 >, std::string, std::shared_ptr< bool[]>, std::shared_ptr< char[]>, std::shared_ptr< char16_t[]>, std::shared_ptr< char32_t[]>, std::shared_ptr< int8_t[]>, std::shared_ptr< int16_t[]>, std::shared_ptr< int32_t[]>, std::shared_ptr< int64_t[]>, std::shared_ptr< uint8_t[]>, std::shared_ptr< uint16_t[]>, std::shared_ptr< uint32_t[]>, std::shared_ptr< uint64_t[]>, std::shared_ptr< float[]>, std::shared_ptr< double[]>, std::shared_ptr< std::complex< float >[]>, std::shared_ptr< std::complex< double >[]>, std::shared_ptr< std::string[]> > variant
variant for querying builder data.
Definition types.hpp:153
const std::string to_string(float f)
get string of float using to_chars.
Definition enums.ipp:128
std::string format_timespec_8601(struct timespec &ts)
Definition builder.ipp:50
scalar_type
field types for scientific data encode/decode with json.
Definition types.hpp:58
@ k_value
Definition types.hpp:109
@ k_none
Definition types.hpp:107
@ k_section
Definition types.hpp:108
@ cp_xml_str
c null-terminated string that contains valid xml
Definition types.hpp:68
@ cp_int64
int64_t
Definition types.hpp:81
@ cp_epoch
time(NULL) seconds since the epoch (UNIX) as int64_t
Definition types.hpp:100
@ cp_f16_e8m7
16 bit bfloat (7 mantissa, 8 exponent); requires ADC_SUPPORT_GPU_FLOATS support
Definition types.hpp:91
@ cp_int32
int32_t
Definition types.hpp:80
@ cp_c_f32
complex<float>
Definition types.hpp:93
@ cp_char
char (8 bit)
Definition types.hpp:61
@ cp_path
c null-terminated string which names a file-system path
Definition types.hpp:70
@ cp_char16
char16_t
Definition types.hpp:62
@ cp_json_str
c null-terminated string that contains valid json
Definition types.hpp:66
@ cp_timespec
(second, nanosecond) as int64_t, int64_t pair from clock_gettime
Definition types.hpp:98
@ cp_timeval
gettimeofday struct timeval (second, microsecond) as int64_t pair
Definition types.hpp:99
@ cp_c_f64
complex<double>
Definition types.hpp:94
@ cp_bool
bool (true/false,1/0)
Definition types.hpp:60
@ cp_int8
int8_t
Definition types.hpp:78
@ cp_f128
128 bit float; requires ADC_SUPPORT_QUAD_FLOATS support
Definition types.hpp:86
@ cp_uint16
uint16_t
Definition types.hpp:74
@ cp_json
json value (object, list, etc)
Definition types.hpp:69
@ cp_c_f80
complex<extended>; requires ADC_SUPPORT_EXTENDED_FLOATS support
Definition types.hpp:95
@ cp_number_str
c null-terminated string containing an exact decimal representation of arbitrary precision
Definition types.hpp:71
@ cp_uint32
uint32_t
Definition types.hpp:75
@ cp_int16
int16_t
Definition types.hpp:79
@ cp_f64
64 bit float
Definition types.hpp:84
@ cp_f80
80 bit float; requires ADC_SUPPORT_EXTENDED_FLOATS support
Definition types.hpp:85
@ cp_none
Definition types.hpp:59
@ cp_f32
32 bit float
Definition types.hpp:83
@ cp_yaml_str
c null-terminated string that contains valid yaml
Definition types.hpp:67
@ cp_f16_e5m10
16 bit float (10 mantissa, 5 exponent); requires ADC_SUPPORT_GPU_FLOATS support
Definition types.hpp:90
@ cp_c_f128
complex<quad>; requires ADC_SUPPORT_QUAD_FLOATS support
Definition types.hpp:96
@ cp_cstr
c null-terminated string
Definition types.hpp:65
@ cp_char32
char32_t
Definition types.hpp:63
@ cp_uint64
uint64_t
Definition types.hpp:76
@ cp_uint8
uint8_t
Definition types.hpp:73
@ cp_f8_e5m2
8 bit float (2 mantissa, 5 exponent); requires ADC_SUPPORT_GPU_FLOATS support
Definition types.hpp:89
@ cp_f8_e4m3
8 bit float (3 mantissa, 4 exponent); requires ADC_SUPPORT_GPU_FLOATS support
Definition types.hpp:88
#define ADC_HS_GPU
ADC_HS_GPU collects gpu data available from lspci (requires lspci installed)
Definition builder.hpp:63
#define ADC_HS_RAMSIZE
ADC_HS_RAMSIZE collects MemTotal.
Definition builder.hpp:53
#define ADC_HS_OS
ADC_HS_OS collects other items from uname().
Definition builder.hpp:50
#define ADC_HS_CPU
ADC_HS_CPU collects details from lscpu -J (requires lscpu installed)
Definition builder.hpp:60
#define ADC_HS_NUMA
ADC_HS_NUMA collects numa node, cpu, and per node memory from numactl -H (requires numactl installed)
Definition builder.hpp:66
#define ADC_HS_ENV
ADC_HS_ENV collects env vars listed in env("ADC_HOST_SECTION_ENV") which is :-separated....
Definition builder.hpp:57
#define ADC_MPI_NAME
include "mpi_name" field from mpi_comm_name
Definition builder.hpp:95
#define ADC_MPI_RANK
include "mpi_rank" field from mpi_comm_rank
Definition builder.hpp:89
#define ADC_MPI_VER
include "mpi_version" field from MPI_VERSION.MPI_SUBVERSIUON
Definition builder.hpp:108
#define ADC_MPI_LIB_VER
include mpi_get_library_version result.
Definition builder.hpp:113
int32_t adc_mpi_field_flags
Definition builder.hpp:83
#define ADC_MPI_RANK_HOST
include "mpi_rank_host" subsection from the communicator
Definition builder.hpp:105
#define ADC_MPI_SIZE
include "mpi_size" field from mpi_comm_size
Definition builder.hpp:92
#define ADC_MPI_NONE
include no mpi fields
Definition builder.hpp:86
#define ADC_MPI_HOSTLIST
include "mpi_hostlist" subsection from the communicator
Definition builder.hpp:100
Definition adc.hpp:75
std::string get_lscpu()
Definition builder.ipp:72
boost::json::object get_gpu_data()
Definition builder.ipp:193
boost::json::kind scalar_type_representation(scalar_type st)
Definition enums.ipp:91
void fill_array_bool(field &f, boost::json::array &a)
Definition builder.ipp:940
std::string get_exe(size_t bufsize)
Definition builder.ipp:35
std::string_view string_view
Definition curl.ipp:14
void update_meminfo()
Definition builder.ipp:339
void fill_array_string(field &f, boost::json::array &a)
Definition builder.ipp:958
std::vector< std::string > get_libs(std::string_view)
Definition builder.ipp:115
boost::json::object get_numa_hardware()
Definition builder.ipp:133
std::vector< std::string > split_string(const std::string &s, char delimiter)
Definition builder.ipp:428
const size_t meminfo_raw
Definition builder.ipp:312
std::string tolower_s(std::string s)
Definition builder.ipp:27
bool array_contains_string(boost::json::array &av, string_view uuid)
Definition builder.ipp:1412
uint64_t get_memtotal()
Definition builder.ipp:315
std::string container
name of the container variety given to see builder::add_array
Definition types.hpp:162
scalar_type st
scalar type of the data as published,
Definition types.hpp:159
size_t count
number of elements in vp.
Definition types.hpp:161
variant data
Definition types.hpp:163
key_type kt
kind of data associated with the name queried
Definition types.hpp:158
const void * vp
address of data to be cast according to st for use with c/fortran
Definition types.hpp:160
uint64_t value
Definition builder.ipp:290
std::string name
Definition builder.ipp:289
std::string output
Definition outpipe.ipp:12
A version with tags list.
Definition types.hpp:24
const std::string name
Definition types.hpp:25