$ nm libnvqir-nvidia-mgpu.so | grep MPICommPlugin
这是典型的C++模板实例化(template instantiation)的结果。这两部分代表了同一个模板类MPICommPlugin的两个不同的模板特化(template specialization)版本。
原因分析:
1.模板参数不同
这两个符号代表同一个模板类MPICommPlugin用不同的模板参数实例化了两次:
上半部分:
custatevec::MPICommPlugin<void*, void*, void*, void*, __GLOBAL__N_::ompi_status_public_t>使用
void*类型的指针参数状态类型是
__GLOBAL__N_::ompi_status_public_t(匿名命名空间内的类型)
下半部分:
custatevec::MPICommPlugin<int, int, int, int, MPI_Status>使用
int类型的参数状态类型是标准的
MPI_Status
2.编译器命名修饰(Name Mangling)
C++编译器为了支持函数重载和模板,会对符号名进行修饰:
_ZN10custatevec13MPICommPluginI开始表示custatevec::MPICommPlugin<E结束表示模板参数列表结束中间的部分是模板参数:
i表示intPv表示void*S1_可能是重复的前一个类型(void*)
3.实际用途
这通常是为了支持不同的数据类型或不同的MPI实现:
void*版本:可能用于处理通用指针,支持任意数据类型int版本:特定用于整型数据的MPI通信不同的
MPI_Status类型可能对应不同的MPI实现(Open MPI vs MPICH等)
4.模板实例化的时机
当代码中使用
MPICommPlugin<int, int, int, int, MPI_Status>时,编译器会生成这个特化版本当使用
MPICommPlugin<void*, void*, void*, void*, ompi_status_public_t>时,会生成另一个版本这发生在编译时,每个特化版本都有独立的代码
验证方法:
可以查看源代码中是否有类似这样的模板类定义:
namespace custatevec { template<typename T1, typename T2, typename T3, typename T4, typename StatusType> class MPICommPlugin { // ... 成员函数 ... }; }然后在不同的地方使用了不同的实例化:
// 实例化1:用于int类型 using IntMPIPlugin = MPICommPlugin<int, int, int, int, MPI_Status>; // 实例化2:用于通用指针类型(可能在Open MPI环境下) using PtrMPIPlugin = MPICommPlugin<void*, void*, void*, void*, ompi_status_public_t>;总结:
这两组符号是同一个模板类的两个不同实例化版本,由于模板参数不同,编译器为每个版本生成了独立的机器代码。这是C++模板编程的典型特征,特别是在需要支持多种数据类型或不同实现的库中很常见。