Data.table: Не удалось выделить счетчики или TMP при назначении g в gforce

Созданный на 10 мар. 2020  ·  27Комментарии  ·  Источник: Rdatatable/data.table

Я работаю с таблицей данных из 1423657324 строк и 14 столбцов.

Есть целочисленная группа ( 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 может быть очень голодным по памяти, поэтому вы обычно видите approx_quantile в SQL "больших данных", а сама медиана полностью отбрасывается.

Возникает ли у вас такая же проблема, если вы попытаетесь отсортировать данные по col1 ? В противном случае может быть, что gmedian пытается выполнить все три столбца одновременно.

В качестве обходного пути выполните ft[ , .N, keyby = .(grp, col1)] и получите медианное значение из таблицы частот, поскольку вы сказали, что уникальных значений гораздо меньше.

Поможет ли изменение median на stats::median ? Это должно предотвратить оптимизацию data.table с помощью gforce .

Отключение gforce или использование stats::median не вызовет эту ошибку. Но мне все еще интересно, почему это происходит?

Память моего сервера составляет 1 ТБ, и ее должно хватить для обработки.

как насчет stats::median(c(col1, col2, col3)) (просто чтобы проверить, влияет ли утроение объема памяти)

stats::median(c(col1, col2, col3)) работает нормально и ничего особенного не происходит.

Ну ошибка выкидывается из

https://github.com/Rdatatable/data.table/blob/b1b1832b0d2d4032b46477d9fe6efb15006664f4/src/gsumm.c#L114 -L115

Однако я также вижу, что nrow объявлен как int

https://github.com/Rdatatable/data.table/blob/b1b1832b0d2d4032b46477d9fe6efb15006664f4/src/gsumm.c#L6

Похоже, это приведет к переполнению для 1423657324 * 2 ...

@ 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

Создано 2020-03-10 пакетом REPEX (v0.3.0)

Да, случай 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 составляет 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 , не используется.

У меня похожая проблема. При запуске моего сценария R в Windows SQL Server (R версии 3.5.2 и data.table 1.12.0) возникает следующая ошибка:
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);

Скрипт объединяет две таблицы данных (X и Y) с помощью оператора on=.(Id,date>=start_date,date<=end_date) и использует by=.EACHI для операции. При запуске того же сценария в моей локальной версии RStudio ошибок нет. Как вы думаете, установка "Id" и "date" соотв. «start_date» и «end_date» в качестве ключей в X и Y предотвратят целочисленную перегрузку? В качестве альтернативы, изменит ли значение by=.EACHI на keyby=.EACHI ?

Заранее благодарю.

Как вы думаете, установка "Id" и "date" соотв. «start_date» и «end_date» в качестве ключей в X и Y предотвратят целочисленную перегрузку? В качестве альтернативы можно изменить с = .EACHI на keyby = .EACHI?

У меня нет опыта работы с MSSQLServer с R, но я не думаю, что это решит вашу проблему. Стоит ли попробовать?

Я попробовал, но ничего не вышло. Вы знаете, что здесь может помочь? Может ли это быть связано с зависимостями между data.table и bit64, поскольку зависимости иногда искажаются в MSSQL?

На мой взгляд, это не должно иметь ничего общего с 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); быть вызвана нехваткой оперативной памяти?

@ scharlatan0139 да, это действительно похоже на ошибку, вызванную нехваткой оперативной памяти.

@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 рейтинги