Skip to content

Commit aecf0f3

Browse files
Merge pull request #221 from justadudewhohacks/external-mem-tracking-followup
External mem tracking followup
2 parents 4efc8c8 + e10f4d4 commit aecf0f3

19 files changed

+207
-150
lines changed

appveyor.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,5 @@ test_script:
5454
- node --version
5555
- cmd: cd c:\projects\opencv4nodejs\test
5656
- npm install
57-
- npm run test-appveyor
57+
- npm run test-appveyor
58+
- npm run test-externalMemTracking

binding.gyp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,12 @@
1717
],
1818
"sources": [
1919
"cc/opencv4nodejs.cc",
20+
"cc/CustomMatAllocator.cc",
21+
"cc/ExternalMemTracking.cc",
2022
"cc/cvTypes/cvTypes.cc",
2123
"cc/cvTypes/imgprocConstants.cc",
2224
"cc/cvTypes/videoCaptureProps.cc",
2325
"cc/core/core.cc",
24-
"cc/core/CustomAllocator.cc",
2526
"cc/core/Mat.cc",
2627
"cc/core/MatImgproc.cc",
2728
"cc/core/MatCalib3d.cc",

cc/core/CustomAllocator.cc renamed to cc/CustomMatAllocator.cc

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
2-
3-
#include "CustomAllocator.h"
1+
#include "CustomMatAllocator.h"
42
//#include <iostream>
53

64
#ifdef OPENCV4NODEJS_ENABLE_EXTERNALMEMTRACKING
@@ -9,7 +7,7 @@ cv::UMatData* CustomMatAllocator::allocate(int dims, const int* sizes, int type,
97
void* data0, size_t* step, int flags, cv::UMatUsageFlags usageFlags) const
108
{
119
cv::UMatData* u = stdAllocator->allocate(dims, sizes, type, data0, step, flags, usageFlags);
12-
10+
1311
if (NULL != u){
1412
u->prevAllocator = u->currAllocator = this;
1513
if( !(u->flags & cv::UMatData::USER_ALLOCATED) ){
@@ -21,7 +19,7 @@ cv::UMatData* CustomMatAllocator::allocate(int dims, const int* sizes, int type,
2119
variables->MemTotalChangeMutex.unlock();
2220
this->FixupJSMem();
2321
} catch (...){
24-
printf("exception adjusting memory\n");
22+
printf("CustomMatAllocator::allocate - exception adjusting memory\n");
2523
}
2624
}
2725
}
@@ -95,7 +93,7 @@ void CustomMatAllocator::FixupJSMem() const {
9593
int64_t adjust = variables->TotalMem - variables->TotalJSMem;
9694
variables->TotalJSMem += adjust;
9795
variables->MemTotalChangeMutex.unlock();
98-
96+
9997
if (adjust){
10098
//printf("will call Nan ajust by %d\n", (int)adjust);
10199
Nan::AdjustExternalMemory(adjust);

cc/core/CustomAllocator.h renamed to cc/CustomMatAllocator.h

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
#ifndef __FF_CUSTOMALLOCATOR_H__
2-
#define __FF_CUSTOMALLOCATOR_H__
3-
1+
#ifndef __FF_CUSTOMATMALLOCATOR_H__
2+
#define __FF_CUSTOMATMALLOCATOR_H__
43

54
#include <thread>
65
#include <stdint.h>
@@ -23,15 +22,12 @@
2322

2423
#ifdef OPENCV4NODEJS_ENABLE_EXTERNALMEMTRACKING
2524

26-
// un-comment to enable by default
27-
// #define OPENCV4NODEJS_ENABLE_EXTERNALMEMTRACKING_DEFAULT_ON
28-
2925
class CustomMatAllocator : public cv::MatAllocator
3026
{
3127
public:
3228
// strange evilness of the functions being tagged const means that the fns cant change
3329
// stuff in the class instance.
34-
// so instead create constant pointer to a structure which we are allowed to change, even
30+
// so instead create constant pointer to a structure which we are allowed to change, even
3531
// from a const function.
3632
typedef struct tag_Variables {
3733
cv::Mutex MemTotalChangeMutex;
@@ -44,17 +40,17 @@ class CustomMatAllocator : public cv::MatAllocator
4440
std::thread::id main_thread_id;
4541
} VARIABLES;
4642

47-
CustomMatAllocator( ) {
48-
stdAllocator = cv::Mat::getStdAllocator();
43+
CustomMatAllocator( ) {
44+
stdAllocator = cv::Mat::getStdAllocator();
4945
variables = new VARIABLES;
5046
variables->TotalMem = 0; // total mem allocated by this allocator
5147
variables->CountMemAllocs = 0;
5248
variables->CountMemDeAllocs = 0;
5349
variables->TotalJSMem = 0; // total mem told to JS so far
54-
50+
5551
variables->main_thread_id = std::this_thread::get_id();
5652
}
57-
~CustomMatAllocator( ) {
53+
~CustomMatAllocator( ) {
5854
delete variables;
5955
variables = NULL;
6056
}
@@ -72,10 +68,10 @@ class CustomMatAllocator : public cv::MatAllocator
7268
// function which adjusts NAN mem to match allocated mem.
7369
// WILL ONLY ACTUALLY DO ANYTHING FROM MAIN JS LOOP
7470
void FixupJSMem() const;
75-
71+
7672

7773
VARIABLES *variables;
78-
74+
7975
const cv::MatAllocator* stdAllocator;
8076
};
8177

cc/ExternalMemTracking.cc

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
#include "ExternalMemTracking.h"
2+
#include <iostream>
3+
4+
#ifdef OPENCV4NODEJS_ENABLE_EXTERNALMEMTRACKING
5+
CustomMatAllocator *ExternalMemTracking::custommatallocator = NULL;
6+
#endif
7+
8+
NAN_MODULE_INIT(ExternalMemTracking::Init) {
9+
#ifdef OPENCV4NODEJS_ENABLE_EXTERNALMEMTRACKING
10+
try {
11+
char* env = std::getenv("OPENCV4NODEJS_DISABLE_EXTERNAL_MEM_TRACKING");
12+
if (env == NULL && custommatallocator == NULL) {
13+
custommatallocator = new CustomMatAllocator();
14+
cv::Mat::setDefaultAllocator(custommatallocator);
15+
}
16+
}
17+
catch (...) {
18+
printf("ExternalMemTracking::Init - fatal exception while trying to read env: OPENCV4NODEJS_DISABLE_EXTERNAL_MEM_TRACKING");
19+
}
20+
#endif
21+
Nan::SetMethod(target, "isCustomMatAllocatorEnabled", IsCustomMatAllocatorEnabled);
22+
Nan::SetMethod(target, "dangerousEnableCustomMatAllocator", DangerousEnableCustomMatAllocator);
23+
Nan::SetMethod(target, "dangerousDisableCustomMatAllocator", DangerousDisableCustomMatAllocator);
24+
Nan::SetMethod(target, "getMemMetrics", GetMemMetrics);
25+
};
26+
27+
NAN_METHOD(ExternalMemTracking::GetMemMetrics) {
28+
29+
int64_t TotalAlloc = -1;
30+
int64_t TotalKnownByJS = -1;
31+
int64_t NumAllocations = -1;
32+
int64_t NumDeAllocations = -1;
33+
34+
#ifdef OPENCV4NODEJS_ENABLE_EXTERNALMEMTRACKING
35+
if (ExternalMemTracking::custommatallocator != NULL){
36+
TotalAlloc = ExternalMemTracking::custommatallocator->readtotalmem();
37+
TotalKnownByJS = ExternalMemTracking::custommatallocator->readmeminformed();
38+
NumAllocations = ExternalMemTracking::custommatallocator->readnumallocated();
39+
NumDeAllocations = ExternalMemTracking::custommatallocator->readnumdeallocated();
40+
}
41+
#endif
42+
43+
FF_OBJ result = FF_NEW_OBJ();
44+
Nan::Set(result, FF_NEW_STRING("TotalAlloc"), Nan::New((double)TotalAlloc));
45+
Nan::Set(result, FF_NEW_STRING("TotalKnownByJS"), Nan::New((double)TotalKnownByJS));
46+
Nan::Set(result, FF_NEW_STRING("NumAllocations"), Nan::New((double)NumAllocations));
47+
Nan::Set(result, FF_NEW_STRING("NumDeAllocations"), Nan::New((double)NumDeAllocations));
48+
49+
info.GetReturnValue().Set(result);
50+
return;
51+
}
52+
53+
54+
NAN_METHOD(ExternalMemTracking::IsCustomMatAllocatorEnabled) {
55+
bool allocatorOn = false;
56+
#ifdef OPENCV4NODEJS_ENABLE_EXTERNALMEMTRACKING
57+
if (ExternalMemTracking::custommatallocator != NULL){
58+
allocatorOn = true;
59+
}
60+
#endif
61+
info.GetReturnValue().Set(allocatorOn);
62+
}
63+
64+
NAN_METHOD(ExternalMemTracking::DangerousEnableCustomMatAllocator) {
65+
bool success = false;
66+
#ifdef OPENCV4NODEJS_ENABLE_EXTERNALMEMTRACKING
67+
if (ExternalMemTracking::custommatallocator == NULL) {
68+
ExternalMemTracking::custommatallocator = new CustomMatAllocator();
69+
cv::Mat::setDefaultAllocator(ExternalMemTracking::custommatallocator);
70+
}
71+
success = ExternalMemTracking::custommatallocator != NULL;
72+
#endif
73+
info.GetReturnValue().Set(success);
74+
}
75+
76+
NAN_METHOD(ExternalMemTracking::DangerousDisableCustomMatAllocator) {
77+
bool success = false;
78+
#ifdef OPENCV4NODEJS_ENABLE_EXTERNALMEMTRACKING
79+
if (ExternalMemTracking::custommatallocator != NULL) {
80+
CustomMatAllocator *allocator = ExternalMemTracking::custommatallocator;
81+
82+
// return default allocator
83+
if (allocator->variables) {
84+
allocator->variables->MemTotalChangeMutex.lock();
85+
}
86+
cv::Mat::setDefaultAllocator(NULL);
87+
ExternalMemTracking::custommatallocator = NULL;
88+
if (allocator->variables) {
89+
allocator->variables->MemTotalChangeMutex.unlock();
90+
}
91+
92+
// sorry, can't delete it, since it may be references by a number of outstanding Mats -> memory leak, but it's small
93+
// and should not happen often, or ever!.
94+
//delete allocator;
95+
}
96+
success = ExternalMemTracking::custommatallocator == NULL;
97+
#endif
98+
info.GetReturnValue().Set(success);
99+
}
100+

cc/ExternalMemTracking.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#include "macros.h"
2+
#include "CustomMatAllocator.h"
3+
4+
#ifndef __FF_EXTERNALMEMTRACKING_H__
5+
#define __FF_EXTERNALMEMTRACKING_H__
6+
7+
class ExternalMemTracking {
8+
public:
9+
10+
#ifdef OPENCV4NODEJS_ENABLE_EXTERNALMEMTRACKING
11+
static CustomMatAllocator *custommatallocator;
12+
#endif
13+
14+
static inline void onMatAllocated() {
15+
#ifdef OPENCV4NODEJS_ENABLE_EXTERNALMEMTRACKING
16+
if (custommatallocator != NULL) {
17+
custommatallocator->FixupJSMem();
18+
}
19+
#endif
20+
}
21+
22+
static NAN_MODULE_INIT(Init);
23+
static NAN_METHOD(IsCustomMatAllocatorEnabled);
24+
static NAN_METHOD(GetMemMetrics);
25+
static NAN_METHOD(DangerousEnableCustomMatAllocator);
26+
static NAN_METHOD(DangerousDisableCustomMatAllocator);
27+
28+
};
29+
30+
#endif

cc/core/Mat.cc

Lines changed: 5 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,11 @@
11
#include "Mat.h"
22
#include "MatImgproc.h"
33
#include "MatCalib3d.h"
4-
4+
#include "ExternalMemTracking.h"
55

66
Nan::Persistent<v8::FunctionTemplate> Mat::constructor;
77

8-
#ifdef OPENCV4NODEJS_ENABLE_EXTERNALMEMTRACKING
9-
CustomMatAllocator *Mat::custommatallocator = NULL;
10-
#endif
11-
12-
138
NAN_MODULE_INIT(Mat::Init) {
14-
15-
// defined in CustomAllocator.h, depends on ocv >= 3.1.0
16-
#ifdef OPENCV4NODEJS_ENABLE_EXTERNALMEMTRACKING
17-
18-
// defined in CustomAllocator.h
19-
#ifdef OPENCV4NODEJS_ENABLE_EXTERNALMEMTRACKING_DEFAULT_ON
20-
if (NULL == custommatallocator){
21-
custommatallocator = new CustomMatAllocator();
22-
cv::Mat::setDefaultAllocator(custommatallocator);
23-
}
24-
#endif
25-
26-
#endif
279

2810
v8::Local<v8::FunctionTemplate> ctor = Nan::New<v8::FunctionTemplate>(Mat::New);
2911
constructor.Reset(ctor);
@@ -193,14 +175,11 @@ NAN_METHOD(Mat::New) {
193175
}
194176
self->Wrap(info.Holder());
195177

196-
#ifdef OPENCV4NODEJS_ENABLE_EXTERNALMEMTRACKING
197-
// I *think* New should be called in JS thread where cv::mat has been created async,
178+
// if ExternalMemTracking is disabled, the following instruction will be a no op
179+
// notes: I *think* New should be called in JS thread where cv::mat has been created async,
198180
// so a good place to rationalise memory
199-
if (self->custommatallocator){
200-
self->custommatallocator->FixupJSMem();
201-
}
202-
#endif
203-
181+
ExternalMemTracking::onMatAllocated();
182+
204183
FF_RETURN(info.Holder());
205184
}
206185

cc/core/Mat.h

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,14 @@
88
#include "RotatedRect.h"
99
#include "Workers.h"
1010

11-
#include "CustomAllocator.h"
12-
1311
#ifndef __FF_MAT_H__
1412
#define __FF_MAT_H__
1513

1614
class Mat : public Nan::ObjectWrap {
1715
public:
18-
cv::Mat mat;
16+
cv::Mat mat;
1917

20-
#ifdef OPENCV4NODEJS_ENABLE_EXTERNALMEMTRACKING
21-
static CustomMatAllocator *custommatallocator;
22-
#endif
23-
24-
static NAN_MODULE_INIT(Init);
18+
static NAN_MODULE_INIT(Init);
2519
static NAN_METHOD(New);
2620

2721
static NAN_METHOD(Eye);

0 commit comments

Comments
 (0)