Skip to content

Commit

Permalink
Mostly bug fixes.
Browse files Browse the repository at this point in the history
  • Loading branch information
NicChr committed Apr 9, 2024
1 parent 27a9b41 commit a352621
Show file tree
Hide file tree
Showing 8 changed files with 104 additions and 200 deletions.
12 changes: 12 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# cheapr (Development version)

* Fixed an inconsistency of when `sequence_()` would error when supplied with
a zero-length size argument.

* Fixed a protection stack imbalance in `count_val(x)` when `x` is `NULL`.

* `sset` has been optimised for wide data frames with many variables.
It is also faster when applied to a data frame with dates, date-times and factors.

* In `sset`, when `i` is a logical vector it must match the length of x.

* `sset` can now handle 'ALTREP' compact real sequences as well.

# cheapr 0.5.0

* `sset` is now parallelised when `i` is an 'ALTREP'
Expand Down
118 changes: 59 additions & 59 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,14 @@ mark(na_locf(x), vec_fill_missing(x, direction = "down"))
#> # A tibble: 2 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 "na_locf(x)" 841.1µs 854.1µs 1144. 0B 0
#> 2 "vec_fill_missing(x, direction… 2.67ms 2.79ms 352. 11.4MB 117.
#> 1 "na_locf(x)" 841.4µs 852.5µs 1165. 0B 0
#> 2 "vec_fill_missing(x, direction… 2.64ms 2.86ms 336. 11.4MB 112.
mark(na_locf(x), vec_fill_missing(x, direction = "down"))
#> # A tibble: 2 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 "na_locf(x)" 841µs 855.9µs 1130. 0B 0
#> 2 "vec_fill_missing(x, direction… 2.57ms 2.79ms 353. 11.4MB 203.
#> 1 "na_locf(x)" 841.8µs 877.6µs 1135. 0B 0
#> 2 "vec_fill_missing(x, direction… 2.61ms 2.82ms 336. 11.4MB 206.
```

All the `NA` handling functions in cheapr can make use of multiple cores
Expand All @@ -71,16 +71,16 @@ mark(num_na(x), sum(is.na(x)))
#> # A tibble: 2 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 num_na(x) 838µs 848.7µs 1149. 0B 0
#> 2 sum(is.na(x)) 974µs 1.07ms 917. 3.81MB 82.1
#> 1 num_na(x) 839µs 859.55µs 1159. 0B 0
#> 2 sum(is.na(x)) 954µs 1.07ms 900. 3.81MB 80.0
# 4 cores
options(cheapr.cores = 4)
mark(num_na(x), sum(is.na(x)))
#> # A tibble: 2 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 num_na(x) 239µs 300.1µs 3054. 0B 0
#> 2 sum(is.na(x)) 967µs 1.07ms 913. 3.81MB 83.5
#> 1 num_na(x) 234µs 296.1µs 3090. 0B 0
#> 2 sum(is.na(x)) 971µs 1.1ms 851. 3.81MB 74.9
```

