首页 \ 问答 \ Rcpp功能比相同的R功能低(Rcpp function to be SLOWER than same R function)

Rcpp功能比相同的R功能低(Rcpp function to be SLOWER than same R function)

我一直在编写一个R函数来计算关于某些分布的积分,参见下面的代码。

EVofPsi = function(psi, probabilityMeasure, eps=0.01, ...){

distFun = function(u){
 probabilityMeasure(u, ...)
}
xx = yy = seq(0,1,length=1/eps+1)
summand=0

for(i in 1:(length(xx)-1)){
  for(j in 1:(length(yy)-1)){
    signPlus = distFun(c(xx[i+1],yy[j+1]))+distFun(c(xx[i],yy[j]))
    signMinus = distFun(c(xx[i+1],yy[j]))+distFun(c(xx[i],yy[j+1]))
    summand = c(summand, psi(c(xx[i],yy[j]))*(signPlus-signMinus))
  }
}
sum(summand)
}

它工作正常,但它很慢。 通常听说用C ++等编译语言对函数进行重新编程会加快速度,特别是因为上面的R代码涉及双循环。 我也是这样,使用Rcpp:

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
double EVofPsiCPP(Function distFun, Function psi, int n, double eps) {

  NumericVector xx(n+1);
  NumericVector yy(n+1);
  xx[0] = 0;
  yy[0] = 0;

  // discretize [0,1]^2
  for(int i = 1; i < n+1; i++) {
      xx[i] = xx[i-1] + eps;
      yy[i] = yy[i-1] + eps;
  }

  Function psiCPP(psi);
  Function distFunCPP(distFun);
  double signPlus;
  double signMinus;
  double summand = 0;

  NumericVector topRight(2); 
  NumericVector bottomLeft(2);
  NumericVector bottomRight(2);
  NumericVector topLeft(2);

  // compute the integral
  for(int i=0; i<n; i++){
    //printf("i:%d \n",i);
    for(int j=0; j<n; j++){
      //printf("j:%d \n",j);
      topRight[0] = xx[i+1];
      topRight[1] = yy[j+1];
      bottomLeft[0] = xx[i];
      bottomLeft[1] = yy[j];
      bottomRight[0] = xx[i+1];
      bottomRight[1] = yy[j];
      topLeft[0] = xx[i];
      topLeft[1] = yy[j+1];
      signPlus = NumericVector(distFunCPP(topRight))[0] +  NumericVector(distFunCPP(bottomLeft))[0];
      signMinus = NumericVector(distFunCPP(bottomRight))[0] + NumericVector(distFunCPP(topLeft))[0];
      summand = summand + NumericVector(psiCPP(bottomLeft))[0]*(signPlus-signMinus);
      //printf("summand:%f \n",summand);
    }
  }
  return summand;
}

我很开心,因为这个C ++函数可以正常工作。 但是,当我测试了这两个函数时,C ++运行了SLOWER:

sourceCpp("EVofPsiCPP.cpp")
pFGM = function(u,theta){
  u[1]*u[2] + theta*u[1]*u[2]*(1-u[1])*(1-u[2])
}
psi = function(u){
  u[1]*u[2]
}
print(system.time(
for(i in 1:10){
  test = EVofPsi(psi, pFGM, 1/100, 0.2)  
}
))
test

print(system.time(
  for(i in 1:10){
    test = EVofPsiCPP(psi, function(u){pFGM(u,0.2)}, 100, 1/100)  
  }
))

那么,是否有一位善意的专家愿意向我解释这一点? 我是否像猴子一样编码,并且有办法加快这一功能? 此外,我还有第二个问题。 事实上,我可以用SEXP替换输出类型double,并且参数类型Function by SEXP也是如此,它似乎没有改变任何东西。 那么区别是什么呢?

非常感谢你,吉尔达斯


I have been coding a R function to compute an integral with respect to certain distributions, see code below.

EVofPsi = function(psi, probabilityMeasure, eps=0.01, ...){

distFun = function(u){
 probabilityMeasure(u, ...)
}
xx = yy = seq(0,1,length=1/eps+1)
summand=0

for(i in 1:(length(xx)-1)){
  for(j in 1:(length(yy)-1)){
    signPlus = distFun(c(xx[i+1],yy[j+1]))+distFun(c(xx[i],yy[j]))
    signMinus = distFun(c(xx[i+1],yy[j]))+distFun(c(xx[i],yy[j+1]))
    summand = c(summand, psi(c(xx[i],yy[j]))*(signPlus-signMinus))
  }
}
sum(summand)
}

