Я работаю с таблицей данных из 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 размера) выполняется с таким же агрегированием.
Я бы предположил, что 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))
работает нормально и ничего особенного не происходит.
Ну ошибка выкидывается из
Однако я также вижу, что nrow
объявлен как int
Похоже, это приведет к переполнению для 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)
Отключение нескольких потоков не помогло. Иногда ошибка меняется на «недопустимый поток 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")
Самый полезный комментарий
Вместо
rep(..., each =)
удалите каждый. При сортировке группировок часть кода, в которой используетсяTMP
, не используется.