-
Notifications
You must be signed in to change notification settings - Fork 128
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
Extended precision floating point support #1972
Comments
I am currently playing around with ways to detect the bit representation of |
I can think of a number of questions that should be answered:
So I think the types that adios2 should support on any given system are:
I guess it's a choice, but supporting a floating point type which isn't natively supported by the compiler / platform would be quite a pain and I don't see the usefulness -- who would want to read data which they then can't process? So on the external API side, you'd want to add I don't see that the binary representation that The other question is what to do with the padding. Currently, adios2 essentially does memcpys of the buffer into BP buffers, which would copy the padding as well. As has already turned up here, that can lead to spurious warnings about uninitialized memory, and potentially even leaking of sensitive information. The other disadvantage would be that it wouldn't be possible to read long double written on 32-bit Linux back on 64-bit Linux or vice versa, even though both are 80-bit float, but with different padding. (Though I doubt there's a lot of use of adios2 on 32-bit Linux.) The alternative would be to rearrange the data to drop the padding before putting things into the BP buffer, and adding it back when reading. The disadvantage to that is that it requires, essentially, a memory copy, and eliminates the possibility of doing anything zero-copy. While touching the entire buffer to eliminate padding is not exactly cheap, I suppose it should be quite a bit cheaper than sending all the useless padding data to disk or over the network, as that bandwidth is much less than memory bandwidth. Finally, there's a question about what to do when reading existing BP3/4 files, which don't encode the details of the actual extended floating point that was written. I suppose if one reads a file on a given architecture, one would want to assume that the The other aspect to this is that going forward one should encode, say, "R80_96" or "R80_128" or whatever as distinct types into the BP3 file, which means that new type ids will need to be introduced, and old readers won't know how to handle them. |
The answer there is that you may well want to read data in a type that isn't natively supported if ADIOS had the ability to convert it to a type that was supported. ADIOS historically has had a pretty rigid type system (not unjustifiably for a middleware focused solely on performance), but a more flexible system might allow you to read a 32-bit float into a 64-bit, or vice versa, if that suited the application's need. It's non-trivial to implement, and if you're really converting from an unsupported type it's going to be costly, but there is usefulness... |
Right, it would of course be useful. I came at this looking at adios2's existing design, where it looks like a choice was made to not support conversions (other than endianness). I'm sure there are situations where it's helpful being able to have the data converted while reading/writing data (like HDF5 does, I believe, though I don't think HDF5 handles extended floating point conversions). There may be even more of a point if support for something like float16 is added, which I don't think has widespread support on CPUs, but can be useful with GPUs. However, if you wanted to add conversions, I think that'll require some thinking on what the API should look like. Right now, the data type is templated into, e.g., adios2::Variable, so InquireVariable(...) will fail if that dataset is using double. That behavior could be updated, but then the next question would if you wanted to support writing, say double data in memory into a float dataset on disk, and what the API would be like. An alternative could be to say the template type is the type on disk, but Get/Put would get overloads that would allow passing data of a different type, which would be converted. So there are certainly options, but doing this as a general feature addition is not a trivial project. |
I bet it's quite the contrary. In my experience, processing the data will be slower than writing the original buffer to disk. That's why compression is not good for speeding up I/O in general. So while we may want to do a flexible way doing buffering, we also need the option to just do it fast. After all, the main consumer requesting this feature cares much about the performance. |
Note: recent HDF5 tutorial at ECP, slides on best practices: first bullet is Do large chunks of IO, second bullet is Avoid datatype conversion. |
Well, I said "I suppose i should be" because I haven't measured it, so I don't know. Note, though, that generally BP3 copies the user provided buffer to the BP3 buffer anyway, so there is already a copy touching both buffers. The access pattern would be slightly more irregular when skipping the padding, but still, it's essentially streaming read/write, so it should perform kinda comparably at that stage, and lead to smaller buffers to deal with later on (only 80 bits out of 128 would be kept in the common case.) Nevertheless, even just dropping the padding is deviation from the overall current design, which mostly considers buffers to be just bits without caring what they represent (with the exception of endianness), and a complication. I think there are pros and cons for going either way, and I personally don't have a strong preference. Note that none of this should ever affect the common case, ie., no-conversion no-padding access would not see any performance impacts.
|
Datatype conversion won't be on anyone's fast path, and if you look at how FFS works, you'll know I believe that it shouldn't be done on the writer side. But it's not like nobody ever moves data from machine to machine or tries to read archival data from unavailable systems. That byte-endian conversion is possible on read is a nod to that necessity, but it's only a small step. |
w.r.t. conversion, we certainly shouldn't make it implicit. Even if it's explicit, the ability to convert between natively supported types is an orthogonal feature that would be independent of the extended precision support (although certainly useful for it). I've also been thinking about "unsupported" types and format. My initial reaction was to simply only support whatever format is native and throw an exception otherwise. i.e. if a Consider the case for |
I think we agree that it's an orthogonal issue in general. (However, when it comes to, e.g., reading an R80_96 float into an R80_128 float, where the latter is
I'm not sure I understand what you mean. Exception would have been my suggested answer. Say on ppc64le (1) throw exception (probably at Are you saying to do (2)? That's essentially what happens today. In this example case it's safe, but on other systems where Even in the cases where (2) is safe, I don't like it, as it's surprising behavior -- adios2 will read the data without any indication that something's amiss, but once you use it, it'll not make sense. E.g., My preference is (1), which is simplest to do, and keeps the option of adding conversion (3) later, or even doing (2) later if somehow that's what people need.
I don't think I get what you're saying here? |
Essentially, while the user may specify So let's take the example of writing a Similarly, writing |
Generally, I support a path to conversion. I don't worry much about whether or not it's implicit. If there's concern that people will be reading non-native data a lot and not know why it's slow, print a warning message. I'd be much more worried about people trying to read non-native data somewhere and the only answer ADIOS has is that "it can't be done"... (Or maybe: "Find a machine that natively supports both the source and destination datatypes and write a program that does the conversion, then bring the data here to read".) |
For implementing it, the |
Okay, that makes perfect sense to me now (it's essentially what I've been thinking to do as well). Obviously, if the internal types match, there's not question that one should be able to read and write them without limitations. What I hadn't thought about doing is providing non-native types on a given system. But I suppose you can do |
And on the by-the-way note, in terms of naming I'd prefer |
Just to make my intent clear: extended precision support (
|
This is to track the issues surrounding support for extended precision float, i.e. long double. Some things to consider:
REAL(16)
may or may not be supported at all and if it is, may not be the same as the corresponding C / C++long double
)The text was updated successfully, but these errors were encountered: