/* * Copyright (c) Advanced Micro Devices, Inc. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include #include #include #include #include #define CHK_AMDSMI_RET(RET) \ { \ if (RET != AMDSMI_STATUS_SUCCESS) { \ const char* err_str; \ std::cout << "AMDSMI call returned " << RET << " at line " << __LINE__ << std::endl; \ amdsmi_status_code_to_string(RET, &err_str); \ std::cout << err_str << std::endl; \ return RET; \ } \ } const char* category_to_string(int category) { switch (category) { case AMDSMI_FABRIC_TELEMETRY_CATEGORY_UALOE: return "UALOE"; case AMDSMI_FABRIC_TELEMETRY_CATEGORY_SWITCH: return "SWITCH"; case AMDSMI_FABRIC_TELEMETRY_CATEGORY_CRYPTO: return "CRYPTO"; case AMDSMI_FABRIC_TELEMETRY_CATEGORY_PFC: return "PFC"; case AMDSMI_FABRIC_TELEMETRY_CATEGORY_NETPORT: return "NETPORT"; case AMDSMI_FABRIC_TELEMETRY_CATEGORY_DERIVED_UALOE: return "DERIVED_UALOE"; case AMDSMI_FABRIC_TELEMETRY_CATEGORY_DERIVED_NETPORT: return "DERIVED_NETPORT"; default: return "UNKNOWN"; } } std::string bdf_to_str(const amdsmi_bdf_t& bdf) { std::ostringstream outstream{}; outstream << std::hex << std::setfill('0') << std::setw(4) << static_cast(bdf.bdf.domain_number) << ":" << std::setw(2) << static_cast(bdf.bdf.bus_number) << ":" << std::setw(2) << static_cast(bdf.bdf.device_number) << "." << static_cast(bdf.bdf.function_number); return outstream.str(); } constexpr auto MAX_UUID_ELEMENTS = std::uint16_t(16); std::string ppod_id_to_str(const std::uint8_t (&id)[MAX_UUID_ELEMENTS]) { std::ostringstream outstream{}; outstream << std::hex << std::setfill('0'); for (auto idx = std::size_t(0); idx < MAX_UUID_ELEMENTS; ++idx) { if ((idx == 4) || (idx == 6) || (idx == 8) || (idx == 10)) { outstream << '-'; } outstream << std::setw(2) << static_cast(id[idx]); } outstream << std::dec; return outstream.str(); } constexpr auto MAX_COLUMNS_PER_GRID = std::uint16_t(8); void print_array_grid(std::ostream& outstrm, std::string_view line_prefix, std::string_view line_title, const uint32_t* array_data, std::size_t array_count, std::size_t columns) { outstrm << line_prefix << "** " << line_title << ":\n"; for (auto idx = std::size_t(0); idx < array_count; ++idx) { if (idx % columns == 0) { outstrm << line_prefix << "\t"; } outstrm << array_data[idx]; const auto is_end_row = static_cast((idx + 1) % columns == 0); const auto is_last = static_cast(idx + 1 == array_count); if (is_end_row || is_last) { outstrm << '\n'; } else { outstrm << ' '; } } } int main() { amdsmi_status_t ret; // Init amdsmi for sockets and devices. ret = amdsmi_init(AMDSMI_INIT_AMD_GPUS); CHK_AMDSMI_RET(ret); // Get all sockets uint32_t socket_count = 0; // Get the socket count available for the system. ret = amdsmi_get_socket_handles(&socket_count, nullptr); CHK_AMDSMI_RET(ret); // Allocate the memory for the sockets std::vector sockets(socket_count); // Get the sockets of the system ret = amdsmi_get_socket_handles(&socket_count, &sockets[0]); CHK_AMDSMI_RET(ret); // For each socket, get identifier and devices for (uint32_t i = 0; i < socket_count; i++) { // Get Socket info char socket_info[128]; ret = amdsmi_get_socket_info(sockets[i], 128, socket_info); CHK_AMDSMI_RET(ret); std::cout << "\t**Socket Info: " << socket_info << std::endl; // Get the device count available for the socket. uint32_t device_count = 0; ret = amdsmi_get_processor_handles(sockets[i], &device_count, nullptr); CHK_AMDSMI_RET(ret); // Allocate the memory for the device handlers on the socket std::vector processor_handles(device_count); // Get all devices of the socket ret = amdsmi_get_processor_handles(sockets[i], &device_count, &processor_handles[0]); CHK_AMDSMI_RET(ret); std::cout << "\t**Processor Count: " << device_count << std::endl; // For each device of the socket, get Fabric telemetry for (uint32_t device_index = 0; device_index < device_count; device_index++) { std::cout << "\t\t**Processing Fabric Device: " << device_index << std::endl; // Allocate storage for Fabric telemetry // Request all categories of telemetry uint32_t category_mask = AMDSMI_FABRIC_TELEMETRY_CATEGORY_MASK_UALOE | AMDSMI_FABRIC_TELEMETRY_CATEGORY_MASK_SWITCH | AMDSMI_FABRIC_TELEMETRY_CATEGORY_MASK_CRYPTO | AMDSMI_FABRIC_TELEMETRY_CATEGORY_MASK_PFC | AMDSMI_FABRIC_TELEMETRY_CATEGORY_MASK_NETPORT | AMDSMI_FABRIC_TELEMETRY_CATEGORY_MASK_DERIVED_UALOE | AMDSMI_FABRIC_TELEMETRY_CATEGORY_MASK_DERIVED_NETPORT; amdsmi_fabric_telemetry_t* telemetry = nullptr; ret = amdsmi_alloc_fabric_telemetry(processor_handles[device_index], category_mask, &telemetry); if (ret != AMDSMI_STATUS_SUCCESS) { std::cout << "\t\t\tFailed to allocate Fabric telemetry storage: " << ret << std::endl; continue; } std::cout << "\t\t\tSuccessfully allocated Fabric telemetry storage" << std::endl; // Get the current telemetry data ret = amdsmi_get_fabric_telemetry_data(processor_handles[device_index], telemetry); if (ret != AMDSMI_STATUS_SUCCESS) { std::cout << "\t\t\tFailed to get Fabric telemetry data: " << ret << std::endl; std::ignore = amdsmi_free_fabric_telemetry(processor_handles[device_index], telemetry); continue; } else { std::cout << "\t\t\tSuccessfully retrieved Fabric telemetry data" << std::endl; // Display telemetry information const char* telem_name; for (int cat = AMDSMI_FABRIC_TELEMETRY_CATEGORY_UALOE; cat < static_cast(AMDSMI_FABRIC_TELEMETRY_CATEGORY_MAX); cat++) { auto category = static_cast(cat); if (telemetry->datasets[cat] != nullptr) { auto dataset = telemetry->datasets[cat]; std::cout << "\t\t\t\tCategory " << category_to_string(category) << ": " << dataset->instance_count << " instances, " << "generation " << dataset->generation_count << std::endl; // Display instances for (uint32_t inst = 0; inst < dataset->instance_count; inst++) { auto instance = &dataset->instances[inst]; std::cout << "\t\t\t\t\tInstance: " << instance->name.text << " (idx: " << instance->logical_idx << ", items: " << instance->item_count << ")" << std::endl; // Display items for this instance for (uint32_t item_idx = 0; item_idx < instance->item_count; item_idx++) { auto& item = instance->items[item_idx]; ret = amdsmi_fabric_telem_id_to_string(item.id, &telem_name); if (ret != AMDSMI_STATUS_SUCCESS) { std::cout << "\t\t\t\t\tWarning: Failed to retrieve Fabric name: " << ret << std::endl; continue; } std::cout << "\t\t\t\t\t\tItem " << item_idx << ": " << "ID=0x" << std::hex << item.id << std::dec << "(" << telem_name << ")" << ", Value=" << item.value << std::endl; } } } } } // Free the telemetry storage ret = amdsmi_free_fabric_telemetry(processor_handles[device_index], telemetry); if (ret != AMDSMI_STATUS_SUCCESS) { std::cout << "\t\t\tWarning: Failed to free Fabric telemetry storage: " << ret << std::endl; } } // For each device of the socket, get Fabric info std::cout << "\n"; for (uint32_t device_index = 0; device_index < device_count; device_index++) { std::cout << "\t\t**Processing Fabric Info: " << device_index << "\n"; // Get BDF info amdsmi_bdf_t bdf = {}; ret = amdsmi_get_gpu_device_bdf(processor_handles[device_index], &bdf); std::cout << "\t\t\t** BDF: " << bdf_to_str(bdf) << "\n"; // Get the fabric info (partial sysfs reads; NO_DATA if no UALoE files had content) amdsmi_fabric_info_t fabric_info{}; ret = amdsmi_get_gpu_fabric_info(processor_handles[device_index], &fabric_info); if (ret != AMDSMI_STATUS_SUCCESS && ret != AMDSMI_STATUS_NO_DATA && ret != AMDSMI_STATUS_NOT_SUPPORTED) { std::cout << "\t\t\tWarning: Failed to get Fabric info: " << ret << "\n"; } else { if (ret == AMDSMI_STATUS_NO_DATA) { std::cout << "\t\t\tNote: Fabric sysfs had no usable lines (NO_DATA); " "numeric fields may be sentinels." << "\n"; } else if (ret == AMDSMI_STATUS_NOT_SUPPORTED) { std::cout << "\t\t\tNote: Fabric info is not supported on this device." << "\n"; continue; } std::cout << "\t\t\tFabric info data: " << "\n"; std::cout << "\t\t\t\t** BDF: " << bdf_to_str(fabric_info.bdf) << "\n"; std::cout << "\t\t\t\t** Fabric Version: " << fabric_info.fabric_version << "\n"; std::cout << "\t\t\t\t** Fabric Type: " << fabric_info.fabric_info.v1.fabric_type << "\n"; std::cout << "\t\t\t\t** Accelerator ID: " << fabric_info.fabric_info.v1.accelerator_id << "\n"; std::cout << "\t\t\t\t** Bandwidth: " << fabric_info.fabric_info.v1.bandwidth << "\n"; std::cout << "\t\t\t\t** Latency: " << fabric_info.fabric_info.v1.latency << "\n"; std::cout << "\t\t\t\t** PPOD ID: " << ppod_id_to_str(fabric_info.fabric_info.v1.ppod_id) << "\n"; std::cout << "\t\t\t\t** PPOD Size: " << fabric_info.fabric_info.v1.ppod_size << "\n"; std::cout << "\t\t\t\t** VPOD ID: " << fabric_info.fabric_info.v1.vpod_id << "\n"; std::cout << "\t\t\t\t** VPOD Size: " << fabric_info.fabric_info.v1.vpod_size << "\n"; print_array_grid(std::cout, "\t\t\t\t", "VPOD Active Accelerators", fabric_info.fabric_info.v1.vpod_active_accelerators, AMDSMI_FABRIC_ACTIVE_ACCELERATORS_BITMAP_SIZE, MAX_COLUMNS_PER_GRID); print_array_grid(std::cout, "\t\t\t\t", "Local Accelerators", fabric_info.fabric_info.v1.local_accelerators, AMDSMI_FABRIC_MAX_LOCAL_GPUS, MAX_COLUMNS_PER_GRID); std::cout << "\t\t\t\t** Address Mode: " << fabric_info.fabric_info.v1.addr_mode << "\n"; std::cout << "\t\t\t\t** Accelerator State: " << fabric_info.fabric_info.v1.accel_state << "\n"; std::cout << "\n"; } } } // Shutdown amdsmi ret = amdsmi_shut_down(); CHK_AMDSMI_RET(ret); std::cout << "Fabric telemetry collection completed successfully!" << std::endl; return 0; }