Skip to content

Commit 67142e7

Browse files
authored
Merge pull request #26 from poncateam/tests_python
[experiment] Use Python to check runtimes using a similar (but much simpler logic) than atime
2 parents 14671ec + bfd4f1a commit 67142e7

7 files changed

Lines changed: 322 additions & 13 deletions

File tree

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
[submodule "src/external/ponca"]
22
path = src/external/ponca
33
url = https://github.com/poncateam/ponca.git
4+
[submodule "src/cpp/json"]
5+
path = src/cpp/json
6+
url = https://github.com/nlohmann/json.git

python/atimeClone.py

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
from git import Repo
2+
import shutil
3+
import os
4+
import json
5+
6+
repo = Repo("..")
7+
repoUrl = repo.remote().url
8+
buiddDir = "build/"
9+
10+
11+
sha= [ "PoncaV0x3"
12+
, "PoncaV1x0"
13+
, "PoncaV1x2"
14+
, "PoncaV1x3"
15+
, "PoncaV1x4"
16+
, "PoncaV2xalpha0"
17+
, "PoncaV2xalpha1"
18+
, "PoncaV2xalpha2"
19+
, "current"
20+
]
21+
22+
config_command = "cmake -B build -DCMAKE_BUILD_TYPE=Release src/ "
23+
build_command = "cmake --build build -j 4"
24+
run_command = "cd build && ./poncatime-test"
25+
26+
print("Processing repository ", repoUrl, " in ", buiddDir)
27+
28+
os.makedirs(buiddDir, exist_ok=True)
29+
30+
31+
32+
33+
34+
35+
36+
37+
38+
def prepareRepository(buildDir, s, copy_src, clone = False):
39+
targetDir = os.path.join(buildDir, s)
40+
41+
subRepo = None
42+
43+
if not os.path.isdir(targetDir):
44+
if clone:
45+
print("Clone repository")
46+
subRepo = Repo.clone_from(repoUrl, targetDir)
47+
else:
48+
if s != "current":
49+
print("Copy repository")
50+
shutil.copytree(os.path.join(copy_src, ".git"), os.path.join(targetDir,".git"), dirs_exist_ok=True)
51+
else:
52+
print("Wipe previous version of the current repository")
53+
shutil.rmtree(targetDir)
54+
55+
if subRepo is None:
56+
print("Init Git")
57+
subRepo = Repo(targetDir)
58+
59+
if s != "current":
60+
print("Switch active branch to ", s)
61+
subRepo.git.checkout(s, force=True)
62+
print("Update submodules")
63+
subRepo.git.submodule('update', '--init', '--recursive')
64+
else:
65+
print("Duplicating current version of the repository")
66+
shutil.copytree(os.path.join("..", "src"), os.path.join(buiddDir, s, "src"), ignore=shutil.ignore_patterns('*build*','*.o'))
67+
68+
69+
70+
for s in sha:
71+
jsonFile = os.path.join(buiddDir, s, "build", "run_output.json")
72+
if os.path.isfile(jsonFile):
73+
print ("json file found for", s, "... Skipping preparation" )
74+
else:
75+
print("**** REPOSITORY PREPARATION ****")
76+
prepareRepository(buiddDir, s, "..")
77+
78+
if s != "current":
79+
print("Overwrite folder `cpp` with current version")
80+
targetCPPDir = os.path.join(buiddDir, s, "src", "cpp")
81+
sourceCPPDir = os.path.join("..", "src", "cpp")
82+
shutil.rmtree(targetCPPDir)
83+
shutil.copytree(sourceCPPDir, targetCPPDir, ignore=shutil.ignore_patterns('*.git'))
84+
shutil.copy(os.path.join("..", "src", "CMakeLists.txt"), os.path.join(buiddDir, s, "src"))
85+
86+
87+
print("**** CONFIGURE ****")
88+
os.system("cd " + os.path.join(buiddDir, s) + " && " + config_command)
89+
print("**** BUILD ****")
90+
os.system("cd " + os.path.join(buiddDir, s) + " && " + build_command)
91+
92+
# json file used to store the results experiments
93+
resJson = {}
94+
95+
for s in sha:
96+
jsonFile = os.path.join(buiddDir, s, "build", "run_output.json")
97+
if os.path.isfile(jsonFile):
98+
print ("json file found for", s, "... Skipping run" )
99+
else:
100+
print("run ", os.path.join(buiddDir, s))
101+
status = os.system("cd " + os.path.join(buiddDir, s) + " && " + run_command)
102+
103+
with open(jsonFile, "r") as file:
104+
data = json.load(file)
105+
resJson[s] = data
106+
107+
with open("results.json", "w") as file:
108+
json.dump(resJson, file, indent=4)

