Skip to content

Commit 2c338da

Browse files
authored
Merge pull request #30 from poncateam/pkg.edit.fun
try pkg.edit.fun
2 parents 67142e7 + 2880bfb commit 2c338da

36 files changed

Lines changed: 2443 additions & 51 deletions

.ci/atime/bisect-test.R

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
tinfo <- atime::atime_pkg_test_info("~/R/poncatime")
2+
(tcall <- tinfo$test.call$asoCurvatureEstimation)
3+
tcall$v2.0.alpha1 <- NULL
4+
tcall$sha.vec[["base=master"]] <- NULL
5+
tcall$seconds.limit <- 0.01
6+
tres <- eval(tcall)
7+
plot(tres)
8+
tref <- atime::references_best(tres)
9+
pred <- predict(tref)
10+
library(data.table)
11+
pred$prediction[, version := ifelse(grepl("HEAD", expr.name), "HEAD", expr.name)][]
12+
pwide <- dcast(pred$prediction, . ~ version, value.var="N")
13+
plong <- melt(pwide, measure.vars=c("v1.0","v1.4"))
14+
plong[, diff := abs(HEAD-value)][]
15+
(closer <- plong[which.min(diff), variable])
16+
(status <- ifelse(closer=="v1.0", 0, 1))
17+
q(status=status)
18+
## Note that the script (my_script in the above example) should exit with
19+
## code 0 if the current source code is good/old, and exit with a code
20+
## between 1 and 127 (inclusive), except 125, if the current source code
21+
## is bad/new.
22+
23+
pred$measurements[N==max(N)]
24+
# pred N=3800 at 0.1 is a good cutoff on my machine.
25+

.ci/atime/bisect-thresh.R

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
atime::atime_versions_remove("Poncatime")
2+
tinfo <- atime::atime_pkg_test_info("../..")
3+
(tcall <- tinfo$test.call$asoCurvatureEstimation)
4+
tres <- eval(tcall)
5+
tref <- atime::references_best(tres)
6+
pred <- predict(tref)
7+
pred
8+
pred$measurements[N==max(N)]
9+
# pred N=3800 at 0.1 is a good cutoff on my machine.
10+

.ci/atime/bisect.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
## git bisect old=equal perf, new=divergent.
2+
cd ../../src/external/ponca
3+
git bisect start
4+
git bisect old v1.0
5+
git bisect new v1.4
6+
git bisect run Rscript ~/R/poncatime/.ci/atime/bisect-test.R

.ci/atime/tests.R

Lines changed: 75 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,68 @@
11
remove.units <- "kilobytes"
2-
base.ref <- "main"
32
version.colors = c(
43
HEAD="#6EA358",
5-
"ponca v1.0" = "#FFD1C7",
6-
"ponca v1.2" = "#FFB5A3",
7-
"ponca v1.3" = "#FF9C85",
8-
"ponca v1.4" = "#FF7D5E",
9-
"ponca v2.alpha0" = "#C9DCFF",
10-
"ponca v2.alpha1" = "#A1C1FF",
11-
"ponca v2.alpha2" = "#82ABFF",
12-
"ponca v2.alpha3" = "#548CFF"
4+
"v1.0" = "#FFD1C7",
5+
"v1.2" = "#FFB5A3",
6+
"v1.3" = "#FF9C85",
7+
"v1.4" = "#FF7D5E",
8+
"v2.0.alpha0" = "#C9DCFF",
9+
"v2.0.alpha1" = "#A1C1FF",
10+
"v2.0.alpha2" = "#82ABFF",
11+
"v2.0.alpha3" = "#548CFF"
1312
)
1413

