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
最满意答案
恭敬地 - Adrian K和Dima的答案都不正确。 正确的答案是使用Windows事件跟踪 (ETW)。 这是我们用于Windows中的所有日志记录。 它非常强大,表现非常好。 例如W7在很多操作系统事件上记录ETW事件 - 包括处理器上下文切换。 在W7中使用过性能监视器吗? 它正在消耗内核中的ETW事件。
我建议您使用ETW进行所有日志记录。 为什么? 几个原因:
- 它无处不在
- 您可以在运行过程中启用禁用日志记录。 无需重新启动过程。 (是的,其他伐木工这样做,但有些不这样做)。
- 其设计用于包含运输代码。
- 记录一个事件保证是非阻塞的:它不会导致“等待”。
- 我们提供了许多用于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:
- Its ubiquitous
- You can enable disable logging in your running process. No process restarts required. (yes, other loggers do this, but some do not).
- Its designed for including in shipping code.
- Logging an event is guaranteed to be non-blocking: it will not cause a 'wait'.
- 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.
相关问答
更多-
代码记录比率?(Code to logging ratio? [closed])[2024-02-19]
实际上,有一个很好的图书馆添加在记录之后的事实,你说, 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 ...
-
实时日志记录[关闭](realtime logging [closed])[2023-04-04]
恭敬地 - Adrian K和Dima的答案都不正确。 正确的答案是使用Windows事件跟踪 (ETW)。 这是我们用于Windows中的所有日志记录。 它非常强大,表现非常好。 例如W7在很多操作系统事件上记录ETW事件 - 包括处理器上下文切换。 在W7中使用过性能监视器吗? 它正在消耗内核中的ETW事件。 我建议您使用ETW进行所有日志记录。 为什么? 几个原因: 它无处不在 您可以在运行过程中启用禁用日志记录。 无需重新启动过程。 (是的,其他伐木工这样做,但有些不这样做)。 其设计用于包含运输代 ... -
性能记录库[关闭](Performance logging library [closed])[2022-11-09]
你绝对应该尝试直布罗陀 。 您可以将它与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.
-
stderr关闭后,System.setErr()不会恢复控制台日志记录(System.setErr() doesn't restore console logging after stderr closed)[2023-10-04]
为了解决这个问题,我不得不重新读取日志配置文件 ,然后自己放回控制台日志记录处理程序 : import java.util.logging.ConsoleHandler; import java.util.logging.Loggger; import java.util.logging.LogManager; ... System.setErr(otherStream); try { LogManager.getLogManager().readConfiguration(); } catc ...