Data.table: 在gforce中分配g时无法分配计数或TMP

创建于 2020-03-10  ·  27评论  ·  资料来源: Rdatatable/data.table

我正在使用1423657324行和14列的data.table。

有一个整数组( grp ),具有3790个唯一值。

当我执行以下操作时

stats <- ft[, .(
      col1 = median(col1, na.rm = TRUE),
      col2 = median(col2, na.rm = TRUE),
      col3 = median(col3, na.rm = TRUE)
    ), keyby = grp]

发生以下错误:

Error in gforce(thisEnv, jsub, o__, f__, len__, irows) :
  Internal error: Failed to allocate counts or TMP when assigning g in gforce

当使用相同的聚合完成较短版本的数据(大小的1/3)时,不会发生这种情况。

GForce bug

最有用的评论

而不是rep(..., each =) ,删除每个。 对分组进行排序时,不使用使用TMP的代码部分。

所有27条评论

我可以想象median可能会非常消耗内存,这就是为什么您通常在“大数据” SQL中看到approx_quantile且中位数本身被完全丢弃的原因。

如果尝试按col1对数据进行排序,是否会遇到相同的问题? 如果不是,则可能是gmedian试图一次完成所有三列。

解决方法是,执行ft[ , .N, keyby = .(grp, col1)]并从频率表中获取中位数,因为您说的唯一值要少得多。

median更改stats::median有所帮助吗? 它应防止data.tablegforce优化。

禁用gforce或使用stats::median不会触发此错误。 但是我仍然很好奇为什么会发生这种情况?

我的服务器内存为1TB,应该足以处理。

stats::median(c(col1, col2, col3))怎么样(只是检查将内存占用量增加三倍是否有影响)

stats::median(c(col1, col2, col3))工作正常,没有发生任何特殊情况。

@ renkun-ken您介意参加考试吗? 只需将数据的行数分别减少到1073741823L / 1073741824L然后尝试使用原始代码即可。

我期望第一种情况(1073741823L行)有效,但第二种将失败。

我相信这就是原因。 溢出导致无限的内存分配...

Rcpp::cppFunction("size_t test(int x) {
                    return x*2*sizeof(int);
                  }")
test(1073741823L)
#> [1] 8589934584
test(1073741824L)
#> [1] 1.844674e+19
test(1423657324L)
#> [1] 1.844674e+19

reprex软件包(v0.3.0)创建于2020-03-10

是的, 1073741823L情况下的效果很好,而1073741824L情况下的效果不理想。

@ renkun-ken当然,如果可以的话,可以验证PR#4297确实可以解决此问题,这将是非常不错的。

@shrektan谢谢! 我会尽快验证。

@shrektan可悲的是太难了,无法获取回购

remote: Enumerating objects: 1431, done.
remote: Counting objects: 100% (1431/1431), done.
remote: Compressing objects: 100% (181/181), done.
Timeout, server github.com not responding. KiB | 2.00 KiB/s  
fatal: the remote end hung up unexpectedly
fatal: early EOF
fatal: index-pack failed

尝试了很多次但没有运气

我之前遇到过网络问题...,所以我打包了源并将其发送到您的电子邮件中(我假设您能够访问您的个人电子邮件)。

感谢您的精美包装! 昨晚我睡觉时,我的git fetch神奇地工作。

我重试了一下,可以确认该错误已通过PR修复。 干得好!

顺便说一句,您是否怀疑还有其他类似的int问题?

这是另外60个左右在代码中具有相似模式的地方(尚未进行梳理)

