9#include <sys/utsname.h>
18#include <boost/algorithm/string.hpp>
21#if defined(__cpp_lib_span) && __cpp_lib_span >= 202002L
47std::string_view
strip(std::string_view s,
char c =
'/')
49 auto first = s.find_first_not_of(c);
50 if (std::string::npos == first) {
53 auto last = s.find_last_not_of(c);
54 auto len = last - first + 1;
55 return s.substr(first, len);
60 std::transform(s.begin(), s.end(), s.begin(),
61 [](
unsigned char c){ return std::tolower(c); }
69 auto buffer = std::make_unique<char[]>(bufsize);
70 ret = readlink(
"/proc/self/exe", buffer.get(), bufsize - 1);
72 sprintf(buffer.get(),
"(nullexe)");
74 buffer.get()[ret] =
'\0';
84 char prefix[40] =
"YYYY-MM-ddTHH:mm:ss";
85 char suffix[40] =
"0000 ";
87 localtime_r(&ts.tv_sec, &tm);
88 sprintf(millis,
"%03ld", ts.tv_nsec / 1000000);
89 strftime(prefix,
sizeof(prefix),
"%Y-%m-%dT%H:%M:%S.", &tm);
90 strftime(suffix,
sizeof(suffix),
"%z", &tm);
91 std::string buf = std::string(prefix) + std::string(millis) + std::string(suffix);
99 snprintf(str,
sizeof(str),
"%ld.%09ld",(
long)ts.tv_sec, (
long)ts.tv_nsec);
100 return std::string(str);
111#define CPUINFO_FILE "/proc/cpuinfo"
114 static std::string affinity_all;
115 if (affinity_all.size() < 2) {
119 while (std::getline(in, line)) {
120 size_t cp = line.find(
' ');
121 std::string name = line.substr(0, cp);
122 if (name ==
"processor") {
124 std::istringstream iss(line.substr(cp+1));
130 pmax = (val > pmax ? val : pmax);
135 affinity_all =
"0-1024";
137 std::ostringstream oss;
139 affinity_all = oss.str();
146std::vector< std::string>
get_libs(std::string_view )
148 pid_t pid = getpid();
149 std::ostringstream cmd;
150 cmd <<
"/usr/bin/grep r-xp /proc/" << pid <<
"/maps | /usr/bin/grep '\\.so' | /usr/bin/sed -e 's%.* /%/%g'";
152 std::vector< std::string> libs;
156 std::istringstream nss(proclibs.
output);
158 while (std::getline(nss, line)) {
159 libs.push_back(line);
166 static bool shell_done;
167 static boost::json::object numa_json;
171 size_t numa_node_count = 0;
173 std::vector<std::string> cpulist;
174 std::vector<int64_t> sizes;
178 std::istringstream nss(numactl.
output);
179 while (std::getline(nss, line)) {
180 size_t cp = line.find(
':');
181 std::string name = line.substr(0, cp);
182 if (name ==
"available") {
183 std::istringstream iss(line.substr(cp+1));
184 iss >> numa_node_count;
187 if (name.substr(name.length()-4) ==
"cpus" ) {
188 cpulist.push_back(line.substr(cp+2));
191 if (name.substr(name.length()-4) ==
"size" ) {
192 std::istringstream iss(line.substr(cp+1));
198 if (name.substr(name.length()-4) ==
"nces" )
201 if (! numa_node_count || sizes.size() != numa_node_count || cpulist.size() != numa_node_count)
204 numa_json[
"numa_node_count"] = numa_node_count;
205 numa_json[
"numa_cpu_list"] = boost::json::value_from(cpulist);
206 numa_json[
"numa_node_megabyte"] = boost::json::value_from(sizes);
208 boost::json::array na;
209 for (
size_t i = 0; i < numa_node_count; i++) {
210 boost::json::object o = {
212 {
"node_megabytes", sizes[i]},
213 {
"cpu_list", cpulist[i]}
217 numa_json[
"node_list"] = na;
225 static bool shell_done;
226 static boost::json::object gpu_json;
229 std::cerr <<
"add_host_section: doing gpu" <<std::endl;
231 size_t gpu_count = 0;
236 std::cerr <<
"add_host_section: parsing gpu" <<std::endl;
238 std::vector<std::string> vendor;
239 std::vector<std::string> device;
240 std::vector<std::string> rev;
241 std::vector<int32_t> numa_node;
244 std::istringstream nss(lspci.
output);
245 while (std::getline(nss, line)) {
246 if (line.substr(0,1) ==
"-")
248 size_t cp = line.find(
':');
249 std::string name = line.substr(0, cp);
250 if (name ==
"Class") {
251 std::string cname = boost::algorithm::trim_copy(line.substr(cp+1));
252 if (cname ==
"3D controller") {
254 std::cerr <<
"add_host_section: found gpu " << gpu_count <<std::endl;
259 std::cerr <<
"add_host_section: found non-gpu " << cname <<std::endl;
264 if (name ==
"Vendor" ) {
265 vendor.push_back(boost::algorithm::trim_copy(line.substr(cp+1)));
268 if (name ==
"Device" ) {
269 device.push_back(boost::algorithm::trim_copy(line.substr(cp+1)));
272 if (name ==
"Rev" ) {
273 rev.push_back(boost::algorithm::trim_copy(line.substr(cp+1)));
276 if (name ==
"NUMANode" ) {
277 std::istringstream iss(line.substr(cp+1));
280 numa_node.push_back(nn);
284 if (vendor.size() != gpu_count ||
285 device.size() != gpu_count ||
286 rev.size() != gpu_count ||
287 numa_node.size() != gpu_count) {
289 std::cerr <<
"add_host_section: size mismatch " <<
299 gpu_json[
"gpu_count"] = gpu_count;
300 boost::json::array ga;
301 for (
size_t i = 0; i < gpu_count; i++) {
302 boost::json::object o = {
304 {
"numa_node", numa_node[i]},
305 {
"vendor", vendor[i]},
306 {
"device", device[i]},
311 gpu_json[
"gpulist"] = ga;
315 std::cerr <<
"add_host_section: lspci fail " << lspci.
rc <<std::endl;
322#define MEMINFO_FILE "/proc/meminfo"
331static std::map<std::string, uint64_t> midata = {
336 {
"SReclaimable", 0 },
340 {
"MemAvailable", 0 },
355 while (std::getline(in, line)) {
356 size_t cp = line.find(
':');
357 std::string name = line.substr(0, cp);
358 if (name ==
"MemTotal") {
359 std::istringstream iss(line.substr(cp+1));
381 while (std::getline(in, line)) {
382 size_t cp = line.find(
':');
383 std::string name = line.substr(0, cp);
384 auto it = midata.find(name);
385 if (it != midata.end()) {
386 std::istringstream iss(line.substr(cp+1));
391 std::cerr <<
"error reading value for " << it->first << std::endl;
397#ifdef ADC_MEMINFO_DEBUG
398 std::cerr <<
"parsed meminfo." << name << std::endl;
404 midata[
"MemUsed"] = midata[
"MemTotal"] - midata[
"MemFree"];
405 midata[
"SwapUsed"] = midata[
"SwapTotal"] - midata[
"SwapFree"];
406 midata[
"CachedAll"] = midata[
"Cached"] + midata[
"SReclaimable"];
407 if (midata[
"MemAvailable"] > midata[
"MemTotal"]) {
408 midata[
"MemAvailable"] = midata[
"MemFree"];
415#ifdef ADC_MEMINFO_DEBUG
416 std::cerr <<
"read meminfo failed" << std::endl;
417 std::cerr <<
"count = " << count << std::endl;
418 std::cerr <<
"mdsize = " << midata.size() << std::endl;
424 const char *env = getenv(
"ADC_BUILDER_DEBUG");
433 uid_t uid = geteuid();
435 struct passwd *pwp =
nullptr;
436 int bsize = sysconf(_SC_GETPW_R_SIZE_MAX);
440 getpwuid_r(uid, &pw, buf, bsize, &pwp);
445 uname =
"<unknown_user>";
448 clock_gettime(CLOCK_REALTIME, &ts);
452 boost::json::object vv = {
457 uuid_generate_random(uuid);
459 uuid_unparse_lower(uuid, uuidbuf);
460 boost::json::value jv = {
461 {
"adc_api_version", vv },
462 {
"timestamp", ts_ns },
463 {
"datestamp", ts_8601 },
465 {
"uid", std::to_string(uid) },
466 {
"application", application_name},
473std::vector<std::string>
split_string(
const std::string& s,
char delimiter)
475 std::vector<std::string> tokens;
476 std::stringstream ss(s);
478 while (std::getline(ss, token, delimiter)) {
479 if (token.length() > 0) {
480 tokens.push_back(token);
486std::vector<std::string> builder::get_host_env_vars()
488 const char *env = getenv(
"ADC_HOST_SECTION_ENV");
492 std::vector<std::string> s;
496#define ADC_HS_BAD ~(ADC_HS_ALL)
503 std::cerr <<
"bad arg to add_host_section: " << subsections <<std::endl;
508 int uerr = uname(&ubuf);
511 std::cerr <<
"uname failed in add_host_section" <<std::endl;
515 boost::json::object jv = {
516 {
"name", std::string(ubuf.nodename) }
519 jv[
"os_family"] = std::string(ubuf.sysname);
520 jv[
"os_version"] = std::string(ubuf.release);
521 jv[
"os_arch"] = std::string(ubuf.machine);
522 jv[
"os_build"] = std::string(ubuf.version);
525 std::vector<std::string> env_vars = get_host_env_vars();
526 for (
auto it = env_vars.begin();
527 it != env_vars.end(); it++) {
528 const char *s = getenv(it->c_str());
531 jv[*it] = std::string(s);
535 if (midata[
"valid"] == 1) {
536 jv[
"mem_total"] = midata[
"MemTotal"];
539 if (midata[
"valid"] == 1)
540 jv[
"mem_total"] = midata[
"MemTotal"];
546 boost::system::error_code ec;
548 auto cv = boost::json::parse(lscpu, ec);
551 std::cerr <<
"unable to parse ("<< ec <<
") lscpu output: " <<
572 auto app_data_derived = std::dynamic_pointer_cast<builder>(app_data);
573 boost::json::object no_details;
574 d[
"app_data"] = app_data_derived ? app_data_derived->flatten() : no_details;
579 if (midata[
"valid"] == 0) {
580 boost::json::object jv;
581 d[
"memory_usage"] = jv;
585 boost::json::value jv = {
586 {
"mem_total", midata[
"MemTotal"]},
587 {
"mem_used", midata[
"MemUsed"]},
588 {
"mem_free", midata[
"MemFree"]},
589 {
"mem_shared", midata[
"Shmem"]},
590 {
"mem_buffers", midata[
"Buffers"]},
591 {
"mem_cache", midata[
"CachedAll"]},
592 {
"mem_available", midata[
"MemAvailable"]},
593 {
"swap_total", midata[
"SwapTotal"]},
594 {
"swap_used", midata[
"SwapUsed"]},
595 {
"swap_free", midata[
"SwapFree"]}
597 d[
"memory_usage"] = jv;
604 auto model_data_derived = std::dynamic_pointer_cast<builder>(model_data);
605 boost::json::object no_details;
606 d[
"model_data"] = model_data_derived ? model_data_derived->flatten() : no_details;
613 std::string fullpath =
get_exe(4096);
614 const char *basename = strrchr(fullpath.c_str(),
'/');
616 basename = fullpath.c_str();
619 std::vector< std::string> libs =
get_libs(fullpath);
620 auto code_details_derived = std::dynamic_pointer_cast<builder>(code_details);
621 auto version_derived = std::dynamic_pointer_cast<builder>(
version);
622 boost::json::object no_details;
623 boost::json::value jv = {
625 {
"program", basename},
627 {
"version", version_derived ? version_derived->d : no_details},
628 {
"libs", boost::json::value_from(libs) },
629 {
"details", code_details_derived ?
630 code_details_derived->flatten() : no_details}
638 auto build_details_derived = std::dynamic_pointer_cast<builder>(build_details);
639 if (build_details_derived) {
640 d[
"code_configuration"] = build_details_derived->flatten();
642 boost::json::object no_details;
643 d[
"code_configuration"] = no_details;
650 auto status_details_derived = std::dynamic_pointer_cast<builder>(status_details);
651 if (status_details && status_details_derived) {
652 boost::json::value jv = {
653 {
"return_code", std::to_string(return_code)},
655 {
"details", status_details_derived->flatten()}
659 boost::json::object no_details;
660 boost::json::value jv = {
661 {
"return_code", std::to_string(return_code)},
663 {
"details", no_details }
675 auto nk = kind(name);
677 auto section_derived = std::dynamic_pointer_cast<builder>(section);
678 if (!section_derived) {
681 sections[std::string(name)] = std::move(section_derived);
687 auto nk = kind(name);
689 return sections[std::string(name)];
691 return std::shared_ptr< builder_api >(
nullptr);
696 std::vector< std::string > result;
697 result.reserve(sections.size());
698 for (
const auto& element : sections) {
699 result.push_back(element.first);
708 std::vector< std::string > result;
709 for (
auto const& element : d) {
710 result.push_back(element.key());
717 boost::json::string *s;
721 f.
vp = &std::get< bool >(f.
data);
725 f.
data =
variant(
static_cast<char>(*(v->if_int64())));
726 f.
vp = &std::get< char >(f.
data);
730 f.
data =
variant(
static_cast<char16_t>(*(v->if_uint64())));
731 f.
vp = &std::get< char16_t >(f.
data);
735 f.
data =
variant(
static_cast<char32_t>(*(v->if_uint64())));
736 f.
vp = &std::get< char32_t >(f.
data);
740 f.
data =
variant(
static_cast<uint8_t
>(*(v->if_uint64())));
741 f.
vp = &std::get< uint8_t >(f.
data);
745 f.
data =
variant(
static_cast<uint16_t
>(*(v->if_uint64())));
746 f.
vp = &std::get< uint16_t >(f.
data);
750 f.
data =
variant(
static_cast<uint32_t
>(*(v->if_uint64())));
751 f.
vp = &std::get< uint32_t >(f.
data);
759 std::istringstream iss(ss);
762 f.
vp = &std::get< uint64_t >(f.
data);
767 f.
data =
variant(
static_cast<int8_t
>(*(v->if_int64())));
768 f.
vp = &std::get< int8_t >(f.
data);
772 f.
data =
variant(
static_cast<int16_t
>(*(v->if_int64())));
773 f.
vp = &std::get< int16_t >(f.
data);
777 f.
data =
variant(
static_cast<int32_t
>(*(v->if_int64())));
778 f.
vp = &std::get< int32_t >(f.
data);
783 f.
vp = &std::get< int64_t >(f.
data);
788 f.
vp = &std::get< int64_t >(f.
data);
802#ifdef ADC_GV_STR_DEBUG
803 std::cerr <<
"s c ptr " << (
void*)(s->c_str()) << std::endl;
806#ifdef ADC_GV_STR_DEBUG
807 std::cerr <<
"ss c ptr " << (
void*)(ss.c_str()) << std::endl;
812#ifdef ADC_GV_STR_DEBUG
813 std::cerr <<
"f ptr " << (
void*)&f.
kt << std::endl;
814 std::cerr <<
"f.data " << (
void*)&std::get< std::string >(f.
data) << std::endl;
815 std::cerr <<
"f.data>data " << (
void*)std::get< std::string >(f.
data).data() << std::endl;
817 f.
vp = (&std::get< std::string >(f.
data))->data();
818#ifdef ADC_GV_STR_DEBUG
819 std::cerr <<
"f.vp " << f.
vp << std::endl;
825 f.
data =
variant(
static_cast<float>(*(v->if_double())));
826 f.
vp = &std::get< float >(f.
data);
831 f.
vp = &std::get< double >(f.
data);
834#if ADC_SUPPORT_EXTENDED_FLOATS
839#if ADC_SUPPORT_QUAD_FLOATS
844#if ADC_SUPPORT_GPU_FLOATS
853 std::complex<float> cv(0,0);
855 float re = 0, im = 0;
856 auto a = v->as_array();
858 a[0].is_double() && a[1].is_double() ) {
859 re =
static_cast<float>(a[0].as_double());
860 im =
static_cast<float>(a[1].as_double());
865 f.
vp = &std::get< std::complex<float> >(f.
data);
870 std::complex<double> cv(0,0);
872 double re = 0, im = 0;
873 auto a = v->as_array();
877 re = a[0].as_double();
878 im = a[1].as_double();
883 f.
vp = &std::get< std::complex<double> >(f.
data);
887#if ADC_SUPPORT_EXTENDED_FLOATS
891#if ADC_SUPPORT_QUAD_FLOATS
898 std::array<int64_t, 2> av = {0,0};
900 int64_t sec = 0, subsec = 0;
901 auto a = v->as_array();
905 sec = a[0].as_int64();
906 subsec = a[1].as_int64();
911 f.
vp = &std::get< std::array<int64_t,2> >(f.
data);
927static void fill_array(field& f,
scalar_type st, boost::json::array& a) {
928 auto a_len = a.size();
930 std::shared_ptr<T[]> sa(
new T[a_len]);
933 for (i = 0; i < a_len; i++) {
934 if ( a[i].kind() == json_type) {
935 boost::system::error_code ec;
936 T x = a[i].to_number<T>(ec);
947 f.vp = (std::get< std::shared_ptr<T[]> >(f.data)).get();
951static void fill_array_u64(field& f, boost::json::array& a) {
952 auto a_len = a.size();
954 std::shared_ptr<uint64_t[]> sa(
new uint64_t[a_len]);
956 for (i = 0; i < a_len; i++) {
957 boost::json::string *s = a[i].if_string();
960 std::istringstream iss(ss);
973 f.vp = (std::get< std::shared_ptr<uint64_t[]> >(f.data)).get();
984static void fill_array_complex(field& f, boost::json::array& a) {
985 auto a_len = a.size();
987 std::shared_ptr<std::complex<T>[]> sa(
new std::complex<T>[a_len]);
989 for (i = 0; i < a_len; i++) {
990 if ( a[i].kind() == boost::json::kind::array) {
992 if (pair.as_array().size() != 2) {
996 boost::system::error_code ecr;
997 boost::system::error_code eci;
998 T re = pair.as_array()[0].to_number<T>(ecr);
999 T im = pair.as_array()[1].to_number<T>(eci);
1000 if (!(ecr.failed() || eci.failed())) {
1010 f.vp = (std::get< std::shared_ptr<std::complex<T>[]> >(f.data)).get();
1018 auto a_len = a.size();
1020 std::shared_ptr<bool[]> sa(
new bool[a_len]);
1022 for (i = 0; i < a_len; i++) {
1023 bool* bptr = a[i].if_bool();
1031 f.
vp = (std::get< std::shared_ptr<bool[]> >(f.
data)).get();
1036 auto a_len = a.size();
1038 std::shared_ptr<std::string[]> sa(
new std::string[a_len]);
1040 for (i = 0; i < a_len; i++) {
1041 boost::json::string* sptr = a[i].if_string();
1043 sa[i] = std::string(sptr->c_str());
1045 sa[i] = std::string(
"");
1049 f.
vp = (std::get< std::shared_ptr<std::string[]> >(f.
data)).get();
1053static void get_array(field& f,
scalar_type st, boost::json::value *v)
1055 if (!v->is_array()) {
1059 auto a = v->as_array();
1065 fill_array<char>(f, st, a);
1068 fill_array<char16_t>(f, st, a);
1071 fill_array<char32_t>(f, st, a);
1074 fill_array<uint8_t>(f, st, a);
1077 fill_array<uint16_t>(f, st, a);
1080 fill_array<uint32_t>(f, st, a);
1083 fill_array_u64(f, a);
1086 fill_array<int8_t>(f, st, a);
1089 fill_array<int16_t>(f, st, a);
1092 fill_array<int32_t>(f, st, a);
1095 fill_array<int64_t>(f, st, a);
1108 fill_array<float>(f, st, a);
1111 fill_array<double>(f, st, a);
1113#if ADC_SUPPORT_EXTENDED_FLOATS
1118#if ADC_SUPPORT_QUAD_FLOATS
1123#if ADC_SUPPORT_GPU_FLOATS
1132 fill_array_complex<float>(f, a);
1135 fill_array_complex<double>(f, a);
1137#if ADC_SUPPORT_EXTENDED_FLOATS
1141#if ADC_SUPPORT_QUAD_FLOATS
1155 auto path =
strip(path_full,
'/');
1158 auto pos = path.find(
"/");
1159 std::string_view name;
1160 if (pos == std::string::npos) {
1163 name = std::string_view(path.begin(), pos);
1166 const boost::json::value jv = d;
1167 const boost::json::value * jit;
1168 boost::system::error_code ec;
1169 auto child = path.substr(pos);
1174 return sections[std::string(name)]->get_value(child);
1176 jit = d[name].find_pointer(child, ec);
1179 std::cerr <<
"get_value json missing: " << child <<
": " << ec.message() << std::endl;
1184 std::cerr <<
"get_value found: " << child <<
": " << *jit << std::endl;
1189 if (jit->kind() == boost::json::kind::object) {
1190 auto obj = jit->as_object();
1191 auto v = obj.if_contains(
"value");
1192 auto type_name_v = obj.if_contains(
"type");
1193 std::string type_name;
1195 type_name = *(type_name_v->if_string());
1197 if (v && type_name.size()) {
1198 auto c = obj.if_contains(
"container_type");
1202 get_scalar(f, st, v);
1207 get_array(f, st, v);
1212 if (jit->kind() == boost::json::kind::array) {
1216 if (jit->kind() == boost::json::kind::object) {
1220 if (jit->kind() == boost::json::kind::string) {
1224 f.
vp = jit->if_string()->c_str();
1225 f.
count = jit->if_string()->size();
1228 if (jit->kind() == boost::json::kind::bool_) {
1231 f.
vp = jit->if_bool();
1235 if (jit->kind() == boost::json::kind::int64) {
1238 f.
vp = jit->if_int64();
1242 if (jit->kind() == boost::json::kind::uint64) {
1245 f.
vp = jit->if_uint64();
1249 if (jit->kind() == boost::json::kind::double_) {
1252 f.
vp = jit->if_double();
1271 return static_cast<const char *
>(f.
vp);
1281 int64_t i = INT64_MAX;
1284 i = *
static_cast<const bool *
>(f.
vp);
1289 i = *
static_cast<const uint64_t *
>(f.
vp);
1300 i = *
static_cast<const int64_t *
>(f.
vp);
1312 uint64_t i = UINT64_MAX;
1315 i = *
static_cast<const bool *
>(f.
vp);
1320 i = *
static_cast<const uint64_t *
>(f.
vp);
1327 i = *
static_cast<const int64_t *
>(f.
vp);
1330 i = std::stoull(std::string(
static_cast<const char *
>(f.
vp)));
1342 std::string commname = std::string(
"mpi_comm_") += name;
1344 if (*(MPI_Comm *)mpi_comm_p == MPI_COMM_NULL)
1346 MPI_Comm *comm = (MPI_Comm *)mpi_comm_p;
1347 boost::json::object jv;
1351 err = MPI_Comm_rank(*comm, &rank);
1353 jv[
"mpi_rank"] = rank;
1359 err = MPI_Comm_size(*comm, &size);
1361 jv[
"mpi_size"] = size;
1366 char name[MPI_MAX_OBJECT_NAME];
1368 err = MPI_Comm_get_name(*comm, name, &len);
1370 jv[
"mpi_name"] = name;
1374 int major=0, minor=0;
1376 err = MPI_Get_version(&major, &minor);
1377 std::ostringstream mversion;
1378 mversion << MPI_VERSION <<
"." << MPI_SUBVERSION;
1380 jv[
"mpi_version"] = mversion.str();
1386 std::ostringstream lversion;
1388#define USE_set_lib_version
1389 lversion <<
"OpenMPI " << OMPI_MAJOR_VERSION <<
"." <<
1390 OMPI_MINOR_VERSION <<
"." << OMPI_RELEASE_VERSION;
1391 goto set_lib_version;
1393#ifdef MVAPICH2_VERSION
1394#define USE_set_lib_version
1395 lversion << MVAPICH2_VERSION;
1396 goto set_lib_version;
1399#define USE_set_lib_version
1400 lversion << MPICH_VERSION;
1401 goto set_lib_version;
1405 char lv[MPI_MAX_LIBRARY_VERSION_STRING];
1407 err = MPI_Get_library_version(lv, &sz);
1409#ifdef USE_set_lib_version
1413 jv[
"mpi_library_version"] = lversion.str();
1419 err = MPI_Comm_rank(*comm, &rank);
1424 err = MPI_Comm_size(*comm, &size);
1428 char *hostnames = (
char *)calloc(size*MPI_MAX_PROCESSOR_NAME, 1);
1430 MPI_Get_processor_name(hostnames + rank * MPI_MAX_PROCESSOR_NAME, &nlen);
1431 MPI_Allgather(hostnames + rank * MPI_MAX_PROCESSOR_NAME,
1432 MPI_MAX_PROCESSOR_NAME,
1435 MPI_MAX_PROCESSOR_NAME,
1439 std::vector<std::string> rh;
1440 for (
auto i = 0; i < size; i++)
1441 rh.push_back(std::string(hostnames + rank * MPI_MAX_PROCESSOR_NAME));
1444 boost::json::array av(rh.begin(), rh.end());
1445 jv[
"mpi_rank_host"] = av;
1449 std::vector<std::string> hl;
1450 std::set<std::string> hm;
1451 for (
auto i = 0; i < size; i++)
1452 hm.insert(std::string(hostnames + rank * MPI_MAX_PROCESSOR_NAME));
1453 for (
auto i = 0; i < size; i++) {
1454 std::string stmp(hostnames + rank * MPI_MAX_PROCESSOR_NAME);
1455 if (hm.count(stmp)) {
1460 boost::json::array hv(hl.begin(), hl.end());
1461 jv[
"mpi_hostlist"] = hv;
1471 boost::json::object jv;
1474 jv[
"mpi_rank"] = rank;
1479 jv[
"mpi_size"] = size;
1483 jv[
"mpi_name"] =
"none";
1487 jv[
"mpi_version"] =
"none";
1491 jv[
"mpi_library_version"] =
"none";
1495 char myhost[HOST_NAME_MAX];
1496 int herr = gethostname(myhost, HOST_NAME_MAX);
1498 sprintf(myhost,
"name_unavailable");
1500 std::vector<std::string> rh;
1501 rh.push_back(myhost);
1502 boost::json::array av(rh.begin(), rh.end());
1505 jv[
"mpi_rank_host"] = av;
1509 jv[
"mpi_hostlist"] = av;
1518 std::vector< std::string >slurmvars;
1524 static std::vector< std::pair<const char *, const char *> > slurm_names =
1526 {
"cluster",
"SLURM_CLUSTER_NAME"},
1527 {
"job_id",
"SLURM_JOB_ID"},
1528 {
"num_nodes",
"SLURM_JOB_NUM_NODES"},
1529 {
"dependency",
"SLURM_JOB_DEPENDENCY"},
1532 boost::json::object jv;
1533 for (
const auto& i : slurm_names) {
1534 const char *val = getenv(i.second);
1540 for (
const auto& i : slurmvars) {
1541 const char *val = getenv(i.c_str());
1552 static std::vector< std::pair<const char *, const char *> > names =
1554 {
"wfid",
"ADC_WFID"},
1555 {
"wfid_parent",
"ADC_WFID_PARENT"},
1556 {
"wfid_path",
"ADC_WFID_PATH"}
1559 boost::json::object jv;
1560 for (
const auto& i : names) {
1561 const char *val = getenv(i.second);
1567 boost::json::array av;
1568 const char *cenv = getenv(
"ADC_WFID_CHILDREN");
1571 std::stringstream ss(cenv);
1574 while (getline(ss, elt, pathsep)) {
1575 if (elt.size() > 0) {
1576#ifdef ADC_WORKFLOW_DEBUG
1577 std::cerr << __func__ <<
": add child " << elt << std::endl;
1579 av.emplace_back(elt);
1583 jv[
"wfid_children"] = av;
1584 d[
"adc_workflow"] = jv;
1589 for (
const auto& v : av) {
1590 if (v.is_string() && v.as_string() == uuid) {
1599 auto wsection = d.if_contains(
"adc_workflow");
1601 std::cerr << __func__ <<
": called before add_workflow_section" << std::endl;
1604 if (! wsection->is_object()) {
1605 std::cerr << __func__ <<
": adc_workflow is not an object. (?!)" << std::endl;
1608 auto haschildren = wsection->as_object().if_contains(
"wfid_children");
1610 std::cerr << __func__ <<
": called before successful add_workflow_section" << std::endl;
1613 auto children = wsection->as_object()[
"wfid_children"];
1614 if (!children.is_array()) {
1615 std::cerr << __func__ <<
": wfid_children is not an array. (?!)" << std::endl;
1618 for (
auto const& uuid : child_uuids) {
1622 wsection->as_object()[
"wfid_children"].as_array().emplace_back(uuid);
1629 static const std::vector<std::string > gitlab_ci_names = {
1631 "CI_RUNNER_VERSION",
1635 "CI_SERVER_VERSION",
1637 "CI_JOB_STARTED_AT",
1639 "CI_PIPELINE_SOURCE",
1643 boost::json::object jv;
1644 for (
const auto& i : gitlab_ci_names) {
1645 const char *val = getenv(i.c_str());
1651 d[
"gitlab_ci"] = jv;
1655 if (
badkey(name))
return;
1656 boost::json::value jv = {
1664 if (
badkey(name))
return;
1665 boost::json::value jv = {
1673 if (
badkey(name))
return;
1674 uint64_t ivalue = value;
1675 boost::json::value jv = {
1683 if (
badkey(name))
return;
1684 uint64_t ivalue = value;
1685 boost::json::value jv = {
1694 if (
badkey(name))
return;
1695 boost::json::value jv = {
1702 if (
badkey(name))
return;
1703 boost::json::value jv = {
1710 if (
badkey(name))
return;
1711 boost::json::value jv = {
1718 if (
badkey(name))
return;
1719 boost::json::value jv = {
1728 if (
badkey(name))
return;
1729 boost::json::value jv = {
1736 if (
badkey(name))
return;
1737 boost::json::value jv = {
1744 if (
badkey(name))
return;
1745 boost::json::value jv = {
1752 if (
badkey(name))
return;
1753 boost::json::value jv = {
1762 if (
badkey(name))
return;
1763 boost::json::value jv = {
1771 if (
badkey(name))
return;
1772 boost::json::value jv = {
1780 if (
badkey(name))
return;
1781 boost::json::value jv = {
1789 if (
badkey(name))
return;
1790 boost::json::value jv = {
1797#if ADC_BOOST_JSON_PUBLIC
1798void builder::add(std::string_view name, boost::json::value value) {
1799 if (
badkey(name))
return;
1800 boost::json::value jv = {
1810 if (
badkey(name))
return;
1811 boost::json::value jv = {
1818 if (
badkey(name))
return;
1819 boost::json::value jv = {
1826 if (
badkey(name))
return;
1827 boost::json::value jv = {
1834 if (
badkey(name))
return;
1835 boost::json::value jv = {
1837 {
"value", std::to_string(value)}
1842 if (
badkey(name))
return;
1843 boost::json::value jv = {
1850 if (
badkey(name))
return;
1851 boost::json::value jv = {
1858 if (
badkey(name))
return;
1859 boost::json::value jv = {
1866 if (
badkey(name))
return;
1867 boost::json::value jv = {
1874 if (
badkey(name))
return;
1875 boost::json::value jv = {
1881void builder::add(std::string_view name,
const std::complex<float>& value) {
1882 if (
badkey(name))
return;
1883 boost::json::value jv = {
1885 {
"value", { value.real(), value.imag() }}
1890 if (
badkey(name))
return;
1891 boost::json::value jv = {
1897void builder::add(std::string_view name,
const std::complex<double>& value) {
1898 if (
badkey(name))
return;
1899 boost::json::value jv = {
1901 {
"value", { value.real(), value.imag() }}
1908 if (
badkey(name))
return;
1909 boost::json::value jv = {
1911 {
"value", { (int64_t)tv.tv_sec, (int64_t)tv.tv_usec }}
1917 if (
badkey(name))
return;
1918 boost::json::value jv = {
1920 {
"value", { (int64_t)ts.tv_sec, (int64_t)ts.tv_nsec }}
1926 if (
badkey(name))
return;
1927 boost::json::value jv = {
1937 if (
badkey(name))
return;
1941 bool *v = (
bool *)p;
1947 char *v = (
char *)p;
1953 char16_t *v = (
char16_t *)p;
1959 char32_t *v = (
char32_t *)p;
1965 char *v = (
char *)p;
1971 char *v = (
char *)p;
1977 char *v = (
char *)p;
1983 char *v = (
char *)p;
1987#if ADC_BOOST_JSON_PUBLIC
1993 char *v = (
char *)p;
1999 char *v = (
char *)p;
2005 uint8_t *v = (uint8_t *)p;
2011 uint16_t *v = (uint16_t *)p;
2017 uint32_t *v = (uint32_t *)p;
2023 uint64_t *v = (uint64_t *)p;
2029 int8_t *v = (int8_t *)p;
2035 int16_t *v = (int16_t *)p;
2041 int32_t *v = (int32_t *)p;
2047 int64_t *v = (int64_t *)p;
2053 float *v = (
float *)p;
2059 double *v = (
double *)p;
2063#if ADC_SUPPORT_EXTENDED_FLOATS
2067 __float80 *v = (__float80 *)p;
2072#if ADC_SUPPORT_QUAD_FLOATS
2075 __float128 *v = (__float128 *)p;
2080#if ADC_SUPPORT_GPU_FLOATS
2104 float *v = (
float *)p;
2105 std::complex<float> c(v[0], v[1]);
2111 double *v = (
double *)p;
2112 std::complex<double> c(v[0], v[1]);
2116#if ADC_SUPPORT_QUAD_FLOATS
2119 __float128 *v = (__float128 *)p;
2120 std::complex<__float128> c(v[0], v[1]);
2125#if ADC_SUPPORT_EXTENDED_FLOATS
2129 __float80 *v = (__float80 *)p;
2130 std::complex<__float80> c(v[0], v[1]);
2137 struct timespec *v = (
struct timespec *)p;
2143 struct timeval *v = (
struct timeval *)p;
2149 int64_t *v = (int64_t *)p;
2159 if (
badkey(name))
return;
2160 boost::json::array av(value, value+len);
2161 boost::json::value jv = {
2163 {
"container_type", c},
2170 if (
badkey(name))
return;
2171 boost::json::array av(value, value+len);
2172 boost::json::value jv = {
2174 {
"container_type", c},
2181 if (
badkey(name))
return;
2182 boost::json::array av(value, value+len);
2183 boost::json::value jv = {
2185 {
"container_type", c},
2192 if (
badkey(name))
return;
2193 boost::json::array av(value, value+len);
2194 boost::json::value jv = {
2196 {
"container_type", c},
2203 if (
badkey(name))
return;
2204 boost::json::array av(value, value+len);
2205 boost::json::value jv = {
2207 {
"container_type", c},
2213 if (
badkey(name))
return;
2214 boost::json::array av(value, value+len);
2215 boost::json::value jv = {
2217 {
"container_type", c},
2223 if (
badkey(name))
return;
2224 boost::json::array av(value, value+len);
2225 boost::json::value jv = {
2227 {
"container_type", c},
2233 if (
badkey(name))
return;
2234 std::vector<std::string> sv(len);
2235 for (
size_t i = 0; i < len; i++)
2236 sv[i] = std::to_string(value[i]);
2237 boost::json::array av(sv.begin(), sv.end());
2238 boost::json::value jv = {
2240 {
"container_type", c},
2246 if (
badkey(name))
return;
2247 boost::json::array av(value, value+len);
2248 boost::json::value jv = {
2250 {
"container_type", c},
2256 if (
badkey(name))
return;
2257 boost::json::array av(value, value+len);
2258 boost::json::value jv = {
2260 {
"container_type", c},
2266 if (
badkey(name))
return;
2267 boost::json::array av(value, value+len);
2268 boost::json::value jv = {
2270 {
"container_type", c},
2276 if (
badkey(name))
return;
2277 boost::json::array av(value, value+len);
2278 boost::json::value jv = {
2280 {
"container_type", c},
2286 if (
badkey(name))
return;
2287 boost::json::array av(value, value+len);
2288 boost::json::value jv = {
2290 {
"container_type", c},
2296void builder::add_array(std::string_view name,
const std::complex<float> value[],
size_t len, std::string_view c) {
2297 if (
badkey(name))
return;
2298 boost::json::array av(value, value+len);
2299 boost::json::value jv = {
2301 {
"container_type", c},
2302 {
"value", { value.real(), value.imag() }}
2308 if (
badkey(name))
return;
2309 boost::json::array av(value, value+len);
2310 boost::json::value jv = {
2312 {
"container_type", c},
2318void builder::add_array(std::string_view name,
const std::complex<double> value[],
size_t len, std::string_view c) {
2319 if (
badkey(name))
return;
2320 boost::json::array av(value, value+len);
2321 boost::json::value jv = {
2323 {
"container_type", c},
2324 {
"value", { value.real(), value.imag() }}
2331 if (
badkey(name))
return;
2332 boost::json::array av(value, value+len);
2333 boost::json::value jv = {
2335 {
"container_type", c},
2341 if (
badkey(name))
return;
2342 boost::json::array av(value, value+len);
2343 boost::json::value jv = {
2345 {
"container_type", c},
2351 if (
badkey(name))
return;
2352 boost::json::array av(value, value+len);
2353 boost::json::value jv = {
2355 {
"container_type", c},
2360void builder::add_array(std::string_view name,
const std::string value[],
size_t len, std::string_view c) {
2361 if (
badkey(name))
return;
2362 boost::json::array av(value, value+len);
2363 boost::json::value jv = {
2365 {
"container_type", c},
2370void builder::add_array(std::string_view name,
const std::vector<std::string> value, std::string_view c) {
2371 if (
badkey(name))
return;
2372 boost::json::value jv = {
2374 {
"container_type", c},
2375 {
"value", boost::json::value_from(value)}
2380 if (
badkey(name))
return;
2381 boost::json::value jv = {
2383 {
"container_type", c},
2384 {
"value", boost::json::value_from(value)}
2389 if (
badkey(name))
return;
2390 boost::json::value jv = {
2392 {
"container_type", c},
2393 {
"value", boost::json::value_from(value)}
2399 if (
badkey(name))
return;
2400 boost::json::array av(value, value+len);
2401 boost::json::value jv = {
2403 {
"container_type", c},
2413boost::json::object builder::flatten()
2415 boost::json::object tot(d);
2416 for (
auto it = sections.begin(); it != sections.end(); it++) {
2417 tot[it->first] = it->second->flatten();
2423 boost::json::object total;
2425 return boost::json::serialize(total);
2428key_type builder::kind(std::string_view name) {
2429 auto sit = sections.find(std::string(name));
2430 if (sit != sections.end())
2432 auto jit = d.find(name);
std::shared_ptr< builder_api > get_section(std::string_view name)
get the existing named section
std::vector< std::string > get_section_names()
get the names of sections
builder(void *mpi_communicator_p=NULL)
void add_json_string(std::string_view name, std::string_view value)
add string which is serialized json.
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...
void add_code_configuration_section(std::shared_ptr< builder_api > build_details)
Populate build/install "configuration" information such as options enabled.
void add_model_data_section(std::shared_ptr< builder_api > model_data)
populate application run-time physics (re)configuration/result to "model_data" section....
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.
void add_xml_string(std::string_view name, std::string_view value)
add string which is xml.
void add_yaml_string(std::string_view name, std::string_view value)
add string which is yaml.
void add(std::string_view name, bool value)
add a named boolean
void add_host_section(int32_t subsections)
auto-populate the "host" section based on bitflags. There are many optional subsections covering cpus...
const char * get_value_string(std::string_view path)
get the existing named nested scalar string value.
void add_workflow_section()
add data from adc_wfid_ environment variables. The section name is "adc_workflow".
void add_array(std::string_view name, bool value[], size_t len, std::string_view c)
Fixed length arrays of scalar members.
void add_from_pointer_type(std::string_view name, void *, enum scalar_type t)
add data from a c pointer
void add_number_string(std::string_view name, std::string_view value)
add string which is an arbitrary precision decimal number
void add_gitlab_ci_section()
add gitlab_ci environment variable dictionary. The section added is named "gitlab_ci".
void add_section(std::string_view name, std::shared_ptr< builder_api > section)
copy populated generic section into the builder under specified name.
void add_memory_usage_section()
populate "memory_usage" section with current host /proc/meminfo data in the style of free(1).
void add_code_section(std::string tag, std::shared_ptr< builder_api > version, std::shared_ptr< builder_api > code_details)
std::vector< std::string > get_field_names()
get the names of non-section fields in the section
uint64_t get_value_uint64(std::string_view path)
get the existing named scalar value that can be correctly cast as int64_t
const field get_value(std::string_view path)
get the existing named nested field in the builder.
int64_t get_value_int64(std::string_view path)
get the existing named scalar value that can be correctly cast as int64_t
void add_slurm_section()
add slurm output environment variable dictionary elements. The section added is named "slurm".
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.
void add_epoch(std::string_view name, int64_t epoch)
add unix epoch seconds (gettimeofday)
void add_app_data_section(std::shared_ptr< builder_api > app_data)
create the "app_data" section with data defined by the application writer.
void add_path(std::string_view name, char *value)
add null-terminated string filepath
std::string serialize()
convert object to a json string reflecting the section hierarchy.
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....
void add_header_section(std::string_view application_name)
auto-populate the "header" section with application name and required local data
static pipe_data run(const std::string &proc)
std::string get_default_affinity()
std::string format_timespec_utc_ns(struct timespec &ts)
key_type
when expanding scalar_type, always update enum.ipp to match.
scalar_type scalar_type_from_name(const std::string &name)
get the enum representation of a scalar_type string
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.
const std::string to_string(float f)
get string of float using to_chars.
std::string format_timespec_8601(struct timespec &ts)
scalar_type
field types for scientific data encode/decode with json.
@ cp_xml_str
c null-terminated string that contains valid xml
@ cp_epoch
time(NULL) seconds since the epoch (UNIX) as int64_t
@ cp_f16_e8m7
16 bit bfloat (7 mantissa, 8 exponent); requires ADC_SUPPORT_GPU_FLOATS support
@ cp_path
c null-terminated string which names a file-system path
@ cp_json_str
c null-terminated string that contains valid json
@ cp_timespec
(second, nanosecond) as int64_t, int64_t pair from clock_gettime
@ cp_timeval
gettimeofday struct timeval (second, microsecond) as int64_t pair
@ cp_c_f64
complex<double>
@ cp_bool
bool (true/false,1/0)
@ cp_f128
128 bit float; requires ADC_SUPPORT_QUAD_FLOATS support
@ cp_json
json value (object, list, etc)
@ cp_c_f80
complex<extended>; requires ADC_SUPPORT_EXTENDED_FLOATS support
@ cp_number_str
c null-terminated string containing an exact decimal representation of arbitrary precision
@ cp_f80
80 bit float; requires ADC_SUPPORT_EXTENDED_FLOATS support
@ cp_yaml_str
c null-terminated string that contains valid yaml
@ cp_f16_e5m10
16 bit float (10 mantissa, 5 exponent); requires ADC_SUPPORT_GPU_FLOATS support
@ cp_c_f128
complex<quad>; requires ADC_SUPPORT_QUAD_FLOATS support
@ cp_cstr
c null-terminated string
@ cp_f8_e5m2
8 bit float (2 mantissa, 5 exponent); requires ADC_SUPPORT_GPU_FLOATS support
@ cp_f8_e4m3
8 bit float (3 mantissa, 4 exponent); requires ADC_SUPPORT_GPU_FLOATS support
#define ADC_HS_GPU
ADC_HS_GPU collects gpu data available from lspci (requires lspci installed)
#define ADC_HS_RAMSIZE
ADC_HS_RAMSIZE collects MemTotal.
#define ADC_HS_OS
ADC_HS_OS collects other items from uname().
#define ADC_HS_CPU
ADC_HS_CPU collects details from lscpu -J (requires lscpu installed)
#define ADC_HS_NUMA
ADC_HS_NUMA collects numa node, cpu, and per node memory from numactl -H (requires numactl installed)
#define ADC_HS_ENV
ADC_HS_ENV collects env vars listed in env("ADC_HOST_SECTION_ENV") which is :-separated....
#define ADC_MPI_NAME
include "mpi_name" field from mpi_comm_name
#define ADC_MPI_RANK
include "mpi_rank" field from mpi_comm_rank
#define ADC_MPI_VER
include "mpi_version" field from MPI_VERSION.MPI_SUBVERSIUON
#define ADC_MPI_LIB_VER
include mpi_get_library_version result.
int32_t adc_mpi_field_flags
#define ADC_MPI_RANK_HOST
include "mpi_rank_host" subsection from the communicator
#define ADC_MPI_SIZE
include "mpi_size" field from mpi_comm_size
#define ADC_MPI_NONE
include no mpi fields
#define ADC_MPI_HOSTLIST
include "mpi_hostlist" subsection from the communicator
std::string_view strip(std::string_view s, char c='/')
boost::json::kind scalar_type_representation(scalar_type st)
void fill_array_bool(field &f, boost::json::array &a)
std::string get_exe(size_t bufsize)
std::string_view string_view
boost::json::object get_gpu_data(bool debug)
void fill_array_string(field &f, boost::json::array &a)
std::vector< std::string > get_libs(std::string_view)
void update_meminfo(bool debug)
bool badkey(std::string_view)
boost::json::object get_numa_hardware()
std::vector< std::string > split_string(const std::string &s, char delimiter)
std::string tolower_s(std::string s)
bool array_contains_string(boost::json::array &av, string_view uuid)
std::string container
name of the container variety given to see builder::add_array
scalar_type st
scalar type of the data as published,
size_t count
number of elements in vp.
key_type kt
kind of data associated with the name queried
const void * vp
address of data to be cast according to st for use with c/fortran
A version with tags list.