仔细研读了各类经典秘籍之后,本王决定找到一只菜鸟勇者练练手.
众所周知,大陆有无穷个平行宇宙的版本,有些地方的勇者技术精湛,能将能力榨干到极限;
也有菜鸟勇者,CD超长,魔术稀烂,完全不是本王的对手。
不如趁着周中勇者都在上班,抓个找不到工作的弱鸡勇者吧!
🗡🗡🗡勇者の试炼:归约
与勇者比拼,无非速度,耐力,攻击力。比如如何快速地计算1e8次攻击的总伤害,好安排下一次的攻击。
一个菜鸟勇者会不加思索地写道:
const int N = 1e8;
int main() {
int sum = 0;
int *a;
get_actions(a, N); //生成N个值
for (int i=0; i<N; i++) {
sum += a[i];
}
return 0;
}
正合我意。在他挨个记数的时候,60ms已经过去。按照本王先前的精细化管理经验, 这世间足够成千上万的小兵进行攻击了。
😈😈😈魔王の挑战
从cuda大陆的认真笔记中,我了解到,要打败勇者,需要考虑这么几个方面:
- 计算密度
- 存储类型
- 合并度
计算密度在这个基础的挑战中毫无用武之地,毕竟只是单纯的加法全局考量。
于是本王将目光转向存储类型。
存储类型决定着读取记忆的快慢。假设小妖们要谋划A+B,那脑中必定需要首先回忆起A和B。
小兵们所使用的记忆(memory), 既有【全局内存】, 也有【共享内存】
- 全局内存:所有线程都能访问其中数据,容量很大(G级别),访问较慢。
- 共享内存:一个块中的线程能够访问,速度较快,容量有限(KB级别)。
在这里,不同的小兵将结成阵列(block),共享一块存储,如此一来,他们回忆的速度将会加快....
所以shared memory正是本王所要的。。。
正待本王组织动手之际。。。
🗡🗡🗡勇者の反击!
吾等勇者,行侠仗义,救NPC于危难,免其他勇者于冒险。
听闻菜鸟勇者被绑,吾等岂能坐视。
这试炼如此简单,若不好好表现,岂不辱没吾等勇者威名!
吾等十名勇者,自愿结阵,前来相助!
#include <memory>
#include <stdio.h>
#include <stdlib.h>
#include <omp.h>
#include <chrono>
const long N = 1e8;
void get_actions(int *a, int n) {
for (long i=0; i<n; i++) {
a[i] = i % 1000;
}
}
int main() {
long long sum = 0;
int *a = new int[N];
get_actions(a, N); //生成N个值
printf("N is %lld\n", N);
auto t1 = std::chrono::steady_clock::now();
for (int i=0; i<10; i++) {
printf("a %d\n", a[i]);
}
long i;
#pragma omp parallel for private(i)
for (i=0; i<N; i++) {
sum += a[i];
}
auto t2 = std::chrono::steady_clock::now();
auto diff = std::chrono::duration<double>(t2 - t1);
printf("add cost %lf ms, total sum %lld\n", diff.count() * 1000, sum);
delete[] a;
return 0;
}
export OMP_NUM_THREADS=10
勇者们说完一番废言废语,十人接力起来,再看耗时,已经降到了10ms。
😈😈😈魔王の外挂!
情知不能再拖!若是勇者们人数再增加,此次挑战将完败。魔界的魔威何在?
然而,要从头开始打造小兵,申请头脑,按前文的步骤,检查错误,考核绩效,一时半会,绝不能完成......
也不是只有勇者才有外援!本魔王也有外挂thrust,可以一战!
#include <memory>
#include <stdio.h>
#include <stdlib.h>
#include <omp.h>
#include <chrono>
#include <thrust/device_vector.h>
#include <thrust/host_vector.h>
using ll = long long;
const long N = 1e8;
void get_actions(thrust::host_vector<ll> &a, int n) {
for (long i=0; i<n; i++) {
a[i] = i % 1000;
}
}
int main() {
ll sum = 0;
thrust::host_vector<ll> a(N);
get_actions(a, N); //生成N个值
thrust::device_vector<ll> d_a(N);
d_a = a;
printf("N is %lld\n", N);
auto t1 = std::chrono::steady_clock::now();
sum = thrust::reduce(d_a.begin(), d_a.end(), (ll)0, thrust::plus<ll>());
auto t2 = std::chrono::steady_clock::now();
auto diff = std::chrono::duration<double>(t2 - t1);
printf("add cost %lf ms, total sum %lld\n", diff.count() * 1000, sum);
return 0;
}
与勇者类似的篇幅里,本王一王完成了同样的题目。耗时,6ms。
🏆🏆🏆🏆🏆🏆🏆:魔王!
关于thrust的传奇,让本魔王番外来讲。