所以我试图模拟一个名为Tasep的物理模型。
我编写了一个代码来用c ++模拟这个系统,但我肯定需要提升性能。
该模型非常简单(下面的c ++代码) - 1
&{39}和0
的数组。 1
代表一个粒子, 0
是无粒子,意味着空。如果该元素为空,则粒子以1
的速率向右移动一个元素。最后位置的粒子将以beta
(例如0.3)的速率消失。最后,如果第一个位置为空,则粒子将以alpha
的速率出现在那里。
一个线程很容易,我只是随机选择一个元素,并按概率1 / alpha / beta
进行操作,如上所述。但这可能需要很长时间。
所以我尝试用许多线程做类似的事情,使用GPU,这引发了很多问题:
对于这样的事情,是否真的使用GPU和CUDA?
我应该有多少线程?我可以为每个网站设置一个帖子( 10E+6
),我应该吗?
如何在不同线程之间同步对内存的访问?到目前为止,我使用过原子操作。
生成随机数据的正确方法是什么?如果我使用一百万个线程,那么每个都有一个随机生成器吗?
如何处理费率?
我是CUDA的新手。我设法从CUDA示例和一些教程中运行代码。虽然我有一些上面的代码(虽然仍然给出了奇怪的结果),但我没有把它放在这里,因为我认为这些问题更为通用。
所以这是c ++的一个线程版本:
int Tasep()
{
const int L = 750000;
// rates
int alpha = 330;
int beta = 300;
int ProbabilityNormalizer = 1000;
bool system[L];
int pos = 0;
InitArray(system); // init to 0's and 1's
/* Loop */
for (int j = 0; j < 10*L*L; j++)
{
unsigned long randomNumber = xorshf96();
pos = (randomNumber % (L)); // Pick Random location in the the array
if (pos == 0 && system[0] == 0) // First site and empty
system[0] = (alpha > (xorshf96() % ProbabilityNormalizer)); // Insert a particle with chance alpha
else if (pos == L - 1) // last site
system[L - 1] = system[L - 1] && (beta < (xorshf96() % ProbabilityNormalizer)); // Remove a particle if exists with chance beta
else if (system[pos] && !system[pos + 1]) // If current location have a particle and the next one is empty - Jump right
{
system[pos] = false;
system[pos + 1] = true;
}
if ((j % 1000) == 0) // Just do some Loggingg
Log(system, j);
}
getchar();
return 0;
}
对于愿意提供帮助并提出建议的人,我将非常感激。
答案 0 :(得分:-1)
我认为你的目标是执行一项名为蒙特卡罗模拟的事情。 但我未能完全理解你的主要目标(即获得频率或平均功率丢失等)。
问题01
由于您询问了随机数据,我相信您可以拥有多个随机种子(每个线程可能有一个),我建议您使用任意伪随机生成器在GPU中生成种子(您甚至可以使用相同的种子)作为CPU),将种子存储在GPU全局内存中,并使用动态并行性启动尽可能多的线程。 所以,是的,CUDA是一种合适的方法,但请记住,您需要学习的时间与从当前代码获得结果所需的时间之间的平衡。 如果您将来会使用这些知识,那么学习CUDA可能是值得的,或者如果您可以在许多GPU中升级您的代码并且在CPU中花费太多时间,您将需要经常解决这个等式,它也值得。看起来你很接近,但如果它是一个简单的一次性结果,我会建议你让CPU解决它,因为从我的经验来看,你将花费更多的时间来学习CUDA而不是CPU将用来解决它(IMHO)。
问题02
线程数是新手常见的问题。答案非常依赖于您的项目,但是将您的代码作为一种洞察力,我会尽可能多地使用不同种子的每个线程。 我的建议是使用寄存器就是你所谓的“站点”(要知道这是强大的局限性),然后运行多个循环来评估你的粒子,就像汽车轮胎一样的坏道路(SMEM中的数据),所以你的L限制为每循环255(避免以你的成本为您的项目溢出,而较少的寄存器意味着每个循环更多的warp)。为了创建扰动,我会在共享内存中加载向量,一个用于alpha(短),一个用于beta(短)(我确实假设不同的分布),一个“存在或不存在粒子”在下一个站点(char),以及另外两个组合为伪生成器源与threadID,blockID和一些当前时间信息(以帮助您选择初始alpha,beta和是否存在)所以你可以为块中的每个线程重用这个速率,并且因为数据不会改变(只有读取位置改变)你必须在读取后只进行一次同步,你也可以“随机选择扰动位置并重复使用数据。初始值可以从全局存储器加载并在特定的”刷新后“隐藏加载延迟的循环次数。简而言之,您将在共享中多次重复使用相同的数据,但是由于伪随机值,每次交互时为每个线程选择的值都会发生变化。考虑到您正在谈论大型数字,你可以加载不同的数据我在每个块中,伪随机算法应该足够好。此外,您甚至可以使用以前运行中存储在gpu中的结果作为随机源,翻转一个变量并执行一些位操作,因此您可以将每个位用作粒子。
问题03
对于您的特定项目,我强烈建议避免线程合作并使这些完全独立。但是,您可以在同一个warp中使用shuffle,而且成本不高。
问题04
很难生成真正的随机数据,但您应该担心持续时间的频率(因为任何生成器都有一段随机时间并且它们会重复)。我建议你使用一个可以与你的内核并行工作的单个生成器,并使用它来提供内核(你可以使用动态并行)。在你的情况下,因为你想要一些随机你不应该担心一致性。我举了一个在前一个问题中使用伪随机数据的例子,这可能有所帮助。请记住,没有真正的随机生成器,但有一些替代品,例如互联网位。
问题05
已在问题03中解释过,但请记住,您不需要完整的值序列,只需要足够的部分以多种形式使用,为内核提供足够的时间进行处理,然后您可以刷新你按顺序排序,如果你保证不用相同的顺序进给块,就很难陷入模式。
希望我能得到帮助,我和CUDA合作已有一年多了,就像你一样开始,而且每周我都会改进我的代码,现在几乎已经足够好了。现在我看到它完全符合我的统计挑战:集群随机事物。
祝你好运!