Closed lindstro closed 1 year ago
@lindstro thanks for reaching out and using LibPressio. a few comments:
I don't have an ability to test on MacOS, but I'll do my best.
OpenMPI is probably brought in by hdf5. You need to build LibPressio '^ hdf5~mpi' to get a build of LibPressio tools without any MPI dependency if you can't get MPI to build. You can debug why a package gets pulled in with spack spec. A slightly better fix is to make HDF5 an optional dependency not required by default, but IMHO having it by default leads to better user experience with the CLI.
For MGARD try '^ mgard@robertu94+cuda' to your LibPressio install. This has a few extra commits to fix things on various compilers I've found. Unfortunately CUDA doesn't seem to be optional for MGARD. If this works for you I'll change the dependency in LibPressio to pull this version when mgard is requested.
In my experience NDZIP requires a really new gcc compiler, and your compiler may not be new or gnu enough for it to work. I'll do some testing and add a conflicts clause so at least you get a better error message.
The better place for git and openmpi build bugs is the main spack repo. I don't maintain these packages. You might reach out to adamjstewart or the maintainers of these packages (openmpi should have one. I'm not sure about git) because he is the spack dev who uses MacOS the most. You can get a list of maintainers with 'spack maintainers $package'
I'll follow up after the weekend.
You might also look at https://spack.readthedocs.io/en/latest/getting_started.html#mixed-toolchains
@robertu94 Thanks for a quick response. As a Livermoron I guess I should know enough about spack to figure out how to list package dependencies. After a fair amount to tinkering to avoid any openmp and git dependencies, and after removing sperr and tthresh, this is what worked for me:
spack install libpressio-tools~mpi ^ libpressio~mpi+bitgrooming+blosc+digitrounding+fpzip+mgardx+sz+sz3+zfp ^ hdf5~mpi
Regarding the pressio
CLI, is there documentation beyond basic usage? Suppose I have n independent 3D data sets of dimensions nx ny nz. Can I compress them all using pressio
in a single invocation? I would not want to treat this as a 4D data set when there is no correlation along the fourth dimension. Would some combination of -p
and -k
do the job?
@lindstro yes. To do so you need a compressor that natively supports multiple buffers. I believe there are 4 right now:
You probably also need to use several other plugins (namely a default one called historian) to get the metrics you want. You also will want to enable hierarchical names so you can configure and get results from meta-compressors independently. I believe the setting is like -Q. This will change the names of all the settings you reference.
I can send you an example Monday once I sit down and confirm it works as expected.
There are also the pressio-batch tools which is configured with JSON in LibPressio-tools, but these also require MPI.
If OpenMP is a problem on MacOS, It should be possible to quickly write a meta-compressor in C++ that compresses many buffers independently, and LibPressio will detect it if you LD_PRELOAD a shared library containing such a compressor. It would essentially be a copy of many_independent_threaded with the openmp stuff stripped out. You would also need to rename all instances of many_independed_threaded to something else like many_independent_serial.
I checked my advanced examples repo: https://github.com/robertu94/libpressio-interesting-scripts and I don’t currently have one like you suggested, but I’ll add one
@lindstro yes. To do so you need a compressor that natively supports multiple buffers. I believe there are 4 right now:
- optzconfig/LibPressio opt (needs MPI I think, could be made optional use +opt on LibPressio-tools) - this won’t do what you want
- many_independent (needs MPI. Use +mpi on LibPressio)
- many_independent_threaded (Needs OpenMP. Use +openmp on LibPressio)
- many_dependent (needs MPI. Use +mpi on LibPressio)
It is not obvious to me why you would need MPI or OpenMP to compress multiple fields. What I'm trying to do is compress the SDRBench QMCPACK data, which consists of 288 independent and uncorrelated 3D fields of dimensions 69 x 69 x 115 each. You don't want to treat this as a single 4D field as the lack of correlation along the outermost dimension will likely have a very negative impact on compression.
You probably also need to use several other plugins (namely a default one called historian) to get the metrics you want.
I can handle the metrics myself. I just want to compress and then decompress the data.
You also will want to enable hierarchical names so you can configure and get results from meta-compressors independently. I believe the setting is like -Q. This will change the names of all the settings you reference.
Not sure I follow.
I can send you an example Monday once I sit down and confirm it works as expected.
Thanks.
There are also the pressio-batch tools which is configured with JSON in LibPressio-tools, but these also require MPI.
If OpenMP is a problem on MacOS, It should be possible to quickly write a meta-compressor in C++ that compresses many buffers independently, and LibPressio will detect it if you LD_PRELOAD a shared library containing such a compressor. It would essentially be a copy of many_independent_threaded with the openmp stuff stripped out. You would also need to rename all instances of many_independed_threaded to something else like many_independent_serial.
Just to be clear, I'm having issues building OpenMPI (not OpenMP) with Spack on macOS. Still, I'd be perfectly happy with a serial tool that does this for a suite of different compressors without having to learn each of their APIs.
@lindstro
It is not obvious to me why you would need MPI or OpenMP to compress multiple fields
The work was done to support multiple buffers as part of an effort to run parallel invocations to compressors. Because parallel was our focus, the serial version never was written because you could simply set many_independent_threaded:nthreads=1
(the default) to get serial execution.
What I'm trying to do is compress the SDRBench QMCPACK data, which consists of 288 independent and uncorrelated 3D fields of dimensions 69 x 69 x 115 each. You don't want to treat this as a single 4D field as the lack of correlation along the outermost dimension will likely have a very negative impact on compression
Of course.
I can handle the metrics myself. I just want to compress and then decompress the data
I assume then that you want to write out the decompressed data then. That doesn't happen by default with the CLI. I made sure to include that in the example linked below.
I can send you an example Monday once I sit down and confirm it works as expected.
As promised here is the example of using multiple files
For this script to produce the stderr that it does need LibPressio@0.88.0. I think I introduced a regression in 0.83.0 so you might need to update if you want this part to work. If your writing out the files yourself, any recent version should work. Here is the example stderr:
/1/error_stat:error_stat:average_difference <double> = -2.53908e-07
/1/error_stat:error_stat:average_error <double> = 8.82639e-07
/1/error_stat:error_stat:difference_range <double> = 2e-05
/1/error_stat:error_stat:error_range <double> = 1e-05
/1/error_stat:error_stat:max_error <double> = 1e-05
/1/error_stat:error_stat:max_pw_rel_error <double> = 3.17604e+06
/1/error_stat:error_stat:max_rel_error <double> = 0.00488292
/1/error_stat:error_stat:min_error <double> = 0
/1/error_stat:error_stat:min_pw_rel_error <double> = 6.08522e-08
/1/error_stat:error_stat:min_rel_error <double> = 0
/1/error_stat:error_stat:mse <double> = 3.66235e-12
/1/error_stat:error_stat:n <uint64> = 25000000
/1/error_stat:error_stat:psnr <double> = 60.5888
/1/error_stat:error_stat:rmse <double> = 1.91373e-06
/1/error_stat:error_stat:value_max <double> = 0.00204795
/1/error_stat:error_stat:value_mean <double> = 8.59691e-06
/1/error_stat:error_stat:value_min <double> = 0
/1/error_stat:error_stat:value_range <double> = 0.00204795
/1/error_stat:error_stat:value_std <double> = 5.25875e-05
/1/size:size:bit_rate <double> = 0.249271
/1/size:size:compressed_size <uint64> = 778972
/1/size:size:compression_ratio <double> = 128.374
/1/size:size:decompressed_size <uint64> = 100000000
/1/size:size:uncompressed_size <uint64> = 100000000
/2/error_stat:error_stat:average_difference <double> = -3.00063e-07
/2/error_stat:error_stat:average_error <double> = 8.86213e-07
/2/error_stat:error_stat:difference_range <double> = 2e-05
/2/error_stat:error_stat:error_range <double> = 1e-05
/2/error_stat:error_stat:max_error <double> = 1e-05
/2/error_stat:error_stat:max_pw_rel_error <double> = 2.75124e+29
/2/error_stat:error_stat:max_rel_error <double> = 0.00133229
/2/error_stat:error_stat:min_error <double> = 0
/2/error_stat:error_stat:min_pw_rel_error <double> = 0
/2/error_stat:error_stat:min_rel_error <double> = 0
/2/error_stat:error_stat:mse <double> = 3.46985e-12
/2/error_stat:error_stat:n <uint64> = 25000000
/2/error_stat:error_stat:psnr <double> = 72.1049
/2/error_stat:error_stat:rmse <double> = 1.86275e-06
/2/error_stat:error_stat:value_max <double> = 0.00750586
/2/error_stat:error_stat:value_mean <double> = 1.2405e-05
/2/error_stat:error_stat:value_min <double> = 0
/2/error_stat:error_stat:value_range <double> = 0.00750586
/2/error_stat:error_stat:value_std <double> = 7.87036e-05
/2/size:size:bit_rate <double> = 0.157954
/2/size:size:compressed_size <uint64> = 493606
/2/size:size:compression_ratio <double> = 202.591
/2/size:size:decompressed_size <uint64> = 100000000
/2/size:size:uncompressed_size <uint64> = 100000000
You also will want to enable hierarchical names so you can configure and get results from meta-compressors independently. I believe the setting is like -Q. This will change the names of all the settings you reference.
Not sure I follow.
tl;dr -- it turns you that you won't need this; read on for an explanation anyway.
By default, LibPressio uses a flat namespace for compressor settings. There is also a "path-based" hierarchical version which is turned on by the -Q
flag. This becomes important to support what LibPressio calls meta-compressors. One example that illustrates the point is the switch
meta-compressor. Imagine that you have two compression schemes that you want to switch between programmatically based on the presence of some feature that appears in the data. Both use ZFP in accuracy mode, but one applies a domain-specific normalization as a pre-processing step which changes the value range. Because of the different ranges of values, you want to be able to configure each ZFP independently so you can set different accuracy levels. You also want to hide the details of this piece-wise compression approach from the user so they just call compress. The switch meta-compressor lets you do this. But then both zfp
plugins both export a pressio:abs
setting and the name would conflict. By turning on this mode, LibPressio changes the names to something like /pressio/1/zfp:pressio:abs
and /pressio/2/zfp:pressio:abs
so you can refer to these settings independently.
I thought I would need this feature to configure libpressio's metrics functionality when using many_independent_threaded
, but it turns out that it is not needed.
After a fair amount to tinkering to avoid any openmp and git dependencies...
Just to be clear, I'm having issues building OpenMPI (not OpenMP) with Spack on macOS
I judged by the first comment that you also had a problem with OpenMP. Wasn't trying to cause greater confusion.
Also it now possible to drop the hdf5
dependency from LibPressio-tools with libpressio-tools~hdf5
@lindstro just following up to make sure that you have what you need.
Thanks for providing the script--I just now saw it. If I understand correctly, it still needs libpressio to be built with OpenMP or OpenMPI. Please confirm.
Also, my goal is to compress multiple fields from a single file, whereas your example handles one field per file. Moreover, this works well enough for two files but would be quite tedious when there are many (hundreds of) fields, as in the QMCPACK example.
In future versions of zfp, we plan to support more than four dimensions as well as specification of which dimensions are correlated. This way, you could compress a single 3D vector field in AoS layout double field[nz][ny][nx][3]
by specifying that the innermost (fastest varying) dimension is not correlated. Similarly, you could compress the QMCPACK SoA data float field[288][115][69][69]
by specifying that the outermost (slowest varying) dimension is the number of independent fields. You would tell zfp that this is a single 4D array that should be compressed as 288 3D arrays, e.g., by specifying uncorrelated dimensions using negative values (e.g., 69 x 69 x 115 x -288). This would simplify compressing data with zfp, and I was hoping libpressio could provide similar functionality for other compressors as well.
@lindstro this is a neat feature (specifying which dims are correlated) in ZFP. In my mind, there are two questions here:
Can LibPressio something expose this? Of course it could. I would imagine the API could be something like zfp:correlated_dims=1,1,2,2,3 (this isn't the exact syntax, but we can store arrays of integers in a setting) indicating that the first two dims are correlated the next two are correlated but not with the first two, and then the last one is not. This would be a patch to the zfp compressor plug-in. We would need to add something like this. We can make something ZFP specific, but encoding it in the dimensions would not fit our API model well; it would be better to use an option to expose this. I'm open to your suggestions here.
What should the API (across compressors) be? This is not clear to me. ZFP is the only one that has such a feature (as far as I know). Once a few more compressors support this, we can add a general api that works across compressors, but we should get some more implementation experience first. When we do, we reserve the namespace pressio: for these general settings.
For compressors that don't natively support this, we could write a "meta-compressor" that would do something generically to provide this kind of functionality on top of compressors that don't. One idea would be to copy the correlated dims into disjoint buffers, run the compressors separately on each, and then concentrate the results with some meta data. But again more implementation experience is needed because it isn't clear what the right choice is here.
MPI or OpenMP
You probably just need OpenMP. We support both as optional dependencies to expose additional features. The script I sent you uses OpenMP. That doesn't mean it has to run in parallel, but that was what the plug-in that enables this was built for. A user could provide their own 3rd party plug-in in their own code that doesn't need either, but this is the version (with OpenMp) that exists today.
@robertu94 I think you misunderstood what I meant by correlated dimensions. By this, I'm referring to dimensions that exhibit high smoothness (autocorrelation) and along which we should compress the data. For example, a specification +nx -ny -nz +nw would indicate that the 4D array is really ny nz independent, smooth 2D arrays of dimensions nx nw each, and the compressor would be invoked ny * nz times. I'm not suggesting that pairs of dimensions would exhibit additional correlation between them, although that is of course possible. I'm not aware of any compressor that would exploit such pairwise correlation.
The benefit here is that you wouldn't have to reorder the data or set up appropriate strides for ny * nz separate zfp_compress()
calls; the compressor would handle that for you.
As for the API, it could be a Boolean array that indicates whether each dimension is smooth or not.
I agree that we could layer this on top of compressors that do not support such a feature. This is easy enough as long as the compressor supports strided access, like zfp does (though the zfp CLI does not yet expose strides). Without that, you'd potentially have to permute the data first so that the smooth dimensions are the fastest varying ones.
@lindstro
I think you misunderstood what I meant by correlated dimensions
Yes. I think you are right. What you are proposing is indeed simpler. I still think that only ZFP (maybe image magick) currently would be positioned to take advantage of such a feature efficently because of its unique strided compression feature so I stand by my earlier statement that we should start with enabling this for ZFP only before we standardize it.
I think the shortest path to exposing this kind of functionality would be to
zfp:strides
) so that it can be passed down to zfp_compress
and zfp_decompress
zfp:strides
then it could skip the data permutation, but if it doesn't you could fall back to data permuation.LibPressio allows users to define these kinds of novel compressors for themselves without modifying LibPressio. It would also be reasonable to fork LibPressio, introduce your changes, and send back a PR, and I would be happy to merge it. If there is a compelling scientific use case where a paper could be written or it is needed for a deliverable for say ECP, I would be happy to help someone else do this.
@robertu94 I agree with all this.
It seems that libpressio is not quite ready to handle an arbitrary number of (uncorrelated) fields, but this proposed feature would be one way of adding such functionality. I'm afraid I don't have enough spare cycles to contribute a solution myself, but if someone has the time to work on this, it would clearly benefit all compressors. For example, SDRBench suggests compressing the 288 independent 3D QMCPACK fields the following suboptimal way:
pressio -b compressor=$COMP -i einspline_288_115_69_69.pre.f32 -d 69 -d 69 -d 33120 -t float -o rel=1e-2 -m time -m size -M all
where 33120 = 288 * 115. In general, this is not the right way to go as there will be sharp discontinuities along the z dimension whenever you traverse different fields. Such an approach works with zfp whenever nz is a multiple of 4 as then blocks don't straddle two different fields, but that is not the case here (115 mod 4 = 3).
Feel free to close this issue for now. Maybe we can revisit it down the road.
@lindstro One last thought, It should be possible to use the chucking
meta compressor to get some of this functionality. See if this example works for you: https://github.com/robertu94/libpressio-interesting-scripts/blob/5e4cc8fbee732c8b2952cf4ec13977f5886f432b/strides.sh
This does not work for me; pressio reports failed to read input file
. And yes, I changed -i
to point to the right path.
Is chunking
the name of the compressor? Should it go last (usage is pressio [args] [compressor]
)? When I change that, I get another error message: non existent option for the compressor : historian:events
. How would I combine this meta compressor with an actual compressor like zfp? Again, there's no documentation of the pressio CLI (or at least I couldn't find any), which would be helpful.
Your script hints at a bug in pressio 0.82.3, but as far as I can tell there's no way to query the pressio version. That, too, would be helpful.
pressio
or pressio -h
provide some basic documentation.
pressio -a version
prints out the version of the library and the compressor plugins.
pressio -a help $COMP_ID
prints help for a compressor.
You can also add -b foo=bar
or -m
flags to this to get help for metrics and more complete help for meta compressors. A pattern that I use often is pressio -a help chunking
then pressio -a help chunking -b chunking:compressor=many_independent_threaded
and so on until all options you need are configured.
chucking
is the name of a meta-compressor. It takes an input, divides it into chunks (using chunk:size
), and passes each chunk to compress_many
of the compressor it is configured to use. This compressor uses many_independent_threaded
which is a meta compressor that compresses chunks (in parallel using OpenMP when many_independent_threaded:nthreads
> 1 and the compressor is pressio:thead_safe
>= pressio_thread_safety_multiple
) with multiple calls to the compressor that it is configured to use (in this case sz3). I configured sz3 to use the historian metric to calculate and record metrics each time it is called. The metric configured to use is a composite
of error_stat
, size
, and write_debug_inputs
the latter of which writes out the decompressed data files using it's io plugin (by default a binary file using the default io method of posix, but other formats like HDF5, numpy, PETSc are possible with the right configuration options and dependencies). The historian makes a record whenever the compressor is cloned (which is done by many_independent_threaded
, and decompress_many
is called as specified in historian:events
.
The order doesn't matter.
The script as it exists today requires libpressio-tools ^ libpressio@0.88.0:+sz3+openmp
To use it with zfp you would ensure that libpressio is also +zfp
like so libpressio-tools ^ libpressio@0.88.0:+sz3+openmp+zfp
@lindstro do you have what you need here? I things are busy with SC coming up.
I'm afraid I've not yet had a chance to tinker with this. Is the conclusion that it is possible to use the pressio
CLI to compress then decompress and output N independent, contiguous fields, where N can be arbitrarily large, i.e., I don't have to repeat arguments N times on the command line? The example script you provided is for a single field; I'm not sure how it illustrates the use case we've been discussing. Any chance you can adapt it to the QMCPACK data, which consists of 288 independent 3D fields?
@lindstro
This works for me, and has all of the features that the strides.sh
script does.
pressio chunking -b chunking:compressor=many_independent_threaded -b many_independent_threaded:compressor=sz3 -b sz3:metric=historian -b historian:metrics=composite -b many_independent_threaded:metric=noop -b composite:plugins=error_stat -b composite:plugins=size -b composite:plugins=write_debug_inputs -o write_debug_inputs:write_output=true -o write_debug_inputs:display_paths=true -o write_debug_inputs:base_path=/tmp/qmc- -o historian:events=clone -o historian:events=decompress_many -o many_independent_threaded:collect_metrics_on_decompression=1 -o many_independent_threaded:preserve_metrics=1 -o pressio:abs=1e-5 -o chunking:size=69 -o chunking:size=69 -o chunking:size=115 -o chunking:size=1 -i ~/git/datasets/qmc-pack/288x115x69x69/einspline_288_115_69_69.pre.f32 -d 69 -d 69 -d 115 -d 288 -t float -W /tmp/qmc.out -M all -O all
The more minimal version is
pressio chunking -b chunking:compressor=many_independent_threaded -b many_independent_threaded:compressor=sz3 -o pressio:abs=1e-5 -o chunking:size=69 -o chunking:size=69 -o chunking:size=115 -o chunking:size=1 -i ~/git/datasets/qmc-pack/288x115x69x69/einspline_288_115_69_69.pre.f32 -d 69 -d 69 -d 115 -d 288 -t float -W /tmp/qmc.out -M all -O all
Then the minimal version using ZFP instead (only -b many_independent_threaded:compressor=
changes):
pressio chunking -b chunking:compressor=many_independent_threaded -b many_independent_threaded:compressor=zfp -o pressio:abs=1e-5 -o chunking:size=69 -o chunking:size=69 -o chunking:size=115 -o chunking:size=1 -i ~/git/datasets/qmc-pack/288x115x69x69/einspline_288_115_69_69.pre.f32 -d 69 -d 69 -d 115 -d 288 -t float -W /tmp/qmc.out -M all -O all
This still gives me a failed to read input file
. As detailed above, I installed libpressio using
spack install libpressio-tools~mpi ^ libpressio~mpi+bitgrooming+blosc+digitrounding+fpzip+mgardx+sz+sz3+zfp ^ hdf5~mpi
Maybe you can try to reproduce?
@lindstro you are missing +openmp
on libpressio which will cause an error message. However, I get a different error message than you when I leave out this variant: non existent option for the compressor : pressio:abs
. This should probably be improved to be something more helpful like compressor "many_independent_threaded" does not exist
but I would need to plumb that error message up.
You will also need to call spack load after calling spack install if you didn't do that before (spack allows multiple versions to be installed at the same time, so needs a command to choose which one is active).
It might be that the file is not the right size for what we specified, but this gives me the error failed to read input file invalid dims
. For me the files is 630,737,280 bytes according to du -b einspline_288_115_69_69.pre.f32
which is sizeof(float) 6969115288.
The file size is correct. I added +openmp
, but I got the same error message. I noticed I had libpressio 0.87 installed. I tried to upgrade to 0.88, but I'm now getting this error: Error: Package 'z-checker-tools' not found
. I've already added repo robertu94_packages
. Any ideas?
@lindstro I wanted to let you know that the remaining issues that I had with the docker container installations are now resolved. a current version of MGARD, SZ3, QoZ, ndzip are now both available in the container. https://github.com/robertu94/libpressio/pkgs/container/libpressio
@robertu94 Thanks for the update. Working through Docker is a last-resort option for me and not really something that I am willing to use permanently as substitute for my existing shell scripts, which like pressio
basically provide a unified "API" for executing different compressors.
It would be great if the macOS issues could be fixed. I just tried reinstalling using the command-line above:
==> Installing bitgroomingz-2022-10-14-ui5b6fkjlxku6k3bv65no6coxghmjgap
...
>> 51 Undefined symbols for architecture x86_64:
52 "_deflate", referenced from:
53 _zlib_compress3 in callZlib.c.o
54 _zlib_compress5 in callZlib.c.o
55 "_deflateBound", referenced from:
56 _zlib_compress5 in callZlib.c.o
57 "_deflateEnd", referenced from:
...
==> Error: Can't extrapolate a URL for version 3.1.7 because package sz3 defines no URLs
I think you had a fix for the SZ3 package but I can't remember what it was. Oddly enough, this error appears even when I leave +sz3
out, in spite of sz3
being off by default. I had to add ~sz3
to get past this.
As before, pressio
reports a failed to read input file
error.
@lindstro I finally got permissions to the use the debugger on the shared m1 development machine at ANL so I was able to figure out these issues.
I've identified a fix for the linking error here for bitgrooming and the spack error for SZ3. I'll submit the fix to Sheng, and then merged get them into upstream spack. I'll ping you when I create the PR.
I've also found a solution to the pressio chunking bug in the example that I posted here. getopt
on MacOS has different behavior than what glibc
has -- namely, glibc
allows the flags and positional arugments to be any order, and macos requires all flags to be passed before all positional arguments. The following command works for me on MacOS:
pressio -b chunking:compressor=many_independent_threaded -b many_independent_threaded:compressor=zfp -o pressio:abs=1e-5 -o chunking:size=69 -o chunking:size=69 -o chunking:size=115 -o chunking:size=1 -i ~/git/datasets/einspline_288_115_69_69.pre.f32 -d 69 -d 69 -d 115 -d 288 -t float -W /tmp/qmc.out -M all -O all chunking
(I just moved chunking
to the last argument from the second.)
BitGrooming Bug:https://github.com/disheng222/BitGroomingZ/pull/2
@robertu94 Thanks for tracking down the issue. I can confirm that the above command does work for me.
I'm trying to install libpressio and libpressio-tools using spack. While some compressors (e.g., mgard and ndzip) won't build with their default spack recipes, I can in general get libpressio and most compressors to install. However, libpressio-tools depends on OpenMPI--even with ~mpi--which won't install with Apple clang 13.0.0:
So I tried using gcc 12.1.0 instead, which fails to install pig-config:
There's also a dependency on git (not sure which package needs it) that similarly fails. Building with gcc 12.1.0 fails for other reasons.
Is there a known toolchain, process, or set of spack options that will allow a spack install on macOS?