14+
edit_wrapper <- function(pkg.path){
15+
src.dir <- file.path(pkg.path, "src")
16+
h.vec <- Sys.glob(file.path(
17+
src.dir, "wrapper-versions", "*", "curvatureEstimation.h"))
18+
(version.dirs <- c("", dirname(h.vec)))
19+
for(vdir in version.dirs){
20+
cat(sprintf("Attempting to compile with wrapper=%s\n", vdir))
21+
if(vdir != ""){
22+
system(paste("cp", file.path(vdir, "*"), src.dir))
23+
}
24+
unlink(file.path(src.dir, "*o"))
25+
status.int <- atime:::R_CMD_INSTALL(pkg.path)
26+
if(status.int == 0)return(vdir)
27+
}
28+
}
29+
edit_poncatime <- function(old.Package, new.Package, sha, new.pkg.path){
30+
pkg_find_replace <- function(glob, FIND, REPLACE, warn=TRUE){
31+
glob_find_replace(file.path(new.pkg.path, glob), FIND, REPLACE, warn)
32+
}
33+
cat(sprintf("Attempting to find a wrapper for %s\n", sha))
34+
wrapper <- edit_wrapper(new.pkg.path)
35+
if(is.null(wrapper)){
36+
stop(sprintf("failed to find a wrapper which compiles for %s", sha))
37+
}else{
38+
cat(sprintf("wrapper=%s compiles for %s\n", wrapper, sha))
39+
}
40+
pkg_find_replace(
41+
"DESCRIPTION",
42+
paste0("Package:\\s+", old.Package),
43+
paste("Package:", new.Package))
44+
Package_ <- gsub(".", "_", old.Package, fixed=TRUE)
45+
sha_ <- gsub(".", "_", sha, fixed=TRUE)
46+
new.Package_ <- paste0(Package_, "_", sha_)
47+
pkg_find_replace(
48+
file.path("src", "RcppExports.cpp"),
49+
paste0("R_init_", Package_),
50+
paste0("R_init_", new.Package_))
51+
pkg_find_replace(
52+
file.path("R", "RcppExports.R"),
53+
sprintf("PACKAGE = '%s'", old.Package),
54+
sprintf("PACKAGE = '%s'", new.Package),
55+
warn=FALSE)#does not appear if registration used.
56+
pkg_find_replace(
57+
"NAMESPACE",
58+
sprintf('useDynLib\\("?%s"?', Package_),
59+
paste0('useDynLib(', new.Package))
60+
}
61+
1562
test.list <- atime::atime_test_list(
1663
seconds.limit=0.1,
17-
result=TRUE,
1864
N=10^seq(2, 6, by=0.5),
19-
buildKdTree=atime::atime_test(
20-
setup={
21-
N_points <- N
22-
N_queries <- 0
23-
dataScale <- 10
24-
N_list <- Poncatime:::generatePointClouds_interface(N_points, N_queries, dataScale)
25-
},
26-
expr=Poncatime:::buildKdTree_interface(N_list$points)
27-
),
65+
pkg.edit.fun=edit_poncatime,
2866
asoCurvatureEstimationK=atime::atime_test(
2967
setup={
3068
N_points <- N
@@ -64,16 +102,25 @@ test.list <- atime::atime_test_list(
64102
},
65103
setup.version=Poncatime:::buildKdTree_interface(N_list$points),
66104
expr=Poncatime:::planeFit_interface(N_list$queries, dataScale/5)
105+
),
106+
buildKdTree=atime::atime_test(
107+
setup={
108+
N_points <- N
109+
N_queries <- 0
110+
dataScale <- 10
111+
N_list <- Poncatime:::generatePointClouds_interface(N_points, N_queries, dataScale)
112+
},
113+
expr=Poncatime:::buildKdTree_interface(N_list$points)
67114
)
68115
)
69-
for(test.name in names(test.list)){
70-
# test.list[[test.name]][["ponca v0.3"]] <- "PoncaV0x3"
71-
test.list[[test.name]][["ponca v1.0"]] <- "PoncaV1x0"
72-
# test.list[[test.name]][["ponca v1.2"]] <- "PoncaV1x2"
73-
# test.list[[test.name]][["ponca v1.3"]] <- "PoncaV1x3"
74-
test.list[[test.name]][["ponca v1.4"]] <- "PoncaV1x4"
75-
test.list[[test.name]][["ponca v2.alpha0"]] <- "PoncaV2xalpha0"
76-
test.list[[test.name]][["ponca v2.alpha1"]] <- "PoncaV2xalpha1"
77-
test.list[[test.name]][["ponca v2.alpha2"]] <- "PoncaV2xalpha2"
116+
117+
## historical versions of ponca repo to run in each test.
118+
checkout.path.relative <- "src/external/ponca"
119+
ponca.versions <- c(
120+
"v1.0",
121+
"v1.4",
122+
"v2.0.alpha1")
123+
for(test.name in names(test.list))for(ponca.vers in ponca.versions){
124+
test.list[[test.name]][[ponca.vers]] <- ponca.vers
78125
}
79126

.github/workflows/atime.yml

Lines changed: 131 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,135 @@ on:
77
jobs:
88
comment:
99
runs-on: ubuntu-latest
10-
container: ghcr.io/iterative/cml:0-dvc2-base1
11-
env:
12-
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
13-
repo_token: ${{ secrets.GITHUB_TOKEN }}
1410
steps:
15-
- uses: tdhock/atime-ci-dev@main
11+
- name: Start timer
12+
run: echo "START_SETUP_TIME=$(date +%s)" >> $GITHUB_ENV
13+
shell: bash
14+
- name: Checkout
15+
uses: actions/checkout@v6
16+
with:
17+
fetch-depth: 0
18+
- name: Retrieve branch references, necessary for perf testing past versions
19+
shell: bash
20+
run: |
21+
git switch "${GITHUB_BASE_REF}"
22+
git switch "${GITHUB_HEAD_REF}"
23+
- uses: actions/setup-node@v6
24+
name: setup-node https://github.com/actions/setup-node?tab=readme-ov-file#usage
25+
- name: Safe directory exception
26+
run: |
27+
git config --global --add safe.directory '*'
28+
shell: bash
29+
- name: submodules
30+
run: |
31+
git submodule update --init --recursive
32+
cd src/external/ponca
33+
git checkout master
34+
shell: bash
35+
- name: Setup
36+
uses: eddelbuettel/github-actions/r-ci@master
37+
- name: Dependencies
38+
run: ./run.sh install_all
39+
- name: Install and run atime@poncatime
40+
run: |
41+
echo "options(repos = c(CRAN = 'https://cloud.r-project.org'))" >> .Rprofile
42+
Rscript -e 'install.packages(c("atime", "pak", "ggplot2", "directlabels"))'
43+
Rscript -e 'pak::pkg_install("tdhock/atime@poncatime")'
44+
echo "END_SETUP_START_TESTS_TIME=$(date +%s)" >> $GITHUB_ENV
45+
Rscript -e 'atime::atime_pkg(Sys.getenv("GITHUB_WORKSPACE"), tests.dir = ".ci");'
46+
echo "END_TESTS_TIME=$(date +%s)" >> $GITHUB_ENV
47+
shell: bash
48+
49+
- name: Upload artifact
50+
id: artifact-upload-step
51+
uses: actions/upload-artifact@v4
52+
with:
53+
name: atime-results
54+
path: .ci/atime/
55+
56+
- name: comments.json
57+
if: ${{ github.event_name == 'pull_request' }}
58+
env:
59+
PR_NUMBER: ${{ github.event.number }}
60+
TAG: atime
61+
shell: bash
62+
run: |
63+
curl --no-progress-meter -L -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2026-03-10" https://api.github.com/repos/$GITHUB_REPOSITORY/issues/$PR_NUMBER/comments > comments.json
64+
cat comments.json
65+
echo > comment-number.txt
66+
echo "<!-- automatic comment for $TAG -->" > comment.md
67+
cat comment.md
68+
- name: comment-number.txt
69+
if: ${{ github.event_name == 'pull_request' }}
70+
shell: node {0}
71+
run: |
72+
fs = require('fs');
73+
tag = fs.readFileSync('comment.md', 'utf-8');
74+
console.log(tag);
75+
content = fs.readFileSync('comments.json', 'utf-8');
76+
console.log(content);
77+
prc = JSON.parse(content);
78+
flist = prc.filter((o) => { return o.body.startsWith(tag); });
79+
if(flist.length == 0) process.exit(0);
80+
fs.writeFileSync('comment-number.txt', flist[0].id+"");
81+
- name: add images
82+
shell: bash
83+
run: |
84+
uploadImage() {
85+
local png=$1
86+
curl -F "file=@$png" -F "visibility=unlisted" https://picrd.com/api/upload | sed 's/.*image_url":"//' | sed 's/",".*//'
87+
}
88+
PREVIEW_URL=$(uploadImage .ci/atime/tests_preview_facet.png)
89+
ALL_URL=$(uploadImage .ci/atime/tests_all_facet.png)
90+
echo $PREVIEW_URL $ALL_URL
91+
cat .ci/atime/HEAD_issues.md >> comment.md
92+
echo -e "\n[![Comparison Plot]($PREVIEW_URL)]($ALL_URL)" >> comment.md
93+
echo -e "\nGenerated via commit ${{ github.event.pull_request.head.sha }}" >> comment.md
94+
echo -e "\nDownload link for the artifact containing the test results: [↓ atime-results.zip](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}/artifacts/${{ steps.artifact-upload-step.outputs.artifact-id }})" >> comment.md
95+
96+
- name: add content to comment.md
97+
run: |
98+
R_SETUP_DURATION=$((END_SETUP_START_TESTS_TIME - START_SETUP_TIME))
99+
VERSION_SETUP_DURATION=$(cut -d '.' -f 1 ./.ci/atime/install_seconds.txt)
100+
ATIME_TESTS_DURATION=$((END_TESTS_TIME - END_SETUP_START_TESTS_TIME - VERSION_SETUP_DURATION))
101+
102+
formatTime() {
103+
local totalSeconds=$1
104+
if [ $totalSeconds -lt 0 ]; then
105+
echo "Time calculation error: negative duration"
106+
return
107+
fi
108+
if [ $totalSeconds -lt 60 ]; then
109+
echo "${totalSeconds} seconds"
110+
else
111+
local minutes=$((totalSeconds / 60))
112+
local seconds=$((totalSeconds % 60))
113+
echo "${minutes} minutes and ${seconds} seconds"
114+
fi
115+
}
116+
117+
echo -e "\n| Task | Duration |" >> comment.md
118+
echo -e "|---|---|" >> comment.md
119+
echo -e "| R setup and installing dependencies | $(formatTime $R_SETUP_DURATION) |" >> comment.md
120+
echo -e "| Installing different package versions | $(formatTime $VERSION_SETUP_DURATION) |" >> comment.md
121+
echo -e "| Running and plotting the test cases | $(formatTime $ATIME_TESTS_DURATION) |" >> comment.md
122+
- name: post diff in comment
123+
if: ${{ github.event_name == 'pull_request' }}
124+
env:
125+
PR_COMMENT_TOKEN: ${{ secrets.GITHUB_TOKEN }}
126+
PR_NUMBER: ${{ github.event.number }}
127+
shell: bash
128+
run: |
129+
ISSUES_API=https://api.github.com/repos/$GITHUB_REPOSITORY/issues
130+
PR_API=$ISSUES_API/$PR_NUMBER/comments
131+
VERSION=2026-03-10
132+
ACCEPT=application/vnd.github+json
133+
COMMENT_NUMBER=$(cat comment-number.txt)
134+
if [ "$COMMENT_NUMBER" == "" ]; then CMD=$PR_API; else CMD=$ISSUES_API/comments/$COMMENT_NUMBER; fi; echo $CMD
135+
cat comment.md
136+
MD=$(sed 's/"/\\"/g' comment.md | awk '$1=$1' ORS='\\n')
137+
echo '{"body":"'$MD'"}' > pr-comment.json
138+
cat pr-comment.json
139+
curl --no-progress-meter -L -H "Accept: $ACCEPT" -H "X-GitHub-Api-Version: $VERSION" -X POST -H "Authorization: Bearer $PR_COMMENT_TOKEN" $CMD -d "@pr-comment.json"
140+
141+

.github/workflows/build-docs.yaml

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,27 @@ name: Build docs
1111
jobs:
1212
litedown:
1313
runs-on: ubuntu-latest
14-
env:
15-
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
1614
steps:
17-
- uses: actions/checkout@v3
18-
- uses: r-lib/actions/setup-r@v2
19-
- uses: r-lib/actions/setup-r-dependencies@v2
20-
- name: Install package
21-
run: git submodule update --init --recursive && Rscript -e 'install.packages("remotes")' && Rscript -e 'remotes::install_github("tdhock/atime@poncatime")' && R CMD build . && R CMD INSTALL *.tar.gz
22-
- name: Fuse site
23-
run: R -e 'litedown::fuse_site("site")'
15+
- uses: actions/checkout@v6
16+
with:
17+
fetch-depth: 0
18+
- name: Setup
19+
uses: eddelbuettel/github-actions/r-ci@master
20+
- name: Dependencies
21+
run: ./run.sh install_all
22+
- name: install package and build site
23+
run: |
24+
git submodule update --init --recursive
25+
Rscript -e 'install.packages("pak")'
26+
Rscript -e 'pak::pkg_install("tdhock/atime@poncatime")'
27+
R CMD build .
28+
R CMD INSTALL *.tar.gz
29+
R -e 'litedown::fuse_site("site")'
30+
shell: bash
2431
- name: netlify deploy
25-
uses: animint/animint-actions/netlify-deploy-comment@main
32+
uses: animint/animint-actions/netlify-litedown@main
2633
with:
2734
netlify_auth_token: ${{ secrets.NETLIFY_AUTH_TOKEN }}
2835
netlify_site_id: ${{ secrets.NETLIFY_SITE_ID }}
29-
pat_github_pr: ${{ secrets.PAT_GITHUB_PR }}
3036
path: site
31-
netlify_url: poncatime.netlify.app
37+
pr_comment_token: ${{ secrets.GITHUB_TOKEN }}

DESCRIPTION

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Package: Poncatime
22
Type: Package
33
Title: Performance analysis of Ponca library using ATime
4-
Version: 0.0.1
4+
Version: 2026.6.15
55
Authors@R: c(
66
person(given = "Nicolas",
77
family = "Mellado",
@@ -19,11 +19,11 @@ LinkingTo:
1919
Imports:
2020
Rcpp,
2121
RcppEigen
22-
SystemRequirements: CMake
22+
SystemRequirements: CMake, C++20
2323
Encoding: UTF-8
2424
License: MIT + file LICENSE
2525
VignetteBuilder: litedown
2626
Suggests:
2727
testthat,
2828
litedown,
29-
ggplot2, directlabels
29+
ggplot2, directlabels

NEWS.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Changes in version 2026.6.15 (PR#30)
2+
3+
- New custom `pkg.edit.fun` which works to compile arbitrary historical ponca versions, thus enabling git bisect to find the first commit with a performance regression. See `.ci/atime/bisect.sh` for an example.
4+

src/Makevars

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1+
CXX_STD = CXX20
12
PKG_CPPFLAGS += -Iexternal/ponca/ -Iexternal/ponca/external/eigen/
23

src/interface.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ Rcpp::DataFrame asoCurvatureEstimation_interface
3333
Rcpp::Named("meanNeiSize", meanNeiSize));
3434
}
3535

36-
3736
// [[Rcpp::export]]
3837
Rcpp::DataFrame asoCurvatureEstimationK_interface
3938
(const Eigen::MatrixXd& queries,
@@ -47,7 +46,7 @@ Rcpp::DataFrame asoCurvatureEstimationK_interface
4746
}
4847

4948
// [[Rcpp::export]]
50-
Rcpp::DataFrame planeFit_interface
49+
Rcpp::DataFrame planeFit_interface
5150
(const Eigen::MatrixXd& queries,
5251
const double scale
5352
){

0 commit comments

Comments
 (0)