grep -Enr "[^.][0-9]+\s*[*]" src --include=*.c | grep -Ev "^src/[a-z]+[.]c:[0-9]+:\s*[/][/]"
src/forder.c:260:    memset(thiscounts, 0, 256*sizeof(int));
src/forder.c:380:  dmask = dround ? 1 << (8*dround-1) : 0;
src/forder.c:425:  memset(stat,   0, 257*sizeof(uint64_t));
src/forder.c:728:  if (!TMP || !UGRP /*|| TMP%64 || UGRP%64*/) STOP(_("Failed to allocate TMP or UGRP or they weren't cache line aligned: nth=%d"), nth);
src/forder.c:1012:          memcpy(my_starts, my_starts_copy, 256*sizeof(uint16_t));  // restore starting offsets
src/forder.c:1051:  uint8_t  *ugrps =  malloc(nBatch*256*sizeof(uint8_t));
src/frank.c:93:          dans[xorder[j]-1] = (2*xstart[i]+xlen[i]-1)/2.0;
src/frank.c:126:        int offset = 2*xstart[i]+xlen[i]-2;
src/gsumm.c:115:    int *TMP   = malloc(nrow*2*sizeof(int));
src/gsumm.c:132:      int *restrict my_tmp = TMP + b*2*batchSize;
src/gsumm.c:135:        int *p = my_tmp + 2*my_counts[w]++;
src/gsumm.c:146:        const int *restrict p = TMP + b*2*batchSize + start*2;
src/fsort.c:125:  if (batchSize < 1024) batchSize = 1024; // simple attempt to work reasonably for short vector. 1024*8 = 2 4kb pages
src/fsort.c:178:                       (int)(nBatch*MSBsize*sizeof(R_xlen_t)/(1024*1024)),
src/fsort.c:179:                       (int)(nBatch*MSBsize*sizeof(R_xlen_t)/(4*1024*nBatch)),
src/assign.c:21:  SETLENGTH(x,50+n*2*sizeof(void *)/4);  // 1*n for the names, 1*n for the VECSXP itself (both are over allocated).
src/assign.c:575:        char *s5 = (char*) malloc(strlen(tc2) + 5); //4 * '_' + \0
src/bmerge.c:496:                 ival.d-xval.d == rollabs /*#1007*/))
src/bmerge.c:510:                   xval.d-ival.d == rollabs /*#1007*/))
src/fread.c:194:  char *ptr = buf + 501 * flip;
src/fread.c:282:  const char *mostConsumed = start; // tests 1550* includes both 'na' and 'nan' in nastrings. Don't stop after 'na' if 'nan' can be consumed too.
src/fread.c:375:    ans = (double) tp.tv_sec + 1e-9 * (double) tp.tv_nsec;
src/fread.c:379:    ans = (double) tv.tv_sec + 1e-6 * (double) tv.tv_usec;
src/fread.c:434:  mmp_copy = (char *)malloc((size_t)fileSize + 1/* extra \0 */);
src/fread.c:596:    acc = 10*acc + digit;
src/fread.c:628:    acc = 10*acc + digit;
src/fread.c:693:    acc = 10*acc + digit;
src/fread.c:727:      acc = 10*acc + digit;
src/fread.c:914:      E = 10*E + digit;
src/fread.c:1256:      int nbit = 8*sizeof(char *); // #nocov
src/fread.c:1655:    if (jump0size*100*2 < sz) nJumps=100;  // 100 jumps * 100 lines = 10,000 line sample
src/fread.c:1656:    else if (jump0size*10*2 < sz) nJumps=10;
src/fread.c:1663:    else DTPRINT(_("(%"PRIu64" bytes from row 1 to eof) / (2 * %"PRIu64" jump0size) == %"PRIu64"\n"),
src/fread.c:1664:                 (uint64_t)sz, (uint64_t)jump0size, (uint64_t)(sz/(2*jump0size)));
src/fread.c:1687:    if (ch<lastRowEnd) ch=lastRowEnd;  // Overlap when apx 1,200 lines (just over 11*100) with short lines at the beginning and longer lines near the end, #2157
src/fread.c:1823:    allocnrow = clamp_szt((size_t)(bytesRead / fmax(meanLineLen - 2*sd, minLen)),
src/fread.c:1824:                          (size_t)(1.1*estnrow), 2*estnrow);
src/fread.c:1833:      DTPRINT(_("  Initial alloc = %"PRIu64" rows (%"PRIu64" + %d%%) using bytes/max(mean-2*sd,min) clamped between [1.1*estn, 2.0*estn]\n"),
src/fread.c:1973:  size_t chunkBytes = umax((size_t)(1000*meanLineLen), 1ULL/*MB*/ *1024*1024);
src/fread.c:2030:      .buff8 = malloc(rowSize8 * myBuffRows + 8),
src/fread.c:2031:      .buff4 = malloc(rowSize4 * myBuffRows + 4),
src/fread.c:2032:      .buff1 = malloc(rowSize1 * myBuffRows + 1),
src/fread.c:2102:          ctx.buff8 = realloc(ctx.buff8, rowSize8 * myBuffRows + 8);
src/fread.c:2103:          ctx.buff4 = realloc(ctx.buff4, rowSize4 * myBuffRows + 4);
src/fread.c:2104:          ctx.buff1 = realloc(ctx.buff1, rowSize1 * myBuffRows + 1);
src/fread.c:2453:    DTPRINT(_("%8.3fs (%3.0f%%) Memory map %.3fGB file\n"), tMap-t0, 100.0*(tMap-t0)/tTot, 1.0*fileSize/(1024*1024*1024));
src/fread.c:2460:      tAlloc-tColType, 100.0*(tAlloc-tColType)/tTot, (uint64_t)allocnrow, ncol, DTbytes/(1024.0*1024*1024), (uint64_t)DTi, 100.0*DTi/allocnrow);
src/fread.c:2464:            tReread-tAlloc, 100.0*(tReread-tAlloc)/tTot, nJumps, nSwept, (double)chunkBytes/(1024*1024), (int)(DTi/nJumps), nth);
src/fifelse.c:167:    REPROTECT(cons = eval(SEXPPTR_RO(args)[2*i], rho), Icons);
src/fifelse.c:168:    REPROTECT(outs = eval(SEXPPTR_RO(args)[2*i+1], rho), Iouts);
src/fifelse.c:173:      error("Argument #%d must be logical.", 2*i+1);
src/fwrite.c:376:    ch += 7 + 2*!squashDateTime;
src/fwrite.c:389:    ch += 8 + 2*!squashDateTime;
src/fwrite.c:614:  size_t buffSize = (size_t)1024*1024*args.buffMB;
src/fwrite.c:645:  size_t maxLineLen = eolLen + args.ncol*(2*(doQuote!=0) + 1/*sep*/);
src/fwrite.c:648:    maxLineLen += 2*(doQuote!=0/*NA('auto') or true*/) + 1/*sep*/;
src/fwrite.c:782:  if (maxLineLen*2>buffSize) { buffSize=2*maxLineLen; rowsPerBatch=2; }
src/fwrite.c:910:          int used = 100*((double)(ch-myBuff))/buffSize;  // percentage of original buffMB

