这个问题是关于 C++ 优化技术的。我有一个大尺寸的矩阵 vector 乘法,想减少运行时间。我知道有专门的线性代数库,但我实际上想了解一下底层处理器的特性。到目前为止,我正在使用\O2 (Microsoft) 进行编译,并让编译器确认乘法的内部循环是矢量化的。
示例代码是:
#include <stdio.h>
#include <ctime>
#include <iostream>
#define VEC_LENGTH 64
#define ITERATIONS 4000000
void gen_vector_matrix_multiplication(double *vec_result, double *vec_a, double *matrix_B, unsigned int cols_B, unsigned int rows_B)
{
// initialise result vector
for (unsigned int i = 0; i < rows_B; i++)
{
vec_result[i] = 0;
}
// perform multiplication
for (unsigned int j = 0; j < cols_B; j++)
{
const double entry = vec_a[j];
const int col = j*rows_B;
for (unsigned int i = 0; i < rows_B; i++)
{
vec_result[i] += entry * matrix_B[i + col];
}
}
}
int main()
{
double *vec_a = new double[VEC_LENGTH];
double *vec_result = new double[VEC_LENGTH];
double *matrix_B = new double[VEC_LENGTH*VEC_LENGTH];
// start clock
clock_t begin = clock();
// this outer loop is just for test purposes so that the timing becomes meaningful
for (unsigned int i = 0; i < ITERATIONS; i++)
{
gen_vector_matrix_multiplication(vec_result, vec_a, matrix_B, VEC_LENGTH, VEC_LENGTH);
}
// stop clock
double elapsed_time = static_cast<double>(clock() - begin) / CLOCKS_PER_SEC;
std::cout << elapsed_time/(VEC_LENGTH*VEC_LENGTH) << std::endl;
delete[] vec_a;
delete[] vec_result;
delete[] matrix_B;
return 1;
}
多次进行乘法以获得可靠的运行时间估计。我测量了多个不同 vector 长度的运行时间(在这个例子中只有一个元素 N,它是 vector 的长度,同时定义了矩阵的大小NxN) 并将测量的运行时间归一化为元素的数量。
您可以看到,对于足够小的 N,每个操作的运行时间是恒定的。但是,在 N=512 之上,运行时会跳起来。蓝色和红色数据点之间的区别是处理器上的负载。如果示例程序几乎单独运行,则运行时间由蓝点表示,而当其他内核繁忙时,时间由红点表示。
我现在有几个与此相关的问题。
N=512 和 N=1024 之间的跳转与我处理器的 L3 缓存大小有关(Ivy Bridge i5 -3570) 哪个应该是 6MB? 512*512*8byte 大约等于 2MB,1024*1024*8byte 大约等于 8MB。因此矩阵不再适合缓存,因此从 RAM 中获取数据是执行时间较长的原因?N>1024 操作优化此乘法例程的合乎逻辑的后续步骤是什么?我很想听听您的想法。谢谢!
最佳答案
优化此类代码的一个重要方面是处理别名和矢量化,您的帖子表明您已经处理了后者。编译器经常需要一些帮助。在 GCC 5.3.0 上,使用下面的循环大大减少了运行时间。 __restrict__ 限定符告诉编译器不可能存在别名,#pragma GCC ivdep 告诉 GCC 编译器可以对代码进行矢量化。此外,编译器标志也非常重要。我使用 g++ -O3 -march=native -mtune=native matrix_example.cxx 编译了代码。
void gen_vector_matrix_multiplication(double* const __restrict__ vec_result,
const double* const __restrict__ vec_a,
const double* const __restrict__ matrix_B,
const int cols_B,
const int rows_B)
{
// initialise result vector
#pragma GCC ivdep
for (int i = 0; i < rows_B; i++)
vec_result[i] = 0;
// perform multiplication
for (int j = 0; j < cols_B; j++)
{
const double entry = vec_a[j];
const int col = j*rows_B;
#pragma GCC ivdep
for (int i = 0; i < rows_B; i++)
{
vec_result[i] += entry * matrix_B[i + col];
}
}
}
关于c++ - 矩阵 vector 乘法优化 - 缓存大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36597104/
我的目标是转换表单输入,例如“100兆字节”或“1GB”,并将其转换为我可以存储在数据库中的文件大小(以千字节为单位)。目前,我有这个:defquota_convert@regex=/([0-9]+)(.*)s/@sizes=%w{kilobytemegabytegigabyte}m=self.quota.match(@regex)if@sizes.include?m[2]eval("self.quota=#{m[1]}.#{m[2]}")endend这有效,但前提是输入是倍数(“gigabytes”,而不是“gigabyte”)并且由于使用了eval看起来疯狂不安全。所以,功能正常,
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
我试过重新启动apache,缓存的页面仍然出现,所以一定有一个文件夹在某个地方。我没有“公共(public)/缓存”,那么我还应该查看哪些其他地方?是否有一个URL标志也可以触发此效果? 最佳答案 您需要触摸一个文件才能清除phusion,例如:touch/webapps/mycook/tmp/restart.txt参见docs 关于ruby-如何在Ubuntu中清除RubyPhusionPassenger的缓存?,我们在StackOverflow上找到一个类似的问题:
尝试在我的RoR应用程序中实现计数器缓存列时出现错误Unknownkey(s):counter_cache。我在这个问题中实现了模型关联:Modelassociationquestion这是我的迁移:classAddVideoVotesCountToVideos0Video.reset_column_informationVideo.find(:all).eachdo|p|p.update_attributes:videos_votes_count,p.video_votes.lengthendenddefself.downremove_column:videos,:video_vot
点向量坐标矩阵的几何意义介绍旋转矩阵的几何含义之前,先介绍一下点向量坐标矩阵的几何含义点:在一维空间下就是一个标量,如同一条直线上,以任意某一个位置为0点,以一定的尺度间隔为1,2,3...,相反方向为-1,-2,-3...;如此就形成了一维坐标系,这时候任何一个点都可以用一个数值表示,如点p1=5,即即从原点出发沿着x轴正方向移动5个尺度;点p2=-3,负方向移动3个尺度; 在一维坐标系上过原点做垂直于一维坐标系的直线,则形成了二维坐标系,此时描述一个点需要两个数值来表示点p3=(3,2),即从原点出发沿着x轴正方向移动3个尺度,在此基础上沿着y轴正方向移动两个尺度的位置就是点p3。
如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:
Region是HBase数据管理的基本单位,region有一点像关系型数据的分区。region中存储这用户的真实数据,而为了管理这些数据,HBase使用了RegionSever来管理region。Region的结构hbaseregion的大小设置默认情况下,每个Table起初只有一个Region,随着数据的不断写入,Region会自动进行拆分。刚拆分时,两个子Region都位于当前的RegionServer,但处于负载均衡的考虑,HMaster有可能会将某个Region转移给其他的RegionServer。RegionSplit时机:当1个region中的某个Store下所有StoreFile
在添加一些空格以使代码更具可读性时(与上面的代码对齐),我遇到了这个:classCdefx42endendm=C.new现在这将给出“错误数量的参数”:m.x*m.x这将给出“语法错误,意外的tSTAR,期待$end”:2/m.x*m.x这里的解析器到底发生了什么?我使用Ruby1.9.2和2.1.5进行了测试。 最佳答案 *用于运算符(42*42)和参数解包(myfun*[42,42])。当你这样做时:m.x*m.x2/m.x*m.xRuby将此解释为参数解包,而不是*运算符(即乘法)。如果您不熟悉它,参数解包(有时也称为“spl
我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我
我在一段非常简单的代码(如我所想)中得到了一个错误的值:org=4caseorgwhenorg=4val='H'endputsval=>nil请不要生气,我希望我错过了一些非常明显的东西,但我真的想不通。谢谢。 最佳答案 这是典型的Ruby错误。case有两种被调用的方法,一种是你传递一个东西作为分支的基础,另一种是你不传递的东西。如果您确实在case中指定了一个表达式语句然后评估所有其他条件并与===进行比较.在这种情况下org评估为false和org===false显然不是真的。所有其他情况也是如此,它们要么是真的,要么是假的。