Skip to content

Commit 032603b

Browse files
Simplify coroutine demo README section
1 parent 0c10424 commit 032603b

4 files changed

Lines changed: 55 additions & 66 deletions

File tree

README.Rmd

Lines changed: 11 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -765,31 +765,21 @@ tcc_callback_close(cb)
765765

766766
### Stackful C coroutines: streaming BCF/VCF records with htslib
767767

768-
A more experimental pattern is to use Rtinycc as a JIT compiler for native
769-
iterators that keep their own C stack between calls from R. The script
770-
[`scripts/demo-streaming-bcf-reader-ffi.R`](scripts/demo-streaming-bcf-reader-ffi.R)
771-
combines the stackful `ucontext` coroutine pattern from
772-
[`scripts/demo-stackful-coroutine-ffi.R`](scripts/demo-stackful-coroutine-ffi.R)
773-
with [htslib](https://www.htslib.org/) to make a streaming BCF/VCF reader.
774-
Each call from R resumes the native reader until the next `bcf1_t` record is
775-
available, yields back to R, and then lets R copy the current record into a
776-
regular list.
777-
778-
The important safety rule is that the alternate coroutine stack does not call
779-
R's C API. htslib owns the file/header/record state, the coroutine only yields
780-
status codes, and R objects are created after control has returned to the normal
781-
R call stack.
782-
783-
The README runs the demo when htslib is available on the build machine. The
784-
example input is plain VCF text because htslib can stream VCF and BCF through
785-
the same API; no `bcftools` conversion step is needed.
768+
Rtinycc can JIT-compile native iterators that keep their own C stack between R
769+
calls. This demo binds [htslib](https://www.htslib.org/) through a `ucontext`
770+
coroutine: R resumes the reader until the next `bcf1_t`, then copies the current
771+
fields into a regular list. The coroutine stack never calls R's C API; R
772+
objects are created only after control returns to the normal R stack.
773+
774+
The demo uses plain VCF text, opened directly by htslib through the same API as
775+
BCF.
786776

787777
```{r ffi-bcf-coroutine-run, eval=.Platform$OS.type != "windows" && nzchar(Sys.which("pkg-config")) && system2("pkg-config", c("--exists", "htslib")) == 0L}
788-
cat(system2(R.home("bin/Rscript"), "scripts/demo-streaming-bcf-reader-ffi.R", stdout = TRUE), sep = "\n")
778+
source("scripts/demo-streaming-bcf-reader-ffi.R")
779+
run_streaming_bcf_demo()
789780
```
790781

791-
The README also displays the actual demo source below, rather than a shortened
792-
pseudo-example. The full R script is foldable so the page stays readable.
782+
The full demo source is foldable below.
793783

794784
<details>
795785
<summary>Click to show the complete <code>scripts/demo-streaming-bcf-reader-ffi.R</code> script</summary>

README.md

Lines changed: 38 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ tcc_read_cstring(ptr)
178178
tcc_read_bytes(ptr, 5)
179179
#> [1] 68 65 6c 6c 6f
180180
tcc_ptr_addr(ptr, hex = TRUE)
181-
#> [1] "0x5dafff18bed0"
181+
#> [1] "0x57e1a27400f0"
182182
tcc_ptr_is_null(ptr)
183183
#> [1] FALSE
184184
tcc_free(ptr)
@@ -209,11 +209,11 @@ through output parameters.
209209
ptr_ref <- tcc_malloc(.Machine$sizeof.pointer %||% 8L)
210210
target <- tcc_malloc(8)
211211
tcc_ptr_set(ptr_ref, target)
212-
#> <pointer: 0x5dafff262a50>
212+
#> <pointer: 0x57e19ec62480>
213213
tcc_data_ptr(ptr_ref)
214-
#> <pointer: 0x5db00198a030>
214+
#> <pointer: 0x57e19e05f410>
215215
tcc_ptr_set(ptr_ref, tcc_null_ptr())
216-
#> <pointer: 0x5dafff262a50>
216+
#> <pointer: 0x57e19ec62480>
217217
tcc_free(target)
218218
#> NULL
219219
tcc_free(ptr_ref)
@@ -441,7 +441,7 @@ ffi <- tcc_ffi() |>
441441

442442
x <- as.integer(1:100) # to avoid ALTREP
443443
.Internal(inspect(x))
444-
#> @5db002c5b160 13 INTSXP g0c0 [REF(65535)] 1 : 100 (compact)
444+
#> @57e1a0611640 13 INTSXP g0c0 [REF(65535)] 1 : 100 (compact)
445445
ffi$sum_array(x, length(x))
446446
#> [1] 5050
447447

@@ -457,7 +457,7 @@ y[1]
457457
#> [1] 11
458458

459459
.Internal(inspect(x))
460-
#> @5db002c5b160 13 INTSXP g0c0 [REF(65535)] 11 : 110 (expanded)
460+
#> @57e1a0611640 13 INTSXP g0c0 [REF(65535)] 11 : 110 (expanded)
461461
```
462462

463463
## Advanced FFI features
@@ -484,15 +484,15 @@ ffi <- tcc_ffi() |>
484484

485485
p1 <- ffi$struct_point_new()
486486
ffi$struct_point_set_x(p1, 0.0)
487-
#> <pointer: 0x5db001d8b2f0>
487+
#> <pointer: 0x57e19ff258d0>
488488
ffi$struct_point_set_y(p1, 0.0)
489-
#> <pointer: 0x5db001d8b2f0>
489+
#> <pointer: 0x57e19ff258d0>
490490

491491
p2 <- ffi$struct_point_new()
492492
ffi$struct_point_set_x(p2, 3.0)
493-
#> <pointer: 0x5db0024ee190>
493+
#> <pointer: 0x57e19e089190>
494494
ffi$struct_point_set_y(p2, 4.0)
495-
#> <pointer: 0x5db0024ee190>
495+
#> <pointer: 0x57e19e089190>
496496

497497
ffi$distance(p1, p2)
498498
#> [1] 5
@@ -537,9 +537,9 @@ ffi <- tcc_ffi() |>
537537

538538
s <- ffi$struct_flags_new()
539539
ffi$struct_flags_set_active(s, 1L)
540-
#> <pointer: 0x5dafffa48a90>
540+
#> <pointer: 0x57e19d142ee0>
541541
ffi$struct_flags_set_level(s, 9L)
542-
#> <pointer: 0x5dafffa48a90>
542+
#> <pointer: 0x57e19d142ee0>
543543
ffi$struct_flags_get_active(s)
544544
#> [1] 1
545545
ffi$struct_flags_get_level(s)
@@ -890,28 +890,19 @@ tcc_callback_close(cb)
890890

891891
### Stackful C coroutines: streaming BCF/VCF records with htslib
892892

893-
A more experimental pattern is to use Rtinycc as a JIT compiler for
894-
native iterators that keep their own C stack between calls from R. The
895-
script
896-
[`scripts/demo-streaming-bcf-reader-ffi.R`](scripts/demo-streaming-bcf-reader-ffi.R)
897-
combines the stackful `ucontext` coroutine pattern from
898-
[`scripts/demo-stackful-coroutine-ffi.R`](scripts/demo-stackful-coroutine-ffi.R)
899-
with [htslib](https://www.htslib.org/) to make a streaming BCF/VCF
900-
reader. Each call from R resumes the native reader until the next
901-
`bcf1_t` record is available, yields back to R, and then lets R copy the
902-
current record into a regular list.
903-
904-
The important safety rule is that the alternate coroutine stack does not
905-
call R’s C API. htslib owns the file/header/record state, the coroutine
906-
only yields status codes, and R objects are created after control has
907-
returned to the normal R call stack.
908-
909-
The README runs the demo when htslib is available on the build machine.
910-
The example input is plain VCF text because htslib can stream VCF and
911-
BCF through the same API; no `bcftools` conversion step is needed.
893+
Rtinycc can JIT-compile native iterators that keep their own C stack
894+
between R calls. This demo binds [htslib](https://www.htslib.org/)
895+
through a `ucontext` coroutine: R resumes the reader until the next
896+
`bcf1_t`, then copies the current fields into a regular list. The
897+
coroutine stack never calls R’s C API; R objects are created only after
898+
control returns to the normal R stack.
899+
900+
The demo uses plain VCF text, opened directly by htslib through the same
901+
API as BCF.
912902

913903
``` r
914-
cat(system2(R.home("bin/Rscript"), "scripts/demo-streaming-bcf-reader-ffi.R", stdout = TRUE), sep = "\n")
904+
source("scripts/demo-streaming-bcf-reader-ffi.R")
905+
run_streaming_bcf_demo()
915906
#> Rtinycc version: 0.1.10
916907
#> Demo: stackful coroutine + htslib BCF/VCF API streaming reader
917908
#> Note: htslib reads run on the alternate coroutine stack; R objects are built only after each yield.
@@ -926,9 +917,7 @@ cat(system2(R.home("bin/Rscript"), "scripts/demo-streaming-bcf-reader-ffi.R", st
926917
#> done_after_collect=TRUE
927918
```
928919

929-
The README also displays the actual demo source below, rather than a
930-
shortened pseudo-example. The full R script is foldable so the page
931-
stays readable.
920+
The full demo source is foldable below.
932921

933922
<details>
934923
<summary>
@@ -1384,7 +1373,7 @@ make_demo_vcf <- function() {
13841373
vcf
13851374
}
13861375

1387-
if (identical(sys.nframe(), 0L)) {
1376+
run_streaming_bcf_demo <- function() {
13881377
say("Rtinycc version: ", as.character(utils::packageVersion("Rtinycc")))
13891378
say("Demo: stackful coroutine + htslib BCF/VCF API streaming reader")
13901379
say("Note: htslib reads run on the alternate coroutine stack; R objects are built only after each yield.")
@@ -1419,6 +1408,11 @@ if (identical(sys.nframe(), 0L)) {
14191408
}
14201409

14211410
say("done_after_collect=", isTRUE(ffi$bcf_stream_done(reader$ptr)))
1411+
invisible(NULL)
1412+
}
1413+
1414+
if (identical(sys.nframe(), 0L)) {
1415+
run_streaming_bcf_demo()
14221416
}
14231417
```
14241418

@@ -1774,7 +1768,7 @@ ffi <- tcc_ffi() |>
17741768
tcc_compile()
17751769
17761770
ffi$struct_point_new()
1777-
#> <pointer: 0x5db00115f320>
1771+
#> <pointer: 0x57e19cff8f30>
17781772
ffi$enum_status_OK()
17791773
#> [1] 0
17801774
ffi$global_global_counter_get()
@@ -1891,11 +1885,11 @@ if (Sys.info()[["sysname"]] == "Linux") {
18911885
#> # A tibble: 5 × 13
18921886
#> expression min median `itr/sec` mem_alloc `gc/sec` n_itr n_gc total_time
18931887
#> <bch:expr> <bch:t> <bch:t> <dbl> <bch:byt> <dbl> <int> <dbl> <bch:tm>
1894-
#> 1 read_tabl… 52.26ms 52.26ms 19.1 6.33MB 19.1 1 1 52.3ms
1895-
#> 2 vroom_df_… 6.41ms 6.56ms 152. 1.22MB 0 2 0 13.1ms
1896-
#> 3 vroom_df_… 6.51ms 6.61ms 151. 2.44MB 0 2 0 13.2ms
1897-
#> 4 c_read_df 21.07ms 21.16ms 47.2 1.22MB 0 2 0 42.3ms
1898-
#> 5 io_uring_… 20.18ms 20.66ms 48.4 1.22MB 0 2 0 41.3ms
1888+
#> 1 read_tabl… 49.73ms 49.73ms 20.1 6.33MB 20.1 1 1 49.7ms
1889+
#> 2 vroom_df_… 6.38ms 6.74ms 148. 1.22MB 0 2 0 13.5ms
1890+
#> 3 vroom_df_… 6.58ms 6.92ms 145. 2.44MB 0 2 0 13.8ms
1891+
#> 4 c_read_df 21.05ms 21.06ms 47.5 1.22MB 0 2 0 42.1ms
1892+
#> 5 io_uring_… 19.92ms 19.92ms 50.2 1.22MB 0 2 0 39.8ms
18991893
#> # ℹ 4 more variables: result <list>, memory <list>, time <list>, gc <list>
19001894
```
19011895

@@ -1997,9 +1991,9 @@ ffi <- tcc_ffi() |>
19971991

19981992
b <- ffi$struct_buf_new()
19991993
ffi$struct_buf_set_data_elt(b, 0L, 0xCAL)
2000-
#> <pointer: 0x5db00ab77c60>
1994+
#> <pointer: 0x57e1a847e840>
20011995
ffi$struct_buf_set_data_elt(b, 1L, 0xFEL)
2002-
#> <pointer: 0x5db00ab77c60>
1996+
#> <pointer: 0x57e1a847e840>
20031997
ffi$struct_buf_get_data_elt(b, 0L)
20041998
#> [1] 202
20051999
ffi$struct_buf_get_data_elt(b, 1L)
753 Bytes
Loading

scripts/demo-streaming-bcf-reader-ffi.R

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -445,7 +445,7 @@ make_demo_vcf <- function() {
445445
vcf
446446
}
447447

448-
if (identical(sys.nframe(), 0L)) {
448+
run_streaming_bcf_demo <- function() {
449449
say("Rtinycc version: ", as.character(utils::packageVersion("Rtinycc")))
450450
say("Demo: stackful coroutine + htslib BCF/VCF API streaming reader")
451451
say("Note: htslib reads run on the alternate coroutine stack; R objects are built only after each yield.")
@@ -480,4 +480,9 @@ if (identical(sys.nframe(), 0L)) {
480480
}
481481

482482
say("done_after_collect=", isTRUE(ffi$bcf_stream_done(reader$ptr)))
483+
invisible(NULL)
484+
}
485+
486+
if (identical(sys.nframe(), 0L)) {
487+
run_streaming_bcf_demo()
483488
}

0 commit comments

Comments
 (0)