个人环境:
cpu: 3A5000LL, loongnix20.5 ,gcc 8.3.0
正常编译了libproj之后,在ctest测试过程中,CApi.proj_trans_bounds_beyond_global_bounds均
无法测试通过,一开始我以为是依赖库问题,换了自己编译的依赖库以后,问题依旧,我意识到了问题不简单。
在通过与x86平台的相同函数进行数值运算对比之后,问题最终定位到src/4D_api.cpp的antimeridian_min函数,函数实现如下:
static double antimeridian_min(const double *data, const int arr_len) {
double positive_min = HUGE_VAL;
double min_value = HUGE_VAL;
int crossed_meridian_count = 0;
bool positive_meridian = false;
for (int iii = 0; iii < arr_len; iii++) {
if (data[iii] == HUGE_VAL)
continue;
int prev_iii = find_previous_index(iii, data, arr_len);
// check if crossed meridian
double delta = data[prev_iii] - data[iii];
// 180 -> -180
if (delta >= 200 && delta != HUGE_VAL) {
if (crossed_meridian_count == 0)
positive_min = min_value;
crossed_meridian_count++;
positive_meridian = false;
// -180 -> 180
} else if (delta <= -200 && delta != HUGE_VAL) {
if (crossed_meridian_count == 0)
positive_min = data[iii];
crossed_meridian_count++;
positive_meridian = true;
}
// positive meridian side min
if (positive_meridian && data[iii] < positive_min)
positive_min = data[iii];
// track general min value
if (data[iii] < min_value)
min_value = data[iii];
}
if (crossed_meridian_count == 2)
return positive_min;
else if (crossed_meridian_count == 4)
// bounds extends beyond -180/180
return -180;
return min_value;
}
平平无奇的数值运算及比较,越是这样我感觉越是大事不妙了。通过log输出,在龙芯平台上相同的数值返回的是crossed_meridian_count == 2分支,而x86平台返回的是crossed_meridian_count == 4分支,
通过输出crossed_meridian_count++的命中次数,我惊呆了:
在龙芯平台上,crossed_meridian_count++的命中与x86一致,也是4次,但是crossed_meridian_count的值依然为2!,输出每次
crossed_meridian_count的值,产生的结果是 0->1 1->2 1->2 1->2,明显可以看到该函数内对crossed_meridian_count的操作有增无减,我脑子里出现的是“线程间缓存不一致”或是“CPU间内核缓存不一致”,“分支预测问题”等等。我将crossed_meridian_count改为std::atomic<int>进行原子操作,果然结果变为正确的4。
涉及到的还有另一个函数antimeridian_max是一样的问题。有需要该库的注意一下吧,也不知道是编译器问题,还是cpu的问题,等大佬解答。