顺便说一句,对于需要大量数据才能重现的错误,我们是否需要为其构建测试用例?

对于此错误,一个最小的可复制示例是

library(data.table)

n <- 1500000000
ngrp <- 4000
dt <- data.table(group = sample.int(ngrp, n, replace = TRUE), x = runif(n))
res <- dt[, .(
  xmedian = median(x, na.rm = TRUE)
), keyby = group]

但是dt是18GB,创建dt花费5-10分钟。

通过摆脱随机函数,您可以得到一个更快的示例。...只需使用rep()c() ...实际上我确实尝试过测试。

困难在于需要大量内存...

我试过了

dt <- data.table(group = rep(seq_len(ngrp), each = n / ngrp), x = numeric(n))

dt <- data.table(group = rep(seq_len(ngrp), each = n / ngrp), x = rep(rnorm(1000), each = n / 1000))

两者都快得多,但不会产生错误。 👀

而不是rep(..., each =) ,删除每个。 对分组进行排序时,不使用使用TMP的代码部分。

我遇到了类似的问题。 在Windows SQL Server(R版本3.5.2和data.table 1.12.0)中运行R脚本时,发生以下错误:
Error in forderv(ans, cols, sort = TRUE, retGrp = FALSE, order = if (decreasing) -order else order, : Failed to allocate TMP or UGRP or they weren't cache line aligned: nth=8 Call: source ... [ -> [.data.table -> eval -> eval -> forder -> forderv
这是由以下forcer.c行调用的:
src/forder.c:728: if (!TMP || !UGRP /*|| TMP%64 || UGRP%64*/) STOP(_("Failed to allocate TMP or UGRP or they weren't cache line aligned: nth=%d"), nth);

该脚本使用on=.(Id,date>=start_date,date<=end_date)语句连接两个数据表(X和Y),并使用by=.EACHI进行操作。 在本地RStudio版本上运行相同的脚本时,没有错误。 您是否认为分别设置“ Id”和“ date”? “ start_date”和“ end_date”作为X和Y中的键是否可以防止整数重载? 或者,将by=.EACHI更改keyby=.EACHI做什么?

提前谢谢您。

您是否认为分别设置“ Id”和“ date”? “ start_date”和“ end_date”作为X和Y中的键是否可以防止整数重载? 或者,可以将by = .EACHI更改为keyby = .EACHI吗?

我没有使用R的MSSQLServer的经验,但我认为它不会解决您的问题。 尝试昂贵吗?

我尝试了一下,但没有成功。 您知道这里有什么帮助吗? 由于依赖关系有时在MSSQL中会失真,它是否必须对data.table和bit64之间的依赖关系进行某些处理?

我认为它与bit64无关,因为bit64已停止更新3年了。 我为您提供一些(有限的)建议:

  • 关闭多个线程,即data.table::setDTthreads(1L)
  • 使用data.table的开发版本(尽管我怀疑它是否可以工作)
  • 制作一个本地可复制的示例并在此处报告
  • 如果您具有营业执照,请致电Microsoft以寻求支持

关闭多个线程无效。 有时,错误变为“无效的BXL流”,这可以归因于内存不足。

您是否知道错误src/forder.c:728: if (!TMP || !UGRP /*|| TMP%64 || UGRP%64*/) STOP(_("Failed to allocate TMP or UGRP or they weren't cache line aligned: nth=%d"), nth);可能是由于缺少RAM引起的?

@ scharlatan0139是的,它的确看起来像是由于缺少RAM而引起的错误。

@shrektan ,是导入修订的正确方法是remotes :: install_github(“ Rdatatable / data.table#fix4295”)

我尝试了此操作,但收到无效的回购错误

@ Debasis5应该是

remotes::install_github("rdatatable/data.table#4297") 

要么

remotes::install_github("Rdatatable/data.table@fix4295") 
此页面是否有帮助?
0 / 5 - 0 等级