Skip to content

Commit e5e09d5

Browse files
authored
readonly mappedfile wrapper class, use_mapped_model_loading option (#6537)
* test mmap loading
1 parent 37b499c commit e5e09d5

File tree

9 files changed

+196
-14
lines changed

9 files changed

+196
-14
lines changed

docs/how-to-use-and-FAQ/ncnn-load-model.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@
1919
2. Never modify Net opt member after loading
2020

2121
3. Most loading functions return 0 if success, except loading alexnet.param.bin and alexnet.bin from file memory, which returns the bytes consumed after loading
22-
* int Net::load_param(const unsigned char*)
23-
* int Net::load_model(const unsigned char*)
22+
* size_t Net::load_param(const unsigned char*)
23+
* size_t Net::load_model(const unsigned char*)
2424

2525
4. It is recommended to load model from Android asset directly to avoid copying them to sdcard on Android platform
2626

src/c_api.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1541,12 +1541,12 @@ int ncnn_net_load_param_memory(ncnn_net_t net, const char* mem)
15411541
#endif /* NCNN_STRING */
15421542
#endif /* NCNN_STDIO */
15431543

1544-
int ncnn_net_load_param_bin_memory(ncnn_net_t net, const unsigned char* mem)
1544+
size_t ncnn_net_load_param_bin_memory(ncnn_net_t net, const unsigned char* mem)
15451545
{
15461546
return ((Net*)net->pthis)->load_param(mem);
15471547
}
15481548

1549-
int ncnn_net_load_model_memory(ncnn_net_t net, const unsigned char* mem)
1549+
size_t ncnn_net_load_model_memory(ncnn_net_t net, const unsigned char* mem)
15501550
{
15511551
return ((Net*)net->pthis)->load_model(mem);
15521552
}

src/c_api.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -324,8 +324,8 @@ NCNN_EXPORT int ncnn_net_load_model_w(ncnn_net_t net, const wchar_t* path);
324324
NCNN_EXPORT int ncnn_net_load_param_memory(ncnn_net_t net, const char* mem);
325325
#endif /* NCNN_STRING */
326326
#endif /* NCNN_STDIO */
327-
NCNN_EXPORT int ncnn_net_load_param_bin_memory(ncnn_net_t net, const unsigned char* mem);
328-
NCNN_EXPORT int ncnn_net_load_model_memory(ncnn_net_t net, const unsigned char* mem);
327+
NCNN_EXPORT size_t ncnn_net_load_param_bin_memory(ncnn_net_t net, const unsigned char* mem);
328+
NCNN_EXPORT size_t ncnn_net_load_model_memory(ncnn_net_t net, const unsigned char* mem);
329329

330330
#if NCNN_STRING
331331
NCNN_EXPORT int ncnn_net_load_param_datareader(ncnn_net_t net, const ncnn_datareader_t dr);

src/net.cpp

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,10 @@ class NetPrivate
6969
PoolAllocator* local_blob_allocator;
7070
PoolAllocator* local_workspace_allocator;
7171

72+
#if defined _WIN32 || __ANDROID__ || defined __OHOS__ || defined __linux__ || __APPLE__
73+
MappedFile mapped_model_file;
74+
#endif
75+
7276
#if NCNN_VULKAN
7377
const VulkanDevice* vkdev;
7478

@@ -1815,6 +1819,29 @@ int Net::load_model(FILE* fp)
18151819

18161820
int Net::load_model(const char* modelpath)
18171821
{
1822+
#if defined _WIN32 || __ANDROID__ || defined __OHOS__ || defined __linux__ || __APPLE__
1823+
if (opt.use_mapped_model_loading)
1824+
{
1825+
int ret = d->mapped_model_file.open(modelpath);
1826+
if (ret == 0)
1827+
{
1828+
const void* ptr = d->mapped_model_file.mapped_ptr();
1829+
const size_t size = d->mapped_model_file.size();
1830+
size_t consumed = load_model((const unsigned char*)ptr);
1831+
if (consumed != size)
1832+
{
1833+
NCNN_LOGE("mapped_file consumed %zu != %zu", consumed, size);
1834+
d->mapped_model_file.close();
1835+
return -1;
1836+
}
1837+
1838+
return 0;
1839+
}
1840+
1841+
// fallback to regular file loading
1842+
}
1843+
#endif // defined _WIN32 || __ANDROID__ || defined __OHOS__ || defined __linux__ || __APPLE__
1844+
18181845
FILE* fp = fopen(modelpath, "rb");
18191846
if (!fp)
18201847
{
@@ -1830,6 +1857,29 @@ int Net::load_model(const char* modelpath)
18301857
#if _WIN32
18311858
int Net::load_model(const wchar_t* modelpath)
18321859
{
1860+
#if defined _WIN32 || __ANDROID__ || defined __OHOS__ || defined __linux__ || __APPLE__
1861+
if (opt.use_mapped_model_loading)
1862+
{
1863+
int ret = d->mapped_model_file.open(modelpath);
1864+
if (ret == 0)
1865+
{
1866+
const void* ptr = d->mapped_model_file.mapped_ptr();
1867+
const size_t size = d->mapped_model_file.size();
1868+
size_t consumed = load_model((const unsigned char*)ptr);
1869+
if (consumed != size)
1870+
{
1871+
NCNN_LOGE("mapped_file consumed %zu != %zu", consumed, size);
1872+
d->mapped_model_file.close();
1873+
return -1;
1874+
}
1875+
1876+
return 0;
1877+
}
1878+
1879+
// fallback to regular file loading
1880+
}
1881+
#endif // defined _WIN32 || __ANDROID__ || defined __OHOS__ || defined __linux__ || __APPLE__
1882+
18331883
FILE* fp = _wfopen(modelpath, L"rb");
18341884
if (!fp)
18351885
{
@@ -1844,20 +1894,20 @@ int Net::load_model(const wchar_t* modelpath)
18441894
#endif
18451895
#endif // NCNN_STDIO
18461896

1847-
int Net::load_param(const unsigned char* _mem)
1897+
size_t Net::load_param(const unsigned char* _mem)
18481898
{
18491899
const unsigned char* mem = _mem;
18501900
DataReaderFromMemory dr(mem);
18511901
load_param_bin(dr);
1852-
return static_cast<int>(mem - _mem);
1902+
return (size_t)(mem - _mem);
18531903
}
18541904

1855-
int Net::load_model(const unsigned char* _mem)
1905+
size_t Net::load_model(const unsigned char* _mem)
18561906
{
18571907
const unsigned char* mem = _mem;
18581908
DataReaderFromMemory dr(mem);
18591909
load_model(dr);
1860-
return static_cast<int>(mem - _mem);
1910+
return (size_t)(mem - _mem);
18611911
}
18621912

18631913
#if NCNN_PLATFORM_API

src/net.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,14 +98,14 @@ class NCNN_EXPORT Net
9898
// load network structure from external memory
9999
// memory pointer must be 32-bit aligned
100100
// return bytes consumed
101-
int load_param(const unsigned char* mem);
101+
size_t load_param(const unsigned char* mem);
102102

103103
// reference network weight data from external memory
104104
// weight data is not copied but referenced
105105
// so external memory should be retained when used
106106
// memory pointer must be 32-bit aligned
107107
// return bytes consumed
108-
int load_model(const unsigned char* mem);
108+
size_t load_model(const unsigned char* mem);
109109

110110
#if NCNN_PLATFORM_API
111111
#if __ANDROID_API__ >= 9

src/option.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ Option::Option()
5252
use_weights_in_host_memory = false;
5353

5454
flush_denormals = 3;
55+
use_reserved_2f = false;
56+
use_reserved_3f = false;
57+
use_mapped_model_loading = false;
5558

5659
use_local_pool_allocator = true;
5760

src/option.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,11 @@ class NCNN_EXPORT Option
118118
// 1 = DAZ ON , FTZ OFF
119119
// 2 = DAZ OFF, FTZ ON
120120
// 3 = DAZ ON, FTZ ON
121-
int flush_denormals;
121+
unsigned char flush_denormals;
122+
123+
bool use_reserved_2f;
124+
bool use_reserved_3f;
125+
bool use_mapped_model_loading;
122126

123127
bool use_local_pool_allocator;
124128

src/platform.h.in

Lines changed: 123 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,19 @@
6666

6767
#ifdef __cplusplus
6868

69-
#if NCNN_THREADS
7069
#if defined _WIN32
7170
#define WIN32_LEAN_AND_MEAN
7271
#include <windows.h>
72+
#elif defined __ANDROID__ || defined __OHOS__ || defined __linux__ || __APPLE__
73+
#include <sys/types.h>
74+
#include <sys/stat.h>
75+
#include <sys/mman.h>
76+
#include <fcntl.h>
77+
#include <unistd.h>
78+
#endif
79+
80+
#if NCNN_THREADS
81+
#if defined _WIN32
7382
#include <process.h>
7483
#else
7584
#include <pthread.h>
@@ -82,6 +91,8 @@
8291
#endif
8392
#endif // __ANDROID_API__ >= 26
8493

94+
#include <stddef.h>
95+
8596
namespace ncnn {
8697

8798
#if NCNN_THREADS
@@ -282,6 +293,117 @@ private:
282293
Mutex& mutex;
283294
};
284295

296+
#if defined _WIN32
297+
class NCNN_EXPORT MappedFile
298+
{
299+
public:
300+
MappedFile() { ptr = 0; _size = 0; file = INVALID_HANDLE_VALUE; mapping = 0; }
301+
~MappedFile() { close(); }
302+
int open(const char* path)
303+
{
304+
close();
305+
306+
file = CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
307+
if (file == INVALID_HANDLE_VALUE) return -1;
308+
309+
LARGE_INTEGER liSize;
310+
if (!GetFileSizeEx(file, &liSize)) { close(); return -1; }
311+
312+
_size = (size_t)liSize.QuadPart;
313+
if (_size == 0) { close(); return -1; }
314+
315+
mapping = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL);
316+
if (!mapping) { close(); return -1; }
317+
318+
ptr = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
319+
if (!ptr) { close(); return -1; }
320+
return 0;
321+
}
322+
int open(const wchar_t* path)
323+
{
324+
close();
325+
326+
file = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
327+
if (file == INVALID_HANDLE_VALUE) return -1;
328+
329+
LARGE_INTEGER liSize;
330+
if (!GetFileSizeEx(file, &liSize)) { close(); return -1; }
331+
332+
_size = (size_t)liSize.QuadPart;
333+
if (_size == 0) { close(); return -1; }
334+
335+
mapping = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL);
336+
if (!mapping) { close(); return -1; }
337+
338+
ptr = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
339+
if (!ptr) { close(); return -1; }
340+
return 0;
341+
}
342+
void close()
343+
{
344+
if (ptr) { UnmapViewOfFile(ptr); ptr = 0; }
345+
if (mapping) { CloseHandle(mapping); mapping = 0; }
346+
if (file != INVALID_HANDLE_VALUE) { CloseHandle(file); file = INVALID_HANDLE_VALUE; }
347+
_size = 0;
348+
}
349+
const void* mapped_ptr() const { return ptr; }
350+
size_t size() const { return _size; }
351+
private:
352+
void* ptr;
353+
size_t _size;
354+
HANDLE file;
355+
HANDLE mapping;
356+
};
357+
#elif defined __ANDROID__ || defined __OHOS__ || defined __linux__ || __APPLE__
358+
class NCNN_EXPORT MappedFile
359+
{
360+
public:
361+
MappedFile() { ptr = 0; _size = 0; fd = -1; }
362+
~MappedFile() { close(); }
363+
int open(const char* path)
364+
{
365+
close();
366+
367+
fd = ::open(path, O_RDONLY);
368+
if (fd < 0) return -1;
369+
370+
struct stat st;
371+
if (fstat(fd, &st) < 0) { close(); return -1; }
372+
373+
_size = (size_t)st.st_size;
374+
if (_size == 0) { close(); return -1; }
375+
376+
ptr = mmap(NULL, _size, PROT_READ, MAP_PRIVATE, fd, 0);
377+
if (ptr == MAP_FAILED) { close(); return -1; }
378+
return 0;
379+
}
380+
void close()
381+
{
382+
if (ptr && ptr != MAP_FAILED) { munmap(ptr, _size); }
383+
ptr = 0;
384+
if (fd >= 0) { ::close(fd); fd = -1; }
385+
_size = 0;
386+
}
387+
const void* mapped_ptr() const { return ptr; }
388+
size_t size() const { return _size; }
389+
private:
390+
void* ptr;
391+
size_t _size;
392+
int fd;
393+
};
394+
#else // defined _WIN32 || __ANDROID__ || defined __OHOS__ || defined __linux__ || __APPLE__
395+
class NCNN_EXPORT MappedFile
396+
{
397+
public:
398+
MappedFile() {}
399+
~MappedFile() {}
400+
int open(const char* /*path*/) { return -1; }
401+
void close() {}
402+
const void* mapped_ptr() const { return 0; }
403+
size_t size() const { return 0; }
404+
};
405+
#endif // defined _WIN32 || __ANDROID__ || defined __OHOS__ || defined __linux__ || __APPLE__
406+
285407
static inline void swap_endianness_16(void* x)
286408
{
287409
unsigned char* xx = (unsigned char*)x;

tests/test_squeezenet.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,9 @@ int main()
436436
opts[2].use_bf16_storage = false; // FIXME enable me
437437
opts[2].blob_allocator = &g_blob_pool_allocator;
438438
opts[2].workspace_allocator = &g_workspace_pool_allocator;
439+
opts[2].use_weights_in_host_memory = true;
440+
opts[2].use_mapped_model_loading = true;
441+
opts[2].use_local_pool_allocator = false;
439442

440443
opts[3].use_packing_layout = true;
441444
opts[3].use_fp16_packed = true;

0 commit comments

Comments
 (0)