Skip to content

Commit 47713e1

Browse files
committed
add a an timing parameter to enable logtiming option in Pipeline invocations
1 parent 27a1560 commit 47713e1

8 files changed

Lines changed: 65 additions & 11 deletions

File tree

‎README.rst‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ sorts it by the ``X`` dimension:
7373
metadata = pipeline.metadata
7474
log = pipeline.log
7575
76+
Pass ``timing=True`` when creating a pipeline to include PDAL timing
77+
information in ``pipeline.log`` after execution.
78+
7679
Programmatic Pipeline Construction
7780
................................................................................
7881

‎src/pdal/PyPipeline.cpp‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,12 @@ void CountPointTable::reset()
5656

5757

5858
PipelineExecutor::PipelineExecutor(
59-
std::string const& json, std::vector<std::shared_ptr<Array>> arrays, int level)
59+
std::string const& json, std::vector<std::shared_ptr<Array>> arrays, int level, bool timing)
6060
{
6161
if (level < 0 || level > 8)
6262
throw pdal_error("log level must be between 0 and 8!");
6363

64-
LogPtr log(Log::makeLog("pypipeline", &m_logStream));
64+
LogPtr log(Log::makeLog("pypipeline", &m_logStream, timing));
6565
log->setLevel(static_cast<pdal::LogLevel>(level));
6666
m_manager.setLog(log);
6767

‎src/pdal/PyPipeline.hpp‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ class Array;
5858

5959
class PDAL_EXPORT PipelineExecutor {
6060
public:
61-
PipelineExecutor(std::string const& json, std::vector<std::shared_ptr<Array>> arrays, int level);
61+
PipelineExecutor(std::string const& json, std::vector<std::shared_ptr<Array>> arrays, int level, bool timing);
6262
virtual ~PipelineExecutor() = default;
6363

6464
point_count_t execute(pdal::StringList allowedDims);

‎src/pdal/StreamableExecutor.cpp‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,10 +186,11 @@ char *PythonPointTable::getPoint(PointId idx)
186186
StreamableExecutor::StreamableExecutor(std::string const& json,
187187
std::vector<std::shared_ptr<Array>> arrays,
188188
int level,
189+
bool timing,
189190
point_count_t chunkSize,
190191
int prefetch,
191192
pdal::StringList allowedDims)
192-
: PipelineExecutor(json, arrays, level)
193+
: PipelineExecutor(json, arrays, level, timing)
193194
, m_table(chunkSize, prefetch)
194195
, m_exc(nullptr)
195196
{

‎src/pdal/StreamableExecutor.hpp‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ class StreamableExecutor : public PipelineExecutor
8080
StreamableExecutor(std::string const& json,
8181
std::vector<std::shared_ptr<Array>> arrays,
8282
int level,
83+
bool timing,
8384
point_count_t chunkSize,
8485
int prefetch,
8586
pdal::StringList allowedDim);

‎src/pdal/libpdalpython.cpp‎

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ namespace pdal {
186186

187187
std::unique_ptr<PipelineIterator> iterator(int chunk_size, int prefetch, pdal::StringList allowedDims) {
188188
return std::unique_ptr<PipelineIterator>(new PipelineIterator(
189-
getJson(), _inputs, _loglevel, chunk_size, prefetch, allowedDims
189+
getJson(), _inputs, _loglevel, _timing, chunk_size, prefetch, allowedDims
190190
));
191191
}
192192

@@ -214,6 +214,10 @@ namespace pdal {
214214

215215
void setLogLevel(int level) { _loglevel = level; delExecutor(); }
216216

217+
bool getTiming() { return _timing; }
218+
219+
void setTiming(bool timing) { _timing = timing; delExecutor(); }
220+
217221
std::string getLog() { return getExecutor()->getLog(); }
218222

219223
std::string getPipeline() { return getExecutor()->getPipeline(); }
@@ -291,14 +295,15 @@ namespace pdal {
291295
// does for all of the other methods it knows about
292296
py::gil_scoped_acquire acquire;
293297
if (!_executor)
294-
_executor.reset(new PipelineExecutor(getJson(), _inputs, _loglevel));
298+
_executor.reset(new PipelineExecutor(getJson(), _inputs, _loglevel, _timing));
295299
return _executor.get();
296300
}
297301

298302
private:
299303
std::unique_ptr<PipelineExecutor> _executor;
300304
std::vector<std::shared_ptr<pdal::python::Array>> _inputs;
301-
int _loglevel;
305+
int _loglevel = 0;
306+
bool _timing = false;
302307
};
303308

304309

@@ -324,6 +329,7 @@ namespace pdal {
324329
.def("iterator", &Pipeline::iterator, "chunk_size"_a=10000, "prefetch"_a=0, py::arg("allowed_dims") =py::list())
325330
.def_property("inputs", nullptr, &Pipeline::setInputs)
326331
.def_property("loglevel", &Pipeline::getLoglevel, &Pipeline::setLogLevel)
332+
.def_property("timing", &Pipeline::getTiming, &Pipeline::setTiming)
327333
.def_property_readonly("log", &Pipeline::getLog)
328334
.def_property_readonly("schema", &Pipeline::getSchema)
329335
.def_property_readonly("srswkt2", &Pipeline::getSrsWKT2)

‎src/pdal/pipeline.py‎

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ def __init__(
4949
json: Optional[str] = None,
5050
dataframes: Sequence[DataFrame] = (),
5151
stream_handlers: Sequence[Callable[[], int]] = (),
52+
*,
53+
timing: bool = False,
5254
):
5355

5456
if json:
@@ -75,6 +77,7 @@ def __init__(
7577
self.inputs = [(a, None) for a in arrays]
7678

7779
self.loglevel = loglevel
80+
self.timing = timing
7881

7982
def __getstate__(self):
8083
state = self.pipeline
@@ -104,6 +107,14 @@ def loglevel(self, value: int) -> None:
104107
# super() property setter is not supported
105108
libpdalpython.Pipeline.loglevel.__set__(self, loglevel)
106109

110+
@property
111+
def timing(self) -> bool:
112+
return super().timing
113+
114+
@timing.setter
115+
def timing(self, value: bool) -> None:
116+
libpdalpython.Pipeline.timing.__set__(self, bool(value))
117+
107118
def __ior__(self, other: Union[Stage, Pipeline]) -> Pipeline:
108119
if isinstance(other, Stage):
109120
self._stages.append(other)
@@ -124,7 +135,7 @@ def __or__(self, other: Union[Stage, Pipeline]) -> Pipeline:
124135
return new
125136

126137
def __copy__(self) -> Pipeline:
127-
clone = self.__class__(loglevel=self.loglevel)
138+
clone = self.__class__(loglevel=self.loglevel, timing=self.timing)
128139
clone._copy_inputs(self)
129140
clone |= self
130141
return clone
@@ -214,8 +225,13 @@ def inputs(self) -> List[Union[Stage, str]]:
214225
def options(self) -> Dict[str, Any]:
215226
return dict(self._options)
216227

217-
def pipeline(self, *arrays: np.ndarray, loglevel: int = logging.ERROR) -> Pipeline:
218-
return Pipeline((self,), arrays, loglevel)
228+
def pipeline(
229+
self,
230+
*arrays: np.ndarray,
231+
loglevel: int = logging.ERROR,
232+
timing: bool = False,
233+
) -> Pipeline:
234+
return Pipeline((self,), arrays, loglevel=loglevel, timing=timing)
219235

220236
def __or__(self, other: Union[Stage, Pipeline]) -> Pipeline:
221237
return Pipeline((self, other))

‎test/test_pipeline.py‎

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import json
22
import logging
33
import os
4+
import re
45
import sys
56

67
from itertools import product
@@ -53,6 +54,21 @@ def test_construction(self, filename):
5354
assert isinstance(p, pdal.Pipeline)
5455
assert len(p.stages) == 2
5556

57+
def test_timing_is_optional_public_api(self):
58+
with open(os.path.join(DATADIRECTORY, "chip.json"), "r") as f:
59+
pipeline_json = f.read()
60+
61+
p = pdal.Pipeline(None, (), logging.ERROR, pipeline_json)
62+
assert p.timing is False
63+
assert p.execute() == 1065
64+
65+
with pytest.raises(TypeError):
66+
pdal.Pipeline(None, (), logging.ERROR, pipeline_json, (), (), True)
67+
68+
reader = pdal.Reader(os.path.join(DATADIRECTORY, "1.2-with-color.las"))
69+
assert reader.pipeline().timing is False
70+
assert reader.pipeline(timing=True).timing is True
71+
5672
@pytest.mark.parametrize(
5773
"pipeline",
5874
[
@@ -338,6 +354,7 @@ def test_logging(self, filename):
338354
"""Can we fetch log output"""
339355
r = get_pipeline(filename)
340356
assert r.loglevel == logging.ERROR
357+
assert r.timing is False
341358
assert r.log == ""
342359

343360
for loglevel in logging.CRITICAL, -1:
@@ -356,6 +373,17 @@ def test_logging(self, filename):
356373
assert "(pypipeline Debug) Executing pipeline in standard mode" in r.log
357374
assert "(pypipeline writers.las Debug)" in r.log
358375

376+
def test_logging_timing(self):
377+
"""Can we fetch log output decorated with timing information"""
378+
with open(os.path.join(DATADIRECTORY, "chip.json"), "r") as f:
379+
r = pdal.Pipeline(f.read(), loglevel=logging.DEBUG, timing=True)
380+
381+
assert r.timing is True
382+
count = r.execute()
383+
assert count == 1065
384+
assert re.search(r"\(pypipeline readers\.las Debug [0-9.]+\)", r.log)
385+
assert re.search(r"\(pypipeline Debug [0-9.]+\) Executing pipeline in standard mode", r.log)
386+
359387
@pytest.mark.skipif(
360388
not hasattr(pdal.Filter, "python"),
361389
reason="filters.python PDAL plugin is not available",
@@ -904,4 +932,3 @@ def invalid_stream_handler():
904932
with pytest.raises(RuntimeError,
905933
match=f"Stream chunk size not in the range of array length: {invalid_chunk_size}"):
906934
p.execute()
907-

0 commit comments

Comments
 (0)