G-API: oneVPL - Performance: Add async decode pipeline & add cached pool#20901
G-API: oneVPL - Performance: Add async decode pipeline & add cached pool#20901alalek merged 8 commits intoopencv:4.xfrom
Conversation
modules/gapi/src/streaming/onevpl/accelerators/surface/surface_pool.cpp
Outdated
Show resolved
Hide resolved
modules/gapi/src/streaming/onevpl/engine/decode/decode_engine_legacy.cpp
Show resolved
Hide resolved
| GAPI_LOG_WARNING(nullptr, "[" << my_sess.session << | ||
| "] has no surface, reason: " << | ||
| ex.what()); | ||
| // TODO it is supposed to place `break;` here |
There was a problem hiding this comment.
Is it Ok to get into this catch? I mean even now it can be just exited correctly?
There was a problem hiding this comment.
The same comment can be applied to all the catch blocks below
There was a problem hiding this comment.
it's OK here: swap_surface can throw exception in case of no available "free" surface is present in pool. This lack-of-resource state processing (like std::bad_alloc for new allocation ) allows us to go on async-waiting result state and put off decoder queuing job until one or more async result completed and resource freeing
There was a problem hiding this comment.
The issue of bad_alloc is that it can be handled explicitly - here we handle all the exceptions uniformly and this bad-alloc / general error difference is not clear to me
There was a problem hiding this comment.
This is the reason why I adhered my point about using abort() in GAPI_Assert instead of throwing exception:
because abort() means the library itself problem which is not supposed to be handed by user but introducing BUG to fix. Otherwise exception has recoverable semantic
In current catch block we could face with two different kind of exception:
swap_surface ->get_free_surface() -> find KEY in pool (exception means library problem and supposed to be abort() with BUG/Issue creation)
and the second
swap_surface ->get_free_surface()-> pool.find_free() -> no free surface at the time (resource unavailable at moment)
The second is expected to be processed.
No other exception types is throwing.
So, according to idea that GAPI_Assert has no abort inside - we need to catch only second case. So it make sense to find out what types of exception is throwing by GAPI_Assert and sort out different types in pool.find_free
modules/gapi/src/streaming/onevpl/engine/decode/decode_engine_legacy.cpp
Show resolved
Hide resolved
| using namespace cv::gapi::wip::onevpl; | ||
|
|
||
| const auto params = GetParam(); | ||
| source_t src = findDataFile(get<0>(params)); |
There was a problem hiding this comment.
should we put false here as second argument to not complain on file not found error? Or I am wrong?
There was a problem hiding this comment.
maybe yes, i will add it
There was a problem hiding this comment.
looks like false is confusing here. it added but has reverted
From my perspective:
- if user didn't configured EXTRA path in here initTestDataPathSilent() then
SkipExceptionis OK here - IF user did configured EXTRA path here, then IT MUST contain requested test files. So
findDataFilemust request it availability
There was a problem hiding this comment.
Please align it with the latest news from @mpashchenkov
There was a problem hiding this comment.
asked a detailed question in @mpashchenkov PR by #20995 (comment)
There was a problem hiding this comment.
#20995 (comment)
So:
test must fail if no env OPENCV_TEST_DATA_PATH is set (in case of test requires external test data)
test must fail if OPENCV_TEST_DATA_PATH set and filepath is incorrect.
Looks like i need to remove my initTestDataPathSilent check
|
|
||
| const auto params = GetParam(); | ||
| source_t src = findDataFile(get<0>(params)); | ||
| codec_t type = get<1>(params); |
There was a problem hiding this comment.
Don't you find using std::tie(src, type) = params; better?
There was a problem hiding this comment.
as for me this transforms into the same 3 lines
There was a problem hiding this comment.
The idea behind using std::tie instead of get<N> is type safety
There was a problem hiding this comment.
i'm not sure that it is important in UTs, because an one tuple type is for a single one test and when you changed the tuple set - it had caused by the reason that you intended to change test by itself.
If a some common tuple set (hypothetically) was changed by adding new type for a some specific single new one test then it is more convenient for me to do not brake ALL tests which depended from common tuple set by adding std::ignore for all of them (in case if i have 100500 legacy unit tests).
Additionally, AND which is more important for me: please compare
std::string path;
...
std::tie(path,...) = GetParams();
path = findDataFile(path);
...
vs
auto path = findDataFile(std::get<0>(param));
There was a problem hiding this comment.
because an one tuple type is for a single one test and when you changed the tuple set - it had caused by the reason that you intended to change test by itself.
Not always, unfortunately - sometimes these parameters are introduced only for particular tests in the suite and the rest is not updated.
| std::vector<CfgParam> cfg_params { | ||
| CfgParam::create<std::string>("mfxImplDescription.Impl", "MFX_IMPL_TYPE_HARDWARE"), | ||
| CfgParam::create("mfxImplDescription.mfxDecoderDescription.decoder.CodecID", type), | ||
| }; |
There was a problem hiding this comment.
Why there are difference between instantiations? std::string is not deducible?
There was a problem hiding this comment.
first function deduces template argument as const char* which uses as type for construction cv::variant later.
cv::variant is pretty different from std::variant and cannot support construct_as semantic for std::string (At the moment when current PR introduced). Thus explicit template instantiation requested here due to limited functionality of cv::variant
| std::count_if(surfaces.begin(), surfaces.end(), | ||
| [](const surface_ptr_t& val) { | ||
| GAPI_DbgAssert(val && "Pool contains empty surface"); | ||
| return !val->get_locks_count(); |
There was a problem hiding this comment.
it is still more tricky to read !int()
Is this some common way to represent logic statement in some famous libraries (likes STD)?
Just a minor question, not to address!
There was a problem hiding this comment.
I wonder when you asked - as for me it's well known expression, especially in C in the same way as if (num %2) and so on
There was a problem hiding this comment.
+1 to Asya's point, get_lock_count() == 0 is more straight to understand
There was a problem hiding this comment.
ok will change by majority request
| // prepare sync object for new surface | ||
| LegacyDecodeSession::op_handle_t sync_pair{}; | ||
|
|
||
| // enqueue qecode operation with current session surface |
There was a problem hiding this comment.
sorry for such comment!
qecode -> decode
| ready_surface); | ||
| ready_frames.emplace(cv::MediaFrame(std::move(frame_adapter)), sess.generate_frame_meta()); | ||
|
|
||
| // pop away ready sync onject |
|
|
||
| if (my_sess.last_status == MFX_ERR_NONE) { | ||
| my_sess.sync_queue.emplace(sync_pair); | ||
| } else if (MFX_ERR_MORE_DATA != my_sess.last_status) /* suppress MFX_ERR_MORE_DATA warning */ { |
There was a problem hiding this comment.
different order of operands in comparison against if above, however, such order is mostly required for == comparison...
is it intended?
There was a problem hiding this comment.
it was written in different times of day :)
| using namespace cv::gapi::wip::onevpl; | ||
|
|
||
| const auto params = GetParam(); | ||
| source_t src = findDataFile(get<0>(params)); |
There was a problem hiding this comment.
we usually use std::tie instead of std::get<>
| }; | ||
|
|
||
| cv::gapi::wip::IStreamSource::Ptr source_ptr; | ||
| try { |
There was a problem hiding this comment.
hmmm, wondering why it isn't under ifdef ?
There was a problem hiding this comment.
it makes sense.
What is the current order for UT: to skip or to disable ?
There was a problem hiding this comment.
added #ifdef HAVE_ONEVPL in the beginning
There was a problem hiding this comment.
disable (put under ifdef)
| // create empty pool | ||
| pool_t pool; | ||
| pool.reserve(pool_size); | ||
| // create empty pool with reservation |
There was a problem hiding this comment.
I'd start with capital and usually we use these tags before comment:
NB, FIXME, TODO
There was a problem hiding this comment.
sorry, what is NB ?
|
|
||
| const auto params = GetParam(); | ||
| source_t src = findDataFile(get<0>(params)); | ||
| codec_t type = get<1>(params); |
There was a problem hiding this comment.
The idea behind using std::tie instead of get<N> is type safety
modules/gapi/perf/streaming/gapi_streaming_source_perf_tests.cpp
Outdated
Show resolved
Hide resolved
| TEST_CYCLE() | ||
| { | ||
| source_ptr->pull(out); | ||
| } |
There was a problem hiding this comment.
to be honest I'm not sure how well it maps to the idea of a performance test this way.
TEST_CYCLE() measures the same thing again and again to calculate its statistic values. Here you actually decode different frames, but measure it as the same random value - not sure if it is correct.
Maybe running the whole file under the same TEST_CYCLE would make sense w.r.t stats, but then this test can take foerever...
There was a problem hiding this comment.
I's true, because different frames take up different decode duration but...
It's supposed to be compared in performance metrics against VideoCap on the same input streams (and frames) AND find out hotspots by using Vtune metrics in overall pipeline. I means auxiliary code around on direct MFX decode api
Wrapping TEST_CYCLE for all case and to incorporate a source creation also will measure MFX library/DX11 CoCreate load/unload and so on and doesn't give me relative result performance in comparison with VideoCapdecode api
There was a problem hiding this comment.
Wrapping TEST_CYCLE for all case and to incorporate a source creation also will measure MFX library/DX11 CoCreate load/unload and so on and doesn't give me relative result performance in comparison with VideoCapdecode api
This makes sense, but can it be done only once before the TEST_CYCLE() body kicks in? Is there a way to decompose it to prologue/epilogue so that initialization/deinitialization for every individual run is left out of profile?
|
|
||
| using namespace cv::gapi::wip; | ||
|
|
||
| source_t src = findDataFile(GetParam(), false); |
There was a problem hiding this comment.
I believe this is the method which throws SkipTestException so we don't need to test it on our own
There was a problem hiding this comment.
It receives initial PATH and return modified PATH according to the OPENCV_TEST_DAT_PATH prefix but for only single case if file is found by path in result.
So, if path doesn't find then no modified PATH returned and no exception was throws in case of second false params.
So i was confused by changing second params to false
Let's remove false here - false means optional, so when requested file doesn't found it returns non-modified path and throw Skip otherwise.
My suggestions:
if initTestDataPathSilent is success, that means OPENCV EXTRA is present that MUST provide test video file by requested path otherwise configuration is incorrect. so false must be removed
| // create empty pool | ||
| pool_t pool; | ||
| pool.reserve(pool_size); | ||
| // create empty pool with reservation |
| GAPI_LOG_WARNING(nullptr, "[" << my_sess.session << | ||
| "] has no surface, reason: " << | ||
| ex.what()); | ||
| // TODO it is supposed to place `break;` here |
There was a problem hiding this comment.
The issue of bad_alloc is that it can be handled explicitly - here we handle all the exceptions uniformly and this bad-alloc / general error difference is not clear to me
| sess.swap_surface(*this); | ||
| return ExecutionStatus::Continue; | ||
| } catch (const std::exception& ex) { |
| try { | ||
| sess.swap_surface(*this); | ||
| return ExecutionStatus::Continue; | ||
| } catch (const std::exception& ex) { |
| }; | ||
|
|
||
| cv::gapi::wip::IStreamSource::Ptr source_ptr; | ||
| try { |
There was a problem hiding this comment.
disable (put under ifdef)
1220067 to
1d8df9f
Compare
|
@alalek Could you merge it please? alignment with VPL builder would be done later when all parts of vpl source merged |
…perf_mod G-API: oneVPL - Performance: Add async decode pipeline & add cached pool * Add async decode pipeline & intro cached pool * Fix performacne test with checking OPENCV_EXTRA * Add sip perf test with no VPL * Fix misprint * Remove empty line.. * Apply some comments * Apply some comments * Make perf test fail if no OPENCV_TEST_DATA_PATH declared
This PR is a part of large PR #20469
Improve performance of VPL pipeline processing:
Pull Request Readiness Checklist
See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request
Patch to opencv_extra has the same branch name.
Build configuration