-
Notifications
You must be signed in to change notification settings - Fork 143
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Speed up (pre)compile and load times #681
Conversation
src/HDF5.jl
Outdated
native_size === Csize_t(2) ? (return Int16) : | ||
native_size === Csize_t(4) ? (return Int32) : | ||
native_size === Csize_t(8) ? (return Int64) : | ||
throw(KeyError(class_id, is_signed, native_size)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure this line (and similar in the other branches) is actually necessary — the final check size-8 case in principle could just be the else-case of the size-4 ternary. Thoughts?
(H5T_FLOAT, nothing, Csize_t(4)) => Float32, | ||
(H5T_FLOAT, nothing, Csize_t(8)) => Float64, | ||
) | ||
function _hdf5_type_map(class_id, is_signed, native_size) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
fun, propids = hdf5_obj_open[objtype] | ||
props = [p_create(prop; pv...) for prop in propids] | ||
obj = fun(parent, path, props...) | ||
if objtype == H5I_DATASET |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
I also bet this is just simply also far faster
UTF8_ATTRIBUTE_PROPERTIES[] = p_create(H5P_ATTRIBUTE_CREATE) | ||
h5p_set_char_encoding(UTF8_ATTRIBUTE_PROPERTIES[].id, H5T_CSET_UTF8) | ||
|
||
rehash!(hdf5_type_map, length(hdf5_type_map.keys)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yay, glad we can get rid of this now
It might then just be worth it to add type annotations where necessary to help the compiler with inference in these cases, instead of (or in addition to) I kind of think adding the line
Is not that elegant, given it is current experimental status, however the precompilation latency reduction (10% faster) and improved inference are very welcome. Overall, very nice PR. Still reviewing some final changes, but 👍 |
Yeah, doing some more systematic review of types and inference's understanding of the code is something worth doing but wasn't as easy of low-hanging fruit. And just because I was maybe a bit unclear, the inference change of |
@@ -978,19 +994,62 @@ end | |||
t_commit(parent::Union{HDF5File, HDF5Group}, path::String, dtype::HDF5Datatype) = t_commit(parent, path, dtype, p_create(H5P_LINK_CREATE)) | |||
|
|||
a_create(parent::Union{HDF5File, HDF5Object}, name::String, dtype::HDF5Datatype, dspace::HDF5Dataspace) = HDF5Attribute(h5a_create(checkvalid(parent).id, name, dtype.id, dspace.id), file(parent)) | |||
|
|||
function _prop_set!(p::HDF5Properties, name::Symbol, val, check::Bool = true) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this check
arg really needed, It seems a bit superfluous? I think the rationale is that we can squeeze a bit of perf without having to error
check in internal use, but perhaps the compiler is good enough that we don't need such fine grained tuning.
Perhaps these should all be written like (not sure if that helps the compiler guess the right branch?)
if class == H5P_FILE_CREATE
elseif class == H5P_FILE_ACCESS
elseif class H5P_GROUP_CREATE
....
else
error(....
end
OTOH the way to code is written as is, is pretty clear.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
EDIT:
Actually NVM I don't think it's that feasible given the way the code is structured as is, and would remove some important error checking in the if-clauses.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this check arg really needed, It seems a bit superfluous?
The reason I added it was to maintain the current behavior — p_create
does not error even if you pass it properties that are not appropriate for a particular property class, while setindex!
did (by way of just throwing when the underlying h5p_set_*
function errored). The two functions now set false
and true
, respectively, to maintain that.
Co-authored-by: Mustafa M <[email protected]>
Awesome ! |
I kinda wonder if we should just disable the integration tests, it's pretty annoying to see red X on PRs that pass. |
This PR does two primary things with the goal of reducing load time:
Dict
s that are rehashed on init are eliminated, replaced withif-else
chains at their use or in new internal helper functions. This was motivated by looking at the output of@snoopi using HDF5
(where I started Julia withjulia --compiled-modules=no
) and noticed that many of the methods near the end with largest times wereDict
methods.One minor advantage of doing this is that property names can now be valid for multiple HDF5 classes. For instance, the
__init__
code had to callh5p_set_char_encoding
forASCII_ATTRIBUTE_PROPERTIES
andUTF8_ATTRIBUTE_PROPERTIES
because:char_encoding
was already mapped toH5P_LINK_CREATE
so couldn't be used for these two properties which areH5P_ATTRIBUTE_CREATE
properties. After replacing theDict
lookup, though, the_prop_set!
function can have a:char_encoding
case forH5P_ATTRIBUTE_CREATE
without any conflicts.To evaluate the effectiveness of this change, I've timed loading (
using HDF5
) with a missing precompiled cache, loading with a valid precompiled cache, and the time to run the entire test suite (with the precompiled cache active). The times comparing current master versus the first commit from this PR (run with near-latest Julia, average and std over 10 runs) show:Running the same timing tests again:
I've noticed at least one case where type inference improves despite the lower optimization level:
getindex(::Union{HDF5File, HDF5Group}, ::String)
used to infer asAny
but with this PR is inferred returning anHDF5Object
.My hacked together timing script can be found in this gist