It works fine, but it is pretty slow. It is common to hear that re-programming the function in a compiled language such as C++ would speed it up, especially because the R code above involves a double loop. So did I, using Rcpp:

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
double EVofPsiCPP(Function distFun, Function psi, int n, double eps) {

  NumericVector xx(n+1);
  NumericVector yy(n+1);
  xx[0] = 0;
  yy[0] = 0;

  // discretize [0,1]^2
  for(int i = 1; i < n+1; i++) {
      xx[i] = xx[i-1] + eps;
      yy[i] = yy[i-1] + eps;
  }

  Function psiCPP(psi);
  Function distFunCPP(distFun);
  double signPlus;
  double signMinus;
  double summand = 0;

  NumericVector topRight(2); 
  NumericVector bottomLeft(2);
  NumericVector bottomRight(2);
  NumericVector topLeft(2);

  // compute the integral
  for(int i=0; i<n; i++){
    //printf("i:%d \n",i);
    for(int j=0; j<n; j++){
      //printf("j:%d \n",j);
      topRight[0] = xx[i+1];
      topRight[1] = yy[j+1];
      bottomLeft[0] = xx[i];
      bottomLeft[1] = yy[j];
      bottomRight[0] = xx[i+1];
      bottomRight[1] = yy[j];
      topLeft[0] = xx[i];
      topLeft[1] = yy[j+1];
      signPlus = NumericVector(distFunCPP(topRight))[0] +  NumericVector(distFunCPP(bottomLeft))[0];
      signMinus = NumericVector(distFunCPP(bottomRight))[0] + NumericVector(distFunCPP(topLeft))[0];
      summand = summand + NumericVector(psiCPP(bottomLeft))[0]*(signPlus-signMinus);
      //printf("summand:%f \n",summand);
    }
  }
  return summand;
}

I'm pretty happy since this C++ function works fine. However, when I tested both functions, the C++ one ran SLOWER:

sourceCpp("EVofPsiCPP.cpp")
pFGM = function(u,theta){
  u[1]*u[2] + theta*u[1]*u[2]*(1-u[1])*(1-u[2])
}
psi = function(u){
  u[1]*u[2]
}
print(system.time(
for(i in 1:10){
  test = EVofPsi(psi, pFGM, 1/100, 0.2)  
}
))
test

print(system.time(
  for(i in 1:10){
    test = EVofPsiCPP(psi, function(u){pFGM(u,0.2)}, 100, 1/100)  
  }
))

So, is there some kind expert around willing to explain me this? Did I code like a monkey and is there a way to speed up that function? Moreover, I would have a second question. Indeed, I could have replaced the output type double by SEXP, and the argument types Function by SEXP as well, it doesn't seem to change anything. So what is the difference?

Thank you very much in advance, Gildas


原文:https://stackoverflow.com/questions/17958168
更新时间:2024-01-31 15:01

最满意答案

恭敬地 - Adrian K和Dima的答案都不正确。 正确的答案是使用Windows事件跟踪 (ETW)。 这是我们用于Windows中的所有日志记录。 它非常强大,表现非常好。 例如W7在很多操作系统事件上记录ETW事件 - 包括处理器上下文切换。 在W7中使用过性能监视器吗? 它正在消耗内核中的ETW事件。

