【问题标题】:Profiling data.table's setkey operation with Rprof使用 Rprof 分析 data.table 的 setkey 操作
【发布时间】:2014-02-11 16:15:29
【问题描述】:

我正在使用相对较大的 data.table 数据集并尝试分析/优化代码。我正在使用Rprof,但我注意到在 setkey 操作中花费的大部分时间不包含在 Rprof 总结中。有没有办法包括这段时间?

这是一个小测试,显示 Rprof 摘要中没有显示为数据表设置键所花费的时间:

创建一个测试函数,在数据表上运行已分析的 setkey 操作:

    testFun <- function(testTbl) {
        Rprof()
        setkey(testTbl, x, y, z)
        Rprof(NULL)
        print(summaryRprof())
    }

然后创建一个足够大的测试数据表来感受setkey操作的权重:

    testTbl = data.table(x=sample(1:1e7, 1e7), y=sample(1:1e7,1e7), z=sample(1:1e7,1e7))

然后运行代码,并将其包装在一个 system.time 操作中,以显示 system.time 总时间和 rprof 总时间之间的差异:

>   system.time(testFun(testTbl))
$by.self
                self.time self.pct total.time total.pct
"sort.list"          0.88    75.86       0.88     75.86
"<Anonymous>"        0.08     6.90       1.00     86.21
"regularorder1"      0.08     6.90       0.92     79.31
"radixorder1"        0.08     6.90       0.12     10.34
"is.na"              0.02     1.72       0.02      1.72
"structure"          0.02     1.72       0.02      1.72

$by.total
                total.time total.pct self.time self.pct
"setkey"              1.16    100.00      0.00     0.00
"setkeyv"             1.16    100.00      0.00     0.00
"system.time"         1.16    100.00      0.00     0.00
"testFun"             1.16    100.00      0.00     0.00
"fastorder"           1.14     98.28      0.00     0.00
"tryCatch"            1.14     98.28      0.00     0.00
"tryCatchList"        1.14     98.28      0.00     0.00
"tryCatchOne"         1.14     98.28      0.00     0.00
"<Anonymous>"         1.00     86.21      0.08     6.90
"regularorder1"       0.92     79.31      0.08     6.90
"sort.list"           0.88     75.86      0.88    75.86
"radixorder1"         0.12     10.34      0.08     6.90
"doTryCatch"          0.12     10.34      0.00     0.00
"is.na"               0.02      1.72      0.02     1.72
"structure"           0.02      1.72      0.02     1.72
"is.unsorted"         0.02      1.72      0.00     0.00
"simpleError"         0.02      1.72      0.00     0.00

$sample.interval
[1] 0.02

$sampling.time
[1] 1.16

   user  system elapsed 
 31.112   0.211  31.101 

注意 1.16 和 31.101 的时差。

阅读 ?Rprof,我明白为什么会出现这种差异:

