我需要计算一个大集合(>10000)的位向量(std::bitset),其中N从2^10到2^16不等,代码如下:
(a & b).count()
目前我依靠分块多线程和SSE/AVX计算“distances”。幸运的是,我可以使用AVX中的“vpand”来计算“&”,但我的代码仍然使用“popcnt(%rax)”和循环来计算位数。是否有一种方法可以在我的GPU(nVidia 760m)上计算“(a & b).count()”函数?理想情况下,我只需传递两个大小为N的内存块。我正在考虑使用Thrust,但找不到“popcnt”函数。
(a & b).count()
const size_t N = 2048;
std::vector<std::vector<char>> distances;
std::vector<std::bitset<N>> bits(100000);
load_from_file(bits);
for(int i = 0; i < bits.size(); i++){
for(int j = 0; j < bits.size(); j++){
distance[i][j] = (bits[i] & bits[j]).count();
}
}
目前我依靠分块多线程和SSE/AVX计算“distances”。幸运的是,我可以使用AVX中的“vpand”来计算“&”,但我的代码仍然使用“popcnt(%rax)”和循环来计算位数。是否有一种方法可以在我的GPU(nVidia 760m)上计算“(a & b).count()”函数?理想情况下,我只需传递两个大小为N的内存块。我正在考虑使用Thrust,但找不到“popcnt”函数。
编辑:
当前CPU实现。
double validate_pooled(const size_t K) const{
int right = 0;
const size_t num_examples = labels.size();
threadpool tp;
std::vector<std::future<bool>> futs;
for(size_t i = 0; i < num_examples; i++){
futs.push_back(tp.enqueue(&kNN<N>::validate_N, this, i, K));
}
for(auto& fut : futs)
if(fut.get()) right++;
return right / (double) num_examples;
}
bool validate_N(const size_t cmp, const size_t n) const{
const size_t num_examples = labels.size();
std::vector<char> dists(num_examples, -1);
for(size_t i = 0; i < num_examples; i++){
if(i == cmp) continue;
dists[i] = (bits[cmp] & bits[i]).count();
}
typedef std::unordered_map<std::string,size_t> counter;
counter counts;
for(size_t i = 0; i < n; i++){
auto iter = std::max_element(dists.cbegin(), dists.cend());
size_t idx = std::distance(dists.cbegin(), iter);
dists[idx] = -1; // Remove the top result.
counts[labels[idx]] += 1;
}
auto iter = std::max_element(counts.cbegin(), counts.cend(),
[](const counter::value_type& a, const counter::value_type& b){ return a.second < b.second; });
return labels[cmp] == iter->first;;
}
编辑:
这是我想出来的,但速度非常慢。我不确定是否做错了什么。
template<size_t N>
struct popl
{
typedef unsigned long word_type;
std::bitset<N> _cmp;
popl(const std::bitset<N>& cmp) : _cmp(cmp) {}
__device__
int operator()(const std::bitset<N>& x) const
{
int pop_total = 0;
#pragma unroll
for(size_t i = 0; i < N/64; i++)
pop_total += __popcll(x._M_w[i] & _cmp._M_w[i]);
return pop_total;
}
};
int main(void) {
const size_t N = 2048;
thrust::host_vector<std::bitset<N> > h_vec;
load_bits(h_vec);
thrust::device_vector<std::bitset<N> > d_vec = h_vec;
thrust::device_vector<int> r_vec(h_vec.size(), 0);
for(int i = 0; i < h_vec.size(); i++){
r_vec[i] = thrust::transform_reduce(d_vec.cbegin(), d_vec.cend(), popl<N>(d_vec[i]), 0, thrust::maximum<int>());
}
return 0;
}
char
不足以容纳std::bitset<N>
的人口统计数据,其中N
为1024到65536?您是否对按位与的结果做出了一些假设?即使它可以,我猜您正在生成大约10GB的数据(对于bits(100000)
中的distances
)? - Robert Crovella