为了实现统一内存的良好性能,必须达到以下目标:
- 应该避免错误:虽然可回放的错误对于启用更简单的编程模型是基本的,但它们可能严重损害应用程序的性能。错误处理可能需要几十微秒,因为它可能涉及 TLB 失效、数据迁移和页表的更新。同时,应用程序的某些部分的执行将被停止,从而可能影响整体性能。
- 数据应该是访问处理器的本地数据:如前所述,当数据被放置在访问处理器的本地时,内存访问延迟和带宽明显更好。因此,应该适当地迁移数据,以利用较低的延迟和较高的带宽。
- 应该防止内存抖动:如果数据经常被多个处理器访问,并且必须不断迁移才能实现数据局部性,那么迁移的开销可能会超过局部性的好处。应该尽可能地防止内存抖动。如果无法预防,则必须检测并适当地解决。
为了在不使用统一内存的情况下达到尽可能高的性能水平,应用程序必须引导统一内存驱动子系统避免上述缺陷。值得注意的是,统一内存驱动子系统可以检测常见的数据访问模式,并在没有应用程序参与的情况下自动实现其中一些目标。但是,当数据访问模式不明显时,应用程序的显式指导是至关重要的。CUDA 8.0 引入了一些有用的 API,用于向运行时提供内存使用提示(cudaMemAdvise())和显式预取(cudaMemPrefetchAsync())。这些工具支持与显式内存复制和固定 api 相同的功能,而不会回退到显式 GPU 内存分配的限制。
注意: Tegra 设备不支持 cudaMemPrefetchAsync()。
数据预取
数据预取意味着在处理器开始访问数据之前,将数据迁移到处理器的内存并将其映射到处理器的页表中。数据预取的目的是在建立数据局部性的