我建议您使用ETW进行所有日志记录。 为什么? 几个原因:

  1. 它无处不在
  2. 您可以在运行过程中启用禁用日志记录。 无需重新启动过程。 (是的,其他伐木工这样做,但有些不这样做)。
  3. 其设计用于包含运输代码。
  4. 记录一个事件保证是非阻塞的:它不会导致“等待”。
  5. 我们提供了许多用于ETW跟踪处理的工具。 最值得注意的是XPERF工具( 链接链接链接

使用ETW事件处理性能路径的一大好处是可以将您的事件看作与使用XPERF工具的内核事件不可分割的一部分。

编写一个监视你的组件ETW事件的'watch'应用程序也很容易。 对于我们的组件之一,我只有一个组件可以简单地将事件显示到控制台。

强烈建议不要尝试编写自己的高性能日志记录系统。 这样做很难做到,但在性能和可靠性方面。 Windows ETW系统超强健,性能良好。


Respectfully - both Adrian K and Dima's answers are not correct. The right answer is to use Event Tracing For Windows (ETW). This is what we use for all logging in Windows. Its extremely robust and very well performing. For example W7 logs an ETW event on many OS events - all the time - including processor context switch. Ever use the performance monitor in W7? It is consuming ETW events from the kernel.

I recommend you do all your logging with ETW. Why? Several reasons:

  1. Its ubiquitous
  2. You can enable disable logging in your running process. No process restarts required. (yes, other loggers do this, but some do not).
  3. Its designed for including in shipping code.
  4. Logging an event is guaranteed to be non-blocking: it will not cause a 'wait'.
  5. We provide lots of tools for ETW trace processing. most notably the XPERF tools (link, link, link)

A big benefit of instrumenting your performance paths with ETW events is that your events can be seen integral with the kernel events using the XPERF tools.

Its also pretty easy to write a 'watch' application that watches ETW events from your components. I have one for one of our components that simply displays the events to the console.

I highly recommended to not try and write your own high performance logging system. This is challenging to do well, but in terms of performance and reliability. The Windows ETW system is super-robust and very well performing.

相关问答

更多
  • 实际上,有一个很好的图书馆添加在记录之后的事实,你说, PostSharp 。 它允许您通过基于属性的编程,除了记录之外的许多其他非常有用的东西。 我同意你所说的记录有点过分。 其他一些提出了一些好点,特别是银行业务和其他关键任务应用程序。 极端测井可能是必要的,或至少能够在需要时打开和关闭,或者设置各种水平。 There is actually a nice library for adding in logging after the fact as you say, PostSharp. It let ...
  • 记录与第三方库的依赖关系 大多数情况下,Java JDK日志记录本身并不足够。 但是,如果您有一个使用多个开源第三方库的大型项目,那么您将很快发现其中许多具有不同的日志依赖关系。 在这种情况下,需要从日志记录实现中抽象出API。 我建议使用slf4j或logback (使用slf4j API)作为您的API,如果您想坚持使用Java JDK日志记录,您仍然可以! Slf4j可以输出到许多不同的记录器实现,没有任何问题。 在最近的一个项目中,有一个具体的例子就是发生:我们需要使用需要log4j的第三方库,但是 ...
  • 按照api的时间顺序(据我所知): Log4j因为大多数人都用它(在我的经验中) Commons Logging因为开源项目使用它(因此它们可以与集成解决方案中使用的任何日志框架集成); 尤其是如果您是API / Framework / OSS,并且依赖于使用Commons Logging的其他软件包。 Commons Logging因为你不想“锁定”到一个特定的日志框架(所以相反,你锁定到什么Commons Logging给你) - 我认为这是不明智的决定使用这一点的原因。 Java日志记录是因为您不想添 ...
  • 您的要求似乎非常适合HTTP推送技术。 如果您控制客户端(即您知道它将是一个现代的,符合标准的浏览器),您可以使用官方的W3C EventSource或WebSockets 。 否则,您必须使用AJAX定期轮询或每15秒刷新一次。 关于存储本身,最简洁的解决方案是将日志直接存储在MySQL( Apache指南 )中。 如果您对尝试新事物感到鼓舞,可以试用NoSQL数据库,但我没有太多经验。 Your requirements seem to have a perfect fit in HTTP Push t ...
  • 恭敬地 - Adrian K和Dima的答案都不正确。 正确的答案是使用Windows事件跟踪 (ETW)。 这是我们用于Windows中的所有日志记录。 它非常强大,表现非常好。 例如W7在很多操作系统事件上记录ETW事件 - 包括处理器上下文切换。 在W7中使用过性能监视器吗? 它正在消耗内核中的ETW事件。 我建议您使用ETW进行所有日志记录。 为什么? 几个原因: 它无处不在 您可以在运行过程中启用禁用日志记录。 无需重新启动过程。 (是的,其他伐木工这样做,但有些不这样做)。 其设计用于包含运输代 ...
  • 你绝对应该尝试直布罗陀 。 您可以将它与PostSharp结合使用,您的性能监控将是小菜一碟。 请看下面的代码示例: [GTrace] public Connection ConnectToServer(Server server) { ConnectionStatus connectionStatus = server.TryConnect(); return connectionStatus; } 日志中的结果如下所示: 启动方法调用(可 ...
  • 概要 使用v2.x(当前版本),它对于控制台应用程序来说是不可能的,并且可以使用WinForms应用程序。 使用v3.0(未来版本),它将很容易。 这个版本将在几个月内发布。 细节 问题是当前版本的Gibraltar实际上是为了在幕后收集日志而设计的,因此它们可用于诊断任何应用程序问题。 它并非真正用于监控应用程序中的实时日志(尽管这会在v3.0发布时发生变化 - 见下文)。 如果您想要一个支持实时日志记录的WinForms版本,那么您可以按Ctrl-Alt-F5弹出一个仅限当前进程的实时日志记录控制台。 ...
  • 由于某种原因,守护程序不会关闭文件处理程序。 完成日志记录后,您需要手动使用它: logger.removeHandler(handler) For some reason, the daemon does not close the file handler. you will need to it manually using after you finish logging: logger.removeHandler(handler)
  • 我相信谷歌的Breakpad是你正在寻找的。 I believe Google's Breakpad is what you're looking for.
  • 为了解决这个问题,我不得不重新读取日志配置文件 ,然后自己放回控制台日志记录处理程序 : import java.util.logging.ConsoleHandler; import java.util.logging.Loggger; import java.util.logging.LogManager; ... System.setErr(otherStream); try { LogManager.getLogManager().readConfiguration(); } catc ...

相关文章

更多

最新问答

更多
  • 您如何使用git diff文件,并将其应用于同一存储库的副本的本地分支?(How do you take a git diff file, and apply it to a local branch that is a copy of the same repository?)
  • 将长浮点值剪切为2个小数点并复制到字符数组(Cut Long Float Value to 2 decimal points and copy to Character Array)
  • OctoberCMS侧边栏不呈现(OctoberCMS Sidebar not rendering)
  • 页面加载后对象是否有资格进行垃圾回收?(Are objects eligible for garbage collection after the page loads?)
  • codeigniter中的语言不能按预期工作(language in codeigniter doesn' t work as expected)
  • 在计算机拍照在哪里进入
  • 使用cin.get()从c ++中的输入流中丢弃不需要的字符(Using cin.get() to discard unwanted characters from the input stream in c++)
  • No for循环将在for循环中运行。(No for loop will run inside for loop. Testing for primes)
  • 单页应用程序:页面重新加载(Single Page Application: page reload)
  • 在循环中选择具有相似模式的列名称(Selecting Column Name With Similar Pattern in a Loop)
  • System.StackOverflow错误(System.StackOverflow error)
  • KnockoutJS未在嵌套模板上应用beforeRemove和afterAdd(KnockoutJS not applying beforeRemove and afterAdd on nested templates)
  • 散列包括方法和/或嵌套属性(Hash include methods and/or nested attributes)
  • android - 如何避免使用Samsung RFS文件系统延迟/冻结?(android - how to avoid lag/freezes with Samsung RFS filesystem?)
  • TensorFlow:基于索引列表创建新张量(TensorFlow: Create a new tensor based on list of indices)
  • 企业安全培训的各项内容
  • 错误:RPC失败;(error: RPC failed; curl transfer closed with outstanding read data remaining)
  • C#类名中允许哪些字符?(What characters are allowed in C# class name?)
  • NumPy:将int64值存储在np.array中并使用dtype float64并将其转换回整数是否安全?(NumPy: Is it safe to store an int64 value in an np.array with dtype float64 and later convert it back to integer?)
  • 注销后如何隐藏导航portlet?(How to hide navigation portlet after logout?)
  • 将多个行和可变行移动到列(moving multiple and variable rows to columns)
  • 提交表单时忽略基础href,而不使用Javascript(ignore base href when submitting form, without using Javascript)
  • 对setOnInfoWindowClickListener的意图(Intent on setOnInfoWindowClickListener)
  • Angular $资源不会改变方法(Angular $resource doesn't change method)
  • 在Angular 5中不是一个函数(is not a function in Angular 5)
  • 如何配置Composite C1以将.m和桌面作为同一站点提供服务(How to configure Composite C1 to serve .m and desktop as the same site)
  • 不适用:悬停在悬停时:在元素之前[复制](Don't apply :hover when hovering on :before element [duplicate])
  • 常见的python rpc和cli接口(Common python rpc and cli interface)
  • Mysql DB单个字段匹配多个其他字段(Mysql DB single field matching to multiple other fields)
  • 产品页面上的Magento Up出售对齐问题(Magento Up sell alignment issue on the products page)