python/plot.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import json
2+
from plotly.subplots import make_subplots
3+
import plotly.graph_objs as go
4+
import numpy as np
5+
import random
6+
7+
stepsKey = "steps"
8+
9+
jsonFile = "results.json"
10+
with open(jsonFile, "r") as file:
11+
data = json.load(file)
12+
13+
14+
testNames=[]
15+
colors=[]
16+
17+
first = next(iter(data))
18+
for name in data[first]:
19+
if name != stepsKey:
20+
testNames.append(name)
21+
22+
for sha in data:
23+
# Generate random R, G, B values
24+
r = random.randint(0, 255)
25+
g = random.randint(0, 255)
26+
b = random.randint(0, 255)
27+
colors.append(f"rgb({r}, {g}, {b})")
28+
29+
fig = make_subplots(rows=1, cols=len(testNames), subplot_titles=testNames)
30+
31+
i = 1
32+
for testName in testNames:
33+
j=0
34+
for sha in data:
35+
x = data[sha][stepsKey]
36+
x_rev = x[::-1]
37+
y = data[sha][testName]["mean"]
38+
39+
stdDev = np.sqrt(data[sha][testName]["var"])
40+
lowerBound = y - stdDev
41+
upperBound = y + stdDev
42+
43+
fig.add_trace(go.Scatter(x=x, y=y,
44+
name=sha,
45+
legendgroup=sha,
46+
line=dict(color=colors[j]),
47+
mode='lines',
48+
showlegend=i==1
49+
), row=1, col=i)
50+
# color_alpha = colors[j][:-1] + ", 0.2" + colors[j][-1]
51+
# fig.add_trace(go.Scatter(
52+
# x=x+x_rev,
53+
# y=upperBound+lowerBound,
54+
# fill='toself',
55+
# fillcolor=color_alpha,
56+
# line_color=colors[j],
57+
# name='Premium',
58+
# showlegend=False,
59+
# ))
60+
j=j+1
61+
i = i+1
62+
fig.update_layout(title_text="Side By Side Subplots")
63+
fig.update_xaxes(type="log")
64+
fig.update_yaxes(type="log")
65+
66+
fig.write_html("results.html")

python/requirements.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
2+
numpy
3+
plotly
4+
GitPython