## Efficient NA counts by row/col
Expand All @@ -93,16 +93,16 @@ mark(row_na_counts(m),
#> # A tibble: 2 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 row_na_counts(m) 1.3ms 3.14ms 331. 12.9KB 0
#> 2 rowSums(is.na(m)) 2.79ms 2.89ms 344. 3.82MB 34.4
#> 1 row_na_counts(m) 1.9ms 3.36ms 303. 12.9KB 0
#> 2 rowSums(is.na(m)) 2.79ms 2.87ms 345. 3.82MB 33.3
# Number of NA values by col
mark(col_na_counts(m),
colSums(is.na(m)))
#> # A tibble: 2 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 col_na_counts(m) 683.3µs 801.7µs 1253. 12.9KB 0
#> 2 colSums(is.na(m)) 1.97ms 2.07ms 480. 3.82MB 45.6
#> 1 col_na_counts(m) 680.1µs 808.95µs 1203. 12.9KB 0
#> 2 colSums(is.na(m)) 1.92ms 2.06ms 483. 3.82MB 46.6
```

`is_na` is a multi-threaded alternative to `is.na`
Expand All @@ -114,8 +114,8 @@ mark(is.na(x), is_na(x))
#> # A tibble: 2 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 is.na(x) 1.04ms 1.09ms 870. 3.81MB 131.
#> 2 is_na(x) 527.8µs 619.6µs 1565. 3.82MB 227.
#> 1 is.na(x) 1.05ms 1.12ms 834. 3.81MB 122.
#> 2 is_na(x) 570.7µs 694µs 1375. 3.82MB 195.

### posixlt method is much faster
hours <- as.POSIXlt(seq.int(0, length.out = 10^6, by = 3600),
Expand All @@ -126,8 +126,8 @@ mark(is.na(hours), is_na(hours))
#> # A tibble: 2 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 is.na(hours) 1.18s 1.18s 0.846 61MB 0
#> 2 is_na(hours) 5.2ms 5.84ms 171. 9.8MB 8.76
#> 1 is.na(hours) 1.17s 1.17s 0.852 61MB 0
#> 2 is_na(hours) 5.02ms 5.54ms 180. 9.8MB 8.69
```

It differs in 2 regards:
Expand Down Expand Up @@ -182,10 +182,10 @@ overview(df, hist = TRUE)
#>
#> ----- Numeric -----
#> col class n_missing p_complete n_unique mean p0 p25 p50 p75 p100 iqr
#> 1 x integer 0 1 100 50.5 1 25 50 75 100 50
#> 2 z numeric 0 1 10000000 0 -5.39 -0.67 0 0.67 5.23 1.35
#> 1 x integer 0 1 100 50.5 1 25 50 76 100 51
#> 2 z numeric 0 1 10000000 0 -5.17 -0.67 0 0.67 4.9 1.35
#> sd hist
#> 1 28.86 ▇▇▇▇▇
#> 1 28.87 ▇▇▇▇▇
#> 2 1 ▁▂▇▂▁
#>
#> ----- Categorical -----
Expand All @@ -197,7 +197,7 @@ mark(overview(df))
#> # A tibble: 1 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 overview(df) 903ms 903ms 1.11 76.3MB 1.11
#> 1 overview(df) 950ms 950ms 1.05 76.3MB 1.05
```

## Cheaper and consistent subsetting with `sset`
Expand Down Expand Up @@ -232,9 +232,9 @@ mark(sset(x, x %in_% y), sset(x, x %in% y), x[x %in% y])
#> # A tibble: 3 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 sset(x, x %in_% y) 95.2µs 115µs 8203. 88.3KB 2.06
#> 2 sset(x, x %in% y) 155.5µs 229µs 4281. 285.4KB 6.66
#> 3 x[x %in% y] 139.3µs 212µs 4428. 324.5KB 6.75
#> 1 sset(x, x %in_% y) 94.7µs 115µs 8359. 88.2KB 2.06
#> 2 sset(x, x %in% y) 173.5µs 219µs 4417. 285.3KB 6.70
#> 3 x[x %in% y] 143.9µs 199µs 4939. 324.5KB 6.75
```

`sset` uses an internal range-based subset when `i` is an ALTREP integer
Expand All @@ -245,8 +245,8 @@ mark(sset(df, 0:10^5), df[0:10^5, , drop = FALSE])
#> # A tibble: 2 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 sset(df, 0:10^5) 370.6µs 439.4µs 2190. 1.53MB 17.2
#> 2 df[0:10^5, , drop = FALSE] 6.77ms 7.08ms 138. 4.83MB 2.06
#> 1 sset(df, 0:10^5) 365.8µs 424.7µs 2296. 1.53MB 18.1
#> 2 df[0:10^5, , drop = FALSE] 6.5ms 6.97ms 143. 4.83MB 2.07
```

It also accepts negative indexes
Expand All @@ -260,8 +260,8 @@ mark(sset(df, -10^4:0),
#> # A tibble: 2 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 sset(df, -10^4:0) 21.7ms 27.2ms 33.0 152MB 19.4
#> 2 df[-10^4:0, , drop = FALSE] 562.7ms 562.7ms 1.78 776MB 5.33
#> 1 sset(df, -10^4:0) 20.7ms 28.4ms 25.9 152MB 17.9
#> 2 df[-10^4:0, , drop = FALSE] 575.1ms 575.1ms 1.74 776MB 8.69
```

The biggest difference between `sset` and `[` is the way logical vectors
Expand Down Expand Up @@ -308,13 +308,13 @@ mark(gcd(x))
#> # A tibble: 1 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 gcd(x) 1.2µs 1.3µs 687153. 0B 0
#> 1 gcd(x) 1.2µs 1.3µs 674577. 0B 0
x <- seq(0, 10^6, 0.5)
mark(gcd(x))
#> # A tibble: 1 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 gcd(x) 52.2ms 52.3ms 19.1 0B 0
#> 1 gcd(x) 52ms 52ms 19.2 0B 0
```

## Creating many sequences
Expand Down Expand Up @@ -403,41 +403,41 @@ mark(cheapr_which = which_(x),
#> # A tibble: 2 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 cheapr_which 2.56ms 2.76ms 347. 3.81MB 4.16
#> 2 base_which 1.15ms 1.23ms 770. 7.63MB 24.7
#> 1 cheapr_which 2.48ms 2.73ms 346. 3.81MB 2.07
#> 2 base_which 1.13ms 1.24ms 785. 7.63MB 12.4
x <- rep(FALSE, 10^6)
mark(cheapr_which = which_(x),
base_which = which(x))
#> # A tibble: 2 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 cheapr_which 208µs 271µs 3316. 0B 0
#> 2 base_which 456µs 472µs 2092. 3.81MB 33.6
#> 1 cheapr_which 215µs 273µs 3337. 0B 0
#> 2 base_which 457µs 470µs 2101. 3.81MB 17.6
x <- c(rep(TRUE, 5e05), rep(FALSE, 1e06))
mark(cheapr_which = which_(x),
base_which = which(x))
#> # A tibble: 2 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 cheapr_which 1.5ms 1.69ms 565. 1.91MB 4.16
#> 2 base_which 1.02ms 1.08ms 869. 7.63MB 28.6
#> 1 cheapr_which 1.48ms 1.67ms 579. 1.91MB 2.03
#> 2 base_which 1.02ms 1.09ms 891. 7.63MB 17.1
x <- c(rep(FALSE, 5e05), rep(TRUE, 1e06))
mark(cheapr_which = which_(x),
base_which = which(x))
#> # A tibble: 2 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 cheapr_which 3.43ms 3.52ms 279. 3.81MB 4.16
#> 2 base_which 1.37ms 1.48ms 616. 9.54MB 30.2
#> 1 cheapr_which 3.39ms 3.48ms 282. 3.81MB 2.06
#> 2 base_which 1.37ms 1.47ms 645. 9.54MB 14.8
x <- sample(c(TRUE, FALSE), 10^6, TRUE)
x[sample.int(10^6, 10^4)] <- NA
mark(cheapr_which = which_(x),
base_which = which(x))
#> # A tibble: 2 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 cheapr_which 2.16ms 2.27ms 432. 1.89MB 2.04
#> 2 base_which 3.33ms 3.38ms 293. 5.7MB 8.68
#> 1 cheapr_which 2.12ms 2.21ms 445. 1.89MB 0
#> 2 base_which 3.33ms 3.38ms 293. 5.71MB 4.25
```

### factor
Expand All @@ -451,31 +451,29 @@ mark(cheapr_factor = factor_(x),
#> # A tibble: 2 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 cheapr_factor 9.88ms 10.4ms 94.4 4.59MB 0
#> 2 base_factor 507.47ms 507.5ms 1.97 27.84MB 0
#> 1 cheapr_factor 10.4ms 11.2ms 89.7 4.59MB 0
#> 2 base_factor 505.5ms 505.5ms 1.98 27.84MB 0
mark(cheapr_factor = factor_(x, order = FALSE),
base_factor = factor(x, levels = unique(x)))
#> # A tibble: 2 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 cheapr_factor 5.55ms 5.93ms 167. 1.53MB 0
#> 2 base_factor 806.6ms 806.6ms 1.24 22.79MB 0
#> 1 cheapr_factor 5.55ms 5.87ms 169. 1.53MB 0
#> 2 base_factor 803.88ms 803.88ms 1.24 22.79MB 0
mark(cheapr_factor = factor_(y),
base_factor = factor(y))
#> Warning: Some expressions had a GC in every iteration; so filtering is
#> disabled.
#> # A tibble: 2 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 cheapr_factor 244.52ms 255.22ms 3.92 5.23MB 0
#> 2 base_factor 3.06s 3.06s 0.327 54.35MB 0.327
#> 1 cheapr_factor 201.34ms 203.28ms 4.91 5.23MB 0
#> 2 base_factor 2.81s 2.81s 0.355 54.35MB 0
mark(cheapr_factor = factor_(y, order = FALSE),
base_factor = factor(y, levels = unique(y)))
#> # A tibble: 2 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 cheapr_factor 7.77ms 8.17ms 123. 3.49MB 0
#> 2 base_factor 48.35ms 49.82ms 19.2 39.89MB 2.13
#> 1 cheapr_factor 7.55ms 8.04ms 123. 3.49MB 0
#> 2 base_factor 44.81ms 49.18ms 19.7 39.89MB 2.19
```

### intersect & setdiff
Expand All @@ -489,15 +487,15 @@ mark(cheapr_intersect = intersect_(x, y, dups = FALSE),
#> # A tibble: 2 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 cheapr_intersect 3.11ms 3.42ms 287. 1.18MB 0
#> 2 base_intersect 4.39ms 4.64ms 212. 5.16MB 2.18
#> 1 cheapr_intersect 3.17ms 3.37ms 293. 1.18MB 0
#> 2 base_intersect 4.43ms 4.62ms 212. 5.16MB 2.23
mark(cheapr_setdiff = setdiff_(x, y, dups = FALSE),
base_setdiff = setdiff(x, y))
#> # A tibble: 2 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 cheapr_setdiff 3.49ms 3.65ms 271. 1.76MB 0
#> 2 base_setdiff 4.78ms 4.97ms 197. 5.71MB 2.22
#> 1 cheapr_setdiff 3.49ms 3.64ms 272. 1.76MB 0
#> 2 base_setdiff 4.65ms 4.96ms 198. 5.71MB 2.25
```

### `%in_%` and `%!in_%`
Expand All @@ -508,15 +506,15 @@ mark(cheapr = x %in_% y,
#> # A tibble: 2 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 cheapr 1.99ms 2.06ms 477. 781.34KB 2.11
#> 2 base 2.68ms 2.81ms 352. 2.53MB 0
#> 1 cheapr 2ms 2.05ms 480. 781.34KB 0
#> 2 base 2.55ms 2.79ms 356. 2.53MB 2.22
mark(cheapr = x %!in_% y,
base = !x %in% y)
#> # A tibble: 2 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 cheapr 1.92ms 2.05ms 484. 787.85KB 2.19
#> 2 base 2.87ms 2.97ms 331. 2.91MB 0
#> 1 cheapr 1.92ms 2.06ms 479. 787.85KB 0
#> 2 base 2.87ms 2.97ms 333. 2.91MB 2.22
```

### cut.default
Expand All @@ -527,9 +525,11 @@ x <- rnorm(10^7)
b <- seq(0, max(x), 0.2)
mark(cheapr_cut = cut_numeric(x, b),
base_cut = cut(x, b))
#> Warning: Some expressions had a GC in every iteration; so filtering is
#> disabled.
#> # A tibble: 2 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 cheapr_cut 131ms 131ms 7.66 38.1MB 3.83
#> 2 base_cut 403ms 403ms 2.48 267.1MB 2.48
#> 1 cheapr_cut 131ms 131ms 7.62 38.1MB 0
#> 2 base_cut 442ms 485ms 2.06 267.1MB 2.06
```
4 changes: 2 additions & 2 deletions src/cheapr_cpp.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
#define OMP_NUM_PROCS omp_get_num_procs()
#define OMP_THREAD_LIMIT omp_get_thread_limit()
#define OMP_MAX_THREADS omp_get_max_threads()
#define OMP_PARALLEL _Pragma("omp parallel num_threads(n_cores) ")
#define OMP_FOR_SIMD _Pragma("omp for simd ")
#define OMP_PARALLEL _Pragma("omp parallel num_threads(n_cores) ")
#define OMP_FOR_SIMD _Pragma("omp for simd ")
#define OMP_PARALLEL_FOR_SIMD _Pragma("omp parallel for simd num_threads(n_cores) ")
// #if _OPENMP >= 201307
// #define OMP_VER_4
Expand Down
Loading

0 comments on commit a352621

Please sign in to comment.