函数只有在配置文件时才会记录在配置文件日志中 调用堆栈上的上下文(参见 sys.calls)。一些原始函数可以 不要这样做:特别是那些“特殊”类型的(见'R 内部人员手册了解更多详细信息)。

这就是为什么 Rprof 中没有表示在 setkey 操作中花费的时间的原因吗?是否有一种解决方法让 Rprof 监视所有 data.table 的操作(包括 setkey,也许还有我没有注意到的其他操作)?我基本上想让 system.time 和 Rprof 时间匹配。

这是最可能相关的 sessionInfo():

>   sessionInfo()
R version 3.0.2 (2013-09-25)
Platform: x86_64-apple-darwin10.8.0 (64-bit)

data.table_1.8.11

当 Rprof() 不在函数调用中时,我仍然会观察到这个问题:

>   testFun <- function(testTbl) {
+       setkey(testTbl, x, y, z)
+   }

>   Rprof()
>   system.time(testFun(testTbl))
   user  system elapsed 
 28.855   0.191  28.854 
>   Rprof(NULL)
>   summaryRprof()
$by.self
                self.time self.pct total.time total.pct
"sort.list"          0.86    71.67       0.88     73.33
"regularorder1"      0.08     6.67       0.92     76.67
"<Anonymous>"        0.06     5.00       0.98     81.67
"radixorder1"        0.06     5.00       0.10      8.33
"gc"                 0.06     5.00       0.06      5.00
"proc.time"          0.04     3.33       0.04      3.33
"is.na"              0.02     1.67       0.02      1.67
"sys.function"       0.02     1.67       0.02      1.67

$by.total
                total.time total.pct self.time self.pct
"system.time"         1.20    100.00      0.00     0.00
"setkey"              1.10     91.67      0.00     0.00
"setkeyv"             1.10     91.67      0.00     0.00
"testFun"             1.10     91.67      0.00     0.00
"fastorder"           1.08     90.00      0.00     0.00
"tryCatch"            1.08     90.00      0.00     0.00
"tryCatchList"        1.08     90.00      0.00     0.00
"tryCatchOne"         1.08     90.00      0.00     0.00
"<Anonymous>"         0.98     81.67      0.06     5.00
"regularorder1"       0.92     76.67      0.08     6.67
"sort.list"           0.88     73.33      0.86    71.67
"radixorder1"         0.10      8.33      0.06     5.00
"doTryCatch"          0.10      8.33      0.00     0.00
"gc"                  0.06      5.00      0.06     5.00
"proc.time"           0.04      3.33      0.04     3.33
"is.na"               0.02      1.67      0.02     1.67
"sys.function"        0.02      1.67      0.02     1.67
"formals"             0.02      1.67      0.00     0.00
"is.unsorted"         0.02      1.67      0.00     0.00
"match.arg"           0.02      1.67      0.00     0.00

$sample.interval
[1] 0.02

$sampling.time
[1] 1.2

EDIT2:与我的机器上的 1.8.10 相同的问题,仅加载了 data.table 包。即使 Rprof() 调用不在函数内,时间也不相等:

> library(data.table)
data.table 1.8.10  For help type: help("data.table")
> base::source("/tmp/r-plugin-claytonstanley/Rsource-86075-preProcess.R", echo=TRUE)

>   testFun <- function(testTbl) {
+       setkey(testTbl, x, y, z)
+   }
>   testTbl = data.table(x=sample(1:1e7, 1e7), y=sample(1:1e7,1e7), z=sample(1:1e7,1e7))
>   Rprof()
>   system.time(testFun(testTbl))
   user  system elapsed 
 29.516   0.281  29.760 
>   Rprof(NULL)
>   summaryRprof()

EDIT3:即使setkey 不在函数内也不起作用:

> library(data.table)
data.table 1.8.10  For help type: help("data.table")
>   testTbl = data.table(x=sample(1:1e7, 1e7), y=sample(1:1e7,1e7), z=sample(1:1e7,1e7))
>   Rprof()
>   setkey(testTbl, x, y, z)
>   Rprof(NULL)
>   summaryRprof()

EDIT4:即使从--vanilla 基本终端提示符调用 R 也不起作用。

EDIT5:在 Linux VM 上测试时可以工作。但对我来说仍然无法在达尔文机器上工作。

EDIT6:在看到 Rprof.out 文件创建后不起作用,因此这不是写访问问题。

EDIT7:从源代码编译 data.table 并创建新的临时用户并在该帐户上运行后不起作用。

EDIT8:通过 MacPorts 从源代码为 darwin 编译 R 3.0.2 时不起作用。

EDIT9:可以在不同的 darwin 机器上工作,即运行相同操作系统版本 (10.6.8) 的 Macbook Pro 笔记本电脑。仍然无法在运行相同 OS 版本、R 版本、data.table 版本等的 MacPro 台式机上运行。

我认为这是因为台式机运行在 64 位内核模式(不是默认),而笔记本电脑是 32 位(默认)。 确认

【问题讨论】:

  • 我没有发现这个问题(windows 或 linux,R 3.0.1,dt 1.8.11) - setkey Rprofsystem.time 时间对我来说非常匹配跨度>
  • 哦,鉴于您的编辑,您拥有 v1.8.11。我们仍在努力,我不知道您拍摄了哪个 v1.8.11 快照。更大的图景是什么?那么,您是否设计了这个测试来测试 v1.8.11 中的新改进?
  • @MattDowle 我正在使用 v1.8.11 b/c 我需要在大约一个月前为一个单独的项目执行此操作:options(datatable.integer64="character") # Until integer64 setkey is implemented。我将恢复到 1.8.10 并重新测试。
  • 哦,我明白了。在这种情况下,您不需要恢复到 1.8.10。只需在提示符处而不是在函数内部测试 Rprof() 并确认它有效。
  • 看到了编辑。如果setkey 不在函数内怎么办?

标签: r data.table


【解决方案1】:

很好的问题。鉴于编辑,我不确定,不能重现。暂时把剩下的答案留在这里。

我已经在我的(非常慢的)上网本上进行了测试,它运行良好,请参见下面的输出。

我现在可以告诉你为什么setkey 在那个测试用例上这么慢。当级别数很大时(如此处所示大于 100,000),它会恢复为比较排序而不是计数排序。是的,如果您在实践中拥有这样的数据,那就太差了。通常我们在第一列中有不到 100,000 个唯一值,然后在第二列中有日期。两列都可以使用计数排序进行排序,性能还可以。

这是一个已知问题,我们一直在努力解决。 Arun 已经为范围 > 100,000 的整数实现了基数排序来解决这个问题,这将在下一个版本中发布。 但我们仍在整理 v1.8.11。 请参阅我们在科隆的演示文稿,其中更详细地介绍了加速方面的一些想法。

Inroduction to data.table and news from v1.8.11

这是 v1.8.10 的输出,以及 R 版本和 lscpu 信息(供您娱乐)。我喜欢在具有小缓存的非常差的机器上进行测试,以便在开发过程中我可以看到当数据在具有更大缓存的大型机器上扩展时可能会出现什么问题。

$ lscpu
Architecture:          x86_64
CPU op-mode(s):        32-bit, 64-bit
Byte Order:            Little Endian
CPU(s):                2
On-line CPU(s) list:   0,1
Thread(s) per core:    1
Core(s) per socket:    2
Socket(s):             1
NUMA node(s):          1
Vendor ID:             AuthenticAMD
CPU family:            20
Model:                 2
Stepping:              0
CPU MHz:               800.000
BogoMIPS:              1995.01
Virtualisation:        AMD-V
L1d cache:             32K
L1i cache:             32K
L2 cache:              512K
NUMA node0 CPU(s):     0,1

$ R
R version 3.0.2 (2013-09-25) -- "Frisbee Sailing"
Copyright (C) 2013 The R Foundation for Statistical Computing
Platform: x86_64-pc-linux-gnu (64-bit)

> require(data.table)
Loading required package: data.table
data.table 1.8.10  For help type: help("data.table")
> testTbl = data.table(x=sample(1:1e7, 1e7), y=sample(1:1e7,1e7), z=sample(1:1e7,1e7))
> testTbl
                x       y       z
       1: 1748920 6694402 7501082
       2: 4571252  565976 5695727
       3: 1284455 8282944 7706392
       4: 8452994 8765774 6541097
       5: 6429283  329475 5271154
      ---                        
 9999996: 2019750 5956558 1735214
 9999997: 1096888 1657401 3519573
 9999998: 1310171 9002746  350394
 9999999: 5393125 5888350 7657290
10000000: 2210918 7577598 5002307
> Rprof()
> setkey(testTbl, x, y, z)
> Rprof(NULL)
> summaryRprof()
$by.self
                self.time self.pct total.time total.pct
"sort.list"        195.44    91.34     195.44     91.34
".Call"              5.38     2.51       5.38      2.51
"<Anonymous>"        4.32     2.02     203.62     95.17
"radixorder1"        4.32     2.02       4.74      2.22
"regularorder1"      4.28     2.00     199.30     93.15
"is.na"              0.12     0.06       0.12      0.06
"any"                0.10     0.05       0.10      0.05

$by.total
                total.time total.pct self.time self.pct
"setkey"            213.96    100.00      0.00     0.00
"setkeyv"           213.96    100.00      0.00     0.00
"fastorder"         208.36     97.38      0.00     0.00
"tryCatch"          208.36     97.38      0.00     0.00
"tryCatchList"      208.36     97.38      0.00     0.00
"tryCatchOne"       208.36     97.38      0.00     0.00
"<Anonymous>"       203.62     95.17      4.32     2.02
"regularorder1"     199.30     93.15      4.28     2.00
"sort.list"         195.44     91.34    195.44    91.34
".Call"               5.38      2.51      5.38     2.51
"radixorder1"         4.74      2.22      4.32     2.02
"doTryCatch"          4.74      2.22      0.00     0.00
"is.unsorted"         0.22      0.10      0.00     0.00
"is.na"               0.12      0.06      0.12     0.06
"any"                 0.10      0.05      0.10     0.05

$sample.interval
[1] 0.02

$sampling.time
[1] 213.96

>

【讨论】:

    【解决方案2】:

    问题在于 darwin 机器运行的是带有 64 位内核的 Snow Leopard,这不是该 OS X 版本的默认值。

    我还验证了这对于另一台运行 Mountain Lion 的 darwin 机器来说不是问题,它默认使用 64 位内核。所以这是雪豹和运行 64 位内核之间的交互。

    附带说明一下,R 的官方 OS X 二进制安装程序仍然是使用 Snow Leopard 构建的,所以我认为这个问题仍然存在,因为 Snow Leopard 仍然是一个广泛使用的 OS X 版本。

    启用 Snow Leopard 中的 64 位内核时,不会加载仅与 32 位内核兼容的内核扩展。在启动到 Snow Leopard 的默认 32 位内核后,kextfind 显示这些仅 32 位的内核扩展在机器上并且(很可能)已加载:

    $ kextfind -not -arch x86_64
    /System/Library/Extensions/ACard6280ATA.kext
    /System/Library/Extensions/ACard62xxM.kext
    /System/Library/Extensions/ACard67162.kext
    /System/Library/Extensions/ACard671xSCSI.kext
    /System/Library/Extensions/ACard6885M.kext
    /System/Library/Extensions/ACard68xxM.kext
    /System/Library/Extensions/AppleIntelGMA950.kext
    /System/Library/Extensions/AppleIntelGMAX3100.kext
    /System/Library/Extensions/AppleIntelGMAX3100FB.kext
    /System/Library/Extensions/AppleIntelIntegratedFramebuffer.kext
    /System/Library/Extensions/AppleProfileFamily.kext/Contents/PlugIns/AppleIntelYonahProfile.kext
    /System/Library/Extensions/IO80211Family.kext/Contents/PlugIns/AirPortAtheros.kext
    /System/Library/Extensions/IONetworkingFamily.kext/Contents/PlugIns/AppleRTL8139Ethernet.kext
    /System/Library/Extensions/IOSerialFamily.kext/Contents/PlugIns/InternalModemSupport.kext
    /System/Library/Extensions/IOSerialFamily.kext/Contents/PlugIns/MotorolaSM56KUSB.kext
    /System/Library/Extensions/JMicronATA.kext
    /System/Library/Extensions/System.kext/PlugIns/BSDKernel6.0.kext
    /System/Library/Extensions/System.kext/PlugIns/IOKit6.0.kext
    /System/Library/Extensions/System.kext/PlugIns/Libkern6.0.kext
    /System/Library/Extensions/System.kext/PlugIns/Mach6.0.kext
    /System/Library/Extensions/System.kext/PlugIns/System6.0.kext
    /System/Library/Extensions/ufs.kext
    

    因此,它可能是那些加载的扩展中的任何一个使 Rprof 包能够使用某些东西,以便正确分析 data.table 中的 setkey 操作。

    如果有人想进一步调查,深入挖掘,找到问题的根本原因,请发布答案,我很乐意接受。

    【讨论】:

      猜你喜欢
      • 2013-04-27
      • 1970-01-01
      • 2012-07-20
      • 1970-01-01
      • 2016-10-04
      • 2023-03-22
      • 2019-01-13
      • 2013-03-11
      • 1970-01-01
      相关资源
      最近更新 更多