src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,4 @@ endif()
2727
add_executable(poncatime-test cpp/main.cpp)
2828
target_link_libraries(poncatime-test PUBLIC poncatime)
2929
target_include_directories(poncatime-test PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
30+
target_include_directories(poncatime-test PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/cpp/json/include)

src/cpp/json

Submodule json added at d10879b

src/cpp/main.cpp

Lines changed: 139 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,154 @@
11
#include "curvatureEstimation.h"
22

3+
#include <fstream>
4+
#include "nlohmann/json.hpp"
5+
36
#include <iostream>
47

8+
using json = nlohmann::json;
9+
10+
struct TimeResult
11+
{
12+
float mean{0}; /// Mean time in msec
13+
float var{0}; /// Variance in msec
14+
};
15+
16+
17+
template<int nbRuns, typename PProcess, typename RProcessList>
18+
std::vector<TimeResult> mesureTime(PProcess prepare, RProcessList runList, const std::vector<std::string>& names)
19+
{
20+
std::vector<TimeResult> res;
21+
res.resize(names.size());
22+
23+
// collect measurements
24+
std::vector<std::array<int, nbRuns>> times;
25+
times.resize(names.size());
26+
27+
for (int i = 0; i != nbRuns; ++i)
28+
{
29+
prepare();
30+
int j = 0;
31+
for (auto run : runList)
32+
{
33+
auto start = std::chrono::steady_clock::now();
34+
run();
35+
auto end = std::chrono::steady_clock::now();
36+
std::chrono::duration<double, std::milli> elapsed = end - start;
37+
times[j][i] = elapsed.count();
38+
res[j].mean += times[j][i];
39+
++j;
40+
}
41+
}
42+
43+
int j = 0;
44+
for (const auto& name : names)
45+
{
46+
res[j].mean /= float(nbRuns);
47+
48+
// compute mean v
49+
for (int i = 0; i != nbRuns; ++i)
50+
{
51+
res[j].var += std::pow((times[j][i]-res[j].mean),2);
52+
}
53+
res[j].var /= float(nbRuns);
54+
++j;
55+
}
56+
57+
return res;
58+
}
59+
60+
std::vector<int>logScale(int start, double base, int nbElements = 10)
61+
{
62+
63+
std::vector<int> scale;
64+
scale.reserve(nbElements);
65+
double current = start;
66+
67+
// Generate the logarithmically spaced values
68+
std::generate_n(std::back_inserter(scale), nbElements, [&start, base, &current]() {
69+
int c (current);
70+
current *= base;
71+
return c;
72+
});
73+
return scale;
74+
}
75+
576
int main(int argc, char **argv)
677
{
7-
int nbPoints = 10000;
8-
int nbQueries = 100;
978
double dataScale = 10;
10-
double scale = dataScale / 5;
79+
double scale = dataScale / 10;
80+
81+
Eigen::MatrixXd points;
82+
Eigen::MatrixXd queries;
1183

12-
Eigen::MatrixXd points(nbPoints, 6);
13-
Eigen::MatrixXd queries(nbQueries, 3);
84+
int start = 500;
85+
double base = 1.9;
86+
int nbSteps = 10;
87+
auto values = logScale(start, base, nbSteps);
88+
89+
std::vector<std::string> names {
90+
"buildKdTree",
91+
"asoCurvatureEstimation",
92+
"planeFit"};
93+
std::vector<std::function<void(void)>> runs {
94+
[&points](){buildKdTree(points);},
95+
[&queries, scale](){int k; asoCurvatureEstimation(queries, scale, k);},
96+
[&queries, scale](){int k; planeFit(queries, scale, k);}
97+
};
98+
99+
json j;
100+
101+
// prepare json structure
102+
{
103+
std::vector<double>placeholder;
104+
placeholder.resize(nbSteps);
105+
for (const auto& name : names)
106+
{
107+
j[name]["mean"] = placeholder;
108+
j[name]["var"] = placeholder;
109+
}
110+
j["steps"] = values;
111+
}
14112

15-
generatePointClouds(points, queries, dataScale);
16-
if( !buildKdTree(points) )
113+
int stepId = 0;
114+
for (auto v : values)
17115
{
18-
return EXIT_FAILURE;
116+
std::cout << "Run test with nb points = " << v << std::endl;
117+
int n = v; // number of points
118+
int q = v/10; // number of queries
119+
120+
auto prepare = [&points, &queries, dataScale, n, q]()
121+
{
122+
points = Eigen::MatrixXd(n, 6);
123+
queries = Eigen::MatrixXd(q, 3);
124+
generatePointClouds(points, queries, dataScale);
125+
buildKdTree(points);
126+
};
127+
128+
auto res = mesureTime<10>(prepare, runs, names);
129+
130+
int index = 0;
131+
for (const auto& name : names)
132+
{
133+
j[name]["mean"][stepId] = res[index].mean;
134+
j[name]["var"][stepId] = res[index].var;
135+
++index;
136+
}
137+
138+
++stepId;
19139
}
20140

21-
int meanK;
22-
int ret = asoCurvatureEstimation(queries, scale, meanK);
23-
std::cout << "[ASO] Number of fits: " << ret << " (over " << nbQueries << " tries) with " << meanK << " neighbors in average" << std::endl;
24-
ret = planeFit(queries, scale, meanK);
25-
std::cout << "[PLANE] Number of fits: " << ret << " (over " << nbQueries << " tries) with " << meanK << " neighbors in average" << std::endl;
141+
// write prettified JSON
142+
std::ofstream o("run_output.json");
143+
o << std::setw(4) << j<< std::endl;
144+
o.close();
145+
146+
147+
148+
// int ret = asoCurvatureEstimation(queries, scale, meanK);
149+
// std::cout << "[ASO] Number of fits: " << ret << " (over " << nbQueries << " tries) with " << meanK << " neighbors in average" << std::endl;
150+
// ret = planeFit(queries, scale, meanK);
151+
// std::cout << "[PLANE] Number of fits: " << ret << " (over " << nbQueries << " tries) with " << meanK << " neighbors in average" << std::endl;
26152

27153
return EXIT_SUCCESS;
28154
}

0 commit comments

Comments
 (0)