如何摆脱 Core 中的“let”?

2024-01-05

我有一个在内部循环中频繁调用的函数。它看起来像这样:

import qualified Data.Vector.Storable as SV

newtype Timedelta = Timedelta Double

cklsLogDens :: SV.Vector Double -> Timedelta -> Double -> Double -> Double
cklsLogDens p (Timedelta dt) x0 x1 = if si <= 0 then -1e50 else c - 0.5*((x1-mu)/sd)^2 
  where
    al  = p `SV.unsafeIndex` 0
    be  = p `SV.unsafeIndex` 1
    si  = p `SV.unsafeIndex` 2
    xi  = p `SV.unsafeIndex` 3
    sdt = sqrt dt
    mu  = x0 + (al + be*x0)*dt
    sd  = si * (x0 ** xi) * sdt
    c   = sd `seq` -0.5 * log (2*pi*sd^2)

(使用 Data.Vector.Storable 是因为该函数稍后需要处理来自 C 函数的数据)

GHC 对此进行了很好的优化(据我所知,所有变量和操作都是原语),但是看看核心,有一个let它仍然在函数体的内部。我读过了here http://www.haskell.org/ghc/docs/latest/html/users_guide/faster.html(以及我不记得的其他地方)“让”分配惰性重击,因此可能不利于紧密循环中的性能。我可以摆脱它吗?如果可能的话,我宁愿不将我的函数转换为 20 个 case 语句,但如果这要求太多,我会接受。

这是核心:

$wloop_s4Li [Occ=LoopBreaker]
  :: GHC.Prim.Double#
     -> GHC.Prim.Int# -> GHC.Prim.Int# -> GHC.Prim.Double#
