Skip to content

ocl::Context::create(string) reference count wrong when reusing contexts #18906

@diablodale

Description

@diablodale
System information (version)
  • OpenCV => 4.5.0 and master
  • Operating System / Platform => Microsoft Windows [Version 10.0.19042.630]
  • Compiler => VS Community 2019 v16.8.2
Detailed description

The reference count impl->addref() is missing in the supporting functions called by ocl::Context::create(string). PR including two test cases incoming.

if (impl)
{
CV_LOG_INFO(NULL, "OpenCL: reuse context@" << impl->contextId << " for configuration: " << configuration)
return impl;
}

This was discovered as I was creating/binding the same GPU across multiple threads. I saw that the entries in the Context::Impl::getGlobalContainer() entries were being released before they should. And, a later ocl::Context::create(string) with the same string config would create a new context rather than reusing the existing one.

Code review also exposes the missing impl->addref() by comparing the three sibling findOrCreateContext().
And in a Debug build, the log to the console will show creation of new context rather than reuse.

Steps to reproduce

See test cases in PR. Or write your own via...

  1. Save current OpenCLExecutionContext
  2. Create three empty void* variables: p1, p2, p3
  3. Open a scope
  4. Create a new Context via a configuration string
  5. Create a OpenCLExecutionContext with that Context and the first device
  6. bind() that OpenCLExecutionContext
  7. Save handle within the Context via context.ptr() to the p1 variable
  8. End that scope
  9. Create a new scope
  10. Create a new Context via the same configuration string.
  11. Save handle within the Context via context.ptr() to the p2 variable
  12. End that 2nd scope. Note...due to this issue, the ref count of the Context stored in the getGlobalContainer() will go to zero and be deallocated/released.
  13. Create a new scope
  14. Create a new Context via the same configuration string. Due to this issue, and since the Context was prematurely released, a brand new Context will be created and inserted into the getGlobalContainer().
  15. Save handle within the Context via context.ptr() to the p3 variable
  16. End that 3rd scope
  17. Compare the values of all three void* variables
Result

p1 == p2 This is expected.
p2 != p3 This is errant

Expected

All three void* variables to contain the same memory address.

Notes

The PR includes two new test cases

  • Expose this issue and verify its fix
  • Verify the reverse behavior and that the correct number of release() are called and the getGlobalContainer() entry cleared
Issue submission checklist
  • I report the issue, it's not a question
  • I checked the problem with documentation, FAQ, open issues,
    answers.opencv.org, Stack Overflow, etc and have not found solution
  • I updated to latest OpenCV version and the issue is still there
  • There is reproducer code and related data files: videos, images, onnx, etc

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions