You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Improve performance of the nc_reclaim_data and nc_copy_data functions.
re: Issue Unidata#2685
re: PR Unidata#2179
As noted in PR Unidata#2179,
the old code did not allow for reclaiming instances of types,
nor for properly copying them. That PR provided new functions
capable of reclaiming/copying instances of arbitrary types.
However, as noted by Issue Unidata#2685, using these
most general functions resulted in a significant performance
degradation, even for common cases.
This PR attempts to mitigate the cost of using the general
reclaim/copy functions in two ways.
First, the previous functions operating at the top level by
using ncid and typeid arguments. These functions were augmented
with equivalent versions that used the netcdf-c library internal
data structures to allow direct access to needed information.
These new functions are used internally to the library.
The second mitigation involves optimizing the internal functions
by providing early tests for common cases. This avoids
unnecessary recursive function calls.
The overall result is a significant improvement in speed by a
factor of roughly twenty -- your mileage may vary. These
optimized functions are still not as fast as the original (more
limited) functions, but they are getting close. Additional optimizations are
possible. But the cost is a significant "uglification" of the
code that I deemed a step too far, at least for now.
## Misc. Changes
1. Added a test case to check the proper reclamation/copy of complex types.
2. Found and fixed some places where nc_reclaim/copy should have been used.
3. Replaced, in the netcdf-c library, (almost all) occurrences of nc_reclaim_copy with calls to NC_reclaim/copy. This plus the optimizations is the primary speed-up mechanism.
4. In DAP4, the metadata is held in a substrate in-memory file; this required some changes so that the reclaim/copy code accessed that substrate dispatcher rather than the DAP4 dispatcher.
5. Re-factored and isolated the code that computes if a type is (transitively) variable-sized or not.
6. Clean up the reclamation code in ncgen; adding the use of nc_reclaim exposed some memory problems.
Copy file name to clipboardExpand all lines: RELEASE_NOTES.md
+1Lines changed: 1 addition & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -8,6 +8,7 @@ This file contains a high-level description of this package's evolution. Release
8
8
## 4.9.3 - TBD
9
9
10
10
11
+
* Improve performance and testing of the new nc_reclaim/copy functions. See [Github #????](https://github.com/Unidata/netcdf-c/pull/????).
11
12
* Improve S3 documentation, testing, and support See [Github #2686](https://github.com/Unidata/netcdf-c/pull/2686).
12
13
* Remove obsolete code. See [Github #2680](https://github.com/Unidata/netcdf-c/pull/2680).
13
14
*[Bug Fix] Add a crude test to see if an NCZarr path looks like a valid NCZarr/Zarr file. See [Github #2658](https://github.com/Unidata/netcdf-c/pull/2658).
Copy file name to clipboardExpand all lines: docs/cloud.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -258,7 +258,7 @@ This is an experimental SDK provided internally in the netcdf-c library.
258
258
259
259
* It is written in C
260
260
* It provides the minimum functionality necessary to read/write/search an Amazon S3 bucket.
261
-
* It was constructed by heavily modifying the HDF5 *H5FDros3* Virtual File Driver and combining it with crypto code wrappers provided by libcurl. The resulting file was then modified to fit into the netcdf coding style.
261
+
* It was constructed by heavily modifying the HDF5 *H5Fs3commons.c* file and combining it with crypto code wrappers provided by libcurl. The resulting file was then modified to fit into the netcdf coding style.
262
262
* The resulting code is rather ugly, but appears to work under at least Linux and under Windows (using Visual C++).
Copy file name to clipboardExpand all lines: docs/internal.md
+72-57Lines changed: 72 additions & 57 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,10 +4,14 @@ Notes On the Internals of the NetCDF-C Library
4
4
5
5
# Notes On the Internals of the NetCDF-C Library {#intern_head}
6
6
7
-
\tableofcontents
8
-
9
7
This document attempts to record important information about
10
8
the internal architecture and operation of the netcdf-c library.
9
+
It covers the following issues.
10
+
11
+
*[Including C++ Code in the netcdf-c Library](#intern_c++)
12
+
*[Managing instances of variable-length data types](#intern_vlens)
13
+
*[Inferring File Types](#intern_infer)
14
+
*[Adding a Standard Filter](#intern_filters)
11
15
12
16
# 1. Including C++ Code in the netcdf-c Library {#intern_c++}
13
17
@@ -41,46 +45,71 @@ AM_CXXFLAGS = -std=c++11
41
45
````
42
46
It is possible that other values (e.g. *-std=c++14*) may also work.
43
47
44
-
# 2. Managing instances of complex data types
48
+
# 2. Managing instances of variable-length data types {#intern_vlens}
45
49
46
50
For a long time, there have been known problems with the
47
51
management of complex types containing VLENs. This also
48
-
involves the string type because it is stored as a VLEN of
49
-
chars.
52
+
involves the string type because it is stored as a VLEN of chars.
50
53
51
-
The term complex type refers to any type that directly or
52
-
recursively references a VLEN type. So an array of VLENS, a
53
-
compound with a VLEN field, and so on.
54
+
The term "variable-length" refers to any
55
+
type that directly or recursively references a VLEN type. So an
56
+
array of VLENS, a compound with a VLEN field, and so on.
54
57
55
-
In order to properly handle instances of these complex types, it
58
+
In order to properly handle instances of these variable-length types, it
56
59
is necessary to have function that can recursively walk
57
60
instances of such types to perform various actions on them. The
58
61
term "deep" is also used to mean recursive.
59
62
60
-
Two deep walking operations are provided by the netcdf-c library
61
-
to aid in managing instances of complex structures.
62
-
- free'ing an instance of the complex type
63
-
- copying an instance of the complex type.
63
+
Two primary deep walking operations are provided by the netcdf-c library
64
+
to aid in managing instances of variable-length types.
65
+
- free'ing an instance of the type
66
+
- copying an instance of the type.
67
+
68
+
Note that the term "vector" is used in the following text to
69
+
mean a contiguous (in memory) sequence of instances of some
70
+
type. Given an array with, say, dimensions 2 X 3 X 4, this will
71
+
be stored in memory as a vector of length 2\*3\*4=24 instances.
72
+
73
+
## Special case reclamation functions
74
+
75
+
Previously The netcdf-c library provided functions to reclaim an
76
+
instance of a subset of the possible variable-length types. It
77
+
provided no specialized support for copying instances of
78
+
variable-length types.
79
+
80
+
These specialized functions are still available and can be used
81
+
when their pre-conditions are met. They have the advantage of
82
+
being faster than the general purpose functions described
83
+
later in this document.
64
84
65
-
Previously The netcdf-c library only did shallow free and shallow copy of
66
-
complex types. This meant that only the top level was properly
67
-
free'd or copied, but deep internal blocks in the instance were
68
-
not touched. This led to a host of memory leaks and failures
69
-
when the deep data was effectively shared between the netcdf-c library
70
-
internally and the user's data.
85
+
These functions, and their pre and post conditions, are as follows.
86
+
**int nc_free_string(size_t len, char\* data[])*
87
+
<u>Action</u>: reclaim a vector of variable length strings.
88
+
<u>Pre-condition(s)</u>: the data argument is a vector containing *len* pointers to variable length, nul-terminated strings.
89
+
<u>Post-condition(s)</u>: only the strings in the vector are reclaimed -- the vector itself is not reclaimed.
71
90
72
-
Note that the term "vector" is used to mean a contiguous (in
73
-
memory) sequence of instances of some type. Given an array with,
74
-
say, dimensions 2 X 3 X 4, this will be stored in memory as a
75
-
vector of length 2\*3\*4=24 instances.
91
+
* int nc_free_vlens(size_t len, nc_vlen_t vlens[])
92
+
<u>Action</u>: reclaim a vector of VLEN instances.
93
+
<u>Pre-condition(s)</u>: the data argument is a vector containing *len* pointers to variable length, nul-terminated strings.
94
+
<u>Post-condition(s)</u>:
95
+
* only the data pointed to by the VLEN instances (i.e. *nc_vlen_t.p* in the vector are reclaimed -- the vector itself is not reclaimed.
96
+
* the base type of the VLEN must be a fixed-size type -- this means atomic types in the range NC_CHAR thru NC_UINT64, and compound types where the basetype of each field is itself fixed-size.
76
97
77
-
The use cases are primarily these.
98
+
**int nc_free_vlen(nc_vlen_t \*vl)*
99
+
<u>Action</u>: this is equivalent to calling *nc_free_vlens(1,&vl)*.
78
100
79
-
## nc\_get\_vars
101
+
If the pre and post conditions are not met, then using these
102
+
functions can lead to a host of memory leaks and failures
103
+
because the deep data variable-length data is in effect
104
+
shared between the netcdf-c library internally and the user's data.
105
+
106
+
## Typical use cases
107
+
108
+
### *nc\_get\_vars*
80
109
Suppose one is reading a vector of instances using nc\_get\_vars
81
110
(or nc\_get\_vara or nc\_get\_var, etc.). These functions will
82
111
return the vector in the top-level memory provided. All
83
-
interior blocks (form nested VLEN or strings) will have been
112
+
interior blocks (from nested VLEN or strings) will have been
84
113
dynamically allocated. Note that computing the size of the vector
85
114
may be tricky because the strides must be taken into account.
86
115
@@ -90,14 +119,7 @@ memory leak occurs. So, the recursive reclaim function is used
90
119
to walk the returned instance vector and do a deep reclaim of
91
120
the data.
92
121
93
-
Currently functions are defined in netcdf.h that are supposed to
94
-
handle this: nc\_free\_vlen(), nc\_free\_vlens(), and
95
-
nc\_free\_string(). Unfortunately, these functions only do a
96
-
shallow free, so deeply nested instances are not properly
97
-
handled by them. They are marked in the description as
98
-
deprecated in favor of the newer recursive function.
99
-
100
-
## nc\_put\_vars
122
+
### *nc\_put\_vars*
101
123
102
124
Suppose one is writing a vector of instances using nc\_put\_vars
103
125
(or nc\_put\_vara or nc\_put\_var, etc.). These functions will
@@ -113,7 +135,10 @@ So again, the recursive reclaim function can be used
113
135
to walk the returned instance vector and do a deep reclaim of
114
136
the data.
115
137
116
-
## nc\_put\_att
138
+
WARNING: If the data passed into these functions contains statically
139
+
allocated data, then using any of the reclaim functions will fail.
140
+
141
+
### *nc\_put\_att*
117
142
Suppose one is writing a vector of instances as the data of an attribute
118
143
using, say, nc\_put\_att.
119
144
@@ -122,26 +147,18 @@ so that changes/reclamation of the input data will not affect
122
147
the attribute. Note that this copying behavior is different from
123
148
writing to a variable, where the data is written immediately.
124
149
125
-
Again, the code inside the netcdf library used to use only shallow copying
126
-
rather than deep copy. As a result, one saw effects such as described
127
-
in Github Issue https://github.com/Unidata/netcdf-c/issues/2143.
128
-
129
-
Also, after defining the attribute, it may be necessary for the user
150
+
After defining the attribute, it may be necessary for the user
130
151
to free the data that was provided as input to nc\_put\_att() as in the
131
152
nc\_put\_xxx functions (previously described).
132
153
133
-
##nc\_get\_att
154
+
### *nc\_get\_att*
134
155
Suppose one is reading a vector of instances as the data of an attribute
135
156
using, say, nc\_get\_att.
136
157
137
158
Internally, the existing attribute data must be copied and returned
138
159
to the caller, and the caller is responsible for reclaiming
139
160
the returned data.
140
161
141
-
Again, the code inside the netcdf library used to only do shallow copying
142
-
rather than deep copy. So this could lead to memory leaks and errors
143
-
because the deep data was shared between the library and the user.
144
-
145
162
## New Instance Walking API
146
163
147
164
Proper recursive functions were added to the netcdf-c library to
0 commit comments