[LclId, Arity=3, Str=DmdType LLL]
$wloop_s4Li =
  \ (ww_X4OR :: GHC.Prim.Double#)
    (ww1_X4OW :: GHC.Prim.Int#)
    (ww2_X4P1 :: GHC.Prim.Int#) ->
    case GHC.Prim.<# ww1_X4OW ww2_X4P1 of _ {
      GHC.Types.False -> ww_X4OR;
      GHC.Types.True ->
        case GHC.Prim.<=## x_a4tg 0.0 of _ {
          GHC.Types.False ->
            case GHC.Prim.indexDoubleArray#
                   rb2_a4rT (GHC.Prim.+# rb_a4rR (GHC.Prim.-# ww1_X4OW 1))
            of wild17_X4xM { __DEFAULT ->

            let {
      ----  ^^^^ want to get rid off this! 
      ----
      ----
              ipv1_X2S8 [Dmd=Just L] :: GHC.Prim.Double#
              [LclId, Str=DmdType]
              ipv1_X2S8 =
                GHC.Prim.*##
                  (GHC.Prim.*## x_a4tg (GHC.Prim.**## wild17_X4xM y_a3BN))
                  (GHC.Prim.sqrtDouble# tpl1_B3) } in
            case GHC.Prim.logDouble#
                   (GHC.Prim.*##
                      6.283185307179586 (GHC.Prim.*## ipv1_X2S8 ipv1_X2S8))
            of wild18_X3Gn { __DEFAULT ->
            case GHC.Prim.indexDoubleArray#
                   rb2_a4rT (GHC.Prim.+# rb_a4rR ww1_X4OW)
            of wild19_X4AY { __DEFAULT ->
            case GHC.Prim./##
                   (GHC.Prim.-##
                      wild19_X4AY
                      (GHC.Prim.+##
                         wild17_X4xM
                         (GHC.Prim.*##
                            (GHC.Prim.+##
                               x1_X3GA (GHC.Prim.*## x2_X3cb wild17_X4xM))
                            tpl1_B3)))
                   ipv1_X2S8
            of wild20_X3x8 { __DEFAULT ->
            $wloop_s4Li
              (GHC.Prim.+##
                 ww_X4OR
                 (GHC.Prim.-##
                    (GHC.Prim.negateDouble# (GHC.Prim.*## 0.5 wild18_X3Gn))
                    (GHC.Prim.*##
                       0.5 (GHC.Prim.*## wild20_X3x8 wild20_X3x8))))
              (GHC.Prim.+# ww1_X4OW 1)
              ww2_X4P1
            }
            }
            }
            };
          GHC.Types.True ->
            $wloop_s4Li
              (GHC.Prim.+## ww_X4OR -1.0e50)
              (GHC.Prim.+# ww1_X4OW 1)
              ww2_X4P1
        }
    }; }

(是的,当然,既然你一定会问,我在过早的优化上花了太多时间......)

这是当前版本的 NOINLINE

import qualified Data.Vector.Storable as SV

newtype Timedelta = Timedelta Double

cklsLogDens :: SV.Vector Double -> Timedelta -> Double -> Double -> Double
{-# NOINLINE cklsLogDens #-}
cklsLogDens p (Timedelta dt) x0 x1 = si `seq` (if si <= 0 then -1e50 else (sd `seq` (c - 0.5*((x1-mu)/sd)^2)))
  where
    al  = p `SV.unsafeIndex` 0
    be  = p `SV.unsafeIndex` 1
    si  = p `SV.unsafeIndex` 2
    xi  = p `SV.unsafeIndex` 3
    sdt = sqrt dt
    mu  = x0 + (al + be*x0)*dt
    sd  = si * (x0 ** xi) * sdt
    c   = sd `seq` (-0.5 * log (2*pi*sd^2))

main = putStrLn . show $ cklsLogDens SV.empty (Timedelta 0.1) 0.1 0.15

对应的核心片段:

Main.cklsLogDens [InlPrag=NOINLINE]
  :: Data.Vector.Storable.Vector GHC.Types.Double
     -> Main.Timedelta
     -> GHC.Types.Double
     -> GHC.Types.Double
     -> GHC.Types.Double
[GblId, Arity=4, Caf=NoCafRefs, Str=DmdType U(ALL)LLL]
Main.cklsLogDens =
  \ (p_atw :: Data.Vector.Storable.Vector GHC.Types.Double)
    (ds_dVa :: Main.Timedelta)
    (x0_aty :: GHC.Types.Double)
    (x1_atz :: GHC.Types.Double) ->
    case p_atw
    of _ { Data.Vector.Storable.Vector rb_a2ml rb1_a2mm rb2_a2mn ->
    case GHC.Prim.readDoubleOffAddr#
           @ GHC.Prim.RealWorld rb1_a2mm 2 GHC.Prim.realWorld#
    of _ { (# s2_a2nH, x_a2nI #) ->
    case GHC.Prim.touch#
           @ GHC.ForeignPtr.ForeignPtrContents rb2_a2mn s2_a2nH
    of _ { __DEFAULT ->
    case GHC.Prim.<=## x_a2nI 0.0 of _ {
      GHC.Types.False ->
        case x0_aty of _ { GHC.Types.D# x2_a13d ->
        case GHC.Prim.readDoubleOffAddr#
               @ GHC.Prim.RealWorld rb1_a2mm 3 GHC.Prim.realWorld#
        of _ { (# s1_X2oB, x3_X2oD #) ->
        case GHC.Prim.touch#
               @ GHC.ForeignPtr.ForeignPtrContents rb2_a2mn s1_X2oB
        of _ { __DEFAULT ->
        case ds_dVa
             `cast` (Main.NTCo:Timedelta :: Main.Timedelta ~# GHC.Types.Double)
        of _ { GHC.Types.D# x4_a13m ->
        let {
   --- ^^^^ want to get rid of this!
   ---
          ipv_sYP [Dmd=Just L] :: GHC.Prim.Double#
          [LclId, Str=DmdType]
          ipv_sYP =
            GHC.Prim.*##
              (GHC.Prim.*## x_a2nI (GHC.Prim.**## x2_a13d x3_X2oD))
              (GHC.Prim.sqrtDouble# x4_a13m) } in
        case x1_atz of _ { GHC.Types.D# x5_X14E ->
        case GHC.Prim.readDoubleOffAddr#
               @ GHC.Prim.RealWorld rb1_a2mm 0 GHC.Prim.realWorld#
        of _ { (# s3_X2p2, x6_X2p4 #) ->
        case GHC.Prim.touch#
               @ GHC.ForeignPtr.ForeignPtrContents rb2_a2mn s3_X2p2
        of _ { __DEFAULT ->
        case GHC.Prim.readDoubleOffAddr#
               @ GHC.Prim.RealWorld rb1_a2mm 1 GHC.Prim.realWorld#
        of _ { (# s4_X2pi, x7_X2pk #) ->
        case GHC.Prim.touch#
               @ GHC.ForeignPtr.ForeignPtrContents rb2_a2mn s4_X2pi
        of _ { __DEFAULT ->
        case GHC.Prim.logDouble#
               (GHC.Prim.*## 6.283185307179586 (GHC.Prim.*## ipv_sYP ipv_sYP))
        of wild9_a13D { __DEFAULT ->
        case GHC.Prim./##
               (GHC.Prim.-##
                  x5_X14E
                  (GHC.Prim.+##
                     x2_a13d
                     (GHC.Prim.*##
                        (GHC.Prim.+## x6_X2p4 (GHC.Prim.*## x7_X2pk x2_a13d)) x4_a13m)))
               ipv_sYP
        of wild10_a13O { __DEFAULT ->
        GHC.Types.D#
          (GHC.Prim.-##
             (GHC.Prim.negateDouble# (GHC.Prim.*## 0.5 wild9_a13D))
             (GHC.Prim.*## 0.5 (GHC.Prim.*## wild10_a13O wild10_a13O)))
        }
        }
        }
        }
        }
        }
        }
        }
        }
        }
        };
      GHC.Types.True -> lvl_r2v7
    }
    }
    }
    }

丹尼尔是对的——let事实上,有问题的并没有分配一个重击。这实际上是不可能的,因为原始类型如Double#没有堆表示。这些lets 实际上被转换为case转换为 STG 之前的表达式(其中“let=分配”规则实际上在所谓的核心准备阶段成立。请参阅关于此主题的评论CorePrep.lhs https://github.com/ghc/ghc/blob/master/compiler/coreSyn/CorePrep.lhs#L76.

这又是准备之前的核心(-ddump-simpl):

    let {
      ipv_sPL [Dmd=Just L] :: GHC.Prim.Double#
      ipv_sPL =
        GHC.Prim.*##
          (GHC.Prim.*## x_a160 (GHC.Prim.**## x1_a11G x2_X17h))
          (GHC.Prim.sqrtDouble# x3_a11P) } in [...]

这是之后(-ddump-prep):

    case GHC.Prim.sqrtDouble# x3_s1aU of sat_s1cB { __DEFAULT ->
    case GHC.Prim.**## x1_s1aQ x2_s1aR of sat_s1cC { __DEFAULT ->
    case GHC.Prim.*## x_s1aC sat_s1cC of sat_s1cD { __DEFAULT ->
    case GHC.Prim.*## sat_s1cD sat_s1cB of ipv_s1aW [Dmd=Just L] { __DEFAULT ->

所以实际上没有任何堆分配。

另一方面,请注意,核心准备工作还显式地将每个应用程序包装到一个let or case语句,生成非常详细的代码。这就是为什么-ddump-simpl可能被认为是查看 Core 的默认值,尽管它的性能模型实际上稍微令人惊讶。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何摆脱 Core 中的“let”? 的相关文章

  • Haskell:单词,取消单词分隔符

    有什么办法可以提供分隔符words and unwords在haskell中 使其类似于python中的split和join 另请查看友好的包裹split 它提供了一个模块Data List Split http hackage haske
  • Haskell 重叠/不连贯的实例

    我知道这段代码有点傻 但有人可以解释为什么吗isList 42 回报True然而isList2 42 prints False 以及如何防止这种情况发生 我想更好地理解一些更晦涩的 GHC 类型扩展 我认为这将是一个有趣的例子 LANGUA
  • 如何使用 NumPy 的广播来加速相关性计算?

    我正在尝试利用NumPy 广播 https docs scipy org doc numpy user basics broadcasting html和后端数组计算可显着加快此功能 不幸的是 它的扩展性不太好 所以我希望能够大大提高它的性
  • sql server 存储过程首次运行缓慢

    我有一个存储过程 每天在午夜过后运行九次 它不是一个理想的存储过程 但您知道它是怎样的 没有任何计划能够与现实接触 此存储过程通常需要大约一分钟的时间来运行 根据其处理的数据量给出或花费一些时间 然而 在给定早晨的第一次运行中 有时会花费大
  • 在 Haskell 中的列表末尾添加一个元素

    我是 Haskell 的初学者 我正在尝试在列表末尾添加一个元素 我输入一个像 1 2 3 4 这样的列表和一个数字 10 我想要一个像这样的输出 1 2 3 4 10 My code func a a func a x xs x func
  • 缺少 Haskell 原语来连续将函数应用于列表的每个元素?

    在 Haskell 中 众所周知map原语可用于将给定函数应用于all列表的元素 gt map toUpper abcd ABCD gt 在尝试生成有限集 列表 的所有分区时 以下类似的原语会很方便 gt sap toUpper abcd
  • 在 .NET 中,mystring.Length == 0 或 mystring == string.Empty 哪个最好? [复制]

    这个问题在这里已经有答案了 可能的重复 检查字符串内容 字符串长度与空字符串 https stackoverflow com questions 10230 checking for string contents string lengt
  • mod_pagespeed 有什么作用?

    这是参考 http googlecode blogspot com 2011 01 go daddy makes web faster by enabling html http googlecode blogspot com 2011 0
  • 通过列表搜索

    我一直在尝试定义一个函数 给定一个整数列表和一个整数 n 返回一个布尔值 指示 n 是否在列表中恰好出现一次 我有这个 但它不起作用 我无法弄清楚 once a gt a gt Bool gt Bool filter filter p x
  • 主函数抱怨返回非 IO monad

    import Debug Trace main do trace Main function parses and returns 0 return 这会引发错误 app hs 3 1 Couldn t match expected typ
  • 作用域类型变量需要显式 foralls。为什么?

    如果你想使用 GHC词法作用域类型变量 http www haskell org ghc docs 7 6 2 html users guide other type extensions html scoped type variable
  • 如何用 numpy 在 Cython 中表示 inf 或 -inf ?

    我正在用 cython 逐个元素构建一个数组 我想存储常量np inf or 1 np inf 在某些条目中 然而 这将需要返回 Python 进行查找的开销inf 有没有libc math相当于这个常数 或者其他一些可以轻松使用的值 相当
  • 优化 Web 应用程序开发策略

    如今 许多网络应用程序正在使用它们自己无法使用的 API 或代码 并且通常使用效率低下 我想到了一些谷歌地图混搭 对于 php asp 后端 HTML javascript 尤其是现在所有的 AJAX 存在许多潜在的瓶颈 问题 低效率和双重
  • MVC 4 中的运行时动态捆绑和缩小

    我想知道是否有人可以帮助我使用 MVC 4 附带的新优化命名空间进行捆绑和缩小 我有一个多租户应用程序 我想在其中决定应根据每个用户的设置加载哪些 js 文件 一种方法是预先创建所有包并根据用户的设置更改resolvebundleurl的虚
  • 简化 Django 中的表单提交

    我在 Django 中有一个表单 用户可以在其中以单个表单提交文件 图像 文本 如下所示
  • Haskell 程序的 -hc 配置文件中的 PINNED 是什么意思?

    我正在尝试分析我的应用程序 分析内存使用情况时 hcRTS 选项 我注意到很多内存标记为 PINNED 当与 hy内存被标记为ARR WORDS 该程序使用以下命令创建 2400 2400 双精度矩阵Data Packed Matrixhm
  • 理解 Haskell 中的矩阵转置函数

    这个矩阵转置函数有效 但我试图理解它的逐步执行 但我不明白 transpose a gt a transpose transpose x map head x transpose map tail x with transpose 1 2
  • 使用 :first 优化 jQuery 选择器

    我有过这样的感觉 class first 运行速度比 class 所以任何时候我都知道只有一个 class在子集中 我已经使用了它 Does first使查询运行得更快 还是没有必要 这实际上取决于浏览器 first http api jq
  • 具有单变量优化的 NLopt

    任何人都知道 NLopt 是否适用于单变量优化 尝试运行以下代码 using NLopt function myfunc x grad x 2 end opt Opt LD MMA 1 min objective opt myfunc mi
  • 哪个信号被传递到信号处理程序中死锁的进程

    我有一个来自调用信号处理程序后死锁的进程的核心转储 如何确定传送了哪个信号以及是谁发送的 GDB 为接收信号的线程生成的回溯如下 信号处理程序在第 15 帧中被调用 gdb bt 0 0x00007fa9c204654b in sys fu

随机推荐

  • 删除 MagicalRecord 中的实体不会持久

    我在使用 MagicalRecord 时遇到了一个奇怪的问题 删除不会持久 当我删除时 NSFetchedResultsControllerDelegate 正确地看到该对象已被删除 但是 如果我关闭并重新打开应用程序 该实体就会重新出现
  • Executor 上的 AsyncTask 和 PriorityBlockingQueue 实现问题

    在浪潮中这个问题 https stackoverflow com questions 12039596 asynctask on executor and priorityblockingqueue并有许多提示另一个 https stack
  • 测量计时器的精度(例如秒表/QueryPerformanceCounter)

    鉴于StopwatchC 中的类可以在下面使用三个不同的计时器 例如 系统定时器例如精度约 10 ms取决于可以设置的定时器分辨率timeBeginPeriod https msdn microsoft com en us library
  • plot.new尚未被调用

    为什么会发生这种情况 plot x y yx lm lt lm y x lines x predict yx lm col red 错误于plot xy xy coords x y type type plot new尚未被调用 某些操作
  • C# 解码(解压缩)PDF 文件的 Deflate 数据

    我想在 C 中解压缩一些 DeflateCoded 数据 提取的 PDF 不幸的是 我每次都会遇到异常 解码时发现无效数据 但数据是有效的 private void Decompress FileStream fs new FileStre
  • Number::toString() 抽象操作

    我试图理解如何数字 toString x https 262 ecma international org 11 0 sec numeric types number tostring抽象操作有效 据我所知 其要点似乎是非常大 n gt 2
  • exec 总是返回 -1 (或 127)

    我在生产服务器上使用 php 5 2 9 并且 exec 函数的行为似乎是 非标准 如果我跑exec ls output return var then output将按预期包含当前文件夹中的文件列表 但是 return var将被设置为
  • Google Spanner:JDBC 连接字符串?

    虽然 Spanner 看起来令人兴奋 但 Simba JDBC 驱动程序的文档 包含在此处的下载链接中 https cloud google com spanner docs partners drivers https cloud goo
  • 如何确保 slurm 中的 python 提交脚本位于发出 sbatch 命令的位置?

    我有一个运行的 python 提交脚本sbatch using slurm sbatch batch py 当我这样做时 事情无法正常工作 因为我认为 batch py进程没有继承正确的环境变量 因此 而不是运行batch py从哪里sba
  • 使用 Ruby 的 TracePoint 获取方法参数

    我可以使用 TracePoint API 访问 Ruby 方法的参数 def foo foo arg end trace TracePoint trace call c call do tp tp disable case tp metho
  • 在赋值 A(:) = B 中,A 和 B 中的元素数量必须相同

    例如 当尝试运行我的代码时 for ii 1 10 output ii rand 3 end 我收到错误 In an assignment A B the number of elements in A and B must be the
  • 目标 C:SHA1

    如何在 Objective c 中 sha1 一个字符串或一组数字 CommonCrypto Apple 框架 具有计算 SHA 1 哈希值的函数 包括一步哈希值 include
  • 给定 x、y 和色调,获取 HSL 值

    给定一个看起来像这样的颜色选择器 我正在尝试根据光标的 x 和 y 位置以及右侧滑块的色调来计算 HSL 值 我的数学技能相当薄弱 尽管我所拥有的很接近 但尝试获取真正浅的全强度颜色很麻烦 最终会变得太灰 这是我当前使用的功能 getHSL
  • C# 中使用反射进行方法拦截

    我编写了一个抽象类 它使用反射来查找构造函数中标有属性的字段 如下所示 AttributeUsage AttributeTargets Field public class TrackedField Attribute public cla
  • 定义频率上的音量 (C#)

    我不明白为什么音量定义的频率不符合预期 我依次将声音以几个指定的频率发送到麦克风 然后我对麦克风缓冲区进行 FFT 在 FFT 退出时 我有一个复数数组 要了解定义频率上的声音音量 我查看我的数组 该数组中的元素数量是这样得到的 MyFre
  • 使用 Java 在线程之间传输数据

    我正在编写一个模仿电影院的多线程应用程序 每个参与的人都是自己的线程 并发必须完全由信号量来完成 我遇到的唯一问题是如何基本上链接线程以便它们可以通信 例如通过管道 例如 Customer 1 是一个线程 它获取一个信号量 让它走到票房 现
  • VBA:使用两个参数调用 SQL Server 存储过程

    正如标题中提到的 我只想从 VBA 调用 SQL Server 存储过程 我可以这样调用我的存储过程 EXEC dbo spClientXLS Nr 131783 date 21 09 2014 Nr is a varChar 50 输入值
  • 如何在不使用 GlobalKey.currentState 的情况下平滑更新 Flutter AnimatedList?

    我发现的将项目插入 Flutter AnimatedList 的所有示例都利用 GlobalKey currentState 告诉 AnimatedList 小部件已插入项目 从列表中删除也是如此 众所周知 在 Flutter 中 Glob
  • 每个列表视图项目中旋转进度条

    我已经为此挠头很久了 并寻找答案但没有任何运气 这似乎是微不足道的 但据我所知 事实并非如此 我在 Android 应用程序中使用列表视图 其中每个项目 视图 在 内容已加载并显示 内容是通过http调用和json检索的 因此可能需要一段时
  • 如何摆脱 Core 中的“let”?

    我有一个在内部循环中频繁调用的函数 它看起来像这样 import qualified Data Vector Storable as SV newtype Timedelta Timedelta Double cklsLogDens SV