Skip to content

Commit

Permalink
Fix Performance of 'by' Operations when verbose=TRUE (Rdatatable#6296)
Browse files Browse the repository at this point in the history
* replace calls to clock() with wallclock()

* reorganize and clarify time variables following Rdatatable#6228

* better translatability

* NEWS

* better NEWS

---------

Co-authored-by: Michael Chirico <[email protected]>
  • Loading branch information
joshhwuu and MichaelChirico authored Sep 4, 2024
1 parent a9331b6 commit f248bbe
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 11 deletions.
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@

4. The translations submitted for 1.16.0 are now actually shipped with the package -- our deepest apologies to the translators for the omission. We have added a CI check to ensure that the .mo binaries which get shipped with the package are always up-to-date.

5. Some grouping operations run much faster under `verbose=TRUE`, [#6286](https://github.com/Rdatatable/data.table/issues/6286). Thanks @joshhwuu for the report and fix. This overhead was not present on Windows. As a rule, users should expect `verbose=TRUE` operations to run more slowly, as extra statistics might be calculated as part of the report; here was a case where the overhead was particularly high and the fix was particularly easy.

# data.table [v1.16.0](https://github.com/Rdatatable/data.table/milestone/30) (25 August 2024)

## BREAKING CHANGES
Expand Down
23 changes: 12 additions & 11 deletions src/dogroups.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,12 @@ SEXP dogroups(SEXP dt, SEXP dtcols, SEXP groups, SEXP grpcols, SEXP jiscols, SEX
int nprotect=0;
SEXP ans=NULL, jval, thiscol, BY, N, I, GRP, iSD, xSD, rownames, s, RHS, target, source;
Rboolean wasvector, firstalloc=FALSE, NullWarnDone=FALSE;
clock_t tstart=0, tblock[10]={0}; int nblock[10]={0};
const bool verbose = LOGICAL(verboseArg)[0]==1;
const bool showProgress = LOGICAL(showProgressArg)[0]==1;
bool hasPrinted = false;
double startTime = (showProgress) ? wallclock() : 0;
double tstart=0, tblock[10]={0}; int nblock[10]={0}; // For verbose printing, tstart is updated each block
double startTime = (showProgress) ? wallclock() : 0; // For progress printing, startTime is set at the beginning
double nextTime = (showProgress) ? startTime+3 : 0; // wait 3 seconds before printing progress
bool hasPrinted = false;

if (!isInteger(order)) internal_error(__func__, "order not integer vector"); // # nocov
if (TYPEOF(starts) != INTSXP) internal_error(__func__, "starts not integer"); // # nocov
Expand Down Expand Up @@ -230,7 +230,7 @@ SEXP dogroups(SEXP dt, SEXP dtcols, SEXP groups, SEXP grpcols, SEXP jiscols, SEX
writeNA(VECTOR_ELT(xSD, j), 0, 1, false);
}
} else {
if (verbose) tstart = clock();
if (verbose) tstart = wallclock();
SETLENGTH(I, grpn);
int *iI = INTEGER(I);
if (LENGTH(order)==0) {
Expand All @@ -242,22 +242,22 @@ SEXP dogroups(SEXP dt, SEXP dtcols, SEXP groups, SEXP grpcols, SEXP jiscols, SEX
for (int j=0; j<length(xSD); ++j)
memrecycle(VECTOR_ELT(xSD,j), R_NilValue, 0, 1, VECTOR_ELT(dt, INTEGER(xjiscols)[j]-1), rownum, 1, j+1, "Internal error assigning to xSD");
}
if (verbose) { tblock[0] += clock()-tstart; nblock[0]++; }
if (verbose) { tblock[0] += wallclock()-tstart; nblock[0]++; }
} else {
const int rownum = istarts[i]-1;
for (int k=0; k<grpn; ++k) iI[k] = iorder[rownum+k];
for (int j=0; j<length(SDall); ++j) {
// this is the main non-contiguous gather, and is parallel (within-column) for non-SEXP
subsetVectorRaw(VECTOR_ELT(SDall,j), VECTOR_ELT(dt,INTEGER(dtcols)[j]-1), I, anyNA);
}
if (verbose) { tblock[1] += clock()-tstart; nblock[1]++; }
if (verbose) { tblock[1] += wallclock()-tstart; nblock[1]++; }
// The two blocks have separate timing statements to make sure which is running
}
}

if (verbose) tstart = clock(); // call to clock() is more expensive than an 'if'
if (verbose) tstart = wallclock(); // call to wallclock() is more expensive than an 'if'
PROTECT(jval = eval(jexp, env));
if (verbose) { tblock[2] += clock()-tstart; nblock[2]++; }
if (verbose) { tblock[2] += wallclock()-tstart; nblock[2]++; }

if (isNull(jval)) {
// j may be a plot or other side-effect only
Expand Down Expand Up @@ -486,9 +486,10 @@ SEXP dogroups(SEXP dt, SEXP dtcols, SEXP groups, SEXP grpcols, SEXP jiscols, SEX
if (verbose) {
if (nblock[0] && nblock[1]) internal_error(__func__, "block 0 [%d] and block 1 [%d] have both run", nblock[0], nblock[1]); // # nocov
int w = nblock[1]>0;
Rprintf(_("\n %s took %.3fs for %d groups\n"), w ? "collecting discontiguous groups" : "memcpy contiguous groups",
1.0*tblock[w]/CLOCKS_PER_SEC, nblock[w]);
Rprintf(_(" eval(j) took %.3fs for %d calls\n"), 1.0*tblock[2]/CLOCKS_PER_SEC, nblock[2]);
Rprintf(w ? _("\n collecting discontiguous groups took %.3fs for %d groups\n")
: _("\n memcpy contiguous groups took %.3fs for %d groups\n"),
1.0*tblock[w], nblock[w]);
Rprintf(_(" eval(j) took %.3fs for %d calls\n"), 1.0*tblock[2], nblock[2]);
}
UNPROTECT(nprotect);
return(ans);
Expand Down

0 comments on commit f248bbe

Please sign in to comment.