qclib-2.1.0/0000775000175000017500000000000013647300120011626 5ustar rasplrasplqclib-2.1.0/qc_test.c0000664000175000017500000011457013647300120013444 0ustar rasplraspl/* Copyright IBM Corp. 2013, 2019 */ #include #include #include #include #include "query_capacity.h" int err_cnt = 0; int attr_indent = 34; void print_break() { printf("\n"); } void print_separator(int indent) { printf("\n\n"); } void print_header(int indent, int layer, const char* layer_name) { printf("%*s===== Layer %d: %s =============================================\n", indent, "", layer, layer_name); } const char *attr2char(enum qc_attr_id id) { switch (id) { case qc_layer_type: return "qc_layer_type"; case qc_layer_category: return "qc_layer_category"; case qc_layer_type_num: return "qc_layer_type_num"; case qc_layer_category_num: return "qc_layer_category_num"; case qc_layer_name: return "qc_layer_name"; case qc_layer_extended_name: return "qc_layer_extended_name"; case qc_layer_uuid: return "qc_layer_uuid"; case qc_manufacturer: return "qc_manufacturer"; case qc_type: return "qc_type"; case qc_model_capacity: return "qc_model_capacity"; case qc_model: return "qc_model"; case qc_type_name: return "qc_type_name"; case qc_type_family: return "qc_type_family"; case qc_sequence_code: return "qc_sequence_code"; case qc_lic_identifier: return "qc_lic_identifier"; case qc_plant: return "qc_plant"; case qc_num_cpu_total: return "qc_num_cpu_total"; case qc_num_cpu_configured: return "qc_num_cpu_configured"; case qc_num_cpu_standby: return "qc_num_cpu_standby"; case qc_num_cpu_reserved: return "qc_num_cpu_reserved"; case qc_num_cpu_dedicated: return "qc_num_cpu_dedicated"; case qc_num_cpu_shared: return "qc_num_cpu_shared"; case qc_num_cp_total: return "qc_num_cp_total"; case qc_num_cp_dedicated: return "qc_num_cp_dedicated"; case qc_num_cp_shared: return "qc_num_cp_shared"; case qc_num_ifl_total: return "qc_num_ifl_total"; case qc_num_ifl_dedicated: return "qc_num_ifl_dedicated"; case qc_num_ifl_shared: return "qc_num_ifl_shared"; case qc_capability: return "qc_capability"; case qc_secondary_capability: return "qc_secondary_capability"; case qc_capacity_adjustment_indication: return "qc_capacity_adjustment_indication"; case qc_capacity_change_reason: return "qc_capacity_change_reason"; case qc_partition_number: return "qc_partition_number"; case qc_partition_char: return "qc_partition_char"; case qc_partition_char_num: return "qc_partition_char_num"; case qc_adjustment: return "qc_adjustment"; case qc_cp_absolute_capping: return "qc_cp_absolute_capping"; case qc_ifl_absolute_capping: return "qc_ifl_absolute_capping"; case qc_cp_weight_capping: return "qc_cp_weight_capping"; case qc_ifl_weight_capping: return "qc_ifl_weight_capping"; case qc_cluster_name: return "qc_cluster_name"; case qc_control_program_id: return "qc_control_program_id"; case qc_limithard_consumption: return "qc_limithard_consumption"; case qc_prorated_core_time: return "qc_prorated_core_time"; case qc_cp_limithard_cap: return "qc_cp_limithard_cap"; case qc_cp_capacity_cap: return "qc_cp_capacity_cap"; case qc_ifl_limithard_cap: return "qc_ifl_limithard_cap"; case qc_ifl_capacity_cap: return "qc_ifl_capacity_cap"; case qc_capping: return "qc_capping"; case qc_capping_num: return "qc_capping_num"; case qc_mobility_enabled: return "qc_mobility_enabled"; case qc_has_secure: return "qc_has_secure"; case qc_secure: return "qc_secure"; case qc_has_multiple_cpu_types: return "qc_has_multiple_cpu_types"; case qc_cp_dispatch_limithard: return "qc_cp_dispatch_limithard"; case qc_ifl_dispatch_limithard: return "qc_ifl_dispatch_limithard"; case qc_cp_dispatch_type: return "qc_cp_dispatch_type"; case qc_ifl_dispatch_type: return "qc_ifl_dispatch_type"; case qc_cp_capped_capacity: return "qc_cp_capped_capacity"; case qc_ifl_capped_capacity: return "qc_ifl_capped_capacity"; case qc_num_cp_threads: return "qc_num_cp_threads"; case qc_num_ifl_threads: return "qc_num_ifl_threads"; case qc_num_core_total: return "qc_num_core_total"; case qc_num_core_configured: return "qc_num_core_configured"; case qc_num_core_standby: return "qc_num_core_standby"; case qc_num_core_reserved: return "qc_num_core_reserved"; case qc_num_core_dedicated: return "qc_num_core_dedicated"; case qc_num_core_shared: return "qc_num_core_shared"; case qc_ziip_absolute_capping: return "qc_ziip_absolute_capping"; case qc_ziip_capacity_cap: return "qc_ziip_capacity_cap"; case qc_ziip_capped_capacity: return "qc_ziip_capped_capacity"; case qc_ziip_dispatch_limithard: return "qc_ziip_dispatch_limithard"; case qc_ziip_dispatch_type: return "qc_ziip_dispatch_type"; case qc_ziip_limithard_cap: return "qc_ziip_limithard_cap"; case qc_ziip_weight_capping: return "qc_ziip_weight_capping"; case qc_num_ziip_dedicated: return "qc_num_ziip_dedicated"; case qc_num_ziip_shared: return "qc_num_ziip_shared"; case qc_num_ziip_total: return "qc_num_ziip_total"; case qc_num_ziip_threads: return "qc_num_ziip_threads"; default: break; } return NULL; } void verify_nonexistence(void *hdl, enum qc_attr_id id, int layer) { const char *s; float f; int rc, i; rc = qc_get_attribute_string(hdl, id, layer, &s); if (rc != 0) { printf("Error: Attribute '%s' (nonexistent) definition check as string " "at layer %d returned %d\n", attr2char(id), layer, rc); err_cnt++; } if (s) { printf("Error: Attribute '%s' (nonexistent) retrieval as string " "at layer %d returned %s\n", attr2char(id), layer, s); err_cnt++; } rc = qc_get_attribute_int(hdl, id, layer, &i); if (rc != 0) { printf("Error: Attribute '%s' (nonexistent) definition check as int " "at layer %d returned %d\n", attr2char(id), layer, rc); err_cnt++; } if (i >= 0) { printf("Error: Attribute '%s' (nonexistent) retrieval as int " "at layer %d returned %d\n", attr2char(id), layer, i); err_cnt++; } rc = qc_get_attribute_float(hdl, id, layer, &f); if (rc != 0) { printf("Error: Attribute '%s' (nonexistent) definition check as float " "at layer %d returned %d\n", attr2char(id), layer, rc); err_cnt++; } if (f >= 0) { printf("Error: Attribute '%s' (nonexistent) retrieval as float " "at layer %d returned %f\n", attr2char(id), layer, f); err_cnt++; } } void verify_invalid(void *hdl, enum qc_attr_id id, int layer) { const char *s; float f; int rc, i; rc = qc_get_attribute_string(hdl, id, layer, &s); if (rc >= 0) { printf("Error: Attribute '%s' (nonexistent) definition check as string " "at layer %d returned %d\n", attr2char(id), layer, rc); err_cnt++; } if (s) { printf("Error: Attribute '%s' (nonexistent) retrieval as string " "at layer %d returned %s\n", attr2char(id), layer, s); err_cnt++; } rc = qc_get_attribute_int(hdl, id, layer, &i); if (rc >= 0) { printf("Error: Attribute '%s' (nonexistent) definition check as int " "at layer %d returned %d\n", attr2char(id), layer, rc); err_cnt++; } if (i >= 0) { printf("Error: Attribute '%s' (nonexistent) retrieval as int " "at layer %d returned %d\n", attr2char(id), layer, i); err_cnt++; } rc = qc_get_attribute_float(hdl, id, layer, &f); if (rc >= 0) { printf("Error: Attribute '%s' (nonexistent) definition check as float " "at layer %d returned %d\n", attr2char(id), layer, rc); err_cnt++; } if (f >= 0) { printf("Error: Attribute '%s' (nonexistent) retrieval as float " "at layer %d returned %f\n", attr2char(id), layer, f); err_cnt++; } } int sanity_checks(void *hdl, int layers) { int i, rc; float f; const char *s; rc = qc_get_attribute_string(hdl, qc_layer_type, 0, &s); if (rc <= 0) { printf("Error retrieving qc_layer_type at layer 0\n"); err_cnt++; return 1; } if (strcmp("CEC", s)) { printf("Error: First layer is not of type 'CEC'\n"); err_cnt++; return 2; } rc = qc_get_attribute_string(hdl, qc_layer_type, 1, &s); if (rc <= 0) { printf("Error retrieving qc_layer_type at layer 1\n"); err_cnt++; return 1; } if (strncmp("LPAR", s, strlen("LPAR"))) { printf("Oops. The second lowest layer is not LPAR. " \ "Exiting.\n"); err_cnt++; return 3; } // query/retrieve nonexistent attribute for (i = 0; i <= layers; ++i) verify_invalid(hdl, 78923, i); // Check API NULL pointer (and related) handling qc_close(NULL); qc_get_num_layers(NULL, &rc); if (rc >= 0) { printf("Error: qc_get_num_layers(NULL, &rc) worked, returning '%d'\n", rc); err_cnt++; } rc = qc_get_attribute_string(NULL, qc_layer_type, 0, &s); if (rc >= 0) { printf("Error: qc_get_attribute_string(NULL, qc_layer_type, 0, &rc) worked\n"); err_cnt++; } if (s) { printf("Error: qc_get_attribute_string(NULL, qc_layer_type, 0, &rc) returned string\n"); err_cnt++; } rc = qc_get_attribute_string(hdl, -95, 0, &s); if (rc >= 0) { printf("Error: qc_get_attribute_string(hdl, -95, 0, &rc) worked\n"); err_cnt++; } if (s) { printf("Error: qc_get_attribute_string(hdl, -95, 0, &rc) returned string\n"); err_cnt++; } rc = qc_get_attribute_string(hdl, qc_layer_type, -1, &s); if (rc >= 0) { printf("Error: qc_get_attribute_string(hdl, qc_layer_type, -1, &rc) worked\n"); err_cnt++; } if (s) { printf("Error: qc_get_attribute_string(hdl, qc_layer_type, -1, &rc) returned string\n"); err_cnt++; } rc = qc_get_attribute_int(NULL, qc_layer_type, 0, &i); if (rc >= 0) { printf("Error: qc_get_attribute_int(NULL, qc_layer_type, 0, &rc) worked\n"); err_cnt++; } if (i >= 0) { printf("Error: qc_get_attribute_int(NULL, qc_layer_type, 0, &rc) returned value\n"); err_cnt++; } rc = qc_get_attribute_int(hdl, -95, 0, &i); if (rc >= 0) { printf("Error: qc_get_attribute_int(hdl, -95, 0, &rc) worked\n"); err_cnt++; } if (i >= 0) { printf("Error: qc_get_attribute_int(hdl, -95, 0, &rc) returned value\n"); err_cnt++; } rc = qc_get_attribute_int(hdl, qc_layer_type, -1, &i); if (rc >= 0) { printf("Error: qc_get_attribute_int(hdl, qc_layer_type, -1, &rc) worked\n"); err_cnt++; } if (i >= 0) { printf("Error: qc_get_attribute_int(hdl, qc_layer_type, -1, &rc) returned value\n"); err_cnt++; } rc = qc_get_attribute_float(NULL, qc_layer_type, 0, &f); if (rc >= 0) { printf("Error: qc_get_attribute_float(NULL, qc_layer_type, 0, &rc) worked\n"); err_cnt++; } if (f >= 0) { printf("Error: qc_get_attribute_float(NULL, qc_layer_type, 0, &rc) returned value\n"); err_cnt++; } rc = qc_get_attribute_float(hdl, -95, 0, &f); if (rc >= 0) { printf("Error: qc_get_attribute_float(hdl, -05, 0, &rc) worked\n"); err_cnt++; } if (f >= 0) { printf("Error: qc_get_attribute_float(hdl, -95, 0, &rc) returned value\n"); err_cnt++; } rc = qc_get_attribute_float(hdl, qc_layer_type, -1, &f); if (rc >= 0) { printf("Error: qc_get_attribute_float(hdl, qc_layer_type, -1, &rc) worked\n"); err_cnt++; } if (f >= 0) { printf("Error: qc_get_attribute_float(hdl, qc_layer_type, -1, &rc) returned value\n"); err_cnt++; } return 0; } void print_int_attr(void *hdl, enum qc_attr_id id, char *src, int layer, int indent) { int rc, val; float f; const char *s; rc = qc_get_attribute_int(hdl, id, layer, &val); switch (rc) { case 1: if (val < 0) { printf("Error: Attribute '%s' is defined but not set!\n", attr2char(id)); err_cnt++; return; } printf("%*s%*s [%3s]: %d\n", indent, "", attr_indent, attr2char(id), src, val); break; case 0: if (val >= 0) { printf("Error: Attribute '%s' is not defined but set to %d\n", attr2char(id), val); err_cnt++; return; } printf("%*s%*s [%3s]: \n", indent, "", attr_indent, attr2char(id), src); break; default: printf("Error: Attribute '%s' retrieval as int returned %d\n", attr2char(id), rc); err_cnt++; } // False positive tests rc = qc_get_attribute_string(hdl, id, layer, &s); if (rc != 0) { printf("Error: Attribute '%s' definition check as string (is int) returned rc=%d\n", attr2char(id), rc); err_cnt++; } if (s) { printf("Error: Attribute '%s' retrieval as string (is int) returned %s\n", attr2char(id), s); err_cnt++; } rc = qc_get_attribute_float(hdl, id, layer, &f); if (rc != 0) { printf("Error: Attribute '%s' definition check as float (is int) returned rc=%d\n", attr2char(id), rc); err_cnt++; } if (f >= 0) { printf("Error: Attribute '%s' retrieval as float (is int) returned %f\n", attr2char(id), f); err_cnt++; } } void print_float_attr(void *hdl, enum qc_attr_id id, char *src, int layer, int indent) { float fl; int rc, val; const char *s; rc = qc_get_attribute_float(hdl, id, layer, &fl); switch (rc) { case 1: if (fl < 0) { printf("Error: Attribute '%s' is defined but not set!\n", attr2char(id)); err_cnt++; return; } printf("%*s%*s [%3s]: %f\n", indent, "", attr_indent, attr2char(id), src, fl); break; case 0: if (fl >= 0) { printf("Error: Attribute '%s' is not defined but set to %f\n", attr2char(id), fl); err_cnt++; return; } printf("%*s%*s [%3s]: \n", indent, "", attr_indent, attr2char(id), src); break; default: printf("Error: Attribute '%s' retrieval as int returned %d\n", attr2char(id), rc); err_cnt++; } // False positive tests rc = qc_get_attribute_string(hdl, id, layer, &s); if (rc != 0) { printf("Error: Attribute '%s' definition check as string (is float) returned rc=%d\n", attr2char(id), rc); err_cnt++; } if (s) { printf("Error: Attribute '%s' retrieval as string (is float) returned %s\n", attr2char(id), s); err_cnt++; } rc = qc_get_attribute_int(hdl, id, layer, &val); if (rc != 0) { printf("Error: Attribute '%s' definition check as int (is float) returned rc=%d\n", attr2char(id), rc); err_cnt++; } if (val >= 0) { printf("Error: Attribute '%s' retrieval as int (is float) returned %d\n", attr2char(id), val); err_cnt++; } } void print_string_attr(void *hdl, enum qc_attr_id id, char *src, int layer, int indent) { const char *s; float f; int rc, val; rc = qc_get_attribute_string(hdl, id, layer, &s); switch (rc) { case 1: if (!s) { printf("Error: Attribute '%s' is defined but not set!\n", attr2char(id)); err_cnt++; return; } printf("%*s%*s [%3s]: %s\n", indent, "", attr_indent, attr2char(id), src, s); break; case 0: if (s) { printf("Error: Attribute '%s' is not defined but set to '%s'\n", attr2char(id), s); err_cnt++; return; } printf("%*s%*s [%3s]: \n", indent, "", attr_indent, attr2char(id), src); break; default: printf("Error: Attribute '%s' retrieval as string returned %d\n", attr2char(id), rc); err_cnt++; } // False positive tests rc = qc_get_attribute_int(hdl, id, layer, &val); if (rc != 0) { printf("Error: Attribute '%s' definition check as int (is string) returned rc=%d\n", attr2char(id), rc); err_cnt++; } if (val >= 0) { printf("Error: Attribute '%s' retrieval as int (is string) returned %d\n", attr2char(id), val); err_cnt++; } rc = qc_get_attribute_float(hdl, id, layer, &f); if (rc != 0) { printf("Error: Attribute '%s' definition check as float (is string) returned rc=%d\n", attr2char(id), rc); err_cnt++; } if (f >= 0) { printf("Error: Attribute '%s' retrieval as float (is string) returned %f\n", attr2char(id), f); err_cnt++; } } void print_cec_information(void *hdl, int layer, int indent) { print_header(indent, layer, "CEC"); indent += 2; print_string_attr(hdl, qc_layer_type, "n/a", layer, indent); print_string_attr(hdl, qc_layer_category, "n/a", layer, indent); print_int_attr(hdl, qc_layer_type_num, "n/a", layer, indent); print_int_attr(hdl, qc_layer_category_num, "n/a", layer, indent); print_string_attr(hdl, qc_layer_name, "F V", layer, indent); print_string_attr(hdl, qc_manufacturer, "S V", layer, indent); print_string_attr(hdl, qc_type, "S V", layer, indent); print_string_attr(hdl, qc_type_name, "S ", layer, indent); print_int_attr(hdl, qc_type_family, "S ", layer, indent); print_string_attr(hdl, qc_model_capacity, "S ", layer, indent); print_string_attr(hdl, qc_model, "S ", layer, indent); print_string_attr(hdl, qc_sequence_code, "S V", layer, indent); print_string_attr(hdl, qc_lic_identifier, "S ", layer, indent); print_string_attr(hdl, qc_plant, "S V", layer, indent); print_break(); print_int_attr(hdl, qc_num_core_total, "S ", layer, indent); print_int_attr(hdl, qc_num_core_configured, "S ", layer, indent); print_int_attr(hdl, qc_num_core_standby, "S ", layer, indent); print_int_attr(hdl, qc_num_core_reserved, "S ", layer, indent); print_int_attr(hdl, qc_num_core_dedicated, " hV", layer, indent); print_int_attr(hdl, qc_num_core_shared, " hV", layer, indent); print_break(); print_int_attr(hdl, qc_num_cp_total, " HV", layer, indent); print_int_attr(hdl, qc_num_cp_dedicated, " hV", layer, indent); print_int_attr(hdl, qc_num_cp_shared, " hV", layer, indent); print_int_attr(hdl, qc_num_ifl_total, " HV", layer, indent); print_int_attr(hdl, qc_num_ifl_dedicated, " hV", layer, indent); print_int_attr(hdl, qc_num_ifl_shared, " hV", layer, indent); print_int_attr(hdl, qc_num_ziip_total, " HV", layer, indent); print_int_attr(hdl, qc_num_ziip_dedicated, " hV", layer, indent); print_int_attr(hdl, qc_num_ziip_shared, " hV", layer, indent); print_break(); print_int_attr(hdl, qc_num_cp_threads, "S ", layer, indent); print_int_attr(hdl, qc_num_ifl_threads, "S ", layer, indent); print_int_attr(hdl, qc_num_ziip_threads, "S ", layer, indent); print_break(); print_float_attr(hdl, qc_capability, "S ", layer, indent); print_float_attr(hdl, qc_secondary_capability, "S ", layer, indent); print_int_attr(hdl, qc_capacity_adjustment_indication, "S ", layer, indent); print_int_attr(hdl, qc_capacity_change_reason, "S ", layer, indent); // check an attribute that only exists at a different layer verify_nonexistence(hdl, qc_cp_absolute_capping, layer); } void print_lpar_group_information(void *hdl, int layer, int indent) { print_header(indent, layer, "LPAR-Group"); indent += 2; print_string_attr(hdl, qc_layer_type, "n/a", layer, indent); print_string_attr(hdl, qc_layer_category, "n/a", layer, indent); print_int_attr(hdl, qc_layer_type_num, "n/a", layer, indent); print_int_attr(hdl, qc_layer_category_num, "n/a", layer, indent); print_string_attr(hdl, qc_layer_name, " hV", layer, indent); print_int_attr(hdl, qc_cp_absolute_capping, " hV", layer, indent); print_int_attr(hdl, qc_ifl_absolute_capping, " hV", layer, indent); print_int_attr(hdl, qc_ziip_absolute_capping, " hV", layer, indent); // check an attribute that only exists at a different layer verify_nonexistence(hdl, qc_secondary_capability, layer); } void print_lpar_information(void *hdl, int layer, int indent) { print_header(indent, layer, "LPAR"); indent += 2; print_string_attr(hdl, qc_layer_type, "n/a", layer, indent); print_string_attr(hdl, qc_layer_category, "n/a", layer, indent); print_int_attr(hdl, qc_layer_type_num, "n/a", layer, indent); print_int_attr(hdl, qc_layer_category_num, "n/a", layer, indent); print_string_attr(hdl, qc_layer_name, "S V", layer, indent); print_string_attr(hdl, qc_layer_extended_name, "S ", layer, indent); print_string_attr(hdl, qc_layer_uuid, "S ", layer, indent); print_int_attr(hdl, qc_partition_number, "S V", layer, indent); print_string_attr(hdl, qc_partition_char, "S ", layer, indent); print_int_attr(hdl, qc_partition_char_num, "S ", layer, indent); print_int_attr(hdl, qc_adjustment, "S ", layer, indent); print_int_attr(hdl, qc_has_secure, "F ", layer, indent); print_int_attr(hdl, qc_secure, "F ", layer, indent); print_break(); print_int_attr(hdl, qc_num_core_total, "S ", layer, indent); print_int_attr(hdl, qc_num_core_configured, "S ", layer, indent); print_int_attr(hdl, qc_num_core_standby, "S ", layer, indent); print_int_attr(hdl, qc_num_core_reserved, "S ", layer, indent); print_int_attr(hdl, qc_num_core_dedicated, "S ", layer, indent); print_int_attr(hdl, qc_num_core_shared, "S ", layer, indent); print_break(); print_int_attr(hdl, qc_num_cp_total, " HV", layer, indent); print_int_attr(hdl, qc_num_cp_dedicated, " hV", layer, indent); print_int_attr(hdl, qc_num_cp_shared, " hV", layer, indent); print_int_attr(hdl, qc_num_ifl_total, " HV", layer, indent); print_int_attr(hdl, qc_num_ifl_dedicated, " hV", layer, indent); print_int_attr(hdl, qc_num_ifl_shared, " hV", layer, indent); print_int_attr(hdl, qc_num_ziip_total, " HV", layer, indent); print_int_attr(hdl, qc_num_ziip_dedicated, " hV", layer, indent); print_int_attr(hdl, qc_num_ziip_shared, " hV", layer, indent); print_break(); print_int_attr(hdl, qc_num_cp_threads, "S ", layer, indent); print_int_attr(hdl, qc_num_ifl_threads, "S ", layer, indent); print_int_attr(hdl, qc_num_ziip_threads, "S ", layer, indent); print_int_attr(hdl, qc_cp_absolute_capping, " hV", layer, indent); print_int_attr(hdl, qc_cp_weight_capping, " hV", layer, indent); print_int_attr(hdl, qc_ifl_absolute_capping, " hV", layer, indent); print_int_attr(hdl, qc_ifl_weight_capping, " hV", layer, indent); print_int_attr(hdl, qc_ziip_absolute_capping, " hV", layer, indent); print_int_attr(hdl, qc_ziip_weight_capping, " hV", layer, indent); // check an attribute that only exists at a different layer verify_nonexistence(hdl, qc_secondary_capability, layer); } void print_zvmhyp_information(void *hdl, int layer, int indent) { print_header(indent, layer, "z/VM-hypervisor"); indent += 2; print_string_attr(hdl, qc_layer_type, "n/a", layer, indent); print_string_attr(hdl, qc_layer_category, "n/a", layer, indent); print_int_attr(hdl, qc_layer_type_num, "n/a", layer, indent); print_int_attr(hdl, qc_layer_category_num, "n/a", layer, indent); print_string_attr(hdl, qc_layer_name, " V", layer, indent); print_string_attr(hdl, qc_cluster_name, " V", layer, indent); print_string_attr(hdl, qc_control_program_id, "S ", layer, indent); print_int_attr(hdl, qc_adjustment, "S ", layer, indent); print_int_attr(hdl, qc_limithard_consumption, " V", layer, indent); print_int_attr(hdl, qc_prorated_core_time, " V", layer, indent); print_break(); print_int_attr(hdl, qc_num_core_total, " V", layer, indent); print_int_attr(hdl, qc_num_core_dedicated, " V", layer, indent); print_int_attr(hdl, qc_num_core_shared, " V", layer, indent); print_break(); print_int_attr(hdl, qc_num_cp_total, " V", layer, indent); print_int_attr(hdl, qc_num_cp_dedicated, " V", layer, indent); print_int_attr(hdl, qc_num_cp_shared, " V", layer, indent); print_int_attr(hdl, qc_num_ifl_total, " V", layer, indent); print_int_attr(hdl, qc_num_ifl_dedicated, " V", layer, indent); print_int_attr(hdl, qc_num_ifl_shared, " V", layer, indent); print_int_attr(hdl, qc_num_ziip_total, " V", layer, indent); print_int_attr(hdl, qc_num_ziip_dedicated, " V", layer, indent); print_int_attr(hdl, qc_num_ziip_shared, " V", layer, indent); print_break(); print_int_attr(hdl, qc_num_cp_threads, " V", layer, indent); print_int_attr(hdl, qc_num_ifl_threads, " V", layer, indent); print_int_attr(hdl, qc_num_ziip_threads, " V", layer, indent); // check an attribute that only exists at a different layer verify_nonexistence(hdl, qc_cp_absolute_capping, layer); } void print_zoshyp_information(void *hdl, int layer, int indent) { print_header(indent, layer, "z/OS-hypervisor"); indent += 2; print_string_attr(hdl, qc_layer_type, "n/a", layer, indent); print_string_attr(hdl, qc_layer_category, "n/a", layer, indent); print_int_attr(hdl, qc_layer_type_num, "n/a", layer, indent); print_int_attr(hdl, qc_layer_category_num, "n/a", layer, indent); print_string_attr(hdl, qc_layer_name, " V", layer, indent); print_string_attr(hdl, qc_cluster_name, " V", layer, indent); print_string_attr(hdl, qc_control_program_id, "S ", layer, indent); print_int_attr(hdl, qc_adjustment, "S ", layer, indent); print_break(); print_int_attr(hdl, qc_num_core_total, " V", layer, indent); print_int_attr(hdl, qc_num_core_dedicated, " V", layer, indent); print_int_attr(hdl, qc_num_core_shared, " V", layer, indent); print_break(); print_int_attr(hdl, qc_num_cp_total, " V", layer, indent); print_int_attr(hdl, qc_num_cp_dedicated, " V", layer, indent); print_int_attr(hdl, qc_num_cp_shared, " V", layer, indent); print_int_attr(hdl, qc_num_ziip_total, " V", layer, indent); print_int_attr(hdl, qc_num_ziip_dedicated, " V", layer, indent); print_int_attr(hdl, qc_num_ziip_shared, " V", layer, indent); print_break(); print_int_attr(hdl, qc_num_cp_threads, " V", layer, indent); print_int_attr(hdl, qc_num_ziip_threads, " V", layer, indent); // check an attribute that only exists at a different layer verify_nonexistence(hdl, qc_cp_absolute_capping, layer); } void print_zvmpool_information(void *hdl, int layer, int indent) { #ifdef CONFIG_V1_COMPATIBILITY print_header(indent, layer, "z/VM-CPU-pool"); #else print_header(indent, layer, "z/VM-resource-pool"); #endif indent += 2; print_string_attr(hdl, qc_layer_type, "n/a", layer, indent); print_string_attr(hdl, qc_layer_category, "n/a", layer, indent); print_int_attr(hdl, qc_layer_type_num, "n/a", layer, indent); print_int_attr(hdl, qc_layer_category_num, "n/a", layer, indent); print_string_attr(hdl, qc_layer_name, " V", layer, indent); print_break(); print_int_attr(hdl, qc_cp_limithard_cap, " V", layer, indent); print_int_attr(hdl, qc_cp_capacity_cap, " V", layer, indent); print_int_attr(hdl, qc_cp_capped_capacity, " V", layer, indent); print_int_attr(hdl, qc_ifl_limithard_cap, " V", layer, indent); print_int_attr(hdl, qc_ifl_capacity_cap, " V", layer, indent); print_int_attr(hdl, qc_ifl_capped_capacity, " V", layer, indent); print_int_attr(hdl, qc_ziip_limithard_cap, " V", layer, indent); print_int_attr(hdl, qc_ziip_capacity_cap, " V", layer, indent); print_int_attr(hdl, qc_ziip_capped_capacity, " V", layer, indent); // check an attribute that only exists at a different layer verify_nonexistence(hdl, qc_cp_absolute_capping, layer); } void print_zosresgroup_information(void *hdl, int layer, int indent) { print_header(indent, layer, "z/OS-tenant-resource-group"); indent += 2; print_string_attr(hdl, qc_layer_type, "n/a", layer, indent); print_string_attr(hdl, qc_layer_category, "n/a", layer, indent); print_int_attr(hdl, qc_layer_type_num, "n/a", layer, indent); print_int_attr(hdl, qc_layer_category_num, "n/a", layer, indent); print_string_attr(hdl, qc_layer_name, " V", layer, indent); print_break(); print_int_attr(hdl, qc_cp_limithard_cap, " V", layer, indent); print_int_attr(hdl, qc_cp_capacity_cap, " V", layer, indent); print_int_attr(hdl, qc_cp_capped_capacity, " V", layer, indent); print_int_attr(hdl, qc_ziip_limithard_cap, " V", layer, indent); print_int_attr(hdl, qc_ziip_capacity_cap, " V", layer, indent); print_int_attr(hdl, qc_ziip_capped_capacity, " V", layer, indent); // check an attribute that only exists at a different layer verify_nonexistence(hdl, qc_cp_absolute_capping, layer); } void print_zoszcxserver_information(void *hdl, int layer, int indent) { print_header(indent, layer, "z/OS-zCX-Server"); indent += 2; print_string_attr(hdl, qc_layer_type, "n/a", layer, indent); print_string_attr(hdl, qc_layer_category, "n/a", layer, indent); print_int_attr(hdl, qc_layer_type_num, "n/a", layer, indent); print_int_attr(hdl, qc_layer_category_num, "n/a", layer, indent); print_string_attr(hdl, qc_layer_name, "S V", layer, indent); print_string_attr(hdl, qc_capping, " H ", layer, indent); print_int_attr(hdl, qc_capping_num, " H ", layer, indent); print_int_attr(hdl, qc_has_secure, "F ", layer, indent); print_int_attr(hdl, qc_secure, "F ", layer, indent); print_break(); print_int_attr(hdl, qc_num_cpu_total, "S V", layer, indent); print_int_attr(hdl, qc_num_cpu_configured, "S ", layer, indent); print_int_attr(hdl, qc_num_cpu_standby, "S ", layer, indent); print_int_attr(hdl, qc_num_cpu_reserved, "S ", layer, indent); print_int_attr(hdl, qc_num_cpu_dedicated, " HV", layer, indent); print_int_attr(hdl, qc_num_cpu_shared, " HV", layer, indent); print_break(); print_int_attr(hdl, qc_num_cp_total, " V", layer, indent); print_int_attr(hdl, qc_num_cp_dedicated, " V", layer, indent); print_int_attr(hdl, qc_num_cp_shared, " V", layer, indent); print_int_attr(hdl, qc_num_ziip_total, " V", layer, indent); print_int_attr(hdl, qc_num_ziip_dedicated, " V", layer, indent); print_int_attr(hdl, qc_num_ziip_shared, " V", layer, indent); print_break(); print_int_attr(hdl, qc_cp_dispatch_type, " V", layer, indent); print_int_attr(hdl, qc_cp_dispatch_limithard, " V", layer, indent); print_int_attr(hdl, qc_cp_capped_capacity, " V", layer, indent); print_int_attr(hdl, qc_ziip_dispatch_type, " V", layer, indent); print_int_attr(hdl, qc_ziip_dispatch_limithard, " V", layer, indent); print_int_attr(hdl, qc_ziip_capped_capacity, " V", layer, indent); print_break(); print_int_attr(hdl, qc_has_multiple_cpu_types, " V", layer, indent); // check an attribute that only exists at a different layer verify_nonexistence(hdl, qc_cp_absolute_capping, layer); } void print_zvmguest_information(void *hdl, int layer, int indent) { print_header(indent, layer, "z/VM-guest"); indent += 2; print_string_attr(hdl, qc_layer_type, "n/a", layer, indent); print_string_attr(hdl, qc_layer_category, "n/a", layer, indent); print_int_attr(hdl, qc_layer_type_num, "n/a", layer, indent); print_int_attr(hdl, qc_layer_category_num, "n/a", layer, indent); print_string_attr(hdl, qc_layer_name, "S V", layer, indent); print_string_attr(hdl, qc_capping, " H ", layer, indent); print_int_attr(hdl, qc_capping_num, " H ", layer, indent); print_int_attr(hdl, qc_mobility_enabled, " V", layer, indent); print_int_attr(hdl, qc_has_secure, "F ", layer, indent); print_int_attr(hdl, qc_secure, "F ", layer, indent); print_break(); print_int_attr(hdl, qc_num_cpu_total, "S V", layer, indent); print_int_attr(hdl, qc_num_cpu_configured, "S ", layer, indent); print_int_attr(hdl, qc_num_cpu_standby, "S ", layer, indent); print_int_attr(hdl, qc_num_cpu_reserved, "S ", layer, indent); print_int_attr(hdl, qc_num_cpu_dedicated, " HV", layer, indent); print_int_attr(hdl, qc_num_cpu_shared, " HV", layer, indent); print_break(); print_int_attr(hdl, qc_num_cp_total, " V", layer, indent); print_int_attr(hdl, qc_num_cp_dedicated, " V", layer, indent); print_int_attr(hdl, qc_num_cp_shared, " V", layer, indent); print_int_attr(hdl, qc_num_ifl_total, " V", layer, indent); print_int_attr(hdl, qc_num_ifl_dedicated, " V", layer, indent); print_int_attr(hdl, qc_num_ifl_shared, " V", layer, indent); print_int_attr(hdl, qc_num_ziip_total, " V", layer, indent); print_int_attr(hdl, qc_num_ziip_dedicated, " V", layer, indent); print_int_attr(hdl, qc_num_ziip_shared, " V", layer, indent); print_break(); print_int_attr(hdl, qc_cp_dispatch_type, " V", layer, indent); print_int_attr(hdl, qc_cp_dispatch_limithard, " V", layer, indent); print_int_attr(hdl, qc_cp_capped_capacity, " V", layer, indent); print_int_attr(hdl, qc_ifl_dispatch_type, " V", layer, indent); print_int_attr(hdl, qc_ifl_dispatch_limithard, " V", layer, indent); print_int_attr(hdl, qc_ifl_capped_capacity, " V", layer, indent); print_int_attr(hdl, qc_ziip_dispatch_type, " V", layer, indent); print_int_attr(hdl, qc_ziip_dispatch_limithard, " V", layer, indent); print_int_attr(hdl, qc_ziip_capped_capacity, " V", layer, indent); print_break(); print_int_attr(hdl, qc_has_multiple_cpu_types, " V", layer, indent); // check an attribute that only exists at a different layer verify_nonexistence(hdl, qc_cp_absolute_capping, layer); } void print_kvmhyp_information(void *hdl, int layer, int indent) { print_header(indent, layer, "KVM-hypervisor"); indent += 2; print_string_attr(hdl, qc_layer_type, "n/a", layer, indent); print_string_attr(hdl, qc_layer_category, "n/a", layer, indent); print_int_attr(hdl, qc_layer_type_num, "n/a", layer, indent); print_int_attr(hdl, qc_layer_category_num, "n/a", layer, indent); print_string_attr(hdl, qc_control_program_id, "S ", layer, indent); print_int_attr(hdl, qc_adjustment, "S ", layer, indent); print_break(); print_int_attr(hdl, qc_num_core_total, " V", layer, indent); print_int_attr(hdl, qc_num_core_dedicated, "SHV", layer, indent); print_int_attr(hdl, qc_num_core_shared, "SHV", layer, indent); print_break(); print_int_attr(hdl, qc_num_cp_total, " HV", layer, indent); print_int_attr(hdl, qc_num_cp_dedicated, " hV", layer, indent); print_int_attr(hdl, qc_num_cp_shared, " hV", layer, indent); print_int_attr(hdl, qc_num_ifl_total, "SHV", layer, indent); print_int_attr(hdl, qc_num_ifl_dedicated, "ShV", layer, indent); print_int_attr(hdl, qc_num_ifl_shared, "ShV", layer, indent); // check an attribute that only exists at a different layer verify_nonexistence(hdl, qc_cp_absolute_capping, layer); } void print_kvmguest_information(void *hdl, int layer, int indent) { print_header(indent, layer, "KVM-guest"); indent += 2; print_string_attr(hdl, qc_layer_type, "n/a", layer, indent); print_string_attr(hdl, qc_layer_category, "n/a", layer, indent); print_int_attr(hdl, qc_layer_type_num, "n/a", layer, indent); print_int_attr(hdl, qc_layer_category_num, "n/a", layer, indent); print_string_attr(hdl, qc_layer_name, "S ", layer, indent); print_string_attr(hdl, qc_layer_extended_name, "S ", layer, indent); print_string_attr(hdl, qc_layer_uuid, "S ", layer, indent); print_int_attr(hdl, qc_has_secure, "F ", layer, indent); print_int_attr(hdl, qc_secure, "F ", layer, indent); print_break(); print_int_attr(hdl, qc_num_cpu_total, "S ", layer, indent); print_int_attr(hdl, qc_num_cpu_configured, "S ", layer, indent); print_int_attr(hdl, qc_num_cpu_standby, "S ", layer, indent); print_int_attr(hdl, qc_num_cpu_reserved, "S ", layer, indent); print_int_attr(hdl, qc_num_cpu_dedicated, "S ", layer, indent); print_int_attr(hdl, qc_num_cpu_shared, "S ", layer, indent); print_break(); print_int_attr(hdl, qc_num_ifl_total, "S ", layer, indent); print_int_attr(hdl, qc_num_ifl_dedicated, "S ", layer, indent); print_int_attr(hdl, qc_num_ifl_shared, "S ", layer, indent); print_break(); print_int_attr(hdl, qc_ifl_dispatch_type, "SHV", layer, indent); // check an attribute that only exists at a different layer verify_nonexistence(hdl, qc_cp_absolute_capping, layer); } int get_handle(void **hdl, int *layers, int quiet) { int rc; *hdl = qc_open(&rc); if (rc < 0) { if (!quiet) printf("Error: Could not open configuration, rc=%d\n", rc); return 1; } if (rc > 0) { if (!quiet) printf("Warning: Configuration could not be opened completely, rc=%d\n", rc); return 2; } if (!*hdl) { if (!quiet) printf("Error: Could not open configuration\n"); return 3; } *layers = qc_get_num_layers(*hdl, &rc); if (rc != 0) { if (!quiet) printf("Error: Could not retrieve number of layers, rc=%d\n", rc); return 4; } if (*layers < 0) { if (!quiet) printf("Error: Invalid number of layers: %d\n", *layers); return 5; } return 0; } // Retrieve handle, dump data, and return *hdl to leave it at the caller's discretion when to close it static void *run_test(int quiet, int fulltest) { int indent = 0, layers, i, etype; void *hdl = NULL, *hdl2 = NULL; err_cnt = 0; if (fulltest) { // First sanity check: Call with invalid handle before any were opened qc_get_num_layers((void*)0x1, &i); if (i >= 0) { printf("Error: qc_get_num_layers(0x1, &rc) worked, returning '%d'\n", i); err_cnt++; } } if (get_handle(&hdl, &layers, quiet) != 0) { err_cnt++; goto out; } if (quiet) goto out; print_break(); printf("We are running %i layer(s)\n", layers); print_break(); if (sanity_checks(hdl, layers)) goto out; for (i = 0; i < layers; i++) { if (i > 0) print_separator(indent); indent += 2; if (qc_get_attribute_int(hdl, qc_layer_type_num, i, &etype) <= 0) { printf("Error: Failed to retrieve 'qc_layer_type_num'\n"); err_cnt++; goto out; } switch (etype) { case QC_LAYER_TYPE_CEC: print_cec_information(hdl, i, indent); break; case QC_LAYER_TYPE_LPAR_GROUP: print_lpar_group_information(hdl, i, indent); break; case QC_LAYER_TYPE_LPAR: print_lpar_information(hdl, i, indent); break; case QC_LAYER_TYPE_ZVM_HYPERVISOR: print_zvmhyp_information(hdl, i, indent); break; case QC_LAYER_TYPE_KVM_HYPERVISOR: print_kvmhyp_information(hdl, i, indent); break; case QC_LAYER_TYPE_ZOS_HYPERVISOR: print_zoshyp_information(hdl, i, indent); break; case QC_LAYER_TYPE_ZVM_CPU_POOL: print_zvmpool_information(hdl, i, indent); break; case QC_LAYER_TYPE_ZOS_TENANT_RESOURCE_GROUP: print_zosresgroup_information(hdl, i, indent); break; case QC_LAYER_TYPE_ZVM_GUEST: print_zvmguest_information(hdl, i, indent); break; case QC_LAYER_TYPE_KVM_GUEST: print_kvmguest_information(hdl, i, indent); break; case QC_LAYER_TYPE_ZOS_ZCX_SERVER: print_zoszcxserver_information(hdl, i, indent); break; default: printf("Error: Unhandled layer type '%d' at layer %i, no detailed " "information available.\n\n", etype, i); err_cnt++; } } if (fulltest) { // finally, get another handle before closing the existing one if (get_handle(&hdl2, &layers, quiet) != 0) err_cnt++; } out: if (fulltest) { qc_close(hdl); hdl = hdl2; } /* disable debugging on final qc_close() call to have tracing properly disabled without memleaks */ setenv("QC_DEBUG", "0", 1); setenv("QC_AUTODUMP", "0", 1); if (!quiet) { print_separator(indent); if (err_cnt) { printf("%d error(s) detected\n", err_cnt); print_break(); } } return hdl; } static void print_help() { printf("\n"); printf("Usage: qc_test [-q] [-h] [*]\n"); printf("\n"); printf("Print live system information and perform self-test. Specify dumps to display\n"); printf("previously dumped data instead (but skipping a minor part of the self-test).\n"); printf("\n"); printf(" -h, --help Print usage information and exit\n"); printf(" -q, --quiet Quiet mode: Only gather system informtion; skip self-test and\n"); printf(" suppress any output.\n"); printf("\n"); } int main(int argc, char **argv) { static struct option long_options[] = { { "help", no_argument, NULL, 'h'}, { "quiet", no_argument, NULL, 'q'}, { 0, 0, 0, 0 } }; int i, j, c, quiet = 0, rc = 0; void **hdls = NULL; while ((c = getopt_long(argc, argv, "hq", long_options, NULL)) != EOF) { switch (c) { case 'h': print_help(); return 0; case 'q': quiet = 1; break; default: print_help(); return 1; } } setenv("QC_CHECK_CONSISTENCY", "1", 0); hdls = malloc(argc * sizeof(void *)); if (!hdls) return 1; if (optind < argc) { // dump(s) specified on command line - dump all, and close handles later on for (j = 0, i = optind; i < argc; ++i, ++j) { setenv("QC_USE_DUMP", argv[i], 1); if ((hdls[j] = run_test(quiet, 0)) == NULL) rc++; } for (--j; j >= 0; --j) qc_close(hdls[j]); } else { if ((hdls[0] = run_test(quiet, 1)) == NULL) rc = 1; qc_close(hdls[0]); } free(hdls); return rc; } qclib-2.1.0/query_capacity_data.c0000664000175000017500000013517313647300120016017 0ustar rasplraspl/* Copyright IBM Corp. 2013, 2019 */ #include "query_capacity_data.h" /* * Below are the structures that define the attributes. The attributes are * referenced as an enum, see documentation in query_capacity.h. * * Note that strings (char pointers) carry the trailing zero byte. */ #define QC_LEN_CAPPING 5 #define QC_LEN_CLUSTER_NAME 9 #define QC_LEN_CONTROL_PROGRAM_ID 17 #define QC_LEN_LAYER_CATEGORY 6 #define QC_LEN_LAYER_EXTENDED_NAME 257 #define QC_LEN_LAYER_NAME 9 #define QC_LEN_LAYER_TYPE 27 #define QC_LEN_LAYER_UUID 37 #define QC_LEN_LIC_IDENTIFIER 17 #define QC_LEN_MANUFACTURER 17 #define QC_LEN_MODEL 17 #define QC_LEN_MODEL_CAPACITY 17 #define QC_LEN_PARTITION_CHAR 26 #define QC_LEN_PLANT 5 #define QC_LEN_SEQUENCE_CODE 17 #define QC_LEN_TYPE 17 #define QC_LEN_TYPE_NAME 31 // Returns length of string attributes as defined in the respective struct static unsigned int qc_get_str_attr_len(enum qc_attr_id id) { switch (id) { case qc_capping: return QC_LEN_CAPPING; case qc_cluster_name: return QC_LEN_CLUSTER_NAME; case qc_control_program_id: return QC_LEN_CONTROL_PROGRAM_ID; case qc_layer_category: return QC_LEN_LAYER_CATEGORY; case qc_layer_extended_name: return QC_LEN_LAYER_EXTENDED_NAME; case qc_layer_name: return QC_LEN_LAYER_NAME; case qc_layer_type: return QC_LEN_LAYER_TYPE; case qc_layer_uuid: return QC_LEN_LAYER_UUID; case qc_lic_identifier: return QC_LEN_LIC_IDENTIFIER; case qc_manufacturer: return QC_LEN_MANUFACTURER; case qc_model: return QC_LEN_MODEL; case qc_model_capacity: return QC_LEN_MODEL_CAPACITY; case qc_partition_char: return QC_LEN_PARTITION_CHAR; case qc_plant: return QC_LEN_PLANT; case qc_sequence_code: return QC_LEN_SEQUENCE_CODE; case qc_type: return QC_LEN_TYPE; case qc_type_name: return QC_LEN_TYPE_NAME; default: break; } return 0; } struct qc_cec { int layer_type_num; int layer_category_num; char layer_type[QC_LEN_LAYER_TYPE]; char layer_category[QC_LEN_LAYER_CATEGORY]; char layer_name[QC_LEN_LAYER_NAME]; char manufacturer[QC_LEN_MANUFACTURER]; char type[QC_LEN_TYPE]; char model_capacity[QC_LEN_MODEL_CAPACITY]; char model[QC_LEN_MODEL]; char type_name[QC_LEN_TYPE_NAME]; int type_family; char sequence_code[QC_LEN_SEQUENCE_CODE]; char lic_identifier[QC_LEN_LIC_IDENTIFIER]; char plant[QC_LEN_PLANT]; int num_core_total; int num_core_configured; int num_core_standby; int num_core_reserved; int num_core_dedicated; int num_core_shared; int num_cp_total; int num_cp_dedicated; int num_cp_shared; int num_ifl_total; int num_ifl_dedicated; int num_ifl_shared; int num_ziip_total; int num_ziip_dedicated; int num_ziip_shared; int num_cp_threads; int num_ifl_threads; int num_ziip_threads; float capability; float secondary_capability; int capacity_adjustment_indication; int capacity_change_reason; }; /* * valid attributes for a layer, where "layer-type"=="LPAR-Group" */ struct qc_lpar_group { int layer_type_num; int layer_category_num; char layer_type[QC_LEN_LAYER_TYPE]; char layer_category[QC_LEN_LAYER_CATEGORY]; char layer_name[QC_LEN_LAYER_NAME]; int cp_absolute_capping; int ifl_absolute_capping; int ziip_absolute_capping; }; /* * valid attributes for a layer, where "layer-type"=="LPAR" */ struct qc_lpar { int layer_type_num; int layer_category_num; char layer_type[QC_LEN_LAYER_TYPE]; char layer_category[QC_LEN_LAYER_CATEGORY]; int partition_number; char partition_char[QC_LEN_PARTITION_CHAR]; int partition_char_num; char layer_name[QC_LEN_LAYER_NAME]; char layer_extended_name[QC_LEN_LAYER_EXTENDED_NAME]; char layer_uuid[QC_LEN_LAYER_UUID]; int adjustment; int has_secure; int secure; int num_core_total; int num_core_configured; int num_core_standby; int num_core_reserved; int num_core_dedicated; int num_core_shared; int num_cp_total; int num_cp_dedicated; int num_cp_shared; int num_ifl_total; int num_ifl_dedicated; int num_ifl_shared; int num_ziip_total; int num_ziip_dedicated; int num_ziip_shared; int num_cp_threads; int num_ifl_threads; int num_ziip_threads; int cp_absolute_capping; int ifl_absolute_capping; int ziip_absolute_capping; int cp_weight_capping; int ifl_weight_capping; int ziip_weight_capping; }; struct qc_zvm_pool { int layer_type_num; int layer_category_num; char layer_type[QC_LEN_LAYER_TYPE]; char layer_category[QC_LEN_LAYER_CATEGORY]; char layer_name[QC_LEN_LAYER_NAME]; int cp_limithard_cap; int cp_capacity_cap; int ifl_limithard_cap; int ifl_capacity_cap; int ziip_limithard_cap; int ziip_capacity_cap; int cp_capped_capacity; int ifl_capped_capacity; int ziip_capped_capacity; }; struct qc_zvm_hypervisor { int layer_type_num; int layer_category_num; char layer_type[QC_LEN_LAYER_TYPE]; char layer_category[QC_LEN_LAYER_CATEGORY]; char layer_name[QC_LEN_LAYER_NAME]; char cluster_name[QC_LEN_CLUSTER_NAME]; char control_program_id[QC_LEN_CONTROL_PROGRAM_ID]; int adjustment; int limithard_consumption; int prorated_core_time; int num_core_total; int num_core_dedicated; int num_core_shared; int num_cp_total; int num_cp_dedicated; int num_cp_shared; int num_ifl_total; int num_ifl_dedicated; int num_ifl_shared; int num_ziip_total; int num_ziip_dedicated; int num_ziip_shared; int num_cp_threads; int num_ifl_threads; int num_ziip_threads; }; struct qc_zvm_guest { int layer_type_num; int layer_category_num; char layer_type[QC_LEN_LAYER_TYPE]; char layer_category[QC_LEN_LAYER_CATEGORY]; char layer_name[QC_LEN_LAYER_NAME]; char capping[QC_LEN_CAPPING]; int capping_num; int mobility_enabled; int has_secure; int secure; int num_cpu_total; int num_cpu_configured; int num_cpu_standby; int num_cpu_reserved; int num_cpu_dedicated; int num_cpu_shared; int num_cp_total; int num_cp_dedicated; int num_cp_shared; int num_ifl_total; int num_ifl_dedicated; int num_ifl_shared; int num_ziip_total; int num_ziip_dedicated; int num_ziip_shared; int has_multiple_cpu_types; int cp_dispatch_limithard; int cp_dispatch_type; int cp_capped_capacity; int ifl_dispatch_limithard; int ifl_dispatch_type; int ifl_capped_capacity; int ziip_dispatch_limithard; int ziip_dispatch_type; int ziip_capped_capacity; }; struct qc_zos_hypervisor { int layer_type_num; int layer_category_num; char layer_type[QC_LEN_LAYER_TYPE]; char layer_category[QC_LEN_LAYER_CATEGORY]; char layer_name[QC_LEN_LAYER_NAME]; char cluster_name[QC_LEN_CLUSTER_NAME]; char control_program_id[QC_LEN_CONTROL_PROGRAM_ID]; int adjustment; int num_core_total; int num_core_dedicated; int num_core_shared; int num_cp_total; int num_cp_dedicated; int num_cp_shared; int num_ziip_total; int num_ziip_dedicated; int num_ziip_shared; int num_cp_threads; int num_ziip_threads; }; struct qc_zos_tenant_resource_group { int layer_type_num; int layer_category_num; char layer_type[QC_LEN_LAYER_TYPE]; char layer_category[QC_LEN_LAYER_CATEGORY]; char layer_name[QC_LEN_LAYER_NAME]; int cp_limithard_cap; int cp_capacity_cap; int cp_capped_capacity; int ziip_limithard_cap; int ziip_capacity_cap; int ziip_capped_capacity; }; struct qc_zos_zcx_server { int layer_type_num; int layer_category_num; char layer_type[QC_LEN_LAYER_TYPE]; char layer_category[QC_LEN_LAYER_CATEGORY]; char layer_name[QC_LEN_LAYER_NAME]; char capping[QC_LEN_CAPPING]; int capping_num; int has_secure; int secure; int num_cpu_total; int num_cpu_configured; int num_cpu_standby; int num_cpu_reserved; int num_cpu_dedicated; int num_cpu_shared; int num_cp_total; int num_cp_dedicated; int num_cp_shared; int num_ziip_total; int num_ziip_dedicated; int num_ziip_shared; int has_multiple_cpu_types; int cp_dispatch_limithard; int cp_dispatch_type; int cp_capped_capacity; int ziip_dispatch_limithard; int ziip_dispatch_type; int ziip_capped_capacity; }; struct qc_kvm_hypervisor { int layer_type_num; int layer_category_num; char layer_type[QC_LEN_LAYER_TYPE]; char layer_category[QC_LEN_LAYER_CATEGORY]; char control_program_id[QC_LEN_CONTROL_PROGRAM_ID]; int adjustment; int num_core_total; int num_core_dedicated; int num_core_shared; int num_cp_total; int num_cp_dedicated; int num_cp_shared; int num_ifl_total; int num_ifl_dedicated; int num_ifl_shared; }; struct qc_kvm_guest { int layer_type_num; int layer_category_num; char layer_type[QC_LEN_LAYER_TYPE]; char layer_category[QC_LEN_LAYER_CATEGORY]; char layer_name[QC_LEN_LAYER_NAME]; char layer_extended_name[QC_LEN_LAYER_EXTENDED_NAME]; char layer_uuid[QC_LEN_LAYER_UUID]; int has_secure; int secure; int num_cpu_total; int num_cpu_configured; int num_cpu_standby; int num_cpu_reserved; int num_cpu_dedicated; int num_cpu_shared; int num_ifl_total; int num_ifl_dedicated; int num_ifl_shared; int ifl_dispatch_type; }; enum qc_data_type { string, integer, floatingpoint }; struct qc_attr { enum qc_attr_id id; enum qc_data_type type; int offset; }; static struct qc_attr cec_attrs[] = { {qc_layer_type_num, integer, offsetof(struct qc_cec, layer_type_num)}, {qc_layer_category_num, integer, offsetof(struct qc_cec, layer_category_num)}, {qc_layer_type, string, offsetof(struct qc_cec, layer_type)}, {qc_layer_category, string, offsetof(struct qc_cec, layer_category)}, {qc_layer_name, string, offsetof(struct qc_cec, layer_name)}, {qc_manufacturer, string, offsetof(struct qc_cec, manufacturer)}, {qc_type, string, offsetof(struct qc_cec, type)}, {qc_model_capacity, string, offsetof(struct qc_cec, model_capacity)}, {qc_model, string, offsetof(struct qc_cec, model)}, {qc_type_name, string, offsetof(struct qc_cec, type_name)}, {qc_type_family, integer, offsetof(struct qc_cec, type_family)}, {qc_sequence_code, string, offsetof(struct qc_cec, sequence_code)}, {qc_lic_identifier, string, offsetof(struct qc_cec, lic_identifier)}, {qc_plant, string, offsetof(struct qc_cec, plant)}, {qc_num_core_total, integer, offsetof(struct qc_cec, num_core_total)}, {qc_num_core_configured, integer, offsetof(struct qc_cec, num_core_configured)}, {qc_num_core_standby, integer, offsetof(struct qc_cec, num_core_standby)}, {qc_num_core_reserved, integer, offsetof(struct qc_cec, num_core_reserved)}, {qc_num_core_dedicated, integer, offsetof(struct qc_cec, num_core_dedicated)}, {qc_num_core_shared, integer, offsetof(struct qc_cec, num_core_shared)}, {qc_num_cp_total, integer, offsetof(struct qc_cec, num_cp_total)}, {qc_num_cp_dedicated, integer, offsetof(struct qc_cec, num_cp_dedicated)}, {qc_num_cp_shared, integer, offsetof(struct qc_cec, num_cp_shared)}, {qc_num_ifl_total, integer, offsetof(struct qc_cec, num_ifl_total)}, {qc_num_ifl_dedicated, integer, offsetof(struct qc_cec, num_ifl_dedicated)}, {qc_num_ifl_shared, integer, offsetof(struct qc_cec, num_ifl_shared)}, {qc_num_ziip_total, integer, offsetof(struct qc_cec, num_ziip_total)}, {qc_num_ziip_dedicated, integer, offsetof(struct qc_cec, num_ziip_dedicated)}, {qc_num_ziip_shared, integer, offsetof(struct qc_cec, num_ziip_shared)}, {qc_num_cp_threads, integer, offsetof(struct qc_cec, num_cp_threads)}, {qc_num_ifl_threads, integer, offsetof(struct qc_cec, num_ifl_threads)}, {qc_num_ziip_threads, integer, offsetof(struct qc_cec, num_ziip_threads)}, {qc_capability, floatingpoint, offsetof(struct qc_cec, capability)}, {qc_secondary_capability, floatingpoint, offsetof(struct qc_cec, secondary_capability)}, {qc_capacity_adjustment_indication, integer, offsetof(struct qc_cec, capacity_adjustment_indication)}, {qc_capacity_change_reason, integer, offsetof(struct qc_cec, capacity_change_reason)}, {-1, string, -1} }; static struct qc_attr lpar_group_attrs[] = { {qc_layer_type_num, integer, offsetof(struct qc_lpar_group, layer_type_num)}, {qc_layer_category_num, integer, offsetof(struct qc_lpar_group, layer_category_num)}, {qc_layer_type, string, offsetof(struct qc_lpar_group, layer_type)}, {qc_layer_category, string, offsetof(struct qc_lpar_group, layer_category)}, {qc_layer_name, string, offsetof(struct qc_lpar_group, layer_name)}, {qc_cp_absolute_capping, integer, offsetof(struct qc_lpar_group, cp_absolute_capping)}, {qc_ifl_absolute_capping, integer, offsetof(struct qc_lpar_group, ifl_absolute_capping)}, {qc_ziip_absolute_capping, integer, offsetof(struct qc_lpar_group, ziip_absolute_capping)}, {-1, string, -1} }; static struct qc_attr lpar_attrs[] = { {qc_layer_type_num, integer, offsetof(struct qc_lpar, layer_type_num)}, {qc_layer_category_num, integer, offsetof(struct qc_lpar, layer_category_num)}, {qc_layer_type, string, offsetof(struct qc_lpar, layer_type)}, {qc_layer_category, string, offsetof(struct qc_lpar, layer_category)}, {qc_partition_number, integer, offsetof(struct qc_lpar, partition_number)}, {qc_partition_char, string, offsetof(struct qc_lpar, partition_char)}, {qc_partition_char_num, integer, offsetof(struct qc_lpar, partition_char_num)}, {qc_layer_name, string, offsetof(struct qc_lpar, layer_name)}, {qc_layer_extended_name, string, offsetof(struct qc_lpar, layer_extended_name)}, {qc_layer_uuid, string, offsetof(struct qc_lpar, layer_uuid)}, {qc_adjustment, integer, offsetof(struct qc_lpar, adjustment)}, {qc_has_secure, integer, offsetof(struct qc_lpar, has_secure)}, {qc_secure, integer, offsetof(struct qc_lpar, secure)}, {qc_num_core_total, integer, offsetof(struct qc_lpar, num_core_total)}, {qc_num_core_configured, integer, offsetof(struct qc_lpar, num_core_configured)}, {qc_num_core_standby, integer, offsetof(struct qc_lpar, num_core_standby)}, {qc_num_core_reserved, integer, offsetof(struct qc_lpar, num_core_reserved)}, {qc_num_core_dedicated, integer, offsetof(struct qc_lpar, num_core_dedicated)}, {qc_num_core_shared, integer, offsetof(struct qc_lpar, num_core_shared)}, {qc_num_cp_total, integer, offsetof(struct qc_lpar, num_cp_total)}, {qc_num_cp_dedicated, integer, offsetof(struct qc_lpar, num_cp_dedicated)}, {qc_num_cp_shared, integer, offsetof(struct qc_lpar, num_cp_shared)}, {qc_num_ifl_total, integer, offsetof(struct qc_lpar, num_ifl_total)}, {qc_num_ifl_dedicated, integer, offsetof(struct qc_lpar, num_ifl_dedicated)}, {qc_num_ifl_shared, integer, offsetof(struct qc_lpar, num_ifl_shared)}, {qc_num_ziip_total, integer, offsetof(struct qc_lpar, num_ziip_total)}, {qc_num_ziip_dedicated, integer, offsetof(struct qc_lpar, num_ziip_dedicated)}, {qc_num_ziip_shared, integer, offsetof(struct qc_lpar, num_ziip_shared)}, {qc_num_cp_threads, integer, offsetof(struct qc_lpar, num_cp_threads)}, {qc_num_ifl_threads, integer, offsetof(struct qc_lpar, num_ifl_threads)}, {qc_num_ziip_threads, integer, offsetof(struct qc_lpar, num_ziip_threads)}, {qc_cp_absolute_capping, integer, offsetof(struct qc_lpar, cp_absolute_capping)}, {qc_ifl_absolute_capping, integer, offsetof(struct qc_lpar, ifl_absolute_capping)}, {qc_ziip_absolute_capping, integer, offsetof(struct qc_lpar, ziip_absolute_capping)}, {qc_cp_weight_capping, integer, offsetof(struct qc_lpar, cp_weight_capping)}, {qc_ifl_weight_capping, integer, offsetof(struct qc_lpar, ifl_weight_capping)}, {qc_ziip_weight_capping, integer, offsetof(struct qc_lpar, ziip_weight_capping)}, {-1, string, -1} }; static struct qc_attr zvm_hv_attrs[] = { {qc_layer_type_num, integer, offsetof(struct qc_zvm_hypervisor, layer_type_num)}, {qc_layer_category_num, integer, offsetof(struct qc_zvm_hypervisor, layer_category_num)}, {qc_layer_type, string, offsetof(struct qc_zvm_hypervisor, layer_type)}, {qc_layer_category, string, offsetof(struct qc_zvm_hypervisor, layer_category)}, {qc_layer_name, string, offsetof(struct qc_zvm_hypervisor, layer_name)}, {qc_cluster_name, string, offsetof(struct qc_zvm_hypervisor, cluster_name)}, {qc_control_program_id, string, offsetof(struct qc_zvm_hypervisor, control_program_id)}, {qc_adjustment, integer, offsetof(struct qc_zvm_hypervisor, adjustment)}, {qc_limithard_consumption, integer, offsetof(struct qc_zvm_hypervisor, limithard_consumption)}, {qc_prorated_core_time, integer, offsetof(struct qc_zvm_hypervisor, prorated_core_time)}, {qc_num_core_total, integer, offsetof(struct qc_zvm_hypervisor, num_core_total)}, {qc_num_core_dedicated, integer, offsetof(struct qc_zvm_hypervisor, num_core_dedicated)}, {qc_num_core_shared, integer, offsetof(struct qc_zvm_hypervisor, num_core_shared)}, {qc_num_cp_total, integer, offsetof(struct qc_zvm_hypervisor, num_cp_total)}, {qc_num_cp_dedicated, integer, offsetof(struct qc_zvm_hypervisor, num_cp_dedicated)}, {qc_num_cp_shared, integer, offsetof(struct qc_zvm_hypervisor, num_cp_shared)}, {qc_num_ifl_total, integer, offsetof(struct qc_zvm_hypervisor, num_ifl_total)}, {qc_num_ifl_dedicated, integer, offsetof(struct qc_zvm_hypervisor, num_ifl_dedicated)}, {qc_num_ifl_shared, integer, offsetof(struct qc_zvm_hypervisor, num_ifl_shared)}, {qc_num_ziip_total, integer, offsetof(struct qc_zvm_hypervisor, num_ziip_total)}, {qc_num_ziip_dedicated, integer, offsetof(struct qc_zvm_hypervisor, num_ziip_dedicated)}, {qc_num_ziip_shared, integer, offsetof(struct qc_zvm_hypervisor, num_ziip_shared)}, {qc_num_cp_threads, integer, offsetof(struct qc_zvm_hypervisor, num_cp_threads)}, {qc_num_ifl_threads, integer, offsetof(struct qc_zvm_hypervisor, num_ifl_threads)}, {qc_num_ziip_threads, integer, offsetof(struct qc_zvm_hypervisor, num_ziip_threads)}, {-1, string, -1} }; static struct qc_attr zos_hv_attrs[] = { {qc_layer_type_num, integer, offsetof(struct qc_zos_hypervisor, layer_type_num)}, {qc_layer_category_num, integer, offsetof(struct qc_zos_hypervisor, layer_category_num)}, {qc_layer_type, string, offsetof(struct qc_zos_hypervisor, layer_type)}, {qc_layer_category, string, offsetof(struct qc_zos_hypervisor, layer_category)}, {qc_layer_name, string, offsetof(struct qc_zos_hypervisor, layer_name)}, {qc_cluster_name, string, offsetof(struct qc_zos_hypervisor, cluster_name)}, {qc_control_program_id, string, offsetof(struct qc_zos_hypervisor, control_program_id)}, {qc_adjustment, integer, offsetof(struct qc_zos_hypervisor, adjustment)}, {qc_num_core_total, integer, offsetof(struct qc_zos_hypervisor, num_core_total)}, {qc_num_core_dedicated, integer, offsetof(struct qc_zos_hypervisor, num_core_dedicated)}, {qc_num_core_shared, integer, offsetof(struct qc_zos_hypervisor, num_core_shared)}, {qc_num_cp_total, integer, offsetof(struct qc_zos_hypervisor, num_cp_total)}, {qc_num_cp_dedicated, integer, offsetof(struct qc_zos_hypervisor, num_cp_dedicated)}, {qc_num_cp_shared, integer, offsetof(struct qc_zos_hypervisor, num_cp_shared)}, {qc_num_ziip_total, integer, offsetof(struct qc_zos_hypervisor, num_ziip_total)}, {qc_num_ziip_dedicated, integer, offsetof(struct qc_zos_hypervisor, num_ziip_dedicated)}, {qc_num_ziip_shared, integer, offsetof(struct qc_zos_hypervisor, num_ziip_shared)}, {qc_num_cp_threads, integer, offsetof(struct qc_zos_hypervisor, num_cp_threads)}, {qc_num_ziip_threads, integer, offsetof(struct qc_zos_hypervisor, num_ziip_threads)}, {-1, string, -1} }; static struct qc_attr zos_tenant_resgroup_attrs[] = { {qc_layer_type_num, integer, offsetof(struct qc_zos_tenant_resource_group, layer_type_num)}, {qc_layer_category_num, integer, offsetof(struct qc_zos_tenant_resource_group, layer_category_num)}, {qc_layer_type, string, offsetof(struct qc_zos_tenant_resource_group, layer_type)}, {qc_layer_category, string, offsetof(struct qc_zos_tenant_resource_group, layer_category)}, {qc_layer_name, string, offsetof(struct qc_zos_tenant_resource_group, layer_name)}, {qc_cp_limithard_cap, integer, offsetof(struct qc_zos_tenant_resource_group, cp_limithard_cap)}, {qc_cp_capacity_cap, integer, offsetof(struct qc_zos_tenant_resource_group, cp_capacity_cap)}, {qc_ziip_limithard_cap, integer, offsetof(struct qc_zos_tenant_resource_group, ziip_limithard_cap)}, {qc_ziip_capacity_cap, integer, offsetof(struct qc_zos_tenant_resource_group, ziip_capacity_cap)}, {qc_cp_capped_capacity, integer, offsetof(struct qc_zos_tenant_resource_group, cp_capped_capacity)}, {qc_ziip_capped_capacity, integer, offsetof(struct qc_zos_tenant_resource_group, ziip_capped_capacity)}, {-1, string, -1} }; static struct qc_attr kvm_hv_attrs[] = { {qc_layer_type_num, integer, offsetof(struct qc_kvm_hypervisor, layer_type_num)}, {qc_layer_category_num, integer, offsetof(struct qc_kvm_hypervisor, layer_category_num)}, {qc_layer_type, string, offsetof(struct qc_kvm_hypervisor, layer_type)}, {qc_layer_category, string, offsetof(struct qc_kvm_hypervisor, layer_category)}, {qc_control_program_id, string, offsetof(struct qc_kvm_hypervisor, control_program_id)}, {qc_adjustment, integer, offsetof(struct qc_kvm_hypervisor, adjustment)}, {qc_num_core_total, integer, offsetof(struct qc_kvm_hypervisor, num_core_total)}, {qc_num_core_dedicated, integer, offsetof(struct qc_kvm_hypervisor, num_core_dedicated)}, {qc_num_core_shared, integer, offsetof(struct qc_kvm_hypervisor, num_core_shared)}, {qc_num_cp_total, integer, offsetof(struct qc_kvm_hypervisor, num_cp_total)}, {qc_num_cp_dedicated, integer, offsetof(struct qc_kvm_hypervisor, num_cp_dedicated)}, {qc_num_cp_shared, integer, offsetof(struct qc_kvm_hypervisor, num_cp_shared)}, {qc_num_ifl_total, integer, offsetof(struct qc_kvm_hypervisor, num_ifl_total)}, {qc_num_ifl_dedicated, integer, offsetof(struct qc_kvm_hypervisor, num_ifl_dedicated)}, {qc_num_ifl_shared, integer, offsetof(struct qc_kvm_hypervisor, num_ifl_shared)}, {-1, string, -1} }; static struct qc_attr zvm_pool_attrs[] = { {qc_layer_type_num, integer, offsetof(struct qc_zvm_pool, layer_type_num)}, {qc_layer_category_num, integer, offsetof(struct qc_zvm_pool, layer_category_num)}, {qc_layer_type, string, offsetof(struct qc_zvm_pool, layer_type)}, {qc_layer_category, string, offsetof(struct qc_zvm_pool, layer_category)}, {qc_layer_name, string, offsetof(struct qc_zvm_pool, layer_name)}, {qc_cp_limithard_cap, integer, offsetof(struct qc_zvm_pool, cp_limithard_cap)}, {qc_cp_capacity_cap, integer, offsetof(struct qc_zvm_pool, cp_capacity_cap)}, {qc_ifl_limithard_cap, integer, offsetof(struct qc_zvm_pool, ifl_limithard_cap)}, {qc_ifl_capacity_cap, integer, offsetof(struct qc_zvm_pool, ifl_capacity_cap)}, {qc_ziip_limithard_cap, integer, offsetof(struct qc_zvm_pool, ziip_limithard_cap)}, {qc_ziip_capacity_cap, integer, offsetof(struct qc_zvm_pool, ziip_capacity_cap)}, {qc_cp_capped_capacity, integer, offsetof(struct qc_zvm_pool, cp_capped_capacity)}, {qc_ifl_capped_capacity, integer, offsetof(struct qc_zvm_pool, ifl_capped_capacity)}, {qc_ziip_capped_capacity, integer, offsetof(struct qc_zvm_pool, ziip_capped_capacity)}, {-1, string, -1} }; static struct qc_attr zvm_guest_attrs[] = { {qc_layer_type_num, integer, offsetof(struct qc_zvm_guest, layer_type_num)}, {qc_layer_category_num, integer, offsetof(struct qc_zvm_guest, layer_category_num)}, {qc_layer_type, string, offsetof(struct qc_zvm_guest, layer_type)}, {qc_layer_category, string, offsetof(struct qc_zvm_guest, layer_category)}, {qc_layer_name, string, offsetof(struct qc_zvm_guest, layer_name)}, {qc_capping, string, offsetof(struct qc_zvm_guest, capping)}, {qc_capping_num, integer, offsetof(struct qc_zvm_guest, capping_num)}, {qc_mobility_enabled, integer, offsetof(struct qc_zvm_guest, mobility_enabled)}, {qc_has_secure, integer, offsetof(struct qc_zvm_guest, has_secure)}, {qc_secure, integer, offsetof(struct qc_zvm_guest, secure)}, {qc_num_cpu_total, integer, offsetof(struct qc_zvm_guest, num_cpu_total)}, {qc_num_cpu_configured, integer, offsetof(struct qc_zvm_guest, num_cpu_configured)}, {qc_num_cpu_standby, integer, offsetof(struct qc_zvm_guest, num_cpu_standby)}, {qc_num_cpu_reserved, integer, offsetof(struct qc_zvm_guest, num_cpu_reserved)}, {qc_num_cpu_dedicated, integer, offsetof(struct qc_zvm_guest, num_cpu_dedicated)}, {qc_num_cpu_shared, integer, offsetof(struct qc_zvm_guest, num_cpu_shared)}, {qc_num_cp_total, integer, offsetof(struct qc_zvm_guest, num_cp_total)}, {qc_num_cp_dedicated, integer, offsetof(struct qc_zvm_guest, num_cp_dedicated)}, {qc_num_cp_shared, integer, offsetof(struct qc_zvm_guest, num_cp_shared)}, {qc_num_ifl_total, integer, offsetof(struct qc_zvm_guest, num_ifl_total)}, {qc_num_ifl_dedicated, integer, offsetof(struct qc_zvm_guest, num_ifl_dedicated)}, {qc_num_ifl_shared, integer, offsetof(struct qc_zvm_guest, num_ifl_shared)}, {qc_num_ziip_total, integer, offsetof(struct qc_zvm_guest, num_ziip_total)}, {qc_num_ziip_dedicated, integer, offsetof(struct qc_zvm_guest, num_ziip_dedicated)}, {qc_num_ziip_shared, integer, offsetof(struct qc_zvm_guest, num_ziip_shared)}, {qc_has_multiple_cpu_types, integer, offsetof(struct qc_zvm_guest, has_multiple_cpu_types)}, {qc_cp_dispatch_limithard, integer, offsetof(struct qc_zvm_guest, cp_dispatch_limithard)}, {qc_cp_capped_capacity, integer, offsetof(struct qc_zvm_guest, cp_capped_capacity)}, {qc_ifl_dispatch_limithard, integer, offsetof(struct qc_zvm_guest, ifl_dispatch_limithard)}, {qc_ifl_capped_capacity, integer, offsetof(struct qc_zvm_guest, ifl_capped_capacity)}, {qc_ziip_dispatch_limithard, integer, offsetof(struct qc_zvm_guest, ziip_dispatch_limithard)}, {qc_ziip_capped_capacity, integer, offsetof(struct qc_zvm_guest, ziip_capped_capacity)}, {qc_cp_dispatch_type, integer, offsetof(struct qc_zvm_guest, cp_dispatch_type)}, {qc_ifl_dispatch_type, integer, offsetof(struct qc_zvm_guest, ifl_dispatch_type)}, {qc_ziip_dispatch_type, integer, offsetof(struct qc_zvm_guest, ziip_dispatch_type)}, {-1, string, -1} }; static struct qc_attr zos_zcx_server_attrs[] = { {qc_layer_type_num, integer, offsetof(struct qc_zos_zcx_server, layer_type_num)}, {qc_layer_category_num, integer, offsetof(struct qc_zos_zcx_server, layer_category_num)}, {qc_layer_type, string, offsetof(struct qc_zos_zcx_server, layer_type)}, {qc_layer_category, string, offsetof(struct qc_zos_zcx_server, layer_category)}, {qc_layer_name, string, offsetof(struct qc_zos_zcx_server, layer_name)}, {qc_capping, string, offsetof(struct qc_zos_zcx_server, capping)}, {qc_capping_num, integer, offsetof(struct qc_zos_zcx_server, capping_num)}, {qc_has_secure, integer, offsetof(struct qc_zos_zcx_server, has_secure)}, {qc_secure, integer, offsetof(struct qc_zos_zcx_server, secure)}, {qc_num_cpu_total, integer, offsetof(struct qc_zos_zcx_server, num_cpu_total)}, {qc_num_cpu_configured, integer, offsetof(struct qc_zos_zcx_server, num_cpu_configured)}, {qc_num_cpu_standby, integer, offsetof(struct qc_zos_zcx_server, num_cpu_standby)}, {qc_num_cpu_reserved, integer, offsetof(struct qc_zos_zcx_server, num_cpu_reserved)}, {qc_num_cpu_dedicated, integer, offsetof(struct qc_zos_zcx_server, num_cpu_dedicated)}, {qc_num_cpu_shared, integer, offsetof(struct qc_zos_zcx_server, num_cpu_shared)}, {qc_num_cp_total, integer, offsetof(struct qc_zos_zcx_server, num_cp_total)}, {qc_num_cp_dedicated, integer, offsetof(struct qc_zos_zcx_server, num_cp_dedicated)}, {qc_num_cp_shared, integer, offsetof(struct qc_zos_zcx_server, num_cp_shared)}, {qc_num_ziip_total, integer, offsetof(struct qc_zos_zcx_server, num_ziip_total)}, {qc_num_ziip_dedicated, integer, offsetof(struct qc_zos_zcx_server, num_ziip_dedicated)}, {qc_num_ziip_shared, integer, offsetof(struct qc_zos_zcx_server, num_ziip_shared)}, {qc_has_multiple_cpu_types, integer, offsetof(struct qc_zos_zcx_server, has_multiple_cpu_types)}, {qc_cp_dispatch_limithard, integer, offsetof(struct qc_zos_zcx_server, cp_dispatch_limithard)}, {qc_cp_capped_capacity, integer, offsetof(struct qc_zos_zcx_server, cp_capped_capacity)}, {qc_ziip_dispatch_limithard, integer, offsetof(struct qc_zos_zcx_server, ziip_dispatch_limithard)}, {qc_ziip_capped_capacity, integer, offsetof(struct qc_zos_zcx_server, ziip_capped_capacity)}, {qc_cp_dispatch_type, integer, offsetof(struct qc_zos_zcx_server, cp_dispatch_type)}, {qc_ziip_dispatch_type, integer, offsetof(struct qc_zos_zcx_server, ziip_dispatch_type)}, {-1, string, -1} }; static struct qc_attr kvm_guest_attrs[] = { {qc_layer_type_num, integer, offsetof(struct qc_kvm_guest, layer_type_num)}, {qc_layer_category_num, integer, offsetof(struct qc_kvm_guest, layer_category_num)}, {qc_layer_type, string, offsetof(struct qc_kvm_guest, layer_type)}, {qc_layer_category, string, offsetof(struct qc_kvm_guest, layer_category)}, {qc_layer_name, string, offsetof(struct qc_kvm_guest, layer_name)}, {qc_layer_extended_name, string, offsetof(struct qc_kvm_guest, layer_extended_name)}, {qc_layer_uuid, string, offsetof(struct qc_kvm_guest, layer_uuid)}, {qc_has_secure, integer, offsetof(struct qc_kvm_guest, has_secure)}, {qc_secure, integer, offsetof(struct qc_kvm_guest, secure)}, {qc_num_cpu_total, integer, offsetof(struct qc_kvm_guest, num_cpu_total)}, {qc_num_cpu_configured, integer, offsetof(struct qc_kvm_guest, num_cpu_configured)}, {qc_num_cpu_standby, integer, offsetof(struct qc_kvm_guest, num_cpu_standby)}, {qc_num_cpu_reserved, integer, offsetof(struct qc_kvm_guest, num_cpu_reserved)}, {qc_num_cpu_dedicated, integer, offsetof(struct qc_kvm_guest, num_cpu_dedicated)}, {qc_num_cpu_shared, integer, offsetof(struct qc_kvm_guest, num_cpu_shared)}, {qc_num_ifl_total, integer, offsetof(struct qc_kvm_guest, num_ifl_total)}, {qc_num_ifl_dedicated, integer, offsetof(struct qc_kvm_guest, num_ifl_dedicated)}, {qc_num_ifl_shared, integer, offsetof(struct qc_kvm_guest, num_ifl_shared)}, {qc_ifl_dispatch_type, integer, offsetof(struct qc_kvm_guest, ifl_dispatch_type)}, {-1, string, -1} }; const char *qc_attr_id_to_char(struct qc_handle *hdl, enum qc_attr_id id) { switch (id) { case qc_layer_type_num: return "layer_type_num"; case qc_layer_category_num: return "layer_category_num"; case qc_layer_type: return "layer_type"; case qc_layer_category: return "layer_category"; case qc_layer_name: return "layer_name"; case qc_layer_extended_name: return "layer_extended_name"; case qc_layer_uuid: return "layer_uuid"; case qc_lic_identifier: return "lic_identifier"; case qc_manufacturer: return "manufacturer"; case qc_type: return "type"; case qc_model_capacity: return "model_capacity"; case qc_type_family: return "type_family"; case qc_model: return "model"; case qc_type_name: return "type_name"; case qc_sequence_code: return "sequence_code"; case qc_plant: return "plant"; case qc_num_cpu_total: return "num_cpu_total"; case qc_num_cpu_configured: return "num_cpu_configured"; case qc_num_cpu_standby: return "num_cpu_standby"; case qc_num_cpu_reserved: return "num_cpu_reserved"; case qc_num_cpu_dedicated: return "num_cpu_dedicated"; case qc_num_cpu_shared: return "num_cpu_shared"; case qc_num_cp_total: return "num_cp_total"; case qc_num_cp_dedicated: return "num_cp_dedicated"; case qc_num_cp_shared: return "num_cp_shared"; case qc_num_ifl_total: return "num_ifl_total"; case qc_num_ifl_dedicated: return "num_ifl_dedicated"; case qc_num_ifl_shared: return "num_ifl_shared"; case qc_capability: return "capability"; case qc_secondary_capability: return "secondary_capability"; case qc_capacity_adjustment_indication: return "capacity_adjustment_indication"; case qc_capacity_change_reason: return "capacity_change_reason"; case qc_partition_number: return "partition_number"; case qc_partition_char: return "partition_char"; case qc_partition_char_num: return "partition_char_num"; case qc_adjustment: return "adjustment"; case qc_cp_absolute_capping: return "cp_absolute_capping"; case qc_ifl_absolute_capping: return "ifl_absolute_capping"; case qc_cp_weight_capping: return "cp_weight_capping"; case qc_ifl_weight_capping: return "ifl_weight_capping"; case qc_cluster_name: return "cluster_name"; case qc_control_program_id: return "control_program_id"; case qc_limithard_consumption: return "limithard_consumption"; case qc_prorated_core_time: return "prorated_core_time"; case qc_cp_limithard_cap: return "pool_cp_limithard_cap"; case qc_cp_capacity_cap: return "pool_cp_capacity_cap"; case qc_ifl_limithard_cap: return "pool_ifl_limithard_cap"; case qc_ifl_capacity_cap: return "pool_ifl_capacity_cap"; case qc_capping: return "capping"; case qc_capping_num: return "capping_num"; case qc_mobility_enabled: return "mobility_enabled"; case qc_has_secure: return "has_secure"; case qc_secure: return "secure"; case qc_has_multiple_cpu_types: return "has_multiple_cpu_types"; case qc_cp_dispatch_limithard: return "cp_dispatch_limithard"; case qc_ifl_dispatch_limithard: return "ifl_dispatch_limithard"; case qc_cp_dispatch_type: return "cp_dispatch_type"; case qc_ifl_dispatch_type: return "ifl_dispatch_type"; case qc_cp_capped_capacity: return "cp_capped_capacity"; case qc_ifl_capped_capacity: return "ifl_capped_capacity"; case qc_num_cp_threads: return "num_cp_threads"; case qc_num_ifl_threads: return "num_ifl_threads"; case qc_num_core_total: return "num_core_total"; case qc_num_core_configured: return "num_core_configured"; case qc_num_core_standby: return "num_core_standby"; case qc_num_core_reserved: return "num_core_reserved"; case qc_num_core_dedicated: return "num_core_dedicated"; case qc_num_core_shared: return "num_core_shared"; case qc_ziip_absolute_capping: return "qc_ziip_absolute_capping"; case qc_ziip_capacity_cap: return "qc_ziip_capacity_cap"; case qc_ziip_capped_capacity: return "qc_ziip_capped_capacity"; case qc_ziip_dispatch_limithard: return "qc_ziip_dispatch_limithard"; case qc_ziip_dispatch_type: return "qc_ziip_dispatch_type"; case qc_ziip_limithard_cap: return "qc_ziip_limithard_cap"; case qc_ziip_weight_capping: return "qc_ziip_weight_capping"; case qc_num_ziip_dedicated: return "qc_num_ziip_dedicated"; case qc_num_ziip_shared: return "qc_num_ziip_shared"; case qc_num_ziip_total: return "qc_num_ziip_total"; case qc_num_ziip_threads: return "qc_num_ziip_threads"; default: break; } qc_debug(hdl, "Error: Cannot convert unknown attribute '%d' to char*\n", id); return NULL; } // 'hdl' is for error reporting, as 'tgthdl' might not be part of the pointer lists yet int qc_new_handle(struct qc_handle *hdl, struct qc_handle **tgthdl, int layer_no, int layer_type_num) { int num_attrs, layer_category_num; char *layer_type, *layer_category; struct qc_attr *attrs; size_t layer_sz; switch (layer_type_num) { case QC_LAYER_TYPE_CEC: layer_sz = sizeof(struct qc_cec); attrs = cec_attrs; layer_category_num = QC_LAYER_CAT_HOST; layer_category = "HOST"; layer_type = "CEC"; break; case QC_LAYER_TYPE_LPAR_GROUP: layer_sz = sizeof(struct qc_lpar); attrs = lpar_group_attrs; layer_category_num = QC_LAYER_CAT_POOL; layer_category = "POOL"; layer_type = "LPAR-GROUP"; break; case QC_LAYER_TYPE_LPAR: layer_sz = sizeof(struct qc_lpar); attrs = lpar_attrs; layer_category_num = QC_LAYER_CAT_GUEST; layer_category = "GUEST"; layer_type = "LPAR"; break; case QC_LAYER_TYPE_ZVM_HYPERVISOR: layer_sz = sizeof(struct qc_zvm_hypervisor); attrs = zvm_hv_attrs; layer_category_num = QC_LAYER_CAT_HOST; layer_category = "HOST"; layer_type = "z/VM-hypervisor"; break; case QC_LAYER_TYPE_ZVM_RESOURCE_POOL: layer_sz = sizeof(struct qc_zvm_pool); attrs = zvm_pool_attrs; layer_category_num = QC_LAYER_CAT_POOL; layer_category = "POOL"; #ifdef CONFIG_V1_COMPATIBILITY layer_type = "z/VM-CPU-pool"; #else layer_type = "z/VM-resource-pool"; #endif break; case QC_LAYER_TYPE_ZVM_GUEST: layer_sz = sizeof(struct qc_zvm_guest); attrs = zvm_guest_attrs; layer_category_num = QC_LAYER_CAT_GUEST; layer_category = "GUEST"; layer_type = "z/VM-guest"; break; case QC_LAYER_TYPE_ZOS_HYPERVISOR: layer_sz = sizeof(struct qc_zos_hypervisor); attrs = zos_hv_attrs; layer_category_num = QC_LAYER_CAT_HOST; layer_category = "HOST"; layer_type = "z/OS-hypervisor"; break; case QC_LAYER_TYPE_ZOS_TENANT_RESOURCE_GROUP: layer_sz = sizeof(struct qc_zos_tenant_resource_group); attrs = zos_tenant_resgroup_attrs; layer_category_num = QC_LAYER_CAT_POOL; layer_category = "POOL"; layer_type = "z/OS-tenant-resource-group"; break; case QC_LAYER_TYPE_KVM_HYPERVISOR: layer_sz = sizeof(struct qc_kvm_hypervisor); attrs = kvm_hv_attrs; layer_category_num = QC_LAYER_CAT_HOST; layer_category = "HOST"; layer_type = "KVM-hypervisor"; break; case QC_LAYER_TYPE_KVM_GUEST: layer_sz = sizeof(struct qc_kvm_guest); attrs = kvm_guest_attrs; layer_category_num = QC_LAYER_CAT_GUEST; layer_category = "GUEST"; layer_type = "KVM-guest"; break; case QC_LAYER_TYPE_ZOS_ZCX_SERVER: layer_sz = sizeof(struct qc_zos_zcx_server); attrs = zos_zcx_server_attrs; layer_category_num = QC_LAYER_CAT_GUEST; layer_category = "GUEST"; layer_type = "z/OS-zCX-Server"; break; default: qc_debug(hdl, "Error: Unhandled layer type in qc_new_handle()\n"); return -1; } // determine number of attributes for (num_attrs = 0; attrs[num_attrs].offset >= 0; ++num_attrs); num_attrs++; if (hdl || *tgthdl == NULL) { // Possibly reuse existing handle when alloc'ing the cec layer. // Otherwise we'd change the handle which serves as an identified in // our log output, which could be confusing. *tgthdl = malloc(sizeof(struct qc_handle)); if (!*tgthdl) { qc_debug(hdl, "Error: Failed to allocate handle\n"); return -2; } } memset(*tgthdl, 0, sizeof(struct qc_handle)); (*tgthdl)->layer_no = layer_no; (*tgthdl)->attr_list = attrs; if (hdl) (*tgthdl)->root = hdl->root; else (*tgthdl)->root = *tgthdl; (*tgthdl)->layer = malloc(layer_sz); if (!(*tgthdl)->layer) { qc_debug(hdl, "Error: Failed to allocate layer\n"); free(*tgthdl); *tgthdl = NULL; return -3; } memset((*tgthdl)->layer, 0, layer_sz); (*tgthdl)->attr_present = calloc(num_attrs, sizeof(int)); (*tgthdl)->src = calloc(num_attrs, sizeof(int)); if (!(*tgthdl)->attr_present || !(*tgthdl)->src) { qc_debug(hdl, "Error: Failed to allocate attr_present array\n"); free((*tgthdl)->layer); free(*tgthdl); *tgthdl = NULL; return -4; } if (qc_set_attr_int(*tgthdl, qc_layer_type_num, layer_type_num, ATTR_SRC_UNDEF) || qc_set_attr_int(*tgthdl, qc_layer_category_num, layer_category_num, ATTR_SRC_UNDEF) || qc_set_attr_string(*tgthdl, qc_layer_type, layer_type, ATTR_SRC_UNDEF) || qc_set_attr_string(*tgthdl, qc_layer_category, layer_category, ATTR_SRC_UNDEF)) return -5; return 0; } int qc_insert_handle(struct qc_handle *hdl, struct qc_handle **inserted_hdl, int type) { struct qc_handle *prev_hdl = qc_get_prev_handle(hdl); if (!prev_hdl) return -1; if (qc_new_handle(hdl, inserted_hdl, hdl->layer_no, type)) return -2; (*inserted_hdl)->next = hdl; prev_hdl->next = *inserted_hdl; // adjust layer_no in remaining layers for (; hdl != NULL; hdl = hdl->next) hdl->layer_no++; return 0; } int qc_append_handle(struct qc_handle *hdl, struct qc_handle **appended_hdl, int type) { struct qc_handle *next_hdl = hdl->next; if (qc_new_handle(hdl, appended_hdl, hdl->layer_no + 1, type)) return -1; hdl->next = *appended_hdl; (*appended_hdl)->next = next_hdl; // adjust layer_no in remaining layers for (hdl = next_hdl; hdl != NULL; hdl = hdl->next) hdl->layer_no++; return 0; } #ifdef CONFIG_V1_COMPATIBILITY /* Maps qc_num_cpu_* to qc_num_core_* attributes where required to preserve backwards compatibility. * Should be removed in a qclib v2.0 release. */ static enum qc_attr_id preserve_v1_attr_compatibility(struct qc_handle *hdl, enum qc_attr_id id) { if (id != qc_layer_type_num) { int *layer_type = qc_get_attr_value_int(hdl, qc_layer_type_num); switch (*layer_type) { case QC_LAYER_TYPE_CEC: case QC_LAYER_TYPE_LPAR: switch (id) { case qc_num_cpu_configured: return qc_num_core_configured; case qc_num_cpu_standby: return qc_num_core_standby; case qc_num_cpu_reserved: return qc_num_core_reserved; default: break; } // fallthrough case QC_LAYER_TYPE_ZVM_HYPERVISOR: case QC_LAYER_TYPE_KVM_HYPERVISOR: switch (id) { case qc_num_cpu_total: return qc_num_core_total; case qc_num_cpu_dedicated: return qc_num_core_dedicated; case qc_num_cpu_shared: return qc_num_core_shared; default: break; } } } return id; } #endif // Indicates the attribute as 'set', returning a ptr to its content static char *qc_set_attr(struct qc_handle *hdl, enum qc_attr_id id, enum qc_data_type type, char src, int *prev_set) { struct qc_attr *attr_list = hdl->attr_list; int count; for (count = 0; attr_list[count].offset >= 0; ++count) { if (attr_list[count].id == id && attr_list[count].type == type) { *prev_set = hdl->attr_present[count]; hdl->attr_present[count] = 1; hdl->src[count] = src; return (char *)hdl->layer + attr_list[count].offset; } } qc_debug(hdl, "Error: Failed to set attr=%s (not found)\n", qc_attr_id_to_char(hdl, id)); return NULL; } // Sets attribute 'id' in layer as pointed to by 'hdl' int qc_set_attr_int(struct qc_handle *hdl, enum qc_attr_id id, int val, char src) { char orig_src = qc_get_attr_value_src_int(hdl, id); int *ptr, prev_set; #ifdef CONFIG_V1_COMPATIBILITY id = preserve_v1_attr_compatibility(hdl, id); #endif if ((ptr = (int *)qc_set_attr(hdl, id, integer, src, &prev_set)) == NULL) return -1; if (qc_consistency_check_requested && prev_set && *ptr != val) { #ifdef CONFIG_TEXTUAL_HYPFS int *layer_type = qc_get_attr_value_int(hdl, qc_layer_type_num); // Affects ids qc_num_cp_total and qc_num_ifl_total only if (orig_src != ATTR_SRC_HYPFS || *layer_type != QC_LAYER_TYPE_LPAR) { #endif qc_debug(hdl, "Error: Consistency at layer %d: Attr %s had value %d from %c, try to set to %d from %c\n", hdl->layer_no, qc_attr_id_to_char(hdl, id), *ptr, orig_src, val, src); return -2; #ifdef CONFIG_TEXTUAL_HYPFS } #endif } *ptr = val; return 0; } // Sets attribute 'id' in layer as pointed to by 'hdl' int qc_set_attr_float(struct qc_handle *hdl, enum qc_attr_id id, float val, char src) { char orig_src = qc_get_attr_value_src_int(hdl, id); int prev_set; float *ptr; if ((ptr = (float *)qc_set_attr(hdl, id, floatingpoint, src, &prev_set)) == NULL) return -1; if (qc_consistency_check_requested && prev_set && *ptr != val) { qc_debug(hdl, "Error: Consistency at layer %d: Attr %s had value %f from %c, try to set to %f from %c\n", hdl->layer_no, qc_attr_id_to_char(hdl, id), *ptr, orig_src, val, src); return -2; } *ptr = val; return 0; } // Sets string attribute 'id' in layer as pointed to by 'hdl', stripping trailing blanks, but // leaving the original string unmodified int qc_set_attr_string(struct qc_handle *hdl, enum qc_attr_id id, const char *str, char src) { char orig_src = qc_get_attr_value_src_int(hdl, id); unsigned int attr_len = qc_get_str_attr_len(id); char *ptr, *tmp, *s; int prev_set; if ((ptr = qc_set_attr(hdl, id, string, src, &prev_set)) == NULL) return -1; if (qc_consistency_check_requested && prev_set) { if ((tmp = strdup(str)) == NULL) { qc_debug(hdl, "Error: Failed to duplicate string\n"); return -2; } for (s = &tmp[strlen(tmp) - 1]; (*s == ' ' || *s == '\n') && s != tmp; --s) *s = '\0'; if (strcmp(ptr, tmp)) { qc_debug(hdl, "Error: Consistency at layer %d: Attr %s had value %s from %c, try to set to %s from %c\n", hdl->layer_no, qc_attr_id_to_char(hdl, id), ptr, orig_src, tmp, src); free(tmp); return -3; } free(tmp); } ptr[attr_len - 1] = '\0'; strncpy(ptr, str, attr_len - 1); // strip trailing blanks for (s = &ptr[strlen(ptr) - 1]; (*s == ' ' || *s == '\n') && s != ptr; --s) *s = '\0'; return 0; } // Sets ebcdic string attribute 'id' in layer as pointed to by 'hdl' // Note: Copy content to temporary buffer for conversion first, as we do not want to modify the source data. int qc_set_attr_ebcdic_string(struct qc_handle *hdl, enum qc_attr_id id, unsigned char *str, unsigned int str_len, char src) { char *buf; int rc; buf = malloc(str_len + 1); if (!buf) { qc_debug(hdl, "Error: Memory allocation error\n"); return -1; } memset(buf, '\0', str_len + 1); memcpy(buf, str, str_len); if ((rc = qc_ebcdic_to_ascii(hdl, buf, str_len)) == 0) { if (strlen(buf) && qc_set_attr_string(hdl, id, (char *)buf, src)) rc = -2; } free(buf); return rc; } int qc_is_nonempty_ebcdic(__u64 *str) { // CPU Pools in STHYI have all EBCDIC spaces if not set return *str != 0x0 && *str != 0x4040404040404040ULL; } // Returns whether attribute 'id' in layer as pointed to by 'hdl' is set/defined static int qc_is_attr_set(struct qc_handle *hdl, enum qc_attr_id id, enum qc_data_type type) { struct qc_attr *attr_list = hdl->attr_list; int count = 0; while (attr_list[count].offset >= 0) { if (attr_list[count].id == id && attr_list[count].type == type) return hdl->attr_present[count]; count++; } return 0; } int qc_is_attr_set_int(struct qc_handle *hdl, enum qc_attr_id id) { return qc_is_attr_set(hdl, id, integer); } int qc_is_attr_set_float(struct qc_handle *hdl, enum qc_attr_id id) { return qc_is_attr_set(hdl, id, floatingpoint); } int qc_is_attr_set_string(struct qc_handle *hdl, enum qc_attr_id id) { return qc_is_attr_set(hdl, id, string); } struct qc_handle *qc_get_root_handle(struct qc_handle *hdl) { return hdl ? hdl->root : NULL; } struct qc_handle *qc_get_top_handle(struct qc_handle *hdl) { for (; hdl->next != NULL; hdl = hdl->next); return hdl; } struct qc_handle *qc_get_prev_handle(struct qc_handle *hdl) { struct qc_handle *prev_hdl = NULL; for (prev_hdl = hdl->root; prev_hdl->next != NULL; prev_hdl = prev_hdl->next) if (prev_hdl->next == hdl) return prev_hdl; qc_debug(hdl, "Error: Couldn't find handle pointing at layer %d handle\n", hdl->layer_no); return NULL; } static int qc_get_attr_idx(struct qc_handle *hdl, enum qc_attr_id id, enum qc_data_type type) { struct qc_attr *attr_list = hdl->attr_list; int idx; for (idx = 0; attr_list[idx].offset >= 0; ++idx) if (attr_list[idx].id == id && attr_list[idx].type == type) return idx; return -1; } /// Retrieve value of attribute 'id' of layer pointed at by 'hdl' static void *qc_get_attr_value(struct qc_handle *hdl, enum qc_attr_id id, enum qc_data_type type) { struct qc_attr *attr_list = hdl->attr_list; int idx; if ((idx = qc_get_attr_idx(hdl, id, type)) < 0 || !hdl->attr_present[idx]) return NULL; return (char *)hdl->layer + attr_list[idx].offset; } int *qc_get_attr_value_int(struct qc_handle *hdl, enum qc_attr_id id) { #ifdef CONFIG_V1_COMPATIBILITY id = preserve_v1_attr_compatibility(hdl, id); #endif return (int *)qc_get_attr_value(hdl, id, integer); } float *qc_get_attr_value_float(struct qc_handle *hdl, enum qc_attr_id id) { return (float *)qc_get_attr_value(hdl, id, floatingpoint); } char *qc_get_attr_value_string(struct qc_handle *hdl, enum qc_attr_id id) { return (char *)qc_get_attr_value(hdl, id, string); } static char qc_get_attr_value_src(struct qc_handle *hdl, enum qc_attr_id id, enum qc_data_type type) { int idx; if ((idx = qc_get_attr_idx(hdl, id, type)) < 0) return 'x'; return hdl->src[idx]; } char qc_get_attr_value_src_int(struct qc_handle *hdl, enum qc_attr_id id) { #ifdef CONFIG_V1_COMPATIBILITY id = preserve_v1_attr_compatibility(hdl, id); #endif return qc_get_attr_value_src(hdl, id, integer); } char qc_get_attr_value_src_float(struct qc_handle *hdl, enum qc_attr_id id) { return qc_get_attr_value_src(hdl, id, floatingpoint); } char qc_get_attr_value_src_string(struct qc_handle *hdl, enum qc_attr_id id) { return qc_get_attr_value_src(hdl, id, string); } qclib-2.1.0/Makefile0000664000175000017500000000557013647300120013275 0ustar rasplraspl# Copyright IBM Corp. 2013, 2017 # Versioning scheme: major.minor.bugfix # major : Backwards compatible changes to the API # minor : Additions leaving the API unmodified # bugfix: Bugfixes only VERSION = 2.1.0 VERM = $(shell echo $(VERSION) | cut -d '.' -f 1) CFLAGS ?= -g -Wall -O2 CFILES = query_capacity.c query_capacity_data.c query_capacity_sysinfo.c \ query_capacity_sysfs.c query_capacity_hypfs.c query_capacity_sthyi.c OBJECTS = $(patsubst %.c,%.o,$(CFILES)) .SUFFIXES: .o .c LEVEL := $(shell git log --pretty=format:'%h' -n 1) DATE := $(shell git log --pretty=format:'%ai' -n 1) ifneq ("${V}","1") MAKEFLAGS += --quiet cmd = echo $1$2; else cmd = endif CC = $(call cmd," CC ",$@)gcc LINK = $(call cmd," LINK ",$@)gcc AR = $(call cmd," AR ",$@)ar DOC = $(call cmd," DOC ",$@)doxygen TAR = $(call cmd," TAR ",$@)tar GEN = $(call cmd," GEN ",$@)grep all: libqc.a libqc.so.$(VERSION) qc_test qc_test-sh hcpinfbk_qclib.h: hcpinfbk.h $(GEN) -ve "^#pragma " $< > $@ # strip off z/VM specific pragmas %.o: %.c query_capacity.h query_capacity_int.h query_capacity_data.h hcpinfbk_qclib.h $(CC) $(CFLAGS) -fpic -c $< -o $@ libqc.a: $(OBJECTS) $(AR) rcs $@ $^ libqc.so.$(VERSION): $(OBJECTS) $(LINK) -Wl,-soname,libqc.so.$(VERM) -shared $^ -o $@ -rm libqc.so.$(VERM) 2>/dev/null ln -s libqc.so.$(VERSION) libqc.so.$(VERM) qc_test: qc_test.c libqc.a $(CC) $(CFLAGS) -static $< -L. -lqc -o $@ qc_test-sh: qc_test.c libqc.so.$(VERSION) $(CC) $(CFLAGS) -L. $< -o $@ libqc.so.$(VERSION) test: qc_test ./$< test-sh: qc_test-sh LD_LIBRARY_PATH=. ./$< doc: html html: $(CFILES) query_capacity.h query_capacity_int.h query_capacity_data.h hcpinfbk_qclib.h @if [ "`which doxygen 2>/dev/null`" != "" ]; then \ $(DOC) config.doxygen 2>&1 | sed 's/^/ /'; \ else \ echo "Error: 'doxygen' not installed"; \ fi install: libqc.a libqc.so.$(VERSION) echo " INSTALL" install -Dm 644 libqc.a $(DESTDIR)/usr/lib64/libqc.a install -Dm 755 libqc.so.$(VERSION) $(DESTDIR)/usr/lib64/libqc.so.$(VERSION) ln -sr $(DESTDIR)/usr/lib64/libqc.so.$(VERSION) $(DESTDIR)/usr/lib64/libqc.so.$(VERM) ln -sr $(DESTDIR)/usr/lib64/libqc.so.$(VERSION) $(DESTDIR)/usr/lib64/libqc.so install -Dm 644 query_capacity.h $(DESTDIR)/usr/include/query_capacity.h install -Dm 644 README $(DESTDIR)/usr/share/doc/packages/qclib/README install -Dm 644 LICENSE $(DESTDIR)/usr/share/doc/packages/qclib/LICENSE installdoc: doc echo " INSTALLDOC" install -dm 755 $(DESTDIR)/usr/share/doc/packages/qclib/html cp -r html/* $(DESTDIR)/usr/share/doc/packages/qclib/html chmod 644 $(DESTDIR)/usr/share/doc/packages/qclib/html/search/* chmod 644 $(DESTDIR)/usr/share/doc/packages/qclib/html/* chmod 755 $(DESTDIR)/usr/share/doc/packages/qclib/html/search clean: echo " CLEAN" rm -f $(OBJECTS) libqc.a libqc.so.$(VERSION) qc_test qc_test-sh hcpinfbk_qclib.h rm -rf html libqc.so.$(VERM) qclib-2.1.0/query_capacity_hypfs.c0000664000175000017500000007756013647300120016244 0ustar rasplraspl/* Copyright IBM Corp. 2013, 2019 */ #define _GNU_SOURCE #define _DEFAULT_SOURCE #include #include #include #include #include #include "query_capacity_data.h" #define QC_HYPFS_LPAR "/s390_hypfs/diag_204" #define QC_HYPFS_ZVM "/s390_hypfs/diag_2fc" #define QC_NAME_LEN 8 #define QC_CPU_TYPE_CP 0 #define QC_CPU_TYPE_IFL 3 #define QC_CPU_TYPE_ZIIP 5 #define QC_FLAG_PHYS 0x80 #define QC_CPU_DEDICATED 0xffff #define QC_CPU_CONFIGURED 0x20 #define QC_CPU_CAPPED 0x40 #define HYPFS_NA 0 #ifdef CONFIG_TEXTUAL_HYPFS #define HYPFS_AVAIL_ASCII_LPAR 1 #define HYPFS_AVAIL_ASCII_ZVM 2 #endif #define HYPFS_AVAIL_BIN_LPAR 3 #define HYPFS_AVAIL_BIN_ZVM 4 struct dfs_diag_hdr { __u64 len; __u16 version; __u8 tod_ext[16]; __u64 count; __u8 reserved[30]; } __attribute__ ((packed)); struct dfs_info_blk_hdr { __u8 npar; __u8 flags; __u8 reserved1[4]; __u16 thispart; __u64 curtod1; __u64 curtod2; __u8 reserved[40]; } __attribute__ ((packed)); struct dfs_sys_hdr { __u8 reserved1; __u8 cpus; __u8 rcpus; __u8 reserved2[5]; char sys_name[8]; __u8 reserved3[48]; char grp_name[8]; __u8 reserved4[24]; } __attribute__ ((packed)); // Note: We do with a single struct for CPU info only, though formally each section type // has its own struct defined. However, all relevant parts match across all sections. struct dfs_cpu_info { __u16 cpu_addr; __u16 reserved1; __u8 ctidx; __u8 cflag; __u16 weight; __u64 acc_time; __u64 lp_time; __u64 reserved3; __u64 online_time; __u32 reserved4[4]; __u32 cpuTypeCap; __u32 groupCpuTypeCap; __u32 reserved5[8]; } __attribute__ ((packed)); struct dfs_diag2fc { __u32 version; __u32 flags; __u64 used_cpu; __u64 el_time; __u64 mem_min_kb; __u64 mem_max_kb; __u64 mem_share_kb; __u64 mem_used_kb; __u32 pcpus; __u32 lcpus; __u32 vcpus; __u32 ocpus; __u32 cpu_max; __u32 cpu_shares; __u32 cpu_use_samp; __u32 cpu_delay_samp; __u32 page_wait_samp; __u32 idle_samp; __u32 other_samp; __u32 total_samp; char guest_name[QC_NAME_LEN]; } __attribute__ ((packed)); struct hypfs_priv { char *data; int avail; ssize_t len; char *diag; char *hypfs; }; // Returns a malloc'd string with the concatenated path static char *qc_get_path(struct qc_handle *hdl, const char *dbgfs, const char *file) { char *buf; if (asprintf(&buf, "%s%s", dbgfs, file) == -1) { qc_debug(hdl, "Error: Buffer allocation failed\n"); buf = NULL; } return buf; } #ifdef CONFIG_TEXTUAL_HYPFS static void qc_dump_hypfs(struct qc_handle *hdl, char *hypfs) { char *cmd; int rc; qc_debug_indent_inc(); /* dumping textual hypfs this way and a lot later than the actual parse can give us different data from what we parsed before - but that is the best that we can do */ if (!hypfs) { qc_debug(hdl, "Error: Failed to dump textual hypfs as hypfs==NULL\n"); qc_mark_dump_incomplete(hdl, "hypfs textual"); qc_debug_indent_dec(); return; } /* We read all files individually during regular processing, so we can do now is to copy the content with 'cp -r' */ if (asprintf(&cmd, "/bin/cp -r %s/hyp %s/cpus %s/systems %s > /dev/null 2>&1", hypfs, hypfs, hypfs, qc_dbg_dump_dir) == -1) { qc_debug(hdl, "Error: Mem alloc failure, cannot dump textual hypfs\n"); qc_mark_dump_incomplete(hdl, "hypfs textual"); qc_debug_indent_dec(); return; } if ((rc = system(cmd)) == 0) { qc_debug(hdl, "hypfs (textual) dumped to '%s'\n", qc_dbg_dump_dir); } else { qc_debug(hdl, "Error: Failed to dump textual hypfs with command '%s', rc=%d\n", cmd, rc); qc_mark_dump_incomplete(hdl, "hypfs textual"); } free(cmd); qc_debug_indent_dec(); return; } #endif static void qc_dump_hypfs_bin(struct qc_handle *hdl, const char *diag, __u8 *data, ssize_t len) { char *fname = NULL, *cmd; int fd, rc, success = 0; /* We re-create the same directory/file structure that we read from */ // first off, create a subdirectory so the files look exactly like on dbgfs if (!data) { qc_debug(hdl, "Error: No data passed in, cannot write binary dump\n"); goto out; } if (asprintf(&fname, "%s/s390_hypfs", qc_dbg_dump_dir) == -1) { qc_debug(hdl, "Error: Mem alloc error, cannot create dump dir\n"); goto out; } mkdir(fname, S_IRWXU); // we don't care about a failure - could exist from a previous dump, // and we'll know when we store the actual data if things are good free(fname); if (asprintf(&fname, "%s/%s", qc_dbg_dump_dir, strcmp(diag, QC_HYPFS_LPAR) ? QC_HYPFS_ZVM : QC_HYPFS_LPAR) == -1) { qc_debug(hdl, "Error: Mem alloc error, cannot write dump\n"); goto out; } fd = open(fname, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); if (fd == -1) { qc_debug(hdl, "Error: Failed to open file '%s' to write dump\n", fname); goto out; } rc = write(fd, data, len); close(fd); if (rc == -1) { qc_debug(hdl, "Error: Failed to write binary hypfs data into dump: %s\n", strerror(errno)); } else { qc_debug(hdl, "hypfs binary data dumped to '%s'\n", fname); success = 1; } if (strcmp(diag, QC_HYPFS_ZVM) == 0) { // if we're on z/VM, we need to make sure that the LPAR file exists, as logic // uses it as a flag to indicate presence of the binary hypfs API if (asprintf(&cmd, "/bin/touch %s/%s > /dev/null 2>&1", qc_dbg_dump_dir, QC_HYPFS_LPAR) == -1) { qc_debug(hdl, "Error: Mem alloc failure, could not touch '%s'. " "Dump will not work without, fix by adding it manually later on.\n", QC_HYPFS_LPAR); qc_mark_dump_incomplete(hdl, QC_HYPFS_LPAR); goto out; } if ((rc = system(cmd)) != 0) { qc_debug(hdl, "Error: Command '%s' failed, rc=%d. Dump will not work " "without, fix by adding it manually later on.\n", cmd, rc); qc_mark_dump_incomplete(hdl, QC_HYPFS_LPAR); } free(cmd); } out: free(fname); if (!success) qc_mark_dump_incomplete(hdl, "hypfs binary"); } static void qc_hypfs_dump(struct qc_handle *hdl, char *buf) { struct hypfs_priv *priv = (struct hypfs_priv *)buf; qc_debug(hdl, "Dump hypfs\n"); qc_debug_indent_inc(); if (!priv) goto out; switch(priv->avail) { #ifdef CONFIG_TEXTUAL_HYPFS case HYPFS_AVAIL_ASCII_LPAR: case HYPFS_AVAIL_ASCII_ZVM: qc_dump_hypfs(hdl, priv->hypfs); break; #endif case HYPFS_AVAIL_BIN_LPAR: case HYPFS_AVAIL_BIN_ZVM: qc_dump_hypfs_bin(hdl, priv->diag, (__u8 *)priv->data, priv->len); break; case HYPFS_NA: default: break; } out: qc_debug_indent_dec(); return; } #ifdef CONFIG_TEXTUAL_HYPFS // path must be hypfs path ending with '.../cpus' static int qc_get_hypfs_cpu_types(struct qc_handle *hdl, const char *path, int *ifl_total, int *cp_total) { char str_buf[STR_BUF_SIZE]; struct dirent **namelist; int n, no_files, un_total = 0, rc = 0; FILE *file; char *tmp; *ifl_total = *cp_total = 0; no_files = scandir(path, &namelist, NULL, alphasort); for (n = 0; n < no_files; n++) { if (*namelist[n]->d_name == '.') // skip '.' and '..' to avoid false positives continue; if (asprintf(&tmp, "%s/%s/type", path, namelist[n]->d_name) == -1) { qc_debug(hdl, "Error: Couldn't allocate buffer for hypfs type path\n"); rc = -1; goto out; } file = fopen(tmp, "r"); if (!file) { free(tmp); continue; } qc_debug(hdl, "Parsing file %s\n", tmp); free(tmp); memset(str_buf, 0, STR_BUF_SIZE); if (fread(str_buf, 1, STR_BUF_SIZE, file) > 0) { if (!strncmp("CP", str_buf, strlen("CP"))) (*cp_total)++; else if (!strncmp("IFL", str_buf, strlen("IFL"))) (*ifl_total)++; else un_total++; } fclose(file); } qc_debug(hdl, "Found %d cpus total (%d CP, %d IFL, %d UN)\n", *cp_total + *ifl_total + un_total, *cp_total, *ifl_total, un_total); out: for (n = 0; n < no_files; n++) free(namelist[n]); if (no_files > 0) free(namelist); return rc; } static int qc_fill_in_hypfs_lpar_values(struct qc_handle *hdl, const char *hypfs) { int num_ifl = 0, num_cp = 0; char *fpath = NULL; const char *s; int rc = -1; qc_debug(hdl, "Add LPAR values from textual hypfs API\n"); qc_debug_indent_inc(); hdl = qc_get_lpar_handle(hdl); if ((s = qc_get_attr_value_string(hdl, qc_layer_name)) == NULL) { rc = -1; goto out; } if (asprintf(&fpath, "%s/systems/%s/cpus", hypfs, s) == -1) { qc_debug(hdl, "Error: Couldn't allocate buffer for hypfs systems path\n"); goto out; } rc = qc_get_hypfs_cpu_types(hdl, fpath, &num_ifl, &num_cp); free(fpath); if (rc) goto out; if (qc_set_attr_int(hdl, qc_num_cp_total, num_cp, ATTR_SRC_HYPFS) || qc_set_attr_int(hdl, qc_num_ifl_total, num_ifl, ATTR_SRC_HYPFS)) goto out; rc = 0; out: qc_debug_indent_dec(); return rc; } static int qc_fill_in_hypfs_cec_values(struct qc_handle *hdl, const char *hypfs) { int num_ifl = 0, num_cp = 0; char *fpath = NULL; int rc = -1; qc_debug(hdl, "Add CEC values from textual hypfs API\n"); qc_debug_indent_inc(); if (asprintf(&fpath, "%s/cpus", hypfs) == -1) { qc_debug(hdl, "Error: Couldn't allocate buffer for hypfs systems path\n"); goto out; } rc = qc_get_hypfs_cpu_types(hdl, fpath, &num_ifl, &num_cp); free(fpath); if (rc) goto out; if (qc_set_attr_int(hdl, qc_num_cp_total, num_cp, ATTR_SRC_HYPFS) || qc_set_attr_int(hdl, qc_num_ifl_total, num_ifl, ATTR_SRC_HYPFS)) goto out; rc = 0; out: qc_debug_indent_dec(); return rc; } #endif static int qc_fill_in_hypfs_lpar_values_bin(struct qc_handle *hdl, __u8 *data) { int ziip = 0, ziip_ded = 0, ziip_cap = 0, ziip_weight = 0, ziip_abs_cap = 0, ziip_all_weight = 0, ziip_w, *ziip_sh; int ifl = 0, ifl_ded = 0, ifl_cap = 0, ifl_weight = 0, ifl_abs_cap = 0, ifl_all_weight = 0, ifl_w, *ifl_sh; int cp = 0, cp_ded = 0, cp_cap = 0, cp_weight = 0, cp_abs_cap = 0, cp_all_weight = 0, cp_w, *cp_sh; int un = 0, i, j, rc = -1, gpd_available; struct dfs_sys_hdr *sys_hdr, *tgt_lpar; struct dfs_info_blk_hdr *time_hdr; struct dfs_cpu_info *cpu; struct qc_handle *group; int cap_active = 0; qc_debug(hdl, "Add LPAR values from binary hypfs API\n"); qc_debug_indent_inc(); time_hdr = (struct dfs_info_blk_hdr *)(data + sizeof(struct dfs_diag_hdr)); sys_hdr = (struct dfs_sys_hdr *)(time_hdr + 1); tgt_lpar = (void *)(struct dfs_info_blk_hdr *)(data + sizeof(struct dfs_diag_hdr)) + htobe16(time_hdr->thispart); gpd_available = time_hdr->flags & QC_FLAG_PHYS; qc_debug(hdl, "Found data for %d LPAR(s), GPD data is %savailable\n", time_hdr->npar, gpd_available ? "" : "NOT "); for (i = 0; i < time_hdr->npar; ++i) { cpu = (struct dfs_cpu_info*)(sys_hdr + 1); cp_w = ifl_w = 0, ziip_w = 0; for (j = 0; j < sys_hdr->rcpus; ++j, ++cpu) { if (!(cpu->cflag & QC_CPU_CONFIGURED)) continue; if (sys_hdr == tgt_lpar && cpu->cflag & QC_CPU_CAPPED) cap_active = 1; switch (cpu->ctidx) { case QC_CPU_TYPE_CP: if (sys_hdr == tgt_lpar) { cp++; cp_cap = htobe32(cpu->groupCpuTypeCap); cp_abs_cap = htobe32(cpu->cpuTypeCap); if (cpu->weight == QC_CPU_DEDICATED) cp_ded++; else cp_weight = htobe16(cpu->weight); } if (cpu->weight != QC_CPU_DEDICATED) cp_w = htobe16(cpu->weight); break; case QC_CPU_TYPE_IFL: if (sys_hdr == tgt_lpar) { ifl++; ifl_cap = htobe32(cpu->groupCpuTypeCap); ifl_abs_cap = htobe32(cpu->cpuTypeCap); if (cpu->weight == QC_CPU_DEDICATED) ifl_ded++; else ifl_weight = htobe16(cpu->weight); } if (cpu->weight != QC_CPU_DEDICATED) ifl_w = htobe16(cpu->weight); break; case QC_CPU_TYPE_ZIIP: if (sys_hdr == tgt_lpar) { ziip++; ziip_cap = htobe32(cpu->groupCpuTypeCap); ziip_abs_cap = htobe32(cpu->cpuTypeCap); if (cpu->weight == QC_CPU_DEDICATED) ziip_ded++; else ziip_weight = htobe16(cpu->weight); } if (cpu->weight != QC_CPU_DEDICATED) ziip_w = htobe16(cpu->weight); break; default: if (sys_hdr == tgt_lpar) un++; break; } } cp_all_weight += cp_w; ifl_all_weight += ifl_w; ziip_all_weight += ziip_w; sys_hdr = (struct dfs_sys_hdr *)cpu; } qc_debug(hdl, "Found %d cpus total (%d CP, %d IFL, %d zIIP, %d UN)\n", cp + ifl + ziip + un, cp, ifl, ziip, un); hdl = qc_get_lpar_handle(hdl); if (qc_set_attr_int(hdl, qc_num_cp_total, cp, ATTR_SRC_HYPFS) || qc_set_attr_int(hdl, qc_num_cp_dedicated, cp_ded, ATTR_SRC_HYPFS) || qc_set_attr_int(hdl, qc_num_cp_shared, cp - cp_ded, ATTR_SRC_HYPFS) || qc_set_attr_int(hdl, qc_num_ifl_total, ifl, ATTR_SRC_HYPFS) || qc_set_attr_int(hdl, qc_num_ifl_dedicated, ifl_ded, ATTR_SRC_HYPFS) || qc_set_attr_int(hdl, qc_num_ifl_shared, ifl - ifl_ded, ATTR_SRC_HYPFS) || qc_set_attr_int(hdl, qc_num_ziip_total, ziip, ATTR_SRC_HYPFS) || qc_set_attr_int(hdl, qc_num_ziip_dedicated, ziip_ded, ATTR_SRC_HYPFS) || qc_set_attr_int(hdl, qc_num_ziip_shared, ziip - ziip_ded, ATTR_SRC_HYPFS) || qc_set_attr_int(hdl, qc_cp_absolute_capping, cp_abs_cap * 0x10000 / 100, ATTR_SRC_HYPFS) || qc_set_attr_int(hdl, qc_ifl_absolute_capping, ifl_abs_cap * 0x10000 / 100, ATTR_SRC_HYPFS) || qc_set_attr_int(hdl, qc_ziip_absolute_capping, ziip_abs_cap * 0x10000 / 100, ATTR_SRC_HYPFS)) goto out_err; if (gpd_available) { cp_sh = qc_get_attr_value_int(qc_get_cec_handle(hdl), qc_num_cp_shared); ifl_sh = qc_get_attr_value_int(qc_get_cec_handle(hdl), qc_num_ifl_shared); ziip_sh = qc_get_attr_value_int(qc_get_cec_handle(hdl), qc_num_ziip_shared); if (cap_active && cp_sh && ifl_sh && (qc_set_attr_int(hdl, qc_cp_weight_capping, cp_weight ? *cp_sh * 0x10000 * cp_weight / cp_all_weight : 0, ATTR_SRC_HYPFS) || qc_set_attr_int(hdl, qc_ifl_weight_capping, ifl_weight ? *ifl_sh * 0x10000 * ifl_weight / ifl_all_weight : 0, ATTR_SRC_HYPFS) || qc_set_attr_int(hdl, qc_ziip_weight_capping, ziip_weight ? *ziip_sh * 0x10000 * ziip_weight / ziip_all_weight : 0, ATTR_SRC_HYPFS))) goto out_err; } if (qc_is_nonempty_ebcdic((__u64*)tgt_lpar->grp_name)) { /* LPAR group is only defined in case group name is not binary zero */ qc_debug(hdl, "Insert LPAR group layer\n"); if (qc_insert_handle(hdl, &group, QC_LAYER_TYPE_LPAR_GROUP)) { qc_debug(hdl, "Error: Failed to insert LPAR group layer\n"); goto out_err; } rc = qc_set_attr_ebcdic_string(group, qc_layer_name, (unsigned char *)tgt_lpar->grp_name, sizeof(tgt_lpar->grp_name), ATTR_SRC_STHYI); if (cp_cap) rc |= qc_set_attr_int(group, qc_cp_absolute_capping, cp_cap * 0x10000 / 100, ATTR_SRC_STHYI); if (ifl_cap) rc |= qc_set_attr_int(group, qc_ifl_absolute_capping, ifl_cap * 0x10000 / 100, ATTR_SRC_STHYI); if (ziip_cap) rc |= qc_set_attr_int(group, qc_ziip_absolute_capping, ziip_cap * 0x10000 / 100, ATTR_SRC_STHYI); } rc = 0; out_err: qc_debug_indent_dec(); return rc; } static int qc_fill_in_hypfs_cec_values_bin(struct qc_handle *hdl, __u8 *data) { int num_ifl = 0, num_ifl_ded = 0, num_ziip = 0, num_ziip_ded = 0, num_cp = 0, num_cp_ded = 0, num_un = 0, i, rc = 0; struct dfs_sys_hdr *sys_hdr = NULL; struct dfs_info_blk_hdr *time_hdr; struct dfs_cpu_info *cpu; qc_debug(hdl, "Add CEC values from binary hypfs API\n"); qc_debug_indent_inc(); time_hdr = (struct dfs_info_blk_hdr *)(data + sizeof(struct dfs_diag_hdr)); if (!(time_hdr->flags & QC_FLAG_PHYS)) { qc_debug(hdl, "GPD data is NOT available\n"); goto out; } data = (__u8 *)(time_hdr + 1); for (i = 0; i < time_hdr->npar; ++i) { sys_hdr = (struct dfs_sys_hdr*)data; data += (sizeof(struct dfs_sys_hdr) + (sys_hdr->rcpus * sizeof(struct dfs_cpu_info))); } sys_hdr = (struct dfs_sys_hdr*)data; cpu = (struct dfs_cpu_info*)(sys_hdr + 1); for (i = 0; i < sys_hdr->cpus; ++i, ++cpu) { switch (cpu->ctidx) { case QC_CPU_TYPE_CP: num_cp++; if (cpu->weight == QC_CPU_DEDICATED) num_cp_ded++; break; case QC_CPU_TYPE_IFL: num_ifl++; if (cpu->weight == QC_CPU_DEDICATED) num_ifl_ded++; break; case QC_CPU_TYPE_ZIIP: num_ziip++; if (cpu->weight == QC_CPU_DEDICATED) num_ziip_ded++; break; default: num_un++; break; } } qc_debug(hdl, "CPs=%d, dedicated CPs=%d, IFLs=%d, dedicated IFLs=%d, zIIPs=%d, dedicated zIIPs=%d, unknown=%d\n", num_cp, num_cp_ded, num_ifl, num_ifl_ded, num_ziip, num_ziip_ded, num_un); if (qc_set_attr_int(hdl, qc_num_cp_total, num_cp, ATTR_SRC_HYPFS) || qc_set_attr_int(hdl, qc_num_cp_dedicated, num_cp_ded, ATTR_SRC_HYPFS) || qc_set_attr_int(hdl, qc_num_cp_shared, num_cp - num_cp_ded, ATTR_SRC_HYPFS) || qc_set_attr_int(hdl, qc_num_ifl_total, num_ifl, ATTR_SRC_HYPFS) || qc_set_attr_int(hdl, qc_num_ifl_dedicated, num_ifl_ded, ATTR_SRC_HYPFS) || qc_set_attr_int(hdl, qc_num_ifl_shared, num_ifl - num_ifl_ded, ATTR_SRC_HYPFS) || qc_set_attr_int(hdl, qc_num_ziip_total, num_ziip, ATTR_SRC_HYPFS) || qc_set_attr_int(hdl, qc_num_ziip_dedicated, num_ziip_ded, ATTR_SRC_HYPFS) || qc_set_attr_int(hdl, qc_num_ziip_shared, num_ziip - num_ziip_ded, ATTR_SRC_HYPFS) || qc_set_attr_int(hdl, qc_num_core_dedicated, num_cp_ded + num_ifl_ded, ATTR_SRC_HYPFS) || qc_set_attr_int(hdl, qc_num_core_shared, num_ifl + num_cp - num_cp_ded - num_ifl_ded, ATTR_SRC_HYPFS)) rc = -1; out: qc_debug_indent_dec(); return rc; } #ifdef CONFIG_TEXTUAL_HYPFS static int qc_read_file(struct qc_handle *hdl, const char *fpath, char *buf, int buflen) { FILE *file; int rc = 0; qc_debug(hdl, "Read file %s\n", fpath); file = fopen(fpath, "r"); if (file) { memset(buf, 0, buflen); rc = fread(buf, 1, buflen, file); fclose(file); } else qc_debug(hdl, "Could not open file %s: %s\n", fpath, strerror(errno)); return rc; } #endif static int qc_read_diag_file(struct qc_handle *hdl, const char *dbgfs, struct hypfs_priv *priv) { long buflen = sizeof(struct dfs_diag_hdr); struct dfs_diag_hdr *hdr; int fh, i = 0, rc = 0; char *fpath = NULL; ssize_t lrc; if ((fpath = qc_get_path(hdl, dbgfs, priv->diag)) == NULL) goto out_fail; qc_debug(hdl, "Read in file '%s'\n", fpath); // file content needs to be read in one(!) go for (i = 0; i < 10; ++i) { fh = open(fpath, O_RDONLY); if (fh == -1) { qc_debug(hdl, "Error: Failed to open file '%s'\n", fpath); goto out_fail; } priv->data = malloc(buflen); if (!priv->data) { qc_debug(hdl, "Error: Failed to allocate '%ld' Bytes for file content\n", buflen); goto out_fail; } lrc = read(fh, priv->data, buflen); close(fh); if (lrc == -1) { qc_debug(hdl, "Error: Failed to read '%ld' Bytes from '%s'\n", buflen, priv->diag); close(fh); goto out_fail; } hdr = (struct dfs_diag_hdr*)priv->data; if ((buflen = sizeof(struct dfs_diag_hdr) + htobe64(hdr->len)) == lrc) { priv->len = lrc; break; } free(priv->data); priv->data = NULL; } if (i >= 10) { qc_debug(hdl, "Error: Tried %d times, still no consistent content " "- giving up\n", i + 1); rc = 1; } goto out; out_fail: free(priv->data); priv->data = NULL; rc = -1; out: free(fpath); return rc; } /* Returns handle to top-layer z/VM instance along with its name. */ static struct qc_handle *qc_get_zvm_hdl(struct qc_handle *hdl, const char **s) { int *i; while (hdl->next) hdl = hdl->next; i = qc_get_attr_value_int(hdl, qc_layer_type_num); if (!i) { qc_debug(hdl, "Error: Attr 'qc_layer_type' not defined at layer %d\n", hdl->layer_no); return NULL; } if (*i != QC_LAYER_TYPE_ZVM_GUEST) { qc_debug(hdl, "Error: Layer type is '%d', expected %d\n", *i, QC_LAYER_TYPE_ZVM_GUEST); return NULL; } *s = qc_get_attr_value_string(hdl, qc_layer_name); if (!*s) { qc_debug(hdl, "Error: Required attr 'qc_layer_name' at layer %d not defined\n", hdl->layer_no); return NULL; } return hdl; } #ifdef CONFIG_TEXTUAL_HYPFS static int qc_fill_in_hypfs_zvm_values(struct qc_handle *hdl, const char *hypfs) { int fplen, cpu_count = 0, cap_num, rc = 0; char str_buf[STR_BUF_SIZE], *fpath = NULL, *cap = NULL; int dedicated = -1; /* can be 0 or 1, if set; remains -1, if not set */ const char *s; qc_debug(hdl, "Add z/VM values from textual hypfs API\n"); qc_debug_indent_inc(); if ((hdl = qc_get_zvm_hdl(hdl, &s)) == NULL) { rc = -1; goto out; } fplen = strlen(hypfs) + strlen("/systems/") + strlen(s) + strlen("/cpus/"); fpath = malloc(fplen + strlen("dedicated") + 1); // longest string possible if (!fpath) { qc_debug(hdl, "Error: Could not allocate systems path\n"); rc = -2; goto out; } /* read capping off/soft/hard */ sprintf(fpath, "%s/systems/%s/cpus/capped", hypfs, s); // fill string 1st time only, // overwrite filename in all successive occasions if (qc_read_file(hdl, fpath, str_buf, STR_BUF_SIZE)) { if (!strncmp("1", str_buf, 1)) { cap_num = QC_CAPPING_SOFT; cap = "soft"; } else if (!strncmp("2", str_buf, 1)) { cap_num = QC_CAPPING_HARD; cap = "hard"; } else { cap_num = QC_CAPPING_OFF; cap = "off"; } if (qc_set_attr_int(hdl, qc_capping_num, cap_num, ATTR_SRC_HYPFS) || qc_set_attr_string(hdl, qc_capping, cap, ATTR_SRC_HYPFS)) { rc = -3; goto out; } } /* if guest dedicated, all cpus are dedicated, update sums */ strcpy(fpath + fplen, "dedicated"); if (qc_read_file(hdl, fpath, str_buf, STR_BUF_SIZE)) { if (!strncmp("0", str_buf, 1)) dedicated = 0; else if (!strncmp("1", str_buf, 1)) dedicated = 1; } strcpy(fpath + fplen, "count"); if (qc_read_file(hdl, fpath, str_buf, STR_BUF_SIZE) && sscanf(str_buf, "%i", &cpu_count) <= 0) cpu_count = 0; qc_debug(hdl, "Raw data: %d cpus, dedicated=%u, capped=%s\n", cpu_count, dedicated, cap); if (cpu_count) { /* the dedicated flag tells us, if the guest has got at least one dedicated CPU. * That means, we can only derive information, if no CPU is dedicated (i.e. all shared) */ if (dedicated == 0) { /* dedicated flag present and not set */ if (qc_set_attr_int(hdl, qc_num_cpu_shared, cpu_count, ATTR_SRC_HYPFS) || qc_set_attr_int(hdl, qc_num_cpu_dedicated, 0, ATTR_SRC_HYPFS)) { rc = -4; goto out; } } } out: free(fpath); qc_debug_indent_dec(); return rc; } #endif // Returns diag data for highest layer z/VM instance in var 'data', with pointer to entire data // stored in 'buf' (must be free()'d), and updates hdl to point to respective handle. static int qc_get_zvm_diag_data(struct qc_handle **hdl, struct dfs_diag_hdr *hdr, struct dfs_diag2fc **data) { char name[QC_NAME_LEN + 1]; const char *s; int i; if ((*hdl = qc_get_zvm_hdl(*hdl, &s)) == NULL) return -1; qc_debug(*hdl, "Found data for %" PRIu64 " z/VM guest(s)\n", htobe64((uint64_t)hdr->count)); for (i = 0, *data = (struct dfs_diag2fc*)(hdr + 1); i < htobe64(hdr->count); ++i, ++*data) { memset(&name, 0, QC_NAME_LEN + 1); memcpy(name, (*data)->guest_name, QC_NAME_LEN); if (qc_ebcdic_to_ascii(*hdl, name, QC_NAME_LEN) != 0) return -2; if (strcmp(name, s) == 0) return 0; } qc_debug(*hdl, "Error: No matching data found for z/VM guest '%s'\n", s); return -3; } static int qc_fill_in_hypfs_zvm_values_bin(struct qc_handle *hdl, struct hypfs_priv *priv) { unsigned int dedicated, capped; struct dfs_diag2fc *data; int rc = 0, cap_num; char *cap; qc_debug(hdl, "Add z/VM values from binary hypfs API\n"); qc_debug_indent_inc(); if ((rc = qc_get_zvm_diag_data(&hdl, (struct dfs_diag_hdr *)priv->data, &data)) != 0) goto out; // update capping information capped = (htobe32(data->flags) & 0x00000006) >> 1; dedicated = (htobe32(data->flags) & 0x00000008) >> 3; qc_debug(hdl, "Raw data: %u cpus, dedicated=%u, capped=%u\n", htobe32(data->vcpus), dedicated, capped); switch (capped) { case 1: cap_num = QC_CAPPING_SOFT; cap = "soft"; break; case 2: cap_num = QC_CAPPING_HARD; cap = "hard"; break; default: cap_num = QC_CAPPING_OFF; cap = "off"; } if (qc_set_attr_int(hdl, qc_capping_num, cap_num, ATTR_SRC_HYPFS) || qc_set_attr_string(hdl, qc_capping, cap, ATTR_SRC_HYPFS)) { rc = -1; goto out; } // update shared cpu counts if (dedicated == 0) { /* the dedicated flag tells us, if the guest has got at least one dedicated CPU. * That means, we can only derive information, if no CPU is dedicated (i.e. all shared) */ if (qc_set_attr_int(hdl, qc_num_cpu_shared, htobe32(data->vcpus), ATTR_SRC_HYPFS) || qc_set_attr_int(hdl, qc_num_cpu_dedicated, 0, ATTR_SRC_HYPFS)) { rc = -4; goto out; } } out: qc_debug_indent_dec(); return rc; } /* Retrieve mountpoint of fstype from /etc/mtab. Returns 0 on success with malloc'd mountpoint in 'mp', >0 if not found and <0 in case of an error. */ static int qc_get_mountpoint(struct qc_handle *hdl, char *fstype, char **mp) { struct mntent *mntbuf; FILE *mounts; char *fname; int rc; if (qc_dbg_use_dump) { // dumped data will look exactly like if on dbgfs or hypfs, so all we need // to do is point *mp to the right directory - if the respective data is present, // which we check with a simple sanity check qc_debug(hdl, "Read hypfs from dump\n"); if (strcmp(fstype, "s390_hypfs") == 0) { if (asprintf(&fname, "%s/hyp", qc_dbg_use_dump) == -1) { qc_debug(hdl, "Error: Mem alloc failed, cannot read dump\n"); return -1; } } else { if (asprintf(&fname, "%s/%s", qc_dbg_use_dump, QC_HYPFS_LPAR) == -1) { qc_debug(hdl, "Error: Mem alloc failed, cannot read dump\n"); return -1; } } rc = access(fname, R_OK); free(fname); if (rc) return 1; *mp = strdup(qc_dbg_use_dump); return 0; } qc_debug(hdl, "Locate mount point of %s\n", fstype); *mp = NULL; mounts = setmntent(_PATH_MOUNTED, "r"); if (!mounts) { qc_debug(hdl, "Error: Failed to open %s\n", _PATH_MOUNTED); return -1; } while ((mntbuf = getmntent(mounts)) != NULL) { if (strcmp(mntbuf->mnt_type, fstype) == 0) { *mp = strdup(mntbuf->mnt_dir); if (!*mp) { qc_debug(hdl, "Error: Failed to allocate buffer\n"); endmntent(mounts); return -2; } break; } } endmntent(mounts); if (!*mp) { qc_debug(hdl, "%s not mounted according to '%s'\n", fstype, _PATH_MOUNTED); return 1; } qc_debug(hdl, "%s mounted at '%s'\n", fstype, *mp); return 0; } #ifdef CONFIG_TEXTUAL_HYPFS static int qc_update_hypfs(struct qc_handle *hdl, const char *upath) { FILE *file; size_t rc; qc_debug(hdl, "Update hypfs using %s\n", upath); file = fopen(upath, "w"); if (!file) { /* Don't treat as an error in case hypfs is mounted but not accessible. But we assume the remainder of hypfs won't be accessible either, so out we go. */ qc_debug(hdl, "Warning: Failed to open '%s': %s\n", upath, strerror(errno)); return 1; } rc = fwrite("1\n", 1, strlen("1\n"), file); fclose(file); if (rc < strlen("1\n")) { // Could be file access rights preventing us from a proper update qc_debug(hdl, "Warning: Failed to write to '%s', rc=%zd\n", upath, rc); return 2; } return 0; } static int qc_get_update_mod_time(struct qc_handle *hdl, const char *hypfs, time_t *mtime) { char *fpath = NULL; struct stat buf; if (qc_dbg_use_dump) { *mtime = 37; return 0; } qc_debug(hdl, "Retrieve mod time of %s/update\n", hypfs); if ((fpath = qc_get_path(hdl, hypfs, "/update")) == NULL) return -1; if (stat(fpath, &buf)) { qc_debug(hdl, "Error: Couldn't stat '%s'\n", fpath); free(fpath); return -2; } free(fpath); *mtime = buf.st_mtime; qc_debug(hdl, "Mod time: %ld\n", *mtime); return 0; } #endif static int qc_hypfs_open(struct qc_handle *hdl, char **buf) { char *dbgfs = NULL, *fpath = NULL; struct hypfs_priv *priv; int rc = 0; qc_debug(hdl, "Retrieve hypfs information\n"); qc_debug_indent_inc(); if ((priv = malloc(sizeof(struct hypfs_priv))) == NULL) { qc_debug(hdl, "Error: Failed to allocate hypfs_priv\n"); rc = -1; goto out; } bzero(priv, sizeof(struct hypfs_priv)); *buf = (char *)priv; // check for binary hypfs interface if ((rc = qc_get_mountpoint(hdl, "debugfs", &dbgfs)) < 0) goto out; if (rc == 0) { // LPAR diag file is always present if binary interface is available if ((fpath = qc_get_path(hdl, dbgfs, QC_HYPFS_LPAR)) == NULL) { rc = -2; goto out; } rc = access(fpath, R_OK); free(fpath); fpath = NULL; if (rc == 0) { qc_debug(hdl, "Use binary hypfs API\n"); if ((fpath = qc_get_path(hdl, dbgfs, QC_HYPFS_ZVM)) == NULL) { rc = -3; goto out; } if (access(fpath, R_OK) == 0) { /* if z/VM diag file exists, the LPAR diag file's content isn't valid, so we're done after handling the z/VM file */ priv->diag = QC_HYPFS_ZVM; if ((rc = qc_read_diag_file(hdl, dbgfs, priv)) != 0) goto out; priv->avail = HYPFS_AVAIL_BIN_ZVM; } else { qc_debug(hdl, "No z/VM diag file found, must be an LPAR\n"); priv->diag = QC_HYPFS_LPAR; if ((rc = qc_read_diag_file(hdl, dbgfs, priv)) != 0) goto out; priv->avail = HYPFS_AVAIL_BIN_LPAR; } } else { qc_debug(hdl, "Binary hypfs API not available: %s\n", strerror(errno)); rc = 0; } } else rc = 0; out: qc_debug_indent_dec(); free(dbgfs); free(fpath); return rc; } static void qc_hypfs_close(struct qc_handle *hdl, char *buf) { struct hypfs_priv *priv = (struct hypfs_priv *)buf; if (priv) { free(priv->data); free(priv->hypfs); free(priv); } } static int qc_hypfs_process(struct qc_handle *hdl, char *buf) { struct hypfs_priv *priv = (struct hypfs_priv *)buf; #ifdef CONFIG_TEXTUAL_HYPFS char str_buf[STR_BUF_SIZE] = ""; time_t mtime, mtime_old; char *fpath = NULL; FILE *file = NULL; int i; #endif int rc = 0; qc_debug(hdl, "Process hypfs\n"); qc_debug_indent_inc(); if (!priv) { qc_debug(hdl, "qc_hypfs_process() called with priv==NULL, exiting\n"); goto out; } if (priv->avail == HYPFS_AVAIL_BIN_LPAR) { rc = qc_fill_in_hypfs_cec_values_bin(hdl->root, (__u8 *)priv->data) || qc_fill_in_hypfs_lpar_values_bin(hdl, (__u8 *)priv->data); goto out; } if (priv->avail == HYPFS_AVAIL_BIN_ZVM) { rc = qc_fill_in_hypfs_zvm_values_bin(hdl, priv); goto out; } #ifdef CONFIG_TEXTUAL_HYPFS /* fallback to textual interface */ qc_debug(hdl, "Use textual hypfs API\n"); rc = qc_get_mountpoint(hdl, "s390_hypfs", &priv->hypfs); if (rc < 0) goto out; if (rc > 0) { rc = 0; // don't treat non-presence of hypfs as an error qc_debug(hdl, "hypfs info not available\n"); goto out; } if ((fpath = qc_get_path(hdl, priv->hypfs, "/update")) == NULL) goto mem_err; rc = qc_update_hypfs(hdl, fpath); if (rc < 0) goto out; if (rc > 0) { qc_debug(hdl, "hypfs info not available\n"); rc = 0; // don't treat as an error goto out; } free(fpath); fpath = NULL; /* If we can't get it right within 3 tries, we give up */ for(i = 0; i < 3; ++i) { if (qc_get_update_mod_time(hdl, priv->hypfs, &mtime_old)) { rc = -2; goto out; } memset(str_buf, 0, STR_BUF_SIZE); if ((fpath = qc_get_path(hdl, priv->hypfs, "/hyp/type")) == NULL) goto mem_err; if (!qc_read_file(hdl, fpath, str_buf, STR_BUF_SIZE)) { qc_debug(hdl, "Error: Failed to open or read '%s'\n", fpath); rc = -4; goto out; } if (!strncmp(str_buf, "LPAR Hypervisor", strlen("LPAR Hypervisor"))) { if (qc_fill_in_hypfs_cec_values(hdl->root, priv->hypfs) || qc_fill_in_hypfs_lpar_values(hdl, priv->hypfs)) { rc = -6; goto out; } priv->avail = HYPFS_AVAIL_ASCII_LPAR; } else if (!strncmp("z/VM Hypervisor", str_buf, strlen("z/VM Hypervisor"))) { if (qc_fill_in_hypfs_zvm_values(hdl, priv->hypfs)) { rc = -7; goto out; } priv->avail = HYPFS_AVAIL_ASCII_ZVM; } else { qc_debug(hdl, "Error: Unhandled hypervisor '%s', ignored\n", str_buf); rc = 0; goto out; } if (qc_get_update_mod_time(hdl, priv->hypfs, &mtime)) { rc = -8; goto out; } if (mtime == mtime_old) goto out; } /* Ideally we'd clear any data possibly collected in an invalid attempt (mod_time != buf.st_mtime). However, that's complicated, as we'd have to revert to previously filled in values from other sources - which we currently can't */ qc_debug(hdl, "Error: Failed to get consistent data from hypfs\n"); rc = -9; goto out; mem_err: qc_debug(hdl, "Error: Memory allocation error\n"); rc = -10; #endif out: #ifdef CONFIG_TEXTUAL_HYPFS free(fpath); if (file) fclose(file); #endif qc_debug_indent_dec(); return rc; } struct qc_data_src hypfs = {qc_hypfs_open, qc_hypfs_process, qc_hypfs_dump, qc_hypfs_close, NULL, NULL}; qclib-2.1.0/query_capacity_int.h0000664000175000017500000000704413647300120015700 0ustar rasplraspl/* Copyright IBM Corp. 2013, 2016 */ #ifndef QUERY_CAPACITY_INT #define QUERY_CAPACITY_INT #include #include #include #include #include #include #include #include #include #include #include "query_capacity.h" /* Miscellaneous structures and constants */ #define STR_BUF_SIZE 257 #define ATTR_SRC_SYSINFO 'S' #define ATTR_SRC_SYSFS 'F' #define ATTR_SRC_HYPFS 'H' #define ATTR_SRC_STHYI 'V' #define ATTR_SRC_POSTPROC 'P' // Note: Post-processed attributes can have multiple origins - would be // complicated to figure out accurately. We leave it at 'P' for now #define ATTR_SRC_UNDEF '_' #ifndef htobe16 // fallbacks for systems with a glibc < 2.9 #if __BYTE_ORDER == __LITTLE_ENDIAN #define htobe16(x) bswap_16(x) #define htobe32(x) bswap_32(x) #define htobe64(x) bswap_64(x) #else #define htobe16(x) x #define htobe32(x) x #define htobe64(x) x #endif // __BYTE_ORDER #endif // htobe32 struct qc_handle { void *layer; // holds a copy of the respective *_values struct // and is filled by looking up the offset via the respective *_attrs table struct qc_attr *attr_list; int layer_no; int *attr_present; // array indicating whether attributes are set char *src; // array indicating the source of the attribute's value, see ATTR_SRC_* struct qc_handle *next; struct qc_handle *root; // points to top handle }; struct qc_data_src { int (*open)(struct qc_handle *, char **); int (*process)(struct qc_handle *, char *); void (*dump)(struct qc_handle *, char *); void (*close)(struct qc_handle *, char *); int (*lgm_check)(struct qc_handle *, const char *); char *priv; }; extern struct qc_data_src sysinfo, sysfs, hypfs, sthyi; /* Utility functions */ int qc_ebcdic_to_ascii(struct qc_handle *hdl, char *inbuf, size_t insz); int qc_is_nonempty_ebcdic(__u64 *str); int qc_new_handle(struct qc_handle *hdl, struct qc_handle **tgthdl, int layer_no, int layer_type); // Insert new layer 'inserted_hdl' of type 'type' before 'hdl'. Won't support inserting a new root int qc_insert_handle(struct qc_handle *hdl, struct qc_handle **inserted_hdl, int type); // Insert new layer 'appended_hdl' of type 'type' after 'hdl' int qc_append_handle(struct qc_handle *hdl, struct qc_handle **appended_hdl, int type); struct qc_handle *qc_get_cec_handle(struct qc_handle *hdl); struct qc_handle *qc_get_lpar_handle(struct qc_handle *hdl); struct qc_handle *qc_get_root_handle(struct qc_handle *hdl); struct qc_handle *qc_get_prev_handle(struct qc_handle *hdl); struct qc_handle *qc_get_top_handle(struct qc_handle *hdl); /* Debugging-related functions and variables */ extern long qc_dbg_level; extern FILE *qc_dbg_file; extern char *qc_dbg_dump_dir; extern char *qc_dbg_use_dump; extern int qc_dbg_indent; extern int qc_consistency_check_requested; void qc_debug_indent_inc(); void qc_debug_indent_dec(); void qc_mark_dump_incomplete(struct qc_handle *hdl, char *missing_component); #ifdef CONFIG_DEBUG_TIMESTAMPS #define qc_debug(hdl, arg, ...) if (qc_dbg_level > 0) { \ time_t t; \ struct tm *tm; \ time(&t); \ tm = localtime(&t); \ fprintf(qc_dbg_file, "%02d/%02d,%02d:%02d:%02d,%-10p: %*s" arg, \ tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, qc_get_root_handle(hdl), qc_dbg_indent, "", ##__VA_ARGS__); \ } #else #define qc_debug(hdl, arg, ...) if (qc_dbg_level > 0) { \ fprintf(qc_dbg_file, "%-10p: %*s" arg, qc_get_root_handle(hdl), qc_dbg_indent, "", ##__VA_ARGS__); \ } #endif #endif qclib-2.1.0/query_capacity.c0000664000175000017500000007625413647300120015032 0ustar rasplraspl/* Copyright IBM Corp. 2013, 2019 */ #define _GNU_SOURCE #include #include "query_capacity_data.h" long qc_dbg_level; FILE *qc_dbg_file; char *qc_dbg_dump_dir; int qc_dbg_indent; char *qc_dbg_use_dump; int qc_consistency_check_requested; static char *qc_dbg_file_name; static long qc_dbg_autodump; static unsigned int qc_dbg_dump_idx; static iconv_t qc_cd = (iconv_t)-1; struct qc_reg_hdl { struct qc_handle *hdl; struct qc_reg_hdl *next; }; static struct qc_reg_hdl *qc_hdls = NULL; static void __attribute__((destructor)) qc_destructor(void) { if (qc_cd != (iconv_t)-1) iconv_close(qc_cd); } struct qc_handle *qc_get_cec_handle(struct qc_handle *hdl) { return hdl ? hdl->root : hdl; } struct qc_handle *qc_get_lpar_handle(struct qc_handle *hdl) { for (hdl = hdl->root; hdl != NULL && *(int *)(hdl->layer) != QC_LAYER_TYPE_LPAR; hdl = hdl->next); return hdl; } /* Update dbg_level from environment variable */ static void qc_update_dbg_level(void) { char *s, *end; s = getenv("QC_DEBUG"); if (s) { qc_dbg_level = strtol(s, &end, 10); if (end == s || qc_dbg_level < 0) qc_dbg_level = 0; } #ifdef CONFIG_DUMP_READING s = getenv("QC_USE_DUMP"); // if qc_dbg_use_dump is NULL, then there's nothing we can do about it if (s) { free(qc_dbg_use_dump); qc_dbg_use_dump = strdup(s); } #endif s = getenv("QC_AUTODUMP"); if (s) { qc_dbg_autodump = strtol(s, &end, 10); if (end == s || qc_dbg_autodump < 0) qc_dbg_autodump = 0; } } static void qc_debug_deinit(void *hdl) { qc_update_dbg_level(); if (qc_dbg_level <= 0 && qc_dbg_autodump <= 0 && qc_dbg_file) { qc_dbg_level = 1; // temporarily set, or qc_debug won't print anything qc_debug(hdl, "Log level set to %ld, closing\n", qc_dbg_level); qc_dbg_level = 0; fclose(qc_dbg_file); qc_dbg_file = NULL; free(qc_dbg_dump_dir); qc_dbg_dump_dir = NULL; free(qc_dbg_file_name); qc_dbg_file_name = NULL; qc_dbg_dump_idx = 0; qc_dbg_autodump = 0; } free(qc_dbg_use_dump); qc_dbg_use_dump = NULL; } #define QC_DBGFILE "/tmp/qclib-XXXXXX" static int qc_debug_file_init(void) { int fd; if (!qc_dbg_file_name) { char *s = getenv("QC_DEBUG_FILE"); if (s) { qc_dbg_file_name = strdup(s); if (!qc_dbg_file_name) goto out_err; qc_dbg_file = fopen(qc_dbg_file_name, "w"); if (!qc_dbg_file) goto out_err; } else { qc_dbg_file_name = strdup(QC_DBGFILE); if (!qc_dbg_file_name) goto out_err; fd = mkstemp(qc_dbg_file_name); if (fd == -1) goto out_err; qc_dbg_file = fdopen(fd, "w"); if (!qc_dbg_file) { close(fd); goto out_err; } } qc_debug(NULL, "This is qclib v2.1.0, level 3877f257, date 2020-04-15 22:20:26 +0200\n"); } return 0; out_err: free(qc_dbg_file_name); qc_dbg_file_name = NULL; qc_dbg_level = 0; return -1; } static int qc_debug_open_dump_dir(struct qc_handle *hdl) { int i; if (!qc_dbg_file_name && qc_debug_file_init()) return -1; for (i = 0, ++qc_dbg_dump_idx; i < 100; ++i, ++qc_dbg_dump_idx) { free(qc_dbg_dump_dir); qc_dbg_dump_dir = NULL; if (asprintf(&qc_dbg_dump_dir, "%s.dump-%u", qc_dbg_file_name, qc_dbg_dump_idx) == -1) { qc_debug(hdl, "Error: Mem alloc error\n"); goto out_err; } if (mkdir(qc_dbg_dump_dir, S_IRWXU) == 0) break; qc_debug(hdl, "Warning: Could not create dir '%s': %s\n", qc_dbg_dump_dir, strerror(errno)); } if (i == 100) goto out_err; qc_debug(hdl, "Created directory '%s' for all dumps\n", qc_dbg_dump_dir); return 0; out_err: qc_debug(hdl, "Error: Could not create directory for dump, better luck maybe next time...\n"); free(qc_dbg_dump_dir); qc_dbg_dump_dir = NULL; return -1; } static void qc_debug_close_dump_dir(struct qc_handle *hdl) { free(qc_dbg_dump_dir); qc_dbg_dump_dir = NULL; } #define QC_DUMP_INCOMPLETE "INCOMPLETE_DUMP.txt" /* Opens a log file for debug messages if env var QC_DEBUG is >0. Note that the file is only closed in qc_close_configuration() when qc_dbg_level is <=0, so that it's left up to the user to decide whether a single file is used all the time or individual files created for each invocation of the library. */ static int qc_debug_init(void) { static int init = 0; char *path = NULL; int rc = 0; if (!init) { // use a static initializer, as a shared library's init won't work for static libs qc_dbg_indent = 0; qc_dbg_file = NULL; qc_dbg_file_name = NULL; qc_dbg_level = 0; qc_dbg_dump_dir = NULL; qc_dbg_use_dump = NULL; qc_dbg_dump_idx = 0; qc_dbg_autodump = 0; init = 1; } qc_update_dbg_level(); if (qc_dbg_level > 0 && !qc_dbg_file) { if (qc_debug_file_init()) { rc = 1; goto out_err; } qc_debug(NULL, "Log level set to %ld\n", qc_dbg_level); } if (qc_dbg_use_dump) { // usage of dump file requested - any error in here is fatal if (access(qc_dbg_use_dump, R_OK | X_OK) == -1) { qc_debug(NULL, "Error: Dump usage requested, but path '%s' " "not accessible: %s\n", qc_dbg_use_dump, strerror(errno)); rc = 2; goto out_err; } // Check for marker indicating incomplete dump if (asprintf(&path, "%s/%s", qc_dbg_use_dump, QC_DUMP_INCOMPLETE) == -1) { qc_debug(NULL, "Error: Mem alloc failed"); rc = 3; goto out_err; } if (!access(path, R_OK)) { qc_debug(NULL, "Error: Dump at %s is incomplete, cannot use\n", qc_dbg_dump_dir); qc_debug(NULL, " See content of %s for list of missing components\n", path); rc = 4; goto out_err; } free(path); path = NULL; qc_debug(NULL, "Running with dump in '%s'\n", qc_dbg_use_dump); } return 0; out_err: // Nothing we can do about this except to disable debug messages to prevent further damage free(qc_dbg_dump_dir); qc_dbg_dump_dir = NULL; free(qc_dbg_use_dump); qc_dbg_use_dump = NULL; free(path); return rc; } void qc_debug_indent_inc(void) { qc_dbg_indent += 2; } void qc_debug_indent_dec(void) { qc_dbg_indent -= 2; } void qc_mark_dump_incomplete(struct qc_handle *hdl, char *missing_component) { int rc; char *cmd; if (asprintf(&cmd, "/bin/echo %s >> %s/%s", missing_component, qc_dbg_dump_dir, QC_DUMP_INCOMPLETE) == -1) { qc_debug(hdl, "Error: Failed to alloc mem to indicate dump as incomplete\n"); return; } if ((rc = system(cmd)) != 0) qc_debug(hdl, "Error: Failed to exec command to indicate dump as incomplete, " "rc=%d\n", rc); free(cmd); } /* Convert EBCDIC input to ASCII in place, removing trailing whitespace */ int qc_ebcdic_to_ascii(struct qc_handle *hdl, char *inbuf, size_t insz) { char *outbuf, *outbuf_start, *inbuf_start = inbuf; size_t len, outsz = insz, insz_orig, outsz_orig; int rc = 0; if (!(outbuf_start = malloc(outsz))) { qc_debug(hdl, "Error: Failed to alloc tmp buffer of size %zd for iconv\n", outsz); rc = -1; goto out; } outbuf = outbuf_start; insz_orig = insz; outsz_orig = outsz; len = iconv(qc_cd, &inbuf, &insz, &outbuf, &outsz); if (len == (size_t)(-1)) { qc_debug(hdl, "Error: iconv conversion failed: %s\n", strerror(errno)); rc = -2; goto out; } // remove trailing whitespace for (len = 0; len < outsz_orig - outsz; ++len) if (outbuf_start[len] == ' ') { outbuf_start[len] = '\0'; len++; break; } if (len > insz_orig) { qc_debug(hdl, "Error: iconv result exceeds target buffer (%zd > %zd)\n", len, insz); rc = -3; goto out; } memcpy(inbuf_start, outbuf_start, len); out: free(outbuf_start); return rc; } static int qc_hdl_register(struct qc_handle *hdl) { struct qc_reg_hdl *entry; entry = malloc(sizeof(struct qc_reg_hdl)); if (!entry) { qc_debug(hdl, "Error: Failed register hdl\n"); return -1; } entry->hdl = hdl; if (qc_hdls) entry->next = qc_hdls; else entry->next = NULL; qc_hdls = entry; return 0; } static void qc_hdl_unregister(struct qc_handle *hdl) { struct qc_reg_hdl *entry, *prev = NULL; for (entry = qc_hdls; entry != NULL; prev = entry, entry = entry->next) { if (entry->hdl == hdl) { if (prev && entry->next) prev->next = entry->next; else if (!prev) qc_hdls = entry->next; else prev->next = NULL; free(entry); break; } } return; } static int qc_hdl_verify(struct qc_handle *hdl, const char *func) { struct qc_reg_hdl *entry; if (!hdl) return -1; for (entry = qc_hdls; entry != NULL; entry = entry->next) { if (entry->hdl == hdl) return 0; } qc_debug(NULL, "Error: %s() called with unknown handle %p\n", func, hdl); return -1; } // De-alloc hdl, leaving out the actual handle static void qc_hdl_reinit(struct qc_handle *hdl) { struct qc_handle *ptr = hdl, *arg = hdl; while (ptr) { free(ptr->layer); free(ptr->attr_present); free(ptr->src); hdl = ptr->next; if (ptr == arg) { memset(ptr, 0, sizeof(struct qc_handle)); ptr->root = ptr; } else free(ptr); ptr = hdl; } qc_hdl_unregister(arg); } /** Verifies that either a and (b or c), or none are set. I.e. if only one of the attributes is set, then that's an error */ static int qc_verify_capped_capacity(struct qc_handle *hdl, enum qc_attr_id a, enum qc_attr_id b, enum qc_attr_id c) { int *val_a, *val_b, *val_c; // We assume that non-presence of a value is due to...non-presence, as opposed to an error (since that would have been reported previously) val_a = qc_get_attr_value_int(hdl, a); val_b = qc_get_attr_value_int(hdl, b); val_c = qc_get_attr_value_int(hdl, c); if (!val_a && !val_b && !val_c) return 0; if ((*val_a && !*val_b && !*val_c) || (!*val_a && (*val_b || *val_c))) { qc_debug(hdl, "Warning: Consistency check (\"capped capacity\") for '%s && (%s || %s)' failed at layer %d (%s/%s): %d && (%d || %d)\n", qc_attr_id_to_char(hdl, a), qc_attr_id_to_char(hdl, b), qc_attr_id_to_char(hdl, c), hdl->layer_no, qc_get_attr_value_string(hdl, qc_layer_type), qc_get_attr_value_string(hdl, qc_layer_category), *val_a, *val_b, *val_c); return 1; } return 0; } #define ATTR_UNDEF qc_layer_name /** Verifies that a + (b (+ c)) <= d (b and c are optional, where b being unset (==ATTR_UNDEF) implies c being unset, too) * for the respective int-attributes holds true. * @param equals If set, we verify using '=', not '<=' */ static int qc_verify(struct qc_handle *hdl, enum qc_attr_id a, enum qc_attr_id b, enum qc_attr_id c, enum qc_attr_id d, int equals) { int *val_a, *val_b = NULL, *val_c = NULL, *val_d; // We assume that non-presence of a value is due to...non-presence, as opposed to an error (since that would have been reported previously) if ((val_a = qc_get_attr_value_int(hdl, a)) == NULL || (val_d = qc_get_attr_value_int(hdl, d)) == NULL) return 0; if (b != ATTR_UNDEF && (val_b = qc_get_attr_value_int(hdl, b)) == NULL) return 0; if (c != ATTR_UNDEF && (val_c = qc_get_attr_value_int(hdl, c)) == NULL) return 0; if (b == ATTR_UNDEF) { if ((equals && *val_a != *val_d) || (!equals && *val_a > *val_d)) { qc_debug(hdl, "Warning: Consistency check '%s %s %s' failed at layer %d (%s/%s): %d %s %d\n", qc_attr_id_to_char(hdl, a), (equals ? "=" : "<="), qc_attr_id_to_char(hdl, d), hdl->layer_no, qc_get_attr_value_string(hdl, qc_layer_type), qc_get_attr_value_string(hdl, qc_layer_category), *val_a, (equals ? "!=" : ">"), *val_d); return 1; } } else if (c == ATTR_UNDEF) { if ((equals && *val_a + *val_b != *val_d) || (!equals && *val_a + *val_b > *val_d)) { qc_debug(hdl, "Warning: Consistency check '%s + %s %s %s' failed at layer %d (%s/%s): %d + %d %s %d\n", qc_attr_id_to_char(hdl, a), qc_attr_id_to_char(hdl, b), (equals ? "=" : "<="), qc_attr_id_to_char(hdl, d), hdl->layer_no, qc_get_attr_value_string(hdl, qc_layer_type), qc_get_attr_value_string(hdl, qc_layer_category), *val_a, *val_b, (equals ? "!=" : ">"), *val_d); return 2; } } else { if ((equals && *val_a + *val_b + *val_c != *val_d) || (!equals && *val_a + *val_b + *val_c > *val_d)) { qc_debug(hdl, "Warning: Consistency check '%s + %s + %s %s %s' failed at layer %d (%s/%s): %d + %d + %d %s %d\n", qc_attr_id_to_char(hdl, a), qc_attr_id_to_char(hdl, b), qc_attr_id_to_char(hdl, c), (equals ? "=" : "<="), qc_attr_id_to_char(hdl, d), hdl->layer_no, qc_get_attr_value_string(hdl, qc_layer_type), qc_get_attr_value_string(hdl, qc_layer_category), *val_a, *val_b, *val_c, (equals ? "!=" : ">"), *val_d); return 1; } } return 0; } // Check consistency of data across data sources, as well as consistency of data within each data source. // Returns 0 in case of success, <0 for errors, and >0 in case the data is inconsistent. static int qc_consistency_check(struct qc_handle *hdl) { int *etype, rc = 0; if (!qc_consistency_check_requested) return 0; qc_debug(hdl, "Run consistency check\n"); qc_debug_indent_inc(); for (; hdl; hdl = hdl->next) { if ((etype = qc_get_attr_value_int(hdl, qc_layer_type_num)) == NULL) { rc = -1; goto out; } switch (*etype) { case QC_LAYER_TYPE_CEC: if ((rc = qc_verify(hdl, qc_num_core_dedicated, qc_num_core_shared, ATTR_UNDEF, qc_num_core_total, 0)) || (rc = qc_verify(hdl, qc_num_core_configured, qc_num_core_standby, qc_num_core_reserved, qc_num_core_total, 0)) || (rc = qc_verify(hdl, qc_num_cp_total, qc_num_ifl_total, ATTR_UNDEF, qc_num_core_total, 0)) || (rc = qc_verify(hdl, qc_num_ifl_dedicated, qc_num_cp_dedicated, ATTR_UNDEF, qc_num_core_dedicated, 1)) || (rc = qc_verify(hdl, qc_num_ifl_shared, qc_num_cp_shared, ATTR_UNDEF, qc_num_core_shared, 1)) || (rc = qc_verify(hdl, qc_num_cp_dedicated, qc_num_cp_shared, ATTR_UNDEF, qc_num_cp_total, 1)) || (rc = qc_verify(hdl, qc_num_ifl_dedicated, qc_num_ifl_shared, ATTR_UNDEF, qc_num_ifl_total, 1)) || (rc = qc_verify(hdl, qc_num_ziip_dedicated, qc_num_ziip_shared, ATTR_UNDEF, qc_num_ziip_total, 1))) goto out; break; case QC_LAYER_TYPE_LPAR: if ((rc = qc_verify(hdl, qc_num_core_dedicated, qc_num_core_shared, ATTR_UNDEF, qc_num_core_total, 0)) || (rc = qc_verify(hdl, qc_num_core_configured, qc_num_core_reserved, qc_num_core_standby, qc_num_core_total, 0)) || (rc = qc_verify(hdl, qc_num_cp_dedicated, qc_num_cp_shared, ATTR_UNDEF, qc_num_cp_total, 1)) || (rc = qc_verify(hdl, qc_num_ifl_dedicated, qc_num_ifl_shared, ATTR_UNDEF, qc_num_ifl_total, 1)) || (rc = qc_verify(hdl, qc_num_ziip_dedicated, qc_num_ziip_shared, ATTR_UNDEF, qc_num_ziip_total, 1))) goto out; break; case QC_LAYER_TYPE_ZVM_HYPERVISOR: if ((rc = qc_verify(hdl, qc_num_core_dedicated, qc_num_core_shared, ATTR_UNDEF, qc_num_core_total, 1)) || (rc = qc_verify(hdl, qc_num_cp_total, qc_num_ifl_total, ATTR_UNDEF, qc_num_core_total, 1)) || (rc = qc_verify(hdl, qc_num_cp_dedicated, qc_num_ifl_dedicated, ATTR_UNDEF, qc_num_core_dedicated, 1)) || (rc = qc_verify(hdl, qc_num_cp_shared, qc_num_ifl_shared, ATTR_UNDEF, qc_num_core_shared, 1)) || (rc = qc_verify(hdl, qc_num_cp_dedicated, qc_num_cp_shared, ATTR_UNDEF, qc_num_cp_total, 1)) || (rc = qc_verify(hdl, qc_num_ifl_dedicated, qc_num_ifl_shared, ATTR_UNDEF, qc_num_ifl_total, 1)) || (rc = qc_verify(hdl, qc_num_ziip_dedicated, qc_num_ziip_shared, ATTR_UNDEF, qc_num_ziip_total, 1))) goto out; break; case QC_LAYER_TYPE_ZVM_CPU_POOL: case QC_LAYER_TYPE_ZOS_TENANT_RESOURCE_GROUP: if ((rc = qc_verify_capped_capacity(hdl, qc_cp_capped_capacity, qc_cp_capacity_cap, qc_cp_limithard_cap)) || (rc = qc_verify_capped_capacity(hdl, qc_ifl_capped_capacity, qc_ifl_capacity_cap, qc_ifl_limithard_cap)) || (rc = qc_verify_capped_capacity(hdl, qc_ziip_capped_capacity, qc_ziip_capacity_cap, qc_ziip_limithard_cap))) goto out; break; case QC_LAYER_TYPE_ZVM_GUEST: if ((rc = qc_verify(hdl, qc_num_cpu_dedicated, qc_num_cpu_shared, ATTR_UNDEF, qc_num_cpu_total, 1)) || (rc = qc_verify(hdl, qc_num_cpu_configured, qc_num_cpu_reserved, qc_num_cpu_standby, qc_num_cpu_total, 1)) || (rc = qc_verify(hdl, qc_num_cp_total, qc_num_ifl_total, ATTR_UNDEF, qc_num_cpu_total, 1)) || (rc = qc_verify(hdl, qc_num_cp_dedicated, qc_num_ifl_dedicated, ATTR_UNDEF, qc_num_cpu_dedicated, 1)) || (rc = qc_verify(hdl, qc_num_cp_shared, qc_num_ifl_shared, ATTR_UNDEF, qc_num_cpu_shared, 1)) || (rc = qc_verify(hdl, qc_num_cp_dedicated, qc_num_cp_shared, ATTR_UNDEF, qc_num_cp_total, 1)) || (rc = qc_verify(hdl, qc_num_ifl_dedicated, qc_num_ifl_shared, ATTR_UNDEF, qc_num_ifl_total, 1)) || (rc = qc_verify(hdl, qc_num_ziip_dedicated, qc_num_ziip_shared, ATTR_UNDEF, qc_num_ziip_total, 1))) goto out; break; case QC_LAYER_TYPE_KVM_HYPERVISOR: if ((rc = qc_verify(hdl, qc_num_core_shared, qc_num_core_dedicated, ATTR_UNDEF, qc_num_core_total, 1)) || (rc = qc_verify(hdl, qc_num_cp_dedicated, qc_num_cp_shared, ATTR_UNDEF, qc_num_cp_total, 1)) || (rc = qc_verify(hdl, qc_num_ifl_dedicated, qc_num_ifl_shared, ATTR_UNDEF, qc_num_ifl_total, 1)) || (rc = qc_verify(hdl, qc_num_ziip_dedicated, qc_num_ziip_shared, ATTR_UNDEF, qc_num_ziip_total, 1))) goto out; break; case QC_LAYER_TYPE_KVM_GUEST: if ((rc = qc_verify(hdl, qc_num_cpu_configured, qc_num_cpu_reserved, qc_num_cpu_standby, qc_num_cpu_total, 1)) || (rc = qc_verify(hdl, qc_num_cpu_shared, qc_num_cpu_dedicated, ATTR_UNDEF, qc_num_cpu_total, 1)) || (rc = qc_verify(hdl, qc_num_ifl_dedicated, qc_num_ifl_shared, ATTR_UNDEF, qc_num_ifl_total, 1)) || (rc = qc_verify(hdl, qc_num_ifl_dedicated, ATTR_UNDEF, ATTR_UNDEF, 0, 1)) || (rc = qc_verify(hdl, qc_num_ifl_shared, ATTR_UNDEF, ATTR_UNDEF, qc_num_cpu_configured, 1))) goto out; break; default: break; } } out: if (rc) qc_debug(hdl, "Warning: Consistency check failed\n"); qc_debug_indent_dec(); return rc; } static int qc_copy_attr_value(struct qc_handle *tgt, struct qc_handle *src, enum qc_attr_id id) { int *i = qc_get_attr_value_int(src, id); return i ? qc_set_attr_int(tgt, id, *i, ATTR_SRC_POSTPROC) : 0; } // src layer can have either qc_num_core_* (in case of LPAR) or qc_num_cpu_* (in case of e.g. KVM guest) attributes! static int qc_copy_attr_value_rename(struct qc_handle *tgt, enum qc_attr_id tgtid, struct qc_handle *src, enum qc_attr_id altsrcid) { int *i = qc_get_attr_value_int(src, tgtid); if (!i) i = qc_get_attr_value_int(src, altsrcid); return i ? qc_set_attr_int(tgt, tgtid, *i, ATTR_SRC_POSTPROC) : 0; } struct qc_mtype { int type; char *zname; // IBM Z char *lname; // LinuxONE }; static struct qc_mtype mtypes[] = { // IBM Z LinuxONE {4381, "IBM 4381", NULL}, {3090, "IBM 3090", NULL}, {9221, "IBM S/390 9221", NULL}, {9021, "IBM ES/9000 9021", NULL}, {2003, "IBM S/390 Multiprise 2000", NULL}, {3000, "IBM S/390 StarterPak 3000", NULL}, {9672, "IBM S/390 9672", NULL}, {2066, "IBM zSeries 800", NULL}, {2064, "IBM zSeries 900", NULL}, {2086, "IBM zSeries 890", NULL}, {2084, "IBM zSeries 990", NULL}, {2096, "IBM System z9 BC", NULL}, {2094, "IBM System z9 EC", NULL}, {2098, "IBM System z10 BC", NULL}, {2097, "IBM System z10 EC", NULL}, {2818, "IBM zEnterprise 114", NULL}, {2817, "IBM zEnterprise 196", NULL}, {2827, "IBM zEnterprise EC12", NULL}, {2828, "IBM zEnterprise BC12", NULL}, {2965, "IBM z13s", "IBM LinuxONE Rockhopper"}, {2964, "IBM z13", "IBM LinuxONE Emperor"}, {3907, "IBM z14 ZR1", "IBM LinuxONE Rockhopper II"}, {3906, "IBM z14", "IBM LinuxONE Emperor II"}, {8561, "IBM z15", "IBM LinuxONE III"}, {8562, "IBM z15 Model T02", "IBM LinuxONE III Model LT2"}, {0, NULL, NULL} }; static int qc_post_process_ziip_thrds(struct qc_handle *hdl) { int *thrds, *ziips; if ((ziips = qc_get_attr_value_int(hdl, qc_num_ziip_total)) && *ziips) { if ((thrds = qc_get_attr_value_int(hdl, qc_num_ifl_threads)) && qc_set_attr_int(hdl, qc_num_ziip_threads, *thrds, ATTR_SRC_POSTPROC)) return -1; } return 0; } static int qc_post_process_CEC(struct qc_handle *hdl) { int cpuid, rc = -1, family = QC_TYPE_FAMILY_IBMZ; struct qc_mtype *type; char *str; qc_debug(hdl, "Fill CEC layer\n"); qc_debug_indent_inc(); if ((str = qc_get_attr_value_string(hdl, qc_type)) == NULL) goto out; cpuid = atoi(str); for (type = mtypes; type->type; ++type) { if (cpuid == type->type) { if (type->lname && (str = qc_get_attr_value_string(hdl, qc_model)) != NULL && *str == 'L') { str = type->lname; family = QC_TYPE_FAMILY_LINUXONE; } else str = type->zname; if (qc_set_attr_string(hdl, qc_type_name, str, ATTR_SRC_POSTPROC) || qc_set_attr_int(hdl, qc_type_family, family, ATTR_SRC_POSTPROC)) goto out; break; } } if (qc_post_process_ziip_thrds(hdl)) goto out; rc = 0; out: qc_debug_indent_dec(); return rc; } static int qc_post_process_LPAR(struct qc_handle *hdl) { return qc_post_process_ziip_thrds(hdl); } static int qc_post_process_KVM_host(struct qc_handle *hdl) { struct qc_handle *parent = qc_get_prev_handle(hdl); int *num_conf, rc; qc_debug(hdl, "Fill KVM host layer\n"); qc_debug_indent_inc(); // We can copy most information from the parent with few exceptions if (*(int *)(parent->layer) == QC_LAYER_TYPE_KVM_GUEST) // KVM guests ain't got no CPs rc = qc_set_attr_int(hdl, qc_num_cp_total, 0, ATTR_SRC_POSTPROC) || qc_set_attr_int(hdl, qc_num_cp_dedicated, 0, ATTR_SRC_POSTPROC) || qc_set_attr_int(hdl, qc_num_cp_shared, 0, ATTR_SRC_POSTPROC); else rc = qc_copy_attr_value(hdl, parent, qc_num_cp_total) || qc_copy_attr_value(hdl, parent, qc_num_cp_dedicated) || qc_copy_attr_value(hdl, parent, qc_num_cp_shared); // only parent layer's configured CPUs are available to the host num_conf = qc_get_attr_value_int(parent, qc_num_core_configured); if (!num_conf) num_conf = qc_get_attr_value_int(parent, qc_num_cpu_configured); rc |= !num_conf || qc_set_attr_int(hdl, qc_num_core_total, *num_conf, ATTR_SRC_POSTPROC) || qc_copy_attr_value_rename(hdl, qc_num_core_dedicated, parent, qc_num_cpu_dedicated) || qc_copy_attr_value_rename(hdl, qc_num_core_shared, parent, qc_num_cpu_shared) || qc_copy_attr_value(hdl, parent, qc_num_ifl_total) || qc_copy_attr_value(hdl, parent, qc_num_ifl_dedicated) || qc_copy_attr_value(hdl, parent, qc_num_ifl_shared); qc_debug_indent_dec(); return rc; } static int qc_post_process_KVM_guest(struct qc_handle *hdl) { struct qc_handle *parent = qc_get_prev_handle(hdl); int rc = 0, *num_conf, *num_CPs, *num_IFLs; qc_debug(hdl, "Fill KVM guest layer\n"); qc_debug_indent_inc(); // KVM guests support IFLs only - all configured CPUs (comes from sysinfo!) are treated as IFLs num_conf = qc_get_attr_value_int(hdl, qc_num_cpu_configured); if (qc_set_attr_int(hdl, qc_num_ifl_total, *num_conf, ATTR_SRC_SYSINFO) || qc_set_attr_int(hdl, qc_num_ifl_dedicated, 0, ATTR_SRC_SYSINFO) || qc_set_attr_int(hdl, qc_num_ifl_shared, *num_conf, ATTR_SRC_SYSINFO) || qc_set_attr_int(hdl, qc_num_cpu_dedicated, 0, ATTR_SRC_SYSINFO) || qc_set_attr_int(hdl, qc_num_cpu_shared, *num_conf, ATTR_SRC_SYSINFO)) { rc = -1; goto out; } num_CPs = qc_get_attr_value_int(parent, qc_num_cp_total); num_IFLs = qc_get_attr_value_int(parent, qc_num_ifl_total); if (num_CPs && num_IFLs) { if (*num_CPs > 0 && *num_IFLs > 0) { qc_debug(hdl, "Warning: KVM guest running on a mixed-mode host!\n"); goto out; // not an error } if (qc_set_attr_int(hdl, qc_ifl_dispatch_type, *num_IFLs > 0 ? 3 : 0, ATTR_SRC_POSTPROC)) { rc = -3; goto out; } } out: qc_debug_indent_dec(); return rc; } static int qc_post_processing(struct qc_handle *hdl) { qc_debug(hdl, "Post processing: Fill KVM layers\n"); qc_debug_indent_inc(); for (; hdl; hdl = hdl->next) { switch(*(int *)(hdl->layer)) { case QC_LAYER_TYPE_CEC: if (qc_post_process_CEC(hdl)) goto fail; break; case QC_LAYER_TYPE_LPAR: if (qc_post_process_LPAR(hdl)) goto fail; break; case QC_LAYER_TYPE_KVM_HYPERVISOR: if (qc_post_process_KVM_host(hdl)) goto fail; break; case QC_LAYER_TYPE_KVM_GUEST: if (qc_post_process_KVM_guest(hdl)) goto fail; break; default: break; } } qc_debug_indent_dec(); return 0; fail: qc_debug_indent_dec(); return -1; } static void *_qc_open(struct qc_handle *hdl, int *rc) { // sysinfo needs to be handled first, or our LGM check later on will have loopholes // sysfs needs to be handled last, as part of the attributes apply to top-most layer only struct qc_data_src *src, *sources[] = {&sysinfo, &hypfs, &sthyi, &sysfs, NULL}; struct qc_handle *lparhdl; int i; qc_debug(hdl, "_qc_open()\n"); qc_debug_indent_inc(); *rc = 0; if (qc_new_handle(NULL, &hdl, 0, QC_LAYER_TYPE_CEC) || qc_new_handle(hdl, &lparhdl, 1, QC_LAYER_TYPE_LPAR)) { *rc = -1; goto out; } hdl->next = lparhdl; lparhdl->root = hdl->root; // open all data sources for (i = 0; (src = sources[i]) != NULL; i++) if (src->open(hdl, &src->priv)) *rc = -2; // don't exit on error immediately, so we collect all data for a dump later on if (*rc) goto out; // verify that we weren't migrated if ((*rc = sysinfo.lgm_check(hdl, sysinfo.priv)) != 0) goto out; // process data sources for (i = 0; (src = sources[i]) != NULL; i++) { // Return values >0 will be left as is and passed back to caller if ((*rc = src->process(hdl, src->priv)) < 0) { *rc = -3; // match errors to a value that we can identify goto out; } if (*rc) goto out; } if (qc_post_processing(hdl)) { *rc = -4; goto out; } if (qc_dbg_level > 0) { qc_debug(hdl, "Final layers overview:\n"); qc_debug_indent_inc(); for (lparhdl = hdl; lparhdl; lparhdl = lparhdl->next) qc_debug(hdl, "Layer %2i: %s %s\n", lparhdl->layer_no, qc_get_attr_value_string(lparhdl, qc_layer_type), qc_get_attr_value_string(lparhdl, qc_layer_category)); qc_debug_indent_dec(); } out: // Possibly dump all data sources if (qc_dbg_level > 1 || (qc_dbg_autodump && *rc < 0)) { qc_debug(hdl, "Create dump\n"); qc_debug_indent_inc(); if (qc_debug_open_dump_dir(hdl) == 0) { // get a new dump directory for (i = 0; (src = sources[i]) != NULL; i++) src->dump(hdl, src->priv); qc_debug_close_dump_dir(hdl); } else qc_debug(hdl, "Failed, could not open directory\n"); qc_debug_indent_dec(); } // Close all data sources for (i = 0; (src = sources[i]) != NULL; i++) src->close(hdl, src->priv); if (hdl) // nothing else we can do if registration fails qc_hdl_register(hdl); qc_debug(hdl, "Return rc=%d\n", *rc); qc_debug_indent_dec(); return hdl; } void *qc_open(int *rc) { struct qc_handle *hdl = NULL; char *s, *end; int i; *rc = 0; if (qc_debug_init()) { *rc = -1; goto out; } qc_debug(hdl, "qc_open()\n"); qc_debug_indent_inc(); if (qc_cd == (iconv_t)-1) { qc_debug(hdl, "Initialize iconv\n"); qc_cd = iconv_open("ISO8859-1", "IBM-1047"); if (qc_cd == (iconv_t)-1) { qc_debug(hdl, "Error: iconv setup failed: %s\n", strerror(errno)); *rc = -2; goto out; } } if ((s = getenv("QC_CHECK_CONSISTENCY")) != NULL) { qc_consistency_check_requested = strtol(s, &end, 10); if (end == s || qc_consistency_check_requested < 0) qc_consistency_check_requested = 0; } /* Since we retrieve data from multiple sources, CPU hotplugging provides a chance for * inconsistent data. If we detect that, we retry up to a total of 3 times before * giving up. */ for (i = 0; i < 3; ++i) { if (i > 0) { qc_debug(hdl, "Warning: Gathering data failed, retry %d\n", i); qc_hdl_reinit(hdl); } hdl = _qc_open(hdl, rc); if (*rc > 0) continue; if (*rc < 0 || ((*rc = qc_consistency_check(hdl)) <= 0)) break; } if (*rc > 0) qc_debug(hdl, "Error: Unable to retrieve consistent data, giving up\n"); out: qc_debug(hdl, "Return %p, rc=%d\n", *rc ? NULL : hdl, *rc); qc_debug_indent_dec(); if (*rc) { qc_close(hdl); hdl = NULL; } return hdl; } void qc_close(void *hdl) { if (qc_hdl_verify(hdl, "qc_close")) return; qc_debug(hdl, "qc_close()\n"); qc_debug_indent_inc(); qc_debug_deinit(hdl); qc_hdl_reinit(hdl); free(hdl); qc_debug_indent_dec(); } int qc_get_num_layers(void *cfg, int *rc) { struct qc_handle *hdl = cfg; if (qc_hdl_verify(hdl, "qc_get_num_layers")) { *rc = -EFAULT; return *rc; } qc_debug(hdl, "qc_get_num_layers()\n"); qc_debug_indent_inc(); while (hdl->next) hdl = hdl->next; qc_debug(hdl, "Return %d layers\n", hdl->layer_no + 1); *rc = 0; qc_debug_indent_dec(); return hdl->layer_no + 1; } static struct qc_handle *qc_get_layer_handle(void *config, int layer) { struct qc_handle *hdl = config; do { if (hdl->layer_no == layer) return hdl; hdl = hdl->next; } while (hdl); return NULL; } static int qc_is_attr_id_valid(enum qc_attr_id id) { return id <= qc_secure; } int qc_get_attribute_string(void *cfg, enum qc_attr_id id, int layer, const char **value) { struct qc_handle *hdl; int rc; *value = NULL; if (qc_hdl_verify(cfg, "qc_get_attribute_string")) return -4; hdl = qc_get_layer_handle(cfg, layer); qc_debug(cfg, "qc_get_attribute_string(attr=%d, layer=%d)\n", id, layer); qc_debug_indent_inc(); if (!hdl) { rc = -1; goto out; } if (!qc_is_attr_id_valid(id)) { rc = -2; goto out; } if ((*value = qc_get_attr_value_string(hdl, id))) { qc_debug(cfg, "Attr '%s' from '%c' res=%s\n", qc_attr_id_to_char(cfg, id), qc_get_attr_value_src_string(hdl, id), *value); rc = 1; goto out; } if (qc_is_attr_set_string(hdl, id) <= 0) { qc_debug(cfg, "Attr '%s' not defined\n", qc_attr_id_to_char(cfg, id)); rc = 0; goto out; } rc = -3; out: qc_debug(cfg, "Return value='%s', rc=%d\n", *value, rc); qc_debug_indent_dec(); return rc; } int qc_get_attribute_int(void *cfg, enum qc_attr_id id, int layer, int *value) { struct qc_handle *hdl; void *ptr = NULL; int rc; *value = -EINVAL; if (qc_hdl_verify(cfg, "qc_get_attribute_int")) return -4; hdl = qc_get_layer_handle(cfg, layer); qc_debug(cfg, "qc_get_attribute_int(attr=%d, layer=%d)\n", id, layer); qc_debug_indent_inc(); if (!hdl) { rc = -1; goto out; } if (!qc_is_attr_id_valid(id)) { rc = -2; goto out; } if ((ptr = qc_get_attr_value_int(hdl, id))) { qc_debug(cfg, "Attr '%s' from '%c' res=%d\n", qc_attr_id_to_char(cfg, id), qc_get_attr_value_src_int(hdl, id), *(int *)ptr); rc = 1; goto out; } // Attribute value not set - let's figure out why if (qc_is_attr_set_int(hdl, id) <= 0) { qc_debug(cfg, "Attr '%s' not defined\n", qc_attr_id_to_char(cfg, id)); rc = 0; goto out; } rc = -3; out: if (ptr) *value = *(int *)ptr; qc_debug(cfg, "Return value=%d, rc=%d\n", *value, rc); qc_debug_indent_dec(); return rc; } int qc_get_attribute_float(void *cfg, enum qc_attr_id id, int layer, float *value) { struct qc_handle *hdl; void *ptr = NULL; int rc; *value = -EINVAL; if (qc_hdl_verify(cfg, "qc_get_attribute_float")) return -4; hdl = qc_get_layer_handle(cfg, layer); qc_debug(cfg, "qc_get_attribute_float(attr=%d, layer=%d)\n", id, layer); qc_debug_indent_inc(); if (!hdl) { rc = -1; goto out; } if (!qc_is_attr_id_valid(id)) { rc = -2; goto out; } if ((ptr = qc_get_attr_value_float(hdl, id))) { qc_debug(cfg, "Attr '%s' from '%c' res=%f\n", qc_attr_id_to_char(cfg, id), qc_get_attr_value_src_float(hdl, id), *(float *)ptr); rc = 1; goto out; } // Attribute value not set - let's figure out why if (qc_is_attr_set_float(hdl, id) <= 0) { qc_debug(cfg, "Attr '%s' not defined\n", qc_attr_id_to_char(cfg, id)); rc = 0; goto out; } rc = -3; out: if (ptr) *value = *(float *)ptr; qc_debug(cfg, "Return value=%f, rc=%d\n", *value, rc); qc_debug_indent_dec(); return rc; } qclib-2.1.0/query_capacity.h0000664000175000017500000014706113647300120015032 0ustar rasplraspl/* Copyright IBM Corp. 2013, 2019 */ /** @file */ #ifndef QUERY_CAPACITY #define QUERY_CAPACITY /* Build Customization */ #define CONFIG_DEBUG_TIMESTAMPS // Print timestamps in log //#define CONFIG_DUMP_READING // Allow to read in dumps //#define CONFIG_V1_COMPATIBILITY // Support functionality deprecated in v1.x //#define CONFIG_TEXTUAL_HYPFS // Use data from textual hypfs if available /** \enum qc_attr_id * Defines the attributes retrievable by the API. Attributes can * exist for multiple layers. Also, attributes will only be valid if retrieved * as the correct type. * * The following tables detail which attributes of what types are available for * what layers. The letter encoding in the '\c Src' column describes how the * value is gained: * - **S**: Provided by \c /proc/sysinfo, which is present in all Linux on z flavors. * - **F**: Provided by firmware as made available through the \c sysfs filesystem. * - **H**: Provided by hypfs, which is (preferably) available through \c debugfs at * \c /sys/kernel/debug/s390_hypfs, or \c s390_hypfs (typically mounted at * \c /sys/hypervisor/s390). * Proper file access privileges required. * - **h**: See H, but provided by \c debugfs exclusively. * - **V**: Provided by the STHYI instruction. * - z/VM Linux guests: Requires z/VM 6.3 with APAR VM65419 or higher. * UM34746 for z/VM 6.3.0 APAR VM65716 is required for LPAR groups support * (see layer \c #QC_LAYER_TYPE_LPAR_GROUP). * - KVM Linux guests: Requires Linux kernel 4.8 or higher in the KVM host. * - Linux LPAR: Requires Linux kernel 4.15 or higher in the KVM host. * - zCX: Requires z/OS 2.4 or higher. * * Several letters indicate the order in which the value is attempted to be * acquired. If the extraction of the value in a later phase succeeds, it will * overwrite the value acquired in an earlier phase. If the extraction of the * value in a later phase does not succeed, it will not dismiss the existing * value, if a previous phase has set it before.
* * * ### SMT ### * SMT was introduced starting with z13/LinuxONE.
* When SMT is turned off (or not available), the terms core and CPU are * synonymous. But when SMT is enabled, CPU refers to a thread running on a * core.
* As a general rule, CP, IFL and zIIP counts (eg. #qc_num_cp_total, #qc_num_ifl_total * and #qc_num_ziip_total respectively) * - refer to cores if the layer reports cores, and * - refer to CPUs if the layer reports CPUs. * E.g. \c #QC_LAYER_TYPE_LPAR reports cores (see e.g. #qc_num_core_total), hence * #qc_num_ifl_shared refers to cores, too.
* In layers reporting cores, use attributes #qc_num_cp_threads, #qc_num_ifl_threads and * #qc_num_ziip_threads to derive the number of CPUs. * * ### Notes ### * - zIIPs are not included in CPU and core total counts. * - Special care needs to be taken with respect to [5] when processing #qc_num_core_total, * #qc_num_core_dedicated and #qc_num_core_shared in layers of type \c #QC_LAYER_TYPE_LPAR. * - With SMT enabled: * - All layers above (if present) the first hypervisor layer will report each thread as a * separate CPU. * Otherwise, the term CPU is synonymous with core. * - Layers of types \c #QC_LAYER_TYPE_ZVM_HYPERVISOR and \c #QC_LAYER_TYPE_KVM_HYPERVISOR * running above one or more layers of type \c #QC_LAYER_TYPE_ZVM_HYPERVISOR or * \c #QC_LAYER_TYPE_KVM_HYPERVISOR (i.e. within a guest of a hypervisor), will * report CPUs all the time, no matter what the attribute names might imply. * - On Linux, use 'lscpu -e' to get a detailed list of the CPU/core * topology. Likewise, use 'QUERY PROCESSORS' on z/VM for similar * information. However, beware that if the respective instance is not running * immediately on top of a layer of type \c #QC_LAYER_TYPE_LPAR, results need to be * interpreted according to the previous note. * - Layers of type \c #QC_LAYER_TYPE_ZVM_GUEST report any capacity cappings (see attributes * #qc_cp_capped_capacity, #qc_ifl_capped_capacity and #qc_ziip_capped_capacity) in units * of cores, although CPs, IFLs and zIIPs that they refer to are reported as CPUs. * - All strings (char pointers) carry the trailing zero byte. * - See #qc_attr_id for general explanation of attributes, and the \c 'Comment' column * for layer-specific considerations * * Attributes for CECs (layer 0) | Type | Src | Comment * ------------------------------------|------|-----|------------------------------------- * #qc_layer_type_num | int | | Hardcoded to \c #QC_LAYER_TYPE_CEC * #qc_layer_category_num | int | | Hardcoded to \c #QC_LAYER_CAT_HOST * #qc_layer_type |string| | Hardcoded to \c "CEC" * #qc_layer_category |string| | Hardcoded to \c "HOST" * #qc_layer_name |string|F V| CPC name of machine. Available in Linux kernel 3.0 or higher. * #qc_manufacturer |string|S V| \n * #qc_type |string|S V| \n * #qc_type_name |string|S  | \n * #qc_type_family | int |S  | \n * #qc_model_capacity |string|S  | \n * #qc_model |string|S  | \n * #qc_sequence_code |string|S V| \n * #qc_lic_identifier |string|S  | Note: Requires Linux kernel 4.16 or higher, and IBM z14 or later * #qc_plant |string|S V| \n * #qc_num_core_total | int |S| Sum of #qc_num_core_configured, #qc_num_core_reserved and #qc_num_core_standby.
Note: Sum of #qc_num_cp_total and #qc_num_ifl_total might be smaller or larger, since some assists and spares are missing, and only the general purpose CPU type is considered * #qc_num_core_configured | int |S  | General purpose cores only without IFLs and zIIPs * #qc_num_core_standby | int |S  | General purpose cores which are in the (very brief) process of being added to the configuration * #qc_num_core_reserved | int |S  | IFLs, zIIPs, spares, excluding IFPs (Internal Firmware Processors) * #qc_num_core_dedicated | int | hV| Sum of #qc_num_cp_dedicated and #qc_num_ifl_dedicated
Note: \b [4] * #qc_num_core_shared | int | hV| Sum of #qc_num_cp_shared and #qc_num_ifl_shared
Note: \b [4] * #qc_num_cp_total | int | HV| Equals the sum of #qc_num_cp_dedicated and #qc_num_cp_shared
Reported in unit of cores
Note: \b [4] * #qc_num_cp_dedicated | int | hV| Reported in unit of cores
Note: \b [4] * #qc_num_cp_shared | int | hV| Reported in unit of cores
Note: \b [4] * #qc_num_ifl_total | int | HV| Equals the sum of #qc_num_ifl_dedicated and #qc_num_ifl_shared
Reported in unit of cores
Note: \b [4] * #qc_num_ifl_dedicated | int | hV| Reported in unit of cores
Note: \b [4] * #qc_num_ifl_shared | int | hV| Reported in unit of cores
Note: \b [4] * #qc_num_ziip_total | int | HV| Equals the sum of #qc_num_ziip_dedicated and #qc_num_ziip_shared
Reported in unit of cores
Note: \b [4] * #qc_num_ziip_dedicated | int | hV| Reported in unit of cores
Note: \b [4] * #qc_num_ziip_shared | int | hV| Reported in unit of cores
Note: \b [4] * #qc_num_cp_threads | int |S  | Number of threads/CPUs per CP core that the CEC is capable of
Note: Requires Linux kernel 4.4 or higher * #qc_num_ifl_threads | int |S  | Number of threads/CPUs per IFL core that the CEC is capable of
Note: Requires Linux kernel 4.4 or higher * #qc_num_ziip_threads | int |S  | Number of threads/CPUs per zIIP core that the CEC is capable of
Note: Requires Linux kernel 4.4 or higher * #qc_capability | float|S  | \n * #qc_secondary_capability | float|S  | \n * #qc_capacity_adjustment_indication | int |S  | \n * #qc_capacity_change_reason | int |S  | \n * * Attributes for LPAR Groups | Type | Src | Comment * ------------------------------------|------|-----|------------------------------------- * #qc_layer_type_num | int | | Hardcoded to \c #QC_LAYER_TYPE_LPAR_GROUP * #qc_layer_category_num | int | | Hardcoded to \c #QC_LAYER_CAT_POOL * #qc_layer_type |string| | Hardcoded to \c "LPAR-Group" * #qc_layer_category |string| | Hardcoded to \c "POOL" * #qc_layer_name |string| hV| Name of LPAR group * #qc_cp_absolute_capping | int | hV| Reported in unit of cores * #qc_ifl_absolute_capping | int | hV| Reported in unit of cores * #qc_ziip_absolute_capping | int | hV| Reported in unit of cores * * Attributes for LPARs | Type | Src | Comment * ------------------------------------|------|-----|------------------------------------- * #qc_layer_type_num | int | | Hardcoded to \c #QC_LAYER_TYPE_LPAR * #qc_layer_category_num | int | | Hardcoded to \c #QC_LAYER_CAT_GUEST * #qc_layer_type |string| | Hardcoded to \c "LPAR" * #qc_layer_category |string| | Hardcoded to \c "GUEST" * #qc_layer_name |string|S V| Name of LPAR, limited to 8 characters * #qc_layer_extended_name |string|S  | Name of LPAR with up to 256 characters
Note: Requires Linux kernel 4.10 or higher * #qc_layer_uuid |string|S  | Note: Requires Linux kernel 4.10 or higher * #qc_partition_number | int |S  | \n * #qc_partition_char |string|S  | \n * #qc_partition_char_num | int |S  | \n * #qc_adjustment | int |S  | \n * #qc_has_secure | int |F  | \n * #qc_secure | int |F  | \n * #qc_num_core_total | int |S| Total number of CPs and IFLs configured in the LPARs activation profile * #qc_num_core_configured | int |S  | Note: \b [5] * #qc_num_core_standby | int |S  | Operational cores that require add'l configuration within the LPAR image to become usable
Note: \b [5] * #qc_num_core_reserved | int |S  | Operational cores that require add'l interaction by the LPAR's administrator to become usable
Note: \b [5] * #qc_num_core_dedicated | int |S  | Dedicated operational cores only
Note: \b [5], hence sum of #qc_num_cp_dedicated, #qc_num_ifl_dedicated and #qc_num_ziip_dedicated can be larger * #qc_num_core_shared | int |S  | Shared operational cores only
Note: \b [5], hence sum of #qc_num_cp_shared, #qc_num_ifl_shared and #qc_num_ziip_dedicated can be larger * #qc_num_cp_total | int | HV| Sum of #qc_num_cp_dedicated and #qc_num_cp_shared. Considers configured CPs only.
Reported in unit of cores * #qc_num_cp_dedicated | int | hV| Reported in unit of cores * #qc_num_cp_shared | int | hV| Reported in unit of cores * #qc_num_ifl_total | int | HV| Sum of #qc_num_ifl_dedicated and #qc_num_ifl_shared. Considers configured IFLs only.
Reported in unit of cores * #qc_num_ifl_dedicated | int | hV| Reported in unit of cores * #qc_num_ifl_shared | int | hV| Reported in unit of cores * #qc_num_ziip_total | int | HV| Sum of #qc_num_ziip_dedicated and #qc_num_ziip_shared. Considers configured zIIPs only.
Reported in unit of cores * #qc_num_ziip_dedicated | int | hV| Reported in unit of cores * #qc_num_ziip_shared | int | hV| Reported in unit of cores * #qc_num_cp_threads | int |S  | Number of threads/CPUs per CP core configured for this LPAR
Note: Requires Linux kernel 4.3 or higher * #qc_num_ifl_threads | int |S  | Number of threads/CPUs per IFL core configured for this LPAR
Note: Requires Linux kernel 4.3 or higher * #qc_num_ziip_threads | int |S  | Number of threads/CPUs per zIIP core configured for this LPAR
Note: Requires Linux kernel 4.3 or higher * #qc_cp_absolute_capping | int | hV| Reported in unit of cores * #qc_cp_weight_capping | int | hV| Reported in unit of cores
Note: \b [4] * #qc_ifl_absolute_capping | int | hV| Reported in unit of cores * #qc_ifl_weight_capping | int | hV| Reported in unit of cores
Note: \b [4] * #qc_ziip_absolute_capping | int | hV| Reported in unit of cores * #qc_ziip_weight_capping | int | hV| Reported in unit of cores
Note: \b [4] * * * Attributes for z/VM hypervisors | Type | Src | Comment * ------------------------------------|------|-----|------------------------------------- * #qc_layer_type_num | int | | Hardcoded to \c #QC_LAYER_TYPE_ZVM_HYPERVISOR * #qc_layer_category_num | int | | Hardcoded to \c #QC_LAYER_CAT_HOST * #qc_layer_type |string| | Hardcoded to \c "z/VM-hypervisor" * #qc_layer_category |string| | Hardcoded to \c "HOST" * #qc_layer_name |string|  V| System identifier of the hypervisor * #qc_cluster_name |string|  V| \n * #qc_control_program_id |string|S  | ID of CP * #qc_adjustment | int |S  | Adjustment factor of z/VM * #qc_limithard_consumption | int |  V| \n * #qc_prorated_core_time | int |  V| \n * #qc_num_core_total | int |  V| Sum of #qc_num_core_dedicated and #qc_num_core_shared * #qc_num_core_dedicated | int |  V| Sum of #qc_num_cp_dedicated and #qc_num_ifl_dedicated * #qc_num_core_shared | int |  V| Sum of #qc_num_cp_shared and #qc_num_ifl_dedicated * #qc_num_cp_total | int |  V| Sum of #qc_num_cp_dedicated and #qc_num_cp_shared
Reported in unit of cores unless run as a guest of another hypervisor other than LPAR * #qc_num_cp_dedicated | int |  V| Reported in unit of cores unless run as a guest of another hypervisor other than LPAR * #qc_num_cp_shared | int |  V| Reported in unit of cores unless run as a guest of another hypervisor other than LPAR * #qc_num_ifl_total | int |  V| Sum of #qc_num_ifl_dedicated and #qc_num_ifl_shared
Reported in unit of cores unless run as a guest of another hypervisor other than LPAR * #qc_num_ifl_dedicated | int |  V| Reported in unit of cores unless run as a guest of another hypervisor other than LPAR * #qc_num_ifl_shared | int |  V| Reported in unit of cores unless run as a guest of another hypervisor other than LPAR * #qc_num_ziip_total | int |  V| Sum of #qc_num_ziip_dedicated and #qc_num_ziip_shared
Reported in unit of cores unless run as a guest of another hypervisor other than LPAR * #qc_num_ziip_shared | int |  V| Reported in unit of cores unless run as a guest of another hypervisor other than LPAR * #qc_num_ziip_dedicated | int |  V| Reported in unit of cores unless run as a guest of another hypervisor other than LPAR * #qc_num_cp_threads | int |  V| Number of threads/CPUs per CP core in use * #qc_num_ifl_threads | int |  V| Number of threads/CPUs per IFL core in use * #qc_num_ziip_threads | int |  V| Number of threads/CPUs per zIIP core in use * * * Attributes for z/VM resource pools | Type | Src | Comment * ------------------------------------|------|-----|------------------------------------- * #qc_layer_type_num | int | | Hardcoded to \c #QC_LAYER_TYPE_ZVM_RESOURCE_POOL * #qc_layer_category_num | int | | Hardcoded to \c #QC_LAYER_CAT_POOL * #qc_layer_type |string| | Hardcoded to \c "z/VM-resource-pool", or \c "z/VM-CPU-pool" if compiled with CONFIG_V1_COMPATIBILITY * #qc_layer_category |string| | Hardcoded to \c "POOL" * #qc_layer_name |string|  V| Name of resource pool * #qc_cp_limithard_cap | int |  V| \n * #qc_cp_capacity_cap | int |  V| \n * #qc_cp_capped_capacity | int |  V| Reported in unit of cores unless run as a guest of another hypervisor other than LPAR * #qc_ifl_limithard_cap | int |  V| \n * #qc_ifl_capacity_cap | int |  V| \n * #qc_ifl_capped_capacity | int |  V| Reported in unit of cores unless run as a guest of another hypervisor other than LPAR * #qc_ziip_limithard_cap | int |  V| \n * #qc_ziip_capacity_cap | int |  V| \n * #qc_ziip_capped_capacity | int |  V| Reported in unit of cores unless run as a guest of another hypervisor other than LPAR * * * Attributes for z/VM guests | Type | Src | Comment * ------------------------------------|------|-----|------------------------------------- * #qc_layer_type_num | int | | Hardcoded to \c #QC_LAYER_TYPE_ZVM_GUEST * #qc_layer_category_num | int | | Hardcoded to \c #QC_LAYER_CAT_GUEST * #qc_layer_type |string| | Hardcoded to \c "z/VM-guest" * #qc_layer_category |string| | Hardcoded to \c "GUEST" * #qc_layer_name |string|S V| Userid of guest * #qc_capping |string| H| \n * #qc_capping_num | int | H| \n * #qc_mobility_enabled | int |  V| \n * #qc_has_secure | int |F  | \n * #qc_secure | int |F  | \n * #qc_num_cpu_total | int |S V| Sum of #qc_num_cpu_configured, #qc_num_cpu_standby and #qc_num_cpu_reserved, or #qc_num_cpu_dedicated and #qc_num_cpu_shared * #qc_num_cpu_configured | int |S  | \n * #qc_num_cpu_standby | int |S  | \n * #qc_num_cpu_reserved | int |S  | \n * #qc_num_cpu_dedicated | int | HV| Sum of #qc_num_cp_dedicated and #qc_num_ifl_dedicated * #qc_num_cpu_shared | int | HV| Sum of #qc_num_cp_shared and #qc_num_ifl_shared * #qc_num_cp_total | int |  V| Sum of #qc_num_cp_dedicated and #qc_num_cp_shared
Reported in unit of CPUs * #qc_num_cp_dedicated | int |  V| Reported in unit of CPUs * #qc_num_cp_shared | int |  V| Reported in unit of CPUs * #qc_num_ifl_total | int |  V| Sum of #qc_num_ifl_dedicated and #qc_num_ifl_shared
Reported in unit of CPUs * #qc_num_ifl_dedicated | int |  V| Reported in unit of CPUs * #qc_num_ifl_shared | int |  V| Reported in unit of CPUs * #qc_num_ziip_total | int |  V| Sum of #qc_num_ziip_dedicated and #qc_num_ziip_shared
Reported in unit of CPUs * #qc_num_ziip_dedicated | int |  V| Reported in unit of CPUs * #qc_num_ziip_shared | int |  V| Reported in unit of CPUs * #qc_has_multiple_cpu_types | int |  V| \n * #qc_cp_dispatch_limithard | int |  V| \n * #qc_cp_dispatch_type | int |  V| Only set in presence of CPs * #qc_cp_capped_capacity | int |  V| Reported in unit of cores unless run as a guest of another hypervisor other than LPAR * #qc_ifl_dispatch_limithard | int |  V| \n * #qc_ifl_dispatch_type | int |  V| Only set in presence of IFLs * #qc_ifl_capped_capacity | int |  V| Reported in unit of cores unless run as a guest of another hypervisor other than LPAR * #qc_ziip_dispatch_limithard | int |  V| \n * #qc_ziip_dispatch_type | int |  V| Only set in presence of zIIPs * #qc_ziip_capped_capacity | int |  V| Reported in unit of cores unless run as a guest of another hypervisor other than LPAR * * * Attributes for z/OS hypervisors | Type | Src | Comment * ------------------------------------|------|-----|------------------------------------- * #qc_layer_type_num | int | | Hardcoded to \c #QC_LAYER_TYPE_ZOS_HYPERVISOR * #qc_layer_category_num | int | | Hardcoded to \c #QC_LAYER_CAT_HOST * #qc_layer_type |string| | Hardcoded to \c "z/OS-hypervisor" * #qc_layer_category |string| | Hardcoded to \c "HOST" * #qc_layer_name |string|  V| System identifier of the hypervisor * #qc_cluster_name |string|  V| Name of sysplex * #qc_control_program_id |string|S  | ID of z/OS * #qc_adjustment | int |S  | Adjustment factor of z/OS * #qc_num_core_total | int |  V| Sum of #qc_num_core_dedicated and #qc_num_core_shared * #qc_num_core_dedicated | int |  V| Sum of #qc_num_cp_dedicated and #qc_num_ziip_dedicated * #qc_num_core_shared | int |  V| Sum of #qc_num_cp_shared and #qc_num_ziip_shared * #qc_num_cp_total | int |  V| Sum of #qc_num_cp_dedicated and #qc_num_cp_shared
Reported in unit of cores unless run as a guest of another hypervisor other than LPAR * #qc_num_cp_dedicated | int |  V| Reported in unit of cores unless run as a guest of another hypervisor other than LPAR * #qc_num_cp_shared | int |  V| Reported in unit of cores unless run as a guest of another hypervisor other than LPAR * #qc_num_ziip_total | int |  V| Sum of #qc_num_ziip_dedicated and #qc_num_ziip_shared
Reported in unit of cores unless run as a guest of another hypervisor other than LPAR * #qc_num_ziip_shared | int |  V| Reported in unit of cores unless run as a guest of another hypervisor other than LPAR * #qc_num_ziip_dedicated | int |  V| Reported in unit of cores unless run as a guest of another hypervisor other than LPAR * #qc_num_cp_threads | int |  V| Number of threads/CPUs per CP core in use * #qc_num_ziip_threads | int |  V| Number of threads/CPUs per zIIP core in use * * * Attributes for z/OS resource groups | Type | Src | Comment * ------------------------------------|------|-----|------------------------------------- * #qc_layer_type_num | int | | Hardcoded to \c #QC_LAYER_TYPE_ZOS_TENANT_RESOURCE_GROUP * #qc_layer_category_num | int | | Hardcoded to \c #QC_LAYER_CAT_POOL * #qc_layer_type |string| | Hardcoded to \c "z/OS-tenant-resource-group" * #qc_layer_category |string| | Hardcoded to \c "POOL" * #qc_layer_name |string|  V| Name of resource group * #qc_cp_limithard_cap | int |  V| \n * #qc_cp_capacity_cap | int |  V| \n * #qc_cp_capped_capacity | int |  V| Reported in unit of cores unless run as a guest of another hypervisor other than LPAR * #qc_ziip_limithard_cap | int |  V| \n * #qc_ziip_capacity_cap | int |  V| \n * #qc_ziip_capped_capacity | int |  V| Reported in unit of cores unless run as a guest of another hypervisor other than LPAR * * * Attributes for z/OS zCX Servers | Type | Src | Comment * ------------------------------------|------|-----|------------------------------------- * #qc_layer_type_num | int | | Hardcoded to \c #QC_LAYER_TYPE_ZOS_ZCX_SERVER * #qc_layer_category_num | int | | Hardcoded to \c #QC_LAYER_CAT_GUEST * #qc_layer_type |string| | Hardcoded to \c "z/OS-guest" * #qc_layer_category |string| | Hardcoded to \c "GUEST" * #qc_layer_name |string|S V| Userid of guest * #qc_capping |string| H| \n * #qc_capping_num | int | H| \n * #qc_has_secure | int |F  | \n * #qc_secure | int |F  | \n * #qc_num_cpu_total | int |S V| Sum of #qc_num_cpu_configured, #qc_num_cpu_standby and #qc_num_cpu_reserved, or #qc_num_cpu_dedicated and #qc_num_cpu_shared * #qc_num_cpu_configured | int |S  | \n * #qc_num_cpu_standby | int |S  | \n * #qc_num_cpu_reserved | int |S  | \n * #qc_num_cpu_dedicated | int | HV| Sum of #qc_num_cp_dedicated and #qc_num_ifl_dedicated * #qc_num_cpu_shared | int | HV| Sum of #qc_num_cp_shared and #qc_num_ifl_shared * #qc_num_cp_total | int |  V| Sum of #qc_num_cp_dedicated and #qc_num_cp_shared
Reported in unit of CPUs * #qc_num_cp_dedicated | int |  V| Reported in unit of CPUs * #qc_num_cp_shared | int |  V| Reported in unit of CPUs * #qc_num_ziip_total | int |  V| Sum of #qc_num_ziip_dedicated and #qc_num_ziip_shared
Reported in unit of CPUs * #qc_num_ziip_dedicated | int |  V| Reported in unit of CPUs * #qc_num_ziip_shared | int |  V| Reported in unit of CPUs * #qc_has_multiple_cpu_types | int |  V| \n * #qc_cp_dispatch_limithard | int |  V| \n * #qc_cp_dispatch_type | int |  V| Only set in presence of CPs * #qc_cp_capped_capacity | int |  V| Reported in unit of cores unless run as a guest of another hypervisor other than LPAR * #qc_ziip_dispatch_limithard | int |  V| \n * #qc_ziip_dispatch_type | int |  V| Only set in presence of zIIPs
NOTE: I guess it would be cleaner if we would switch to IFL attributes instead of zIIPs, since that is (to my understanding), what Linux will see - and use THIS attribute to indicate that the IFLs are dispatched to zIIPs...? * #qc_ziip_capped_capacity | int |  V| Reported in unit of cores unless run as a guest of another hypervisor other than LPAR * * * Attributes for KVM hypervisors | Type | Src | Comment * ------------------------------------|------|-----|------------------------------------- * #qc_layer_type_num | int | | Hardcoded to \c #QC_LAYER_TYPE_KVM_HYPERVISOR * #qc_layer_category_num | int | | Hardcoded to \c #QC_LAYER_CAT_HOST * #qc_layer_type |string| | Hardcoded to \c "KVM-hypervisor" * #qc_layer_category |string| | Hardcoded to \c "HOST" * #qc_control_program_id |string|S  | Host ID * #qc_adjustment | int |S  | \n * #qc_num_core_total | int |S  | Sum of #qc_num_core_dedicated and #qc_num_core_shared * #qc_num_core_dedicated | int |SHV| Sum of #qc_num_cp_dedicated and #qc_num_ifl_dedicated * #qc_num_core_shared | int |SHV| Sum of #qc_num_cp_shared and #qc_num_ifl_shared * #qc_num_cp_total | int | HV| Sum of #qc_num_cp_dedicated and #qc_num_cp_shared
Reported in unit of cores unless run as a guest of another hypervisor other than LPAR * #qc_num_cp_dedicated | int | hV| Reported in unit of cores unless run as a guest of another hypervisor other than LPAR * #qc_num_cp_shared | int | hV| Reported in unit of cores unless run as a guest of another hypervisor other than LPAR * #qc_num_ifl_total | int |SHV| Sum of #qc_num_ifl_dedicated and #qc_num_ifl_shared
Reported in unit of cores unless run as a guest of another hypervisor other than LPAR * #qc_num_ifl_dedicated | int |ShV| Reported in unit of cores unless run as a guest of another hypervisor other than LPAR * #qc_num_ifl_shared | int |ShV| Reported in unit of cores unless run as a guest of another hypervisor other than LPAR * * * Attributes for KVM guests | Type | Src | Comment * ------------------------------------|------|-----|------------------------------------- * #qc_layer_type_num | int | | Hardcoded to \c #QC_LAYER_TYPE_KVM_GUEST * #qc_layer_category_num | int | | Hardcoded to \c #QC_LAYER_CAT_GUEST * #qc_layer_type |string| | Hardcoded to \c "KVM-guest" * #qc_layer_category |string| | Hardcoded to \c "GUEST" * #qc_layer_name |string|S  | Guest name truncated to 8 characters
Note: \b [1] * #qc_layer_extended_name |string|S  | Guest name with up to 256 characters
Note: Requires Linux kernel 3.19 or higher, [1] * #qc_layer_uuid |string|S  | Note: Requires Linux kernel 3.19 or higher * #qc_has_secure | int |F  | \n * #qc_secure | int |F  | \n * #qc_num_cpu_total | int |S  | Sum of #qc_num_cpu_configured, #qc_num_cpu_standby and #qc_num_cpu_reserved, or #qc_num_cpu_dedicated and #qc_num_cpu_shared * #qc_num_cpu_configured | int |S  | \n * #qc_num_cpu_standby | int |S  | \n * #qc_num_cpu_reserved | int |S  | \n * #qc_num_cpu_dedicated | int |S  | \n * #qc_num_cpu_shared | int |S  | \n * #qc_num_ifl_total | int |S  | Sum of #qc_num_ifl_dedicated and #qc_num_ifl_shared
Reported in unit of CPUs * #qc_num_ifl_dedicated | int |S  | Reported in unit of CPUs * #qc_num_ifl_shared | int |S  | Reported in unit of CPUs * #qc_ifl_dispatch_type | int |SHV| \n * * \b [1] Available starting with RHEL7.2 and SLES12SP1
* \b [2] z/Architecture Principles of Operation, SA22-7832
* \b [3] z/VM: CP Commands and Utilities Reference, SC24-6175
* \b [4] Requires global performance data to be enabled in the LPAR's activation profile
* \b [5] As of this writing, in LPARs with both CPs and IFLs defined in its activation profile, only CPs can become operational. * Therefore, IFL counts would not appear in any of #qc_num_core_configured, #qc_num_core_standby, #qc_num_core_reserved, * #qc_num_core_dedicated or #qc_num_core_shared */ enum qc_layer_types { /** CEC */ QC_LAYER_TYPE_CEC = 1, /** LPAR Capping Group */ QC_LAYER_TYPE_LPAR_GROUP = 8, /** LPAR */ QC_LAYER_TYPE_LPAR = 2, /** z/VM Hypervisor */ QC_LAYER_TYPE_ZVM_HYPERVISOR = 3, /** z/VM CPU Pool (deprecated, use QC_LAYER_TYPE_ZVM_RESOURCE_POOL instead) */ QC_LAYER_TYPE_ZVM_CPU_POOL = 4, /** z/VM Resource Pool */ QC_LAYER_TYPE_ZVM_RESOURCE_POOL = 4, /** z/VM Guest */ QC_LAYER_TYPE_ZVM_GUEST = 5, /** KVM Hypervisor */ QC_LAYER_TYPE_KVM_HYPERVISOR = 6, /** KVM Guest */ QC_LAYER_TYPE_KVM_GUEST = 7, /** z/OS Hypervisor */ QC_LAYER_TYPE_ZOS_HYPERVISOR = 9, /** z/OS Tenant Resource Group */ QC_LAYER_TYPE_ZOS_TENANT_RESOURCE_GROUP = 10, /** z/OS cCX Server */ QC_LAYER_TYPE_ZOS_ZCX_SERVER = 11, }; /** \enum qc_layer_categories * Layer categories. */ enum qc_layer_categories { /** Layer category for guests, namely LPARs, z/VM and KVM guests */ QC_LAYER_CAT_GUEST = 1, /** Layer category for hosts, namely CEC, z/VM and KVM hosts */ QC_LAYER_CAT_HOST = 2, /** Layer category for pools (currently z/VM Pools and LPAR capping groups) */ QC_LAYER_CAT_POOL = 3, }; /** \enum qc_part_chars * Characteristic of an an LPAR. */ enum qc_part_chars { /** LPAR has dedicated resources */ QC_PART_CHAR_DEDICATED = 1, /** LPAR shares resources with other LPARs */ QC_PART_CHAR_SHARED = 2, /** LPAR has limited resources */ QC_PART_CHAR_LIMITED = 4, }; /** \enum qc_cappings * Numeric representation of the capping type, see #qc_capping. */ enum qc_cappings { /** Capping turned off */ QC_CAPPING_OFF = 0, QC_CAPPING_SOFT = 1, QC_CAPPING_HARD = 2, }; /** \enum qc_model_families */ enum qc_model_families { /** IBM Z */ QC_TYPE_FAMILY_IBMZ = 0, /** LinuxONE */ QC_TYPE_FAMILY_LINUXONE = 1, }; /** \enum qc_attr_id */ enum qc_attr_id { /** The adjustment factor indicates the maximum percentage of the machine (in parts of 1000) that could be used by the primary processor type in the worst case by the respective layer, taking cappings and other limiting factors into consideration.
Note: This value can lead to wrong conclusions for layers that utilize more than one processor type! */ qc_adjustment = 0, /** Capability rating, see \c STSI instruction in [2] */ qc_capability = 1, /** Capacity adjustment value, see \c STSI instruction in [2] */ qc_capacity_adjustment_indication = 2, /** Reason for capacity adjustment, see \c STSI instruction in [2] */ qc_capacity_change_reason = 3, /** Capping type: \c "off", \c "soft", \c "hard" */ qc_capping = 4, /** Numeric representation of capping type, see enum #qc_cappings */ qc_capping_num = 5, /** SSI name if part of SSI cluster */ qc_cluster_name = 6, /** ID of control program */ qc_control_program_id = 7, /** CP absolute capping value. Scaled value where 0x10000 equals to one core, or 0 if no capping set */ qc_cp_absolute_capping = 8, /** 1 if pool's CP virtual type has capped capacity
0 if not
See \c DEFINE \c CPUPOOL command in [3] */ qc_cp_capacity_cap = 9, /** Guest current capped capacity for shared virtual CPs -- scaled value where 0x10000 equals to one core, or 0 if no capping set. While this field displays the capacity, either #qc_cp_capacity_cap or #qc_cp_limithard_cap must is set to indicate the kind of limit. */ qc_cp_capped_capacity = 10, /** 1 if guest CP dispatch type has LIMITHARD capping,
0 if not
See \c SET \c SRM command in [3] */ qc_cp_dispatch_limithard = 11, /** Dispatch type for guest CPs:
0=General Purpose (CP) */ qc_cp_dispatch_type = 12, /** 1 if pool's CP virtual type has limithard capping
0 if not
See \c DEFINE \c CPUPOOL command in [3] */ qc_cp_limithard_cap = 13, /** CP weight-based capping value -- scaled value where 0x10000 equals to one core, or 0 if no capping set */ qc_cp_weight_capping = 14, /** 1 if SRM limithard setting is consumption
0 if deadline
See \c SET \c SRM command in [3] */ qc_limithard_consumption = 15, #ifdef CONFIG_V1_COMPATIBILITY /** Deprecated, see #qc_limithard_consumption */ qc_hardlimit_consumption = 15, #endif /** 1 if layer has multiple CPU types (e.g. CPs, IFLs, zIIPs),
0 if not */ qc_has_multiple_cpu_types = 16, /** IFL absolute capping value -- scaled value where 0x10000 equals to one core, or 0 if no capping set */ qc_ifl_absolute_capping = 17, /** 1 if pool's IFL virtual type has capped capacity
0 if not
See \c DEFINE \c CPUPOOL command in [3] */ qc_ifl_capacity_cap = 18, /** Guest current capped capacity for shared virtual IFLs -- scaled value where 0x10000 equals to one core, or 0 if no capping set. While this field displays the capacity, either #qc_ifl_capacity_cap or #qc_ifl_limithard_cap must is set to indicate the kind of limit. */ qc_ifl_capped_capacity = 19, /** 1 if guest IFL dispatch type has LIMITHARD capping,
0 if not
See \c SET \c SRM command in [3] */ qc_ifl_dispatch_limithard = 20, /** Dispatch type for guest IFLs:
0=General Purpose (CP),
3=Integrated Facility for Linux (IFL) */ qc_ifl_dispatch_type = 21, /** 1 if pool's IFL virtual type has limithard capping
0 if not
See \c DEFINE \c CPUPOOL command in [3] */ qc_ifl_limithard_cap = 22, /** IFL weight-based capping value -- scaled value where 0x10000 equals to one core, or 0 if no capping set */ qc_ifl_weight_capping = 23, /** zIIP absolute capping value -- scaled value where 0x10000 equals to one core, or 0 if no capping set */ qc_ziip_absolute_capping = 66, /** 1 if pool's zIIP virtual type has capped capacity
0 if not
See \c DEFINE \c CPUPOOL command in [3] */ qc_ziip_capacity_cap = 67, /** Guest current capped capacity for shared virtual zIIPs -- scaled value where 0x10000 equals to one core, or 0 if no capping set. While this field displays the capacity, either #qc_ziip_capacity_cap or #qc_ziip_limithard_cap must is set to indicate the kind of limit. */ qc_ziip_capped_capacity = 68, /** 1 if guest zIIP dispatch type has LIMITHARD capping,
0 if not
See \c SET \c SRM command in [3] */ qc_ziip_dispatch_limithard = 69, /** Dispatch type for guest zIIPs:
0=General Purpose (CP),
5=zSeries Integrated Information Processor (zIIP),
ff=zIIP or CP */ qc_ziip_dispatch_type = 70, /** 1 if pool's zIIP virtual type has limithard capping
0 if not
See \c DEFINE \c CPUPOOL command in [3] */ qc_ziip_limithard_cap = 71, /** zIIP weight-based capping value -- scaled value where 0x10000 equals to one core, or 0 if no capping set */ qc_ziip_weight_capping = 72, /** Layer category, see layer tables above for details */ qc_layer_category = 24, /** Numeric representation of layer category, see enum #qc_layer_categories */ qc_layer_category_num = 25, /** Guest extended name */ qc_layer_extended_name = 26, /** Name of container, see layer tables for details */ qc_layer_name = 27, /** Layer type, see layer tables above for details */ qc_layer_type = 28, /** Numeric representation of layer type, see enum #qc_layer_types */ qc_layer_type_num = 29, /** Universal unique ID */ qc_layer_uuid = 30, /** Company that manufactured box */ qc_manufacturer = 31, /** 1 if guest is enabled for mobility,
0 if not */ qc_mobility_enabled = 32, #ifdef CONFIG_V1_COMPATIBILITY /** Deprecated, see #qc_mobility_enabled */ qc_mobility_eligible = 32, #endif /** Indicates whether secure boot is available to the entity. Requires Linux kernel 5.3 or later. Note: This attribute is only ever available for the topmost layer. */ qc_has_secure = 77, /** Indicates whether entity was booted using the secure boot feature Requires Linux kernel 5.3 or later. Note: This attribute is only ever available for the topmost layer. */ qc_secure = 78, /** Model identifier, see \c STSI instruction in [2] */ qc_model = 33, /** Model capacity of machine, see \c STSI instruction in [2] */ qc_model_capacity = 34, /** Family of the model, enum #qc_model_families */ qc_type_family = 65, /** Sum of dedicated CPs in layer */ qc_num_cp_dedicated = 35, /** Sum of shared CPs in layer */ qc_num_cp_shared = 36, /** Sum of all CPs in layer */ qc_num_cp_total = 37, /** Sum of configured CPs and IFLs in layer */ qc_num_cpu_configured = 38, /** Sum of dedicated CPs and IFLs in layer */ qc_num_cpu_dedicated = 39, /** Sum of reserved CPs and IFLs in layer */ qc_num_cpu_reserved = 40, /** Sum of shared CPs and IFLs in layer */ qc_num_cpu_shared = 41, /** Sum of standby CPs and IFLs in layer */ qc_num_cpu_standby = 42, /** Sum of all CPs and IFLs in layer */ qc_num_cpu_total = 43, /** Sum of dedicated IFLs in layer */ qc_num_ifl_dedicated = 44, /** Sum of shared IFLs in layer */ qc_num_ifl_shared = 45, /** Sum of all IFLs (Integrated Facility for Linux) in layer */ qc_num_ifl_total = 46, /** Sum of dedicated zIIPs in layer */ qc_num_ziip_dedicated = 73, /** Sum of shared zIIPs in layer */ qc_num_ziip_shared = 74, /** Sum of all zIIPs (Integrated Information Processor) in layer */ qc_num_ziip_total = 75, /** Partition characteristics, any combination of \c "Dedicated", \c "Shared" and \c "Limited", also see \c STSI instruction in [2] */ qc_partition_char = 47, /** Numeric representation of partition characteristics, see enum #qc_part_chars */ qc_partition_char_num = 48, /** Partition number, see \c STSI instruction in [2] */ qc_partition_number = 49, /** Identifier of the manufacturing plant, see \c STSI instruction in [2] */ qc_plant = 50, /** Secondary capability rating, see \c STSI instruction in [2] */ qc_secondary_capability = 51, /** Sequence code of machine, see \c STSI instruction in [2] */ qc_sequence_code = 52, /** 4-digit machine type */ qc_type = 53, /** 1 if limithard caps uses prorated core time for capping
0 if raw CPU time is used
See \c APAR \c VM65680 */ qc_prorated_core_time = 54, /** Threads per CP, values >1 indicate that SMT is enabled */ qc_num_cp_threads = 55, /** Threads per IFL, values >1 indicate that SMT is enabled */ qc_num_ifl_threads = 56, /** Threads per zIIP, values >1 indicate that SMT is enabled */ qc_num_ziip_threads = 76, /** Sum of all CP and IFL cores in layer */ qc_num_core_total = 57, /** Sum of configure CP and IFL cores in layer */ qc_num_core_configured = 58, /** Sum of standby CP and IFL cores in layer */ qc_num_core_standby = 59, /** Sum of reserved CP and IFL cores in layer */ qc_num_core_reserved = 60, /** Sum of dedicated CP and IFL cores in layer */ qc_num_core_dedicated = 61, /** Sum of shared CP and IFL cores in layer */ qc_num_core_shared = 62, /** Name of IBM Z model in clear text */ qc_type_name = 63, /** Licensed Internal Code (LIC) level */ qc_lic_identifier = 64, }; /** * Attaches to system information sources and prepares the extraction of * system information. Some information may be gathered at this time * already: under LPAR, \c /proc/sysinfo is read and interpreted; under z/VM, * *VMINFO data is read using the \c STHYI instruction (requires z/VM 6.3 with * \c APAR \c VM65419, or higher). Capacity queries then take place based on this * information which could be considered cached.
* Memory will be allocated in this function, which has to be released by * closing the configuration again. While a configuration is open, SSI * migration in z/VM is not blocked and can occur. In case a migration occurs * after a configuration has been opened, closing the configuration and * re-opening it ensures capacity information is used from the migrated-to * system.
* Use the following environment variables to operate built-in service facilities: * - \c QC_DEBUG: Set to an integer value * - >0 to enable logging to a file \c /tmp/qclib-XXXXXX or as specified by * \c QC_DEBUG_FILE if set. * - >1 to have data dumped to a directory named \c \.dump-XXX * on every qc_open() call (where STEM is \c /tmp/qclib-XXXXXX or as specified * by \c QC_DEBUG_FILE if set.
* To disable logging, either see qc_close(), or set \c QC_DEBUG to a value * <=0 on the next qc_open() call.
* - \c QC_DEBUG_FILE: Stem to use for log files and dump directories (see \c * QC_DEBUG). Defaults to \c /tmp/qclib-XXXXXX. * - \c QC_AUTODUMP: Set to a value >0 to trigger a dump to a directory named * \c /tmp/qclib-XXXXXX.dump-XXX if an error is encountered within qc_open().
* Note: This will also create an empty log file for technical reasons, * unless \c QC_DEBUG was set to a value >0
* - \c QC_USE_DUMP: To run with a previously generated dump instead of live data, point this environment variable to a directory containing the dump data. Requires compilation with \c CONFIG_DUMP_READING set. * - \c QC_CHECK_CONSISTENCY: Check data for consistency. Recommended for debugging * scenarios only. * * @see qc_close() * * @param rc Return parameter indicating the return code. Set to * - 0 on success, * - <0 in case of an error, and * - >0 if the configuration could not be read completely at the moment, * but a retry later on could provide the missing data. * @return Returns a configuration handle which is valid for reading out * capacity data until the configuration is closed. Returns NULL in * case of an error. */ void *qc_open(int *rc); /** * Closes the configuration handle and releases all memory allocated when the * configuration was opened. The configuration handle is invalid after * calling this function, as are any returned pointers of previous capacity * function calls. * * If logging or autodumping was enabled on qc_open(), environment variables * \c QC_DEBUG and \c QC_AUTODUMP need to be set to integers <=0 on the final * call to qc_close() (or whenever neither functionality is not required * anymore) to correctly free up all resources. * * @param hdl Handle of the configuration to close. */ void qc_close(void *hdl); /** * Get the number of layers. * * @param hdl Handle of the configuration to use. * @param rc Return parameter indicating the return code. Set to * - 0 on success, * - <0 in case of an error. * @return Number of layer. E.g. * - 2 if Linux runs in an LPAR * - 4 if a z/VM guest runs in a z/VM Hypervisor in an LPAR, or * - 5 if a z/VM guest runs in a capping group in z/VM running in LPAR. */ int qc_get_num_layers(void *hdl, int *rc); /** * Returns the attribute of type string designated by \p id. If the attribute is * not available at the specified layer, the attribute is not of type string, * or another error occurred, return parameter \p valid will be set accordingly. * * @see qc_get_attribute_int() * @see qc_get_attribute_float() * * @param hdl Handle of the configuration to use. * @param id Attribute to retrieve. * @param layer Specifies the layer, e.g. * - 0: CEC layer information, * - 1: LPAR layer information, etc. * @param value Return parameter returning the string attribute's value or NULL * in case of an error. @return Indicating validity of the queried attribute as follows: * - >0 attribute is valid * - 0 attribute exists but is not set * - <0 an error occurred retrieving the attribute */ int qc_get_attribute_string(void *hdl, enum qc_attr_id id, int layer, const char **value); /** * Returns the attribute of type integer designated by \p id. If the attribute is * not available at the specified layer, the attribute is not of type integer, * or another error occurred, return parameter \p valid will be set accordingly. * * @see qc_get_attribute_string() * @see qc_get_attribute_float() * * @param hdl Handle of the configuration to use. * @param id Attribute to retrieve. * @param layer Specifies the layer, e.g. * - 0: CEC layer information, * - 1: LPAR layer information, etc. * @param value Return parameter returning the string attribute's value or undefined * in case of an error. @return Indicating validity of the queried attribute as follows: * - >0 attribute is valid * - 0 attribute exists but is not set * - <0 an error occurred retrieving the attribute * @return */ int qc_get_attribute_int(void *hdl, enum qc_attr_id id, int layer, int *value); /** * Returns the attribute of type float designated by \p id. If the attribute is * not available at the specified layer, the attribute is not of type float, * or another error occurred, return parameter \p valid will be set accordingly. * * @see qc_get_attribute_string() * @see qc_get_attribute_int() * * @param hdl Handle of the configuration to use. * @param id Attribute to retrieve. * @param layer Specifies the layer, e.g. * - 0: CEC layer information, * - 1: LPAR layer information, etc. * @param value Return parameter returning the float attribute's value or undefined * in case of an error.indicating validity as follows: @return Indicating validity of the queried attribute as follows: * - >0 attribute is valid * - 0 attribute exists but is not set * - <0 an error occurred retrieving the attribute */ int qc_get_attribute_float(void *hdl, enum qc_attr_id id, int layer, float *value); #endif qclib-2.1.0/README0000664000175000017500000002770113647300120012515 0ustar rasplraspl qclib (Query Capacity Library) ============================== qclib provides a C API for extraction of system information for Linux on IBM Z. For instance, it will provide the number of CPUs * on the machine (CEC, Central Electronic Complex) layer * on the PR/SM (Processor Resource/Systems Manager) layer, i.e. visible to LPARs, including LPAR groups * in z/VM hosts, guests and CPU pools * in KVM hosts and guests This allows calculating the upper limit of CPU resources a highest level guest can use. E.g.: If an LPAR on a z13 provides 4 CPUs to a z/VM hypervisor, and the hypervisor provides 8 virtual CPUs to a guest, qclib can be used to retrieve all of these numbers, and it can be concluded that not more capacity than 4 CPUs can be used by the software running in the guest. qclib uses various interfaces and provides this data through a common and consistent API (Application Programming Interface), using information provided by: * STSI (Store System Information) instruction - for more details, refer to the z/Architecture Principles of Operation (SA22-7832) * STHYI (Store Hypervisor Information) instruction as provided by a z/VM hypervisor - for more information, refer to z/VM: V6R3 CP Programming Service (SC24-6179), chapter 'Store Hypervisor Information (STHYI) Instruction'. * hypfs file system - for more information, refer to 'Device Drivers, Features, and Commands', chapter 'S/390 hypervisor file system'. * Firmware and other interfaces as made available through sysfs. For more information, refer to 'Device Drivers, Features, and Commands', chapter 'Identifying the z Systems hardware'. Please refer to: http://www.ibm.com/developerworks/linux/linux390/qclib.html for the latest available version. Usage ===== See query_capacity.h for details on how to use the API, and qc_test.c for a sample program. Requirements ============ See query_capacity.h for details. Build ===== Use the following 'make' targets: * 'all' (default): Build static and dynamic libraries, as well as respective sample programs 'qc_test' (statically linked) and 'qc_test-sh' (dynamically linked). * 'test': Build and run the statically linked test program qc_test. Note: Requires a static version of glibc, which some distributions do not install per default. * 'test-sh': Build and run the dynamically linked test program qc_test. API Documentation ================= All documentation is available in file query_capacity.h. If you have doxygen 1.8.6 (or higher) installed, you will find the documentation in subdirectory html, after using 'make doc'. License ======= See enclosed file LICENSE for details. Bug Reports =========== See section 'Code Contributions'. Code Contributions ================== Code contributions will not be accepted for qclib. Therefore, please do not send DIFFs or code-snippets. Thank you! If you want to report bugs or suggest enhancements, please contact: linux390@de.ibm.com and put "[qclib]" as the first word in the subject line of your mail. For bug reports, at a minimum attach a log file and a dump (see QC_DEBUG as described in query_capacity.h or, yet better, use the qc_dump utility), and describe the scenario in which you observed the bug, so that the problem can be reproduced. For enhancements, please describe the proposed change and its benefits. Release History: ================ 2.1.0 (2020-04-20) Changes: - New attributes in support of secure boot in all final layers: * qc_has_secure * qc_secure Note: Changed src column indicator from 'o' to 'F' to summarize firmware-related data - Recognize IBM z15 midrange models Bug fixes: - qc_open(): Memory leaks on errors 2.0.1 (2020-01-07) Changes: - Retry up to three times when a live guest migration is detected Bug fixes: - Attribute qc_num_ziip_threads in CEC layer was not correctly set. - Do not account zIIPs in layer QC_LAYER_TYPE_ZOS_ZCX_SERVER for qc_num_cpu_* attributes. - qc_dump: Handle non-writable /tmp 2.0.0 (2019-11-11) Changes: - Add support for z/OS Container Extensions (zCX) - New attributes in layer CEC: * qc_type_name * qc_type_family * qc_lic_identifier - qc_test: Reworked output for subtle consistency improvements. - Replaced attribute qc_hardlimit_consumption with qc_limithard_consumption. Use CONFIG_V1_COMPATIBILITY for previous version. - Require CONFIG_DUMP_READING in query_capacity.h to allow running from a dump. Disabled by default. - Disabled v1 compatibility functionality per default. To re-enable, activate CONFIG_V1_COMPATIBILITY in query_capacity.h. 1.4.1 (2018-06-25) Bug fixes: - qc_dump: Don't abort the dump in case qc_test fails. - Attributes qc_cp_weight_capping and qc_ifl_weight_capping were set even when initial capping was not set in the LPAR's activation profile. 1.4.0 (2018-04-10) Changes: - Added SMT support by properly differentiating between cores and CPUs. I.e. switched from qc_num_cpu_* to qc_num_core_* attributes in layers CEC, LPAR, ZVM_HYPERVISOR and KVM_HYPERVISOR. NOTE: qc_num_cpu_* attributes remain to be valid in these cases to preserve backwards compatibility for now. This will be removed in one of the next releases! It is recommended to switch to the new attributes _now_ and test with CONFIG_V1_COMPATIBILITY disabled! - Added new attributes qc_num_threads_cp and qc_num_threads_ifl to layers CEC, LPAR and ZVM_HYPERVISOR. - Deprecated attribute qc_mobility_eligible (remains valid for now) and replaced with qc_mobility_enabled to match z/VM terminology. Likewise switched QC_LAYER_TYPE_ZVM_CPU_POOL to QC_LAYER_TYPE_ZVM_RESOURCE_POOL. - Moved build customization defines (e.g. CONFIG_V1_COMPATIBILITY) to query_capacity.h. - Don't build with textual hypfs per default anymore due to unrecoverable issues (see section 'Bug fixes'). Since all Linux distributions ship with debugfs (providing binary hypfs support), overriding textual hypfs, for years, this change will hardly ever be noticable. Enable define CONFIG_TEXTUAL_HYPFS in query_capacity.h to revert. Note that textual hypfs support will be removed in a future release. Bug fixes: - Added an exception to consistency check to ignore inconsistencies between textual hypfs and STHYI for attributes qc_num_cp_total and qc_num_ifl_total in the LPAR layer. Background: Textual hypfs cannot tell whether a core is configured or not. It therefore reports all cores as configured, which can be wrong. 1.3.1 (2018-01-18) Bug fixes: - Security: Fix PATH attack vulnerability when dumping (see QC_DEBUG=2) - STHYI: Add fallback for pre-glibc 2.16 (not using getauxval()) - Handle mismatching STHYI and /proc/sysinfo layer counts - On LPAR, fix incomplete dump of binary hypfs when textual hypfs is mounted 1.3.0 (2017-10-27) Changes: - Added STHYI support in LPAR - Added new env variable QC_DEBUG_FILE (see qc_open()) Note: Failure to open a file for logging is now treated as a fatal error - Added script qc_dump to collect debug data in a standardized manner - Added attributes qc_layer_uuid and qc_layer_extended_name to LPAR layer - /proc/sysinfo parsing: Switch from "KVM/Linux" to the less strict "KVM" to detect KVM systems - Detect unregistered and closed handles - Makefile: Compile SONAME into shared library Bug fixes: - STHYI: Properly support cc==3&&rc==4 as introduced in APAR VM65419 - Logs: Fix month in timestamp (was off by 1) - qc_test: Fix flags for qc_layer_name in QC_LAYER_TYPE_ZVM_HYPERVISOR 1.2.0 (2016-06-10) Changes: - Removed source [S] for attributes qc_num_cpu_dedicated and qc_num_cpu_shared in LPAR layer for consistency - Retrieve qc_layer_name in CEC layer from OCF - Extended hypfs usage to provide more CP, IFL and CPU counts for CEC and LPAR layers, as well as capping information for LPAR group and LPAR layers - Added attributes for IFLs, CPs and CPUs for KVM hypervisor and guest layers - Added support for LPAR Groups - Added new attribute qc_prorated_core_time - Fill qc_num_cp_total and qc_num_ifl_total in LPAR layer from STHYI - Consistency checks: Detect inconsistent values across data sources - Documentation improvements Bug fixes: - Fixed crash when setting QC_USE_DUMP to an invalid directory and QC_DEBUG=1 - Fixed reset of debug level when QC_CHECK_CONSISTENCY is invalid - Display all values in attribute qc_partition_char in case of multiple - Set qc_cp_dispatch_type in presence of CPs only 1.1.0 (2016-02-15) Changes: - Makefile: Added targets 'clean' and 'install' - qc_test: Support command line options - Performance improvements - Consistency checks: Turned into a run-time option. Disabled per default, enabled in qc_test Bug fixes: - Makefile: Fixed breakages, including when run in verbose mode - Fixed handling of hostnames with <8 characters in presence of hypfs - If no SSI cluster was present, attribute qc_cluster_name was set to an empty string instead of being left undefined - Consistency checks: Fixed wrong positive - Fixed source indicators in log 1.0.0 (2015-08-28) Changes: - Introduced new API, replacing the previous one - Renamed the following attributes for consistency: * qc_container_name became qc_layer_name * qc_entity_* became qc_layer_* - Introduced the following new attributes for a numeric representation of the respective string attributes: * qc_layer_type_num (alternative to qc_layer_type) * qc_layer_category_num (alternative to qc_layer_category) * qc_partition_char_num (alternative to qc_partition_char) * qc_capping_num (alternative to qc_capping) - Removed/renamed the following attributes, since they were duplicates of other layers' content: * In layer type QC_LAYER_TYPE_ZVM_GUEST: Removed qc_hyp_*, qc_pool_* qc_system_identifier, qc_cluster_name, qc_control_program_id, qc_adjustment, and qc_hardlimit_consumption * In layer type QC_LAYER_TYPE_ZVM_CPU_POOL: Removed qc_hyp_*, qc_system_identifier, qc_cluster_name, qc_hardlimit_consumption, and renamed qc_pool_* to qc_* - Added support for KVM hypervisor - Added logging facility - Added dump support: Capability to create and run on dumps - Added autodump support: Create dumps on errors only - Added doxygen support for API description in query_capacity.h - Added support for hypfs mounted at arbitrary locations - Added support for binary hypfs API (requires RHEL6.1 and SLES11.2 or higher) - Added detection of Live Guest Migration while retrieving data - Handled NULL pointer arguments in all API calls - Reported errors as such when occurring while searching for capacity information Bug fixes: - Handled file access errors - Enabled attributes that were incorrectly indicated as not present - Fixed qc_get_num_layers() to return the number of layers (as documented), not the highest index - Fixed race by reading /proc/sysinfo only once - Only set qc_ifl_dispatch_type in presence of IFLs (as intended) 0.9.2 Bug fixes: - Fixed memory leaks 0.9.1 Bug fixes: - Fixed crash with more than 1 layers of nested z/VM virtualization - Fixed crash on 1st layer z/VM systems with hypfs - Fix: Information from /proc/sysinfo was collected in wrong sequence with more than 1 layers of nested virtualization - Fixed left open file handles in hypfs parsing code. - Added consistency check for hypfs 0.9.0 Initial version Copyright IBM Corp. 2013, 2018 qclib-2.1.0/config.doxygen0000644000175000017500000030342713647300120014501 0ustar rasplraspl# Doxyfile 1.8.7 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. # # All text after a double hash (##) is considered a comment and is placed in # front of the TAG it is preceding. # # All text after a single hash (#) is considered a comment and will be ignored. # The format is: # TAG = value [value, ...] # For lists, items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (\" \"). #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all text # before the first occurrence of this tag. Doxygen uses libiconv (or the iconv # built into libc) for the transcoding. See http://www.gnu.org/software/libiconv # for the list of possible encodings. # The default value is: UTF-8. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded by # double-quotes, unless you are using Doxywizard) that should identify the # project for which the documentation is generated. This name is used in the # title of most generated pages and in a few other places. # The default value is: My Project. PROJECT_NAME = qclib # The PROJECT_NUMBER tag can be used to enter a project or revision number. This # could be handy for archiving the generated documentation or if some version # control system is used. PROJECT_NUMBER = # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a # quick idea about the purpose of the project. Keep the description short. PROJECT_BRIEF = # With the PROJECT_LOGO tag one can specify an logo or icon that is included in # the documentation. The maximum height of the logo should not exceed 55 pixels # and the maximum width should not exceed 200 pixels. Doxygen will copy the logo # to the output directory. PROJECT_LOGO = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is # entered, it will be relative to the location where doxygen was started. If # left blank the current directory will be used. OUTPUT_DIRECTORY = # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub- # directories (in 2 levels) under the output directory of each output format and # will distribute the generated files over these directories. Enabling this # option can be useful when feeding doxygen a huge amount of source files, where # putting all generated files in the same directory would otherwise causes # performance problems for the file system. # The default value is: NO. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, # Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), # Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, # Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), # Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, # Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, # Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, # Ukrainian and Vietnamese. # The default value is: English. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member # descriptions after the members that are listed in the file and class # documentation (similar to Javadoc). Set to NO to disable this. # The default value is: YES. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief # description of a member or function before the detailed description # # Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. # The default value is: YES. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator that is # used to form the text in various listings. Each string in this list, if found # as the leading text of the brief description, will be stripped from the text # and the result, after processing the whole list, is used as the annotated # text. Otherwise, the brief description is used as-is. If left blank, the # following values are used ($name is automatically replaced with the name of # the entity):The $name class, The $name widget, The $name file, is, provides, # specifies, contains, represents, a, an and the. ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # doxygen will generate a detailed section even if there is only a brief # description. # The default value is: NO. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. # The default value is: NO. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path # before files name in the file list and in the header files. If set to NO the # shortest path that makes the file name unique will be used # The default value is: YES. FULL_PATH_NAMES = YES # The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. # Stripping is only done if one of the specified strings matches the left-hand # part of the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the path to # strip. # # Note that you can specify absolute paths here, but also relative paths, which # will be relative from the directory where doxygen is started. # This tag requires that the tag FULL_PATH_NAMES is set to YES. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the # path mentioned in the documentation of a class, which tells the reader which # header file to include in order to use a class. If left blank only the name of # the header file containing the class definition is used. Otherwise one should # specify the list of include paths that are normally passed to the compiler # using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but # less readable) file names. This can be useful is your file systems doesn't # support long names like on DOS, Mac, or CD-ROM. # The default value is: NO. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the # first line (until the first dot) of a Javadoc-style comment as the brief # description. If set to NO, the Javadoc-style will behave just like regular Qt- # style comments (thus requiring an explicit @brief command for a brief # description.) # The default value is: NO. JAVADOC_AUTOBRIEF = NO # If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first # line (until the first dot) of a Qt-style comment as the brief description. If # set to NO, the Qt-style will behave just like regular Qt-style comments (thus # requiring an explicit \brief command for a brief description.) # The default value is: NO. QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a # multi-line C++ special comment block (i.e. a block of //! or /// comments) as # a brief description. This used to be the default behavior. The new default is # to treat a multi-line C++ comment block as a detailed description. Set this # tag to YES if you prefer the old behavior instead. # # Note that setting this tag to YES also means that rational rose comments are # not recognized any more. # The default value is: NO. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the # documentation from any documented member that it re-implements. # The default value is: YES. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a # new page for each member. If set to NO, the documentation of a member will be # part of the file/class/namespace that contains it. # The default value is: NO. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen # uses this value to replace tabs by spaces in code fragments. # Minimum value: 1, maximum value: 16, default value: 4. TAB_SIZE = 8 # This tag can be used to specify a number of aliases that act as commands in # the documentation. An alias has the form: # name=value # For example adding # "sideeffect=@par Side Effects:\n" # will allow you to put the command \sideeffect (or @sideeffect) in the # documentation, which will result in a user-defined paragraph with heading # "Side Effects:". You can put \n's in the value part of an alias to insert # newlines. ALIASES = # This tag can be used to specify a number of word-keyword mappings (TCL only). # A mapping has the form "name=value". For example adding "class=itcl::class" # will allow you to use the command class in the itcl::class meaning. TCL_SUBST = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For # instance, some of the names that are used will be different. The list of all # members will be omitted, etc. # The default value is: NO. OPTIMIZE_OUTPUT_FOR_C = YES # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or # Python sources only. Doxygen will then generate output that is more tailored # for that language. For instance, namespaces will be presented as packages, # qualified scopes will look different, etc. # The default value is: NO. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources. Doxygen will then generate output that is tailored for Fortran. # The default value is: NO. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for VHDL. # The default value is: NO. OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and # language is one of the parsers supported by doxygen: IDL, Java, Javascript, # C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: # FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: # Fortran. In the later case the parser tries to guess whether the code is fixed # or free formatted code, this is the default for Fortran type files), VHDL. For # instance to make doxygen treat .inc files as Fortran files (default is PHP), # and .f files as C (default is Fortran), use: inc=Fortran f=C. # # Note For files without extension you can use no_extension as a placeholder. # # Note that for custom extensions you also need to set FILE_PATTERNS otherwise # the files are not read by doxygen. EXTENSION_MAPPING = # If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments # according to the Markdown format, which allows for more readable # documentation. See http://daringfireball.net/projects/markdown/ for details. # The output of markdown processing is further processed by doxygen, so you can # mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in # case of backward compatibilities issues. # The default value is: YES. MARKDOWN_SUPPORT = YES # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can # be prevented in individual cases by by putting a % sign in front of the word # or globally by setting AUTOLINK_SUPPORT to NO. # The default value is: YES. AUTOLINK_SUPPORT = YES # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should set this # tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); # versus func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. # The default value is: NO. BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. # The default value is: NO. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip (see: # http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen # will parse them like normal C++ but will assume all classes use public instead # of private inheritance when no explicit protection keyword is present. # The default value is: NO. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate # getter and setter methods for a property. Setting this option to YES will make # doxygen to replace the get and set methods by a property in the documentation. # This will only work if the methods are indeed getting or setting a simple # type. If this is not the case, or you want to show the methods anyway, you # should set this option to NO. # The default value is: YES. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. # The default value is: NO. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES to allow class member groups of the same type # (for instance a group of public functions) to be put as a subgroup of that # type (e.g. under the Public Functions section). Set it to NO to prevent # subgrouping. Alternatively, this can be done per class using the # \nosubgrouping command. # The default value is: YES. SUBGROUPING = YES # When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions # are shown inside the group in which they are included (e.g. using \ingroup) # instead of on a separate page (for HTML and Man pages) or section (for LaTeX # and RTF). # # Note that this feature does not work in combination with # SEPARATE_MEMBER_PAGES. # The default value is: NO. INLINE_GROUPED_CLASSES = NO # When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions # with only public data fields or simple typedef fields will be shown inline in # the documentation of the scope in which they are defined (i.e. file, # namespace, or group documentation), provided this scope is documented. If set # to NO, structs, classes, and unions are shown on a separate page (for HTML and # Man pages) or section (for LaTeX and RTF). # The default value is: NO. INLINE_SIMPLE_STRUCTS = NO # When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or # enum is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically be # useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. # The default value is: NO. TYPEDEF_HIDES_STRUCT = NO # The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This # cache is used to resolve symbols given their name and scope. Since this can be # an expensive process and often the same symbol appears multiple times in the # code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small # doxygen will become slower. If the cache is too large, memory is wasted. The # cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range # is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 # symbols. At the end of a run doxygen will report the cache usage and suggest # the optimal cache size from a speed point of view. # Minimum value: 0, maximum value: 9, default value: 0. LOOKUP_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. Private # class members and static file members will be hidden unless the # EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. # Note: This will also disable the warnings about undocumented members that are # normally produced when WARNINGS is set to YES. # The default value is: NO. EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES all private members of a class will # be included in the documentation. # The default value is: NO. EXTRACT_PRIVATE = NO # If the EXTRACT_PACKAGE tag is set to YES all members with package or internal # scope will be included in the documentation. # The default value is: NO. EXTRACT_PACKAGE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file will be # included in the documentation. # The default value is: NO. EXTRACT_STATIC = YES # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined # locally in source files will be included in the documentation. If set to NO # only classes defined in header files are included. Does not have any effect # for Java sources. # The default value is: YES. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local methods, # which are defined in the implementation section but not in the interface are # included in the documentation. If set to NO only methods in the interface are # included. # The default value is: NO. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base name of # the file that contains the anonymous namespace. By default anonymous namespace # are hidden. # The default value is: NO. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all # undocumented members inside documented classes or files. If set to NO these # members will be included in the various overviews, but no documentation # section is generated. This option has no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. If set # to NO these classes will be included in the various overviews. This option has # no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend # (class|struct|union) declarations. If set to NO these declarations will be # included in the documentation. # The default value is: NO. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any # documentation blocks found inside the body of a function. If set to NO these # blocks will be appended to the function's detailed documentation block. # The default value is: NO. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation that is typed after a # \internal command is included. If the tag is set to NO then the documentation # will be excluded. Set it to YES to include the internal documentation. # The default value is: NO. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file # names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. # The default value is: system dependent. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with # their full class and namespace scopes in the documentation. If set to YES the # scope will be hidden. # The default value is: NO. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of # the files that are included by a file in the documentation of that file. # The default value is: YES. SHOW_INCLUDE_FILES = NO # If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each # grouped member an include statement to the documentation, telling the reader # which file to include in order to use the member. # The default value is: NO. SHOW_GROUPED_MEMB_INC = NO # If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include # files with double quotes in the documentation rather than with sharp brackets. # The default value is: NO. FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the # documentation for inline members. # The default value is: YES. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the # (detailed) documentation of file and class members alphabetically by member # name. If set to NO the members will appear in declaration order. # The default value is: YES. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief # descriptions of file, namespace and class members alphabetically by member # name. If set to NO the members will appear in declaration order. Note that # this will also influence the order of the classes in the class list. # The default value is: NO. SORT_BRIEF_DOCS = NO # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the # (brief and detailed) documentation of class members so that constructors and # destructors are listed first. If set to NO the constructors will appear in the # respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. # Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief # member documentation. # Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting # detailed member documentation. # The default value is: NO. SORT_MEMBERS_CTORS_1ST = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy # of group names into alphabetical order. If set to NO the group names will # appear in their defined order. # The default value is: NO. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by # fully-qualified names, including namespaces. If set to NO, the class list will # be sorted only by class name, not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the alphabetical # list. # The default value is: NO. SORT_BY_SCOPE_NAME = NO # If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper # type resolution of all parameters of a function it will reject a match between # the prototype and the implementation of a member function even if there is # only one candidate or it is obvious which candidate to choose by doing a # simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still # accept a match between prototype and implementation in such cases. # The default value is: NO. STRICT_PROTO_MATCHING = NO # The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the # todo list. This list is created by putting \todo commands in the # documentation. # The default value is: YES. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the # test list. This list is created by putting \test commands in the # documentation. # The default value is: YES. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug # list. This list is created by putting \bug commands in the documentation. # The default value is: YES. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO) # the deprecated list. This list is created by putting \deprecated commands in # the documentation. # The default value is: YES. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional documentation # sections, marked by \if ... \endif and \cond # ... \endcond blocks. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the # initial value of a variable or macro / define can have for it to appear in the # documentation. If the initializer consists of more lines than specified here # it will be hidden. Use a value of 0 to hide initializers completely. The # appearance of the value of individual variables and macros / defines can be # controlled using \showinitializer or \hideinitializer command in the # documentation regardless of this setting. # Minimum value: 0, maximum value: 10000, default value: 30. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated at # the bottom of the documentation of classes and structs. If set to YES the list # will mention the files that were used to generate the documentation. # The default value is: YES. SHOW_USED_FILES = YES # Set the SHOW_FILES tag to NO to disable the generation of the Files page. This # will remove the Files entry from the Quick Index and from the Folder Tree View # (if specified). # The default value is: YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces # page. This will remove the Namespaces entry from the Quick Index and from the # Folder Tree View (if specified). # The default value is: YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command command input-file, where command is the value of the # FILE_VERSION_FILTER tag, and input-file is the name of an input file provided # by doxygen. Whatever the program writes to standard output is used as the file # version. For an example see the documentation. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated # output files in an output format independent way. To create the layout file # that represents doxygen's defaults, run doxygen with the -l option. You can # optionally specify a file name after the option, if omitted DoxygenLayout.xml # will be used as the name of the layout file. # # Note that if you run doxygen from a directory containing a file called # DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE # tag is left empty. LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files containing # the reference definitions. This must be a list of .bib files. The .bib # extension is automatically appended if omitted. This requires the bibtex tool # to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. # For LaTeX the style of the bibliography can be controlled using # LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the # search path. Do not use file names with spaces, bibtex cannot handle them. See # also \cite for info how to create references. CITE_BIB_FILES = #--------------------------------------------------------------------------- # Configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated to # standard output by doxygen. If QUIET is set to YES this implies that the # messages are off. # The default value is: NO. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES # this implies that the warnings are on. # # Tip: Turn warnings on while writing the documentation. # The default value is: YES. WARNINGS = YES # If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate # warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag # will automatically be disabled. # The default value is: YES. WARN_IF_UNDOCUMENTED = NO # If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some parameters # in a documented function, or documenting parameters that don't exist or using # markup commands wrongly. # The default value is: YES. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # are documented, but have no documentation for their parameters or return # value. If set to NO doxygen will only warn about wrong or incomplete parameter # documentation, but not about the absence of documentation. # The default value is: NO. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that doxygen # can produce. The string should contain the $file, $line, and $text tags, which # will be replaced by the file and line number from which the warning originated # and the warning text. Optionally the format may contain $version, which will # be replaced by the version of the file (if it could be obtained via # FILE_VERSION_FILTER) # The default value is: $file:$line: $text. WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning and error # messages should be written. If left blank the output is written to standard # error (stderr). WARN_LOGFILE = #--------------------------------------------------------------------------- # Configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag is used to specify the files and/or directories that contain # documented source files. You may enter file names like myfile.cpp or # directories like /usr/src/myproject. Separate the files or directories with # spaces. # Note: If this tag is empty the current directory is searched. INPUT = # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses # libiconv (or the iconv built into libc) for the transcoding. See the libiconv # documentation (see: http://www.gnu.org/software/libiconv) for the list of # possible encodings. # The default value is: UTF-8. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and # *.h) to filter out the source-files in the directories. If left blank the # following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii, # *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, # *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, # *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, # *.qsf, *.as and *.js. FILE_PATTERNS = *.c *.h # The RECURSIVE tag can be used to specify whether or not subdirectories should # be searched for input files as well. # The default value is: NO. RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should be # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. # # Note that relative paths are relative to the directory from which doxygen is # run. EXCLUDE = qc_test.c hcpinfbk.h query_capacity_int.h # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded # from the input. # The default value is: NO. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. # # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test # # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories use the pattern */test/* EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or directories # that contain example code fragments that are included (see the \include # command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and # *.h) to filter out the source-files in the directories. If left blank all # files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude commands # irrespective of the value of the RECURSIVE tag. # The default value is: NO. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or directories # that contain images that are to be included in the documentation (see the # \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command: # # # # where is the value of the INPUT_FILTER tag, and is the # name of an input file. Doxygen will then use the output that the filter # program writes to standard output. If FILTER_PATTERNS is specified, this tag # will be ignored. # # Note that the filter must not add or remove lines; it is applied before the # code is scanned, but not when the output code is generated. If lines are added # or removed, the anchors will not be placed correctly. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: pattern=filter # (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how # filters are used. If the FILTER_PATTERNS tag is empty or if none of the # patterns match the file name, INPUT_FILTER is applied. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER ) will also be used to filter the input files that are used for # producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). # The default value is: NO. FILTER_SOURCE_FILES = NO # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file # pattern. A pattern will override the setting for FILTER_PATTERN (if any) and # it is also possible to disable source filtering for a specific pattern using # *.ext= (so without naming a filter). # This tag requires that the tag FILTER_SOURCE_FILES is set to YES. FILTER_SOURCE_PATTERNS = # If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that # is part of the input, its contents will be placed on the main page # (index.html). This can be useful if you have a project on for instance GitHub # and want to reuse the introduction page also for the doxygen output. USE_MDFILE_AS_MAINPAGE = #--------------------------------------------------------------------------- # Configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will be # generated. Documented entities will be cross-referenced with these sources. # # Note: To get rid of all source code in the generated output, make sure that # also VERBATIM_HEADERS is set to NO. # The default value is: NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body of functions, # classes and enums directly into the documentation. # The default value is: NO. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any # special comment blocks from generated source code fragments. Normal C, C++ and # Fortran comments will always remain visible. # The default value is: YES. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES then for each documented # function all documented functions referencing it will be listed. # The default value is: NO. REFERENCED_BY_RELATION = NO # If the REFERENCES_RELATION tag is set to YES then for each documented function # all documented entities called/used by that function will be listed. # The default value is: NO. REFERENCES_RELATION = NO # If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set # to YES, then the hyperlinks from functions in REFERENCES_RELATION and # REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will # link to the documentation. # The default value is: YES. REFERENCES_LINK_SOURCE = YES # If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the # source code will show a tooltip with additional information such as prototype, # brief description and links to the definition and documentation. Since this # will make the HTML file larger and loading of large files a bit slower, you # can opt to disable this feature. # The default value is: YES. # This tag requires that the tag SOURCE_BROWSER is set to YES. SOURCE_TOOLTIPS = YES # If the USE_HTAGS tag is set to YES then the references to source code will # point to the HTML generated by the htags(1) tool instead of doxygen built-in # source browser. The htags tool is part of GNU's global source tagging system # (see http://www.gnu.org/software/global/global.html). You will need version # 4.8.6 or higher. # # To use it do the following: # - Install the latest version of global # - Enable SOURCE_BROWSER and USE_HTAGS in the config file # - Make sure the INPUT points to the root of the source tree # - Run doxygen as normal # # Doxygen will invoke htags (and that will in turn invoke gtags), so these # tools must be available from the command line (i.e. in the search path). # # The result: instead of the source browser generated by doxygen, the links to # source code will now point to the output of htags. # The default value is: NO. # This tag requires that the tag SOURCE_BROWSER is set to YES. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a # verbatim copy of the header file for each class for which an include is # specified. Set to NO to disable this. # See also: Section \class. # The default value is: YES. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # Configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all # compounds will be generated. Enable this if the project contains a lot of # classes, structs, unions or interfaces. # The default value is: YES. ALPHABETICAL_INDEX = YES # The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in # which the alphabetical index list will be split. # Minimum value: 1, maximum value: 20, default value: 5. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all classes will # be put under the same header in the alphabetical index. The IGNORE_PREFIX tag # can be used to specify a prefix (or a list of prefixes) that should be ignored # while generating the index headers. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. IGNORE_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES doxygen will generate HTML output # The default value is: YES. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of # it. # The default directory is: html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for each # generated HTML page (for example: .htm, .php, .asp). # The default value is: .html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a user-defined HTML header file for # each generated HTML page. If the tag is left blank doxygen will generate a # standard header. # # To get valid HTML the header file that includes any scripts and style sheets # that doxygen needs, which is dependent on the configuration options used (e.g. # the setting GENERATE_TREEVIEW). It is highly recommended to start with a # default header using # doxygen -w html new_header.html new_footer.html new_stylesheet.css # YourConfigFile # and then modify the file new_header.html. See also section "Doxygen usage" # for information on how to generate the default header that doxygen normally # uses. # Note: The header is subject to change so you typically have to regenerate the # default header when upgrading to a newer version of doxygen. For a description # of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each # generated HTML page. If the tag is left blank doxygen will generate a standard # footer. See HTML_HEADER for more information on how to generate a default # footer and what special commands can be used inside the footer. See also # section "Doxygen usage" for information on how to generate the default footer # that doxygen normally uses. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading style # sheet that is used by each HTML page. It can be used to fine-tune the look of # the HTML output. If left blank doxygen will generate a default style sheet. # See also section "Doxygen usage" for information on how to generate the style # sheet that doxygen normally uses. # Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as # it is more robust and this tag (HTML_STYLESHEET) will in the future become # obsolete. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_STYLESHEET = # The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user- # defined cascading style sheet that is included after the standard style sheets # created by doxygen. Using this option one can overrule certain style aspects. # This is preferred over using HTML_STYLESHEET since it does not replace the # standard style sheet and is therefor more robust against future updates. # Doxygen will copy the style sheet file to the output directory. For an example # see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_STYLESHEET = # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note # that these files will be copied to the base HTML output directory. Use the # $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these # files. In the HTML_STYLESHEET file, use the file name only. Also note that the # files will be copied as-is; there are no commands or markers available. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the stylesheet and background images according to # this color. Hue is specified as an angle on a colorwheel, see # http://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 # purple, and 360 is red again. # Minimum value: 0, maximum value: 359, default value: 220. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors # in the HTML output. For a value of 0 the output will use grayscales only. A # value of 255 will produce the most vivid colors. # Minimum value: 0, maximum value: 255, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_SAT = 100 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the # luminance component of the colors in the HTML output. Values below 100 # gradually make the output lighter, whereas values above 100 make the output # darker. The value divided by 100 is the actual gamma applied, so 80 represents # a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not # change the gamma. # Minimum value: 40, maximum value: 240, default value: 80. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting this # to NO can help when comparing the output of multiple runs. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_TIMESTAMP = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_DYNAMIC_SECTIONS = NO # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries # shown in the various tree structured indices initially; the user can expand # and collapse entries dynamically later on. Doxygen will expand the tree to # such a level that at most the specified number of entries are visible (unless # a fully collapsed tree already exceeds this amount). So setting the number of # entries 1 will produce a full collapsed tree by default. 0 is a special value # representing an infinite number of entries and will result in a full expanded # tree by default. # Minimum value: 0, maximum value: 9999, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files will be # generated that can be used as input for Apple's Xcode 3 integrated development # environment (see: http://developer.apple.com/tools/xcode/), introduced with # OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a # Makefile in the HTML output directory. Running make will produce the docset in # that directory and running make install will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at # startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html # for more information. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_DOCSET = NO # This tag determines the name of the docset feed. A documentation feed provides # an umbrella under which multiple documentation sets from a single provider # (such as a company or product suite) can be grouped. # The default value is: Doxygen generated docs. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_FEEDNAME = "Doxygen generated docs" # This tag specifies a string that should uniquely identify the documentation # set bundle. This should be a reverse domain-name style string, e.g. # com.mycompany.MyDocSet. Doxygen will append .docset to the name. # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_BUNDLE_ID = org.doxygen.Project # The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify # the documentation publisher. This should be a reverse domain-name style # string, e.g. com.mycompany.MyDocSet.documentation. # The default value is: org.doxygen.Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_ID = org.doxygen.Publisher # The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. # The default value is: Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop # (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on # Windows. # # The HTML Help Workshop contains a compiler that can convert all HTML output # generated by doxygen into a single compiled HTML file (.chm). Compiled HTML # files are now used as the Windows 98 help format, and will replace the old # Windows help format (.hlp) on all Windows platforms in the future. Compressed # HTML files also contain an index, a table of contents, and you can search for # words in the documentation. The HTML workshop also contains a viewer for # compressed HTML files. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_HTMLHELP = NO # The CHM_FILE tag can be used to specify the file name of the resulting .chm # file. You can add a path in front of the file if the result should not be # written to the html output directory. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_FILE = # The HHC_LOCATION tag can be used to specify the location (absolute path # including file name) of the HTML help compiler ( hhc.exe). If non-empty # doxygen will try to run the HTML help compiler on the generated index.hhp. # The file has to be specified with full path. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. HHC_LOCATION = # The GENERATE_CHI flag controls if a separate .chi index file is generated ( # YES) or that it should be included in the master .chm file ( NO). # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. GENERATE_CHI = NO # The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc) # and project file content. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_INDEX_ENCODING = # The BINARY_TOC flag controls whether a binary table of contents is generated ( # YES) or a normal table of contents ( NO) in the .chm file. Furthermore it # enables the Previous and Next buttons. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members to # the table of contents of the HTML help documentation and to the tree view. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that # can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help # (.qch) of the generated HTML documentation. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify # the file name of the resulting .qch file. The path specified is relative to # the HTML output folder. # This tag requires that the tag GENERATE_QHP is set to YES. QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # Project output. For more information please see Qt Help Project / Namespace # (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_QHP is set to YES. QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt # Help Project output. For more information please see Qt Help Project / Virtual # Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- # folders). # The default value is: doc. # This tag requires that the tag GENERATE_QHP is set to YES. QHP_VIRTUAL_FOLDER = doc # If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom # filter to add. For more information please see Qt Help Project / Custom # Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- # filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_NAME = # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see Qt Help Project / Custom # Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- # filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's filter section matches. Qt Help Project / Filter Attributes (see: # http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_SECT_FILTER_ATTRS = # The QHG_LOCATION tag can be used to specify the location of Qt's # qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the # generated .qhp file. # This tag requires that the tag GENERATE_QHP is set to YES. QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be # generated, together with the HTML files, they form an Eclipse help plugin. To # install this plugin and make it available under the help contents menu in # Eclipse, the contents of the directory containing the HTML and XML files needs # to be copied into the plugins directory of eclipse. The name of the directory # within the plugins directory should be the same as the ECLIPSE_DOC_ID value. # After copying Eclipse needs to be restarted before the help appears. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_ECLIPSEHELP = NO # A unique identifier for the Eclipse help plugin. When installing the plugin # the directory name containing the HTML and XML files should also have this # name. Each documentation set should have its own identifier. # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. ECLIPSE_DOC_ID = org.doxygen.Project # If you want full control over the layout of the generated HTML pages it might # be necessary to disable the index and replace it with your own. The # DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top # of each HTML page. A value of NO enables the index and the value YES disables # it. Since the tabs in the index contain the same information as the navigation # tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. DISABLE_INDEX = NO # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. If the tag # value is set to YES, a side panel will be generated containing a tree-like # index structure (just like the one that is generated for HTML Help). For this # to work a browser that supports JavaScript, DHTML, CSS and frames is required # (i.e. any modern browser). Windows users are probably better off using the # HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can # further fine-tune the look of the index. As an example, the default style # sheet generated by doxygen has an example that shows how to put an image at # the root of the tree instead of the PROJECT_NAME. Since the tree basically has # the same information as the tab index, you could consider setting # DISABLE_INDEX to YES when enabling this option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_TREEVIEW = NO # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that # doxygen will group on one line in the generated HTML documentation. # # Note that a value of 0 will completely suppress the enum values from appearing # in the overview section. # Minimum value: 0, maximum value: 20, default value: 4. # This tag requires that the tag GENERATE_HTML is set to YES. ENUM_VALUES_PER_LINE = 4 # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used # to set the initial width (in pixels) of the frame in which the tree is shown. # Minimum value: 0, maximum value: 1500, default value: 250. # This tag requires that the tag GENERATE_HTML is set to YES. TREEVIEW_WIDTH = 250 # When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to # external symbols imported via tag files in a separate window. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. EXT_LINKS_IN_WINDOW = NO # Use this tag to change the font size of LaTeX formulas included as images in # the HTML documentation. When you change the font size after a successful # doxygen run you need to manually remove any form_*.png images from the HTML # output directory to force them to be regenerated. # Minimum value: 8, maximum value: 50, default value: 10. # This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_FONTSIZE = 10 # Use the FORMULA_TRANPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are not # supported properly for IE 6.0, but are supported on all modern browsers. # # Note that when changing this option you need to delete any form_*.png files in # the HTML output directory before the changes have effect. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_TRANSPARENT = YES # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see # http://www.mathjax.org) which uses client side Javascript for the rendering # instead of using prerendered bitmaps. Use this if you do not have LaTeX # installed or if you want to formulas look prettier in the HTML output. When # enabled you may also need to install MathJax separately and configure the path # to it using the MATHJAX_RELPATH option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. USE_MATHJAX = NO # When MathJax is enabled you can set the default output format to be used for # the MathJax output. See the MathJax site (see: # http://docs.mathjax.org/en/latest/output.html) for more details. # Possible values are: HTML-CSS (which is slower, but has the best # compatibility), NativeMML (i.e. MathML) and SVG. # The default value is: HTML-CSS. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_FORMAT = HTML-CSS # When MathJax is enabled you need to specify the location relative to the HTML # output directory using the MATHJAX_RELPATH option. The destination directory # should contain the MathJax.js script. For instance, if the mathjax directory # is located at the same level as the HTML output directory, then # MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax # Content Delivery Network so you can quickly see the result without installing # MathJax. However, it is strongly recommended to install a local copy of # MathJax from http://www.mathjax.org before deployment. # The default value is: http://cdn.mathjax.org/mathjax/latest. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example # MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_EXTENSIONS = # The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces # of code that will be used on startup of the MathJax code. See the MathJax site # (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_CODEFILE = # When the SEARCHENGINE tag is enabled doxygen will generate a search box for # the HTML output. The underlying search engine uses javascript and DHTML and # should work on any modern browser. Note that when using HTML help # (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) # there is already a search function so this one should typically be disabled. # For large projects the javascript based search engine can be slow, then # enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to # search using the keyboard; to jump to the search box use + S # (what the is depends on the OS and browser, but it is typically # , /