Skip to content

Commit 4c9d8c6

Browse files
authored
Merge pull request #121 from GPUOpen-LibrariesAndSDKs/feature/ORO-0-precomp-zstd
Feature/oro 0 precomp zstd
2 parents 0e046f9 + cfd066f commit 4c9d8c6

5 files changed

Lines changed: 117 additions & 11 deletions

File tree

Orochi/OrochiUtils.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@
3636
#include <sys/stat.h>
3737
#endif
3838

39+
#ifdef ORO_LINK_ZSTD
40+
#include <contrib/zstd/lib/zstd.h>
41+
#endif
42+
3943
inline std::wstring utf8_to_wstring( const std::string& str )
4044
{
4145
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> myconv;
@@ -790,3 +794,45 @@ void OrochiUtils::launch2D( oroFunction func, int nx, int ny, const void** args,
790794
OROASSERT( e == oroSuccess, 0 );
791795
}
792796

797+
void OrochiUtils::HandlePrecompiled(std::vector<unsigned char>& out, const CompressedBuffer& buffer)
798+
{
799+
#ifdef ORO_LINK_ZSTD
800+
out.assign(buffer.uncompressedSize,0);
801+
802+
size_t decompressedSize = ZSTD_decompress(
803+
out.data(), // final uncompressed buffer
804+
out.size(), // final size
805+
buffer.data, // compressed buffer
806+
buffer.size // compressed buffer - size
807+
);
808+
809+
if ( decompressedSize != buffer.uncompressedSize )
810+
throw std::runtime_error( "ERROR: ZSTD_decompress FAILED." );
811+
#else
812+
throw std::runtime_error( "ERROR: ZSTD is not part of this build." );
813+
#endif
814+
return;
815+
}
816+
817+
818+
void OrochiUtils::HandlePrecompiled(std::vector<unsigned char>& out, const RawBuffer& buffer)
819+
{
820+
out = std::vector<unsigned char>(buffer.data, buffer.data + buffer.size );
821+
return;
822+
}
823+
824+
825+
void OrochiUtils::HandlePrecompiled(std::vector<unsigned char>& out, const unsigned char* rawData, size_t rawData_sizeByte, std::optional<size_t> uncompressed_sizeByte)
826+
{
827+
if (uncompressed_sizeByte.has_value()) {
828+
// if the input buffer is compressed :
829+
CompressedBuffer buffer{ rawData, rawData_sizeByte, uncompressed_sizeByte.value() };
830+
HandlePrecompiled(out, buffer );
831+
} else {
832+
// if the input buffer is not compressed
833+
RawBuffer buffer{ rawData, rawData_sizeByte };
834+
HandlePrecompiled(out, buffer );
835+
}
836+
}
837+
838+

Orochi/OrochiUtils.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <filesystem>
2828
#include <unordered_map>
2929
#include <vector>
30+
#include <optional>
3031

3132
#if defined( GNUC )
3233
#include <signal.h>
@@ -83,6 +84,20 @@ class OrochiUtils
8384
static void getModule( oroDevice device, const char* code, const char* path, std::vector<const char*>* optsIn, const char* funcName, oroModule* moduleOut );
8485
static void launch1D( oroFunction func, int nx, const void** args, int wgSize = 64, unsigned int sharedMemBytes = 0, oroStream stream = 0 );
8586
static void launch2D( oroFunction func, int nx, int ny, const void** args, int wgSizeX = 8, int wgSizeY = 8, unsigned int sharedMemBytes = 0, oroStream stream = 0 );
87+
88+
89+
struct CompressedBuffer {
90+
const unsigned char* data = nullptr; // compressed data
91+
size_t size = 0; // size in byte of 'data'
92+
size_t uncompressedSize = 0; // size of byte of the uncompressed data.
93+
};
94+
struct RawBuffer {
95+
const unsigned char* data = nullptr;
96+
size_t size = 0;
97+
};
98+
static void HandlePrecompiled(std::vector<unsigned char>& out, const CompressedBuffer& buffer);
99+
static void HandlePrecompiled(std::vector<unsigned char>& out, const RawBuffer& buffer);
100+
static void HandlePrecompiled(std::vector<unsigned char>& out, const unsigned char* rawData, size_t rawData_sizeByte, std::optional<size_t> uncompressed_sizeByte=std::nullopt);
86101

87102
template<typename T>
88103
static void malloc( T*& ptr, size_t n )

ParallelPrimitives/RadixSort.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ static const char** RadixSortKernelsIncludes = nullptr;
5454
#else
5555
const unsigned char oro_compiled_kernels_h[] = "";
5656
const size_t oro_compiled_kernels_h_size = 0;
57+
const size_t oro_compiled_kernels_h_size_uncompressed = 0;
58+
const bool oro_compiled_kernels_h_isCompressed = false;
5759
#endif
5860

5961
constexpr uint64_t div_round_up64( uint64_t val, uint64_t divisor ) noexcept { return ( val + divisor - 1 ) / divisor; }
@@ -189,8 +191,8 @@ void RadixSort::compileKernels( const std::string& kernelPath, const std::string
189191
{
190192
if constexpr( usePrecompiledAndBakedKernel )
191193
{
192-
// Move the raw buffer into a std::vector, which avoids potential issues explained here: github.com/GPUOpen-LibrariesAndSDKs/HIPRT/pull/38#issuecomment-2761698032
193-
std::vector<unsigned char> binary(oro_compiled_kernels_h, oro_compiled_kernels_h + oro_compiled_kernels_h_size);
194+
std::vector<unsigned char> binary;
195+
OrochiUtils::HandlePrecompiled(binary, oro_compiled_kernels_h, oro_compiled_kernels_h_size, oro_compiled_kernels_h_isCompressed ? std::optional<size_t>{oro_compiled_kernels_h_size_uncompressed} : std::nullopt);
194196
oroFunctions[record.kernelType] = m_oroutils.getFunctionFromPrecompiledBinary_asData(binary.data(), binary.size(), record.kernelName.c_str() );
195197
}
196198
else if constexpr( useBakeKernel )

scripts/convert_binary_to_array.py

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,47 @@
1-
# convert_binary_to_header.py
1+
# convert_binary_to_array.py
22
import sys
33
from pathlib import Path
44

5-
def binary_to_c_array(bin_file, array_name):
5+
def binary_to_c_array(bin_file, array_name, size_BeforeCompression, compression_activated):
66
with open(bin_file, 'rb') as f:
77
binary_data = f.read()
88

99
hex_array = ', '.join(f'0x{b:02x}' for b in binary_data)
1010
c_array = f'const unsigned char {array_name}[] = {{\n {hex_array}\n}};\n'
11-
c_array += f'const size_t {array_name}_size = sizeof({array_name});\n'
11+
c_array += f'const size_t {array_name}_size = sizeof({array_name}); // {len(binary_data)}\n'
12+
13+
c_array += f'const size_t {array_name}_size_uncompressed = '
14+
if compression_activated:
15+
c_array += f'{size_BeforeCompression}; // size of the data in bytes, once it has been uncompressed.\n'
16+
else:
17+
c_array += f'{array_name}_size; // same than raw buffer, because data is not compressed.\n'
18+
19+
c_array += f'const bool {array_name}_isCompressed = '
20+
if compression_activated:
21+
c_array += f'true;\n'
22+
else:
23+
c_array += f'false;\n'
1224
return c_array
1325

1426
if __name__ == "__main__":
15-
if len(sys.argv) != 3:
16-
print(f"Usage: {sys.argv[0]} <input_binary_file> <output_header_file>")
27+
if len(sys.argv) != 5:
28+
print(f"Usage: {sys.argv[0]} <input_binary_file_before_compression> <input_binary_file_after_compression> <output_header_file> <compression_activated>")
1729
sys.exit(1)
1830

19-
bin_file = sys.argv[1]
20-
header_file_path = sys.argv[2]
31+
bin_file_beforeCompression = sys.argv[1]
32+
bin_file_afterCompression = sys.argv[2] # not used if 'compression_activated' is OFF
33+
header_file_path = sys.argv[3]
34+
compression_activated = sys.argv[4].lower() == "on" # sys.argv[4] should be "ON" or "OFF"
35+
2136
header_file = Path(header_file_path).name
2237
array_name = header_file.replace('.', '_')
2338

24-
c_array = binary_to_c_array(bin_file, array_name)
39+
if not compression_activated:
40+
bin_file_afterCompression = bin_file_beforeCompression
41+
42+
c_array = binary_to_c_array(bin_file_afterCompression, array_name, Path(bin_file_beforeCompression).stat().st_size, compression_activated )
2543
with open(header_file_path, 'w') as f:
26-
f.write("// generated by convert_binary_to_header.py\n")
44+
f.write("// generated by convert_binary_to_array.py\n")
45+
if compression_activated:
46+
f.write(f"// Data is compressed.\n")
2747
f.write(c_array)

scripts/create_archive.cmake

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
2+
# create_archive.cmake
3+
# Create a raw Zstd-compressed "archive" from a single file.
4+
5+
# Variables expected:
6+
# INPUT_FILE – path to the file to compress
7+
# OUTPUT_FILE – path to the compressed file to generate
8+
# DO_COMPRESS: ON/OFF
9+
10+
11+
if(DO_COMPRESS)
12+
message("Compress ${INPUT_FILE} ...")
13+
file(ARCHIVE_CREATE
14+
OUTPUT "${OUTPUT_FILE}"
15+
PATHS "${INPUT_FILE}"
16+
FORMAT raw
17+
COMPRESSION Zstd
18+
COMPRESSION_LEVEL 9 # 0-9 for cmake >= 3.19 or 0-19 for cmake >= 3.26
19+
)
20+
endif()
21+
22+
23+

0 commit comments

Comments
 (0)