diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8834cd6413..4594313d8a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,10 @@
+# v6.17.0
+- [#2954](https://github.com/xmrig/xmrig/pull/2954) **Dero HE fork support (`astrobwt/v2` algorithm).**
+ - [#2961](https://github.com/xmrig/xmrig/pull/2961) Dero HE (`astrobwt/v2`) CUDA config generator.
+ - [#2969](https://github.com/xmrig/xmrig/pull/2969) Dero HE (`astrobwt/v2`) OpenCL support.
+- Fixed displayed DMI memory information for empty slots.
+- [#2932](https://github.com/xmrig/xmrig/pull/2932) Fixed GhostRider with hwloc disabled.
+
# v6.16.4
- [#2904](https://github.com/xmrig/xmrig/pull/2904) Fixed unaligned memory accesses.
- [#2908](https://github.com/xmrig/xmrig/pull/2908) Added MSVC/2022 to `version.h`.
diff --git a/README.md b/README.md
index f2715d4010..d9c67d0181 100644
--- a/README.md
+++ b/README.md
@@ -10,7 +10,7 @@
XMRig is a high performance, open source, cross platform RandomX, KawPow, CryptoNight, AstroBWT and [GhostRider](https://github.com/xmrig/xmrig/tree/master/src/crypto/ghostrider#readme) unified CPU/GPU miner and [RandomX benchmark](https://xmrig.com/benchmark). Official binaries are available for Windows, Linux, macOS and FreeBSD.
## Mining backends
-- **CPU** (x64/ARMv8)
+- **CPU** (x64/ARMv7/ARMv8)
- **OpenCL** for AMD GPUs.
- **CUDA** for NVIDIA GPUs via external [CUDA plugin](https://github.com/xmrig/xmrig-cuda).
diff --git a/cmake/astrobwt.cmake b/cmake/astrobwt.cmake
index f0ebf53069..5b0b769178 100644
--- a/cmake/astrobwt.cmake
+++ b/cmake/astrobwt.cmake
@@ -3,10 +3,12 @@ if (WITH_ASTROBWT)
list(APPEND HEADERS_CRYPTO
src/crypto/astrobwt/AstroBWT.h
+ src/crypto/astrobwt/sort_indices2.h
)
list(APPEND SOURCES_CRYPTO
src/crypto/astrobwt/AstroBWT.cpp
+ src/crypto/astrobwt/sort_indices2.cpp
)
if (XMRIG_ARM)
@@ -21,6 +23,10 @@ if (WITH_ASTROBWT)
src/crypto/astrobwt/salsa20_ref/salsa20.c
)
else()
+ if (CMAKE_C_COMPILER_ID MATCHES MSVC)
+ set_source_files_properties(src/crypto/astrobwt/sort_indices2.cpp PROPERTIES COMPILE_FLAGS "/std:c++20")
+ endif()
+
if (CMAKE_SIZEOF_VOID_P EQUAL 8)
add_definitions(/DASTROBWT_AVX2)
list(APPEND SOURCES_CRYPTO src/crypto/astrobwt/xmm6int/salsa20_xmm6int-avx2.c)
diff --git a/scripts/build.hwloc.sh b/scripts/build.hwloc.sh
index 022f67fe2b..cae766986b 100755
--- a/scripts/build.hwloc.sh
+++ b/scripts/build.hwloc.sh
@@ -1,6 +1,10 @@
#!/bin/bash -e
-HWLOC_VERSION="2.5.0"
+HWLOC_VERSION_MAJOR="2"
+HWLOC_VERSION_MINOR="7"
+HWLOC_VERSION_PATCH="0"
+
+HWLOC_VERSION="${HWLOC_VERSION_MAJOR}.${HWLOC_VERSION_MINOR}.${HWLOC_VERSION_PATCH}"
mkdir -p deps
mkdir -p deps/include
@@ -8,7 +12,7 @@ mkdir -p deps/lib
mkdir -p build && cd build
-wget https://download.open-mpi.org/release/hwloc/v2.5/hwloc-${HWLOC_VERSION}.tar.gz -O hwloc-${HWLOC_VERSION}.tar.gz
+wget https://download.open-mpi.org/release/hwloc/v${HWLOC_VERSION_MAJOR}.${HWLOC_VERSION_MINOR}/hwloc-${HWLOC_VERSION}.tar.gz -O hwloc-${HWLOC_VERSION}.tar.gz
tar -xzf hwloc-${HWLOC_VERSION}.tar.gz
cd hwloc-${HWLOC_VERSION}
@@ -16,4 +20,4 @@ cd hwloc-${HWLOC_VERSION}
make -j$(nproc || sysctl -n hw.ncpu || sysctl -n hw.logicalcpu)
cp -fr include ../../deps
cp hwloc/.libs/libhwloc.a ../../deps/lib
-cd ..
\ No newline at end of file
+cd ..
diff --git a/scripts/build.libressl.sh b/scripts/build.libressl.sh
index e7495233a8..236d4d335e 100755
--- a/scripts/build.libressl.sh
+++ b/scripts/build.libressl.sh
@@ -1,6 +1,6 @@
#!/bin/bash -e
-LIBRESSL_VERSION="3.0.2"
+LIBRESSL_VERSION="3.4.2"
mkdir -p deps
mkdir -p deps/include
@@ -17,4 +17,4 @@ make -j$(nproc || sysctl -n hw.ncpu || sysctl -n hw.logicalcpu)
cp -fr include ../../deps
cp crypto/.libs/libcrypto.a ../../deps/lib
cp ssl/.libs/libssl.a ../../deps/lib
-cd ..
\ No newline at end of file
+cd ..
diff --git a/scripts/build.openssl.sh b/scripts/build.openssl.sh
index 580557d647..1aba67dacb 100755
--- a/scripts/build.openssl.sh
+++ b/scripts/build.openssl.sh
@@ -1,6 +1,6 @@
#!/bin/bash -e
-OPENSSL_VERSION="1.1.1l"
+OPENSSL_VERSION="1.1.1m"
mkdir -p deps
mkdir -p deps/include
diff --git a/scripts/build.openssl3.sh b/scripts/build.openssl3.sh
new file mode 100755
index 0000000000..935196109e
--- /dev/null
+++ b/scripts/build.openssl3.sh
@@ -0,0 +1,20 @@
+#!/bin/bash -e
+
+OPENSSL_VERSION="3.0.1"
+
+mkdir -p deps
+mkdir -p deps/include
+mkdir -p deps/lib
+
+mkdir -p build && cd build
+
+wget https://www.openssl.org/source/openssl-${OPENSSL_VERSION}.tar.gz -O openssl-${OPENSSL_VERSION}.tar.gz
+tar -xzf openssl-${OPENSSL_VERSION}.tar.gz
+
+cd openssl-${OPENSSL_VERSION}
+./config -no-shared -no-asm -no-zlib -no-comp -no-dgram -no-filenames -no-cms
+make -j$(nproc || sysctl -n hw.ncpu || sysctl -n hw.logicalcpu)
+cp -fr include ../../deps
+cp libcrypto.a ../../deps/lib
+cp libssl.a ../../deps/lib
+cd ..
diff --git a/scripts/build.uv.sh b/scripts/build.uv.sh
index 6179b2d203..8124759d06 100755
--- a/scripts/build.uv.sh
+++ b/scripts/build.uv.sh
@@ -1,6 +1,6 @@
#!/bin/bash -e
-UV_VERSION="1.42.0"
+UV_VERSION="1.43.0"
mkdir -p deps
mkdir -p deps/include
@@ -17,4 +17,4 @@ sh autogen.sh
make -j$(nproc || sysctl -n hw.ncpu || sysctl -n hw.logicalcpu)
cp -fr include ../../deps
cp .libs/libuv.a ../../deps/lib
-cd ..
\ No newline at end of file
+cd ..
diff --git a/scripts/generate_cl.js b/scripts/generate_cl.js
index c3fffbf98a..79e430998c 100644
--- a/scripts/generate_cl.js
+++ b/scripts/generate_cl.js
@@ -76,6 +76,14 @@ function astrobwt()
}
+function astrobwt_v2()
+{
+ const astrobwt = opencl_minify(addIncludes('astrobwt_v2.cl', [ 'BWT.cl', 'salsa20.cl', 'sha3.cl' ]));
+
+ fs.writeFileSync('astrobwt_v2_cl.h', text2h(astrobwt, 'xmrig', 'astrobwt_v2_cl'));
+}
+
+
function kawpow()
{
const kawpow = opencl_minify(addIncludes('kawpow.cl', [ 'defs.h' ]));
@@ -102,6 +110,11 @@ process.chdir(path.resolve('src/backend/opencl/cl/astrobwt'));
astrobwt();
+process.chdir(cwd);
+process.chdir(path.resolve('src/backend/opencl/cl/astrobwt_v2'));
+
+astrobwt_v2();
+
process.chdir(cwd);
process.chdir(path.resolve('src/backend/opencl/cl/kawpow'));
diff --git a/src/3rdparty/hwloc/NEWS b/src/3rdparty/hwloc/NEWS
index 0bf74d4490..71f858a3d0 100644
--- a/src/3rdparty/hwloc/NEWS
+++ b/src/3rdparty/hwloc/NEWS
@@ -17,6 +17,76 @@ bug fixes (and other actions) for each version of hwloc since version
0.9.
+Version 2.7.0
+-------------
+* Backends
+ + Add support for NUMA nodes and caches with more than 64 PUs across
+ multiple processor groups on Windows 11 and Windows Server 2022.
+ + Group objects are not created for Windows processor groups anymore,
+ except if HWLOC_WINDOWS_PROCESSOR_GROUP_OBJS=1 in the environment.
+ + Expose "Cluster" group objects on Linux kernel 5.16+ for CPUs
+ that share some internal cache or bus. This can be equivalent
+ to the L2 Cache level on some platforms (e.g. x86) or a specific
+ level between L2 and L3 on others (e.g. ARM Kungpeng 920).
+ Thanks to Jonathan Cameron for the help.
+ - HWLOC_DONT_MERGE_CLUSTER_GROUPS=1 may be set in the environment
+ to prevent these groups from being merged with identical caches, etc.
+ + Improve the oneAPI LevelZero backend:
+ - Expose subdevices such as "ze0.1" inside root OS devices ("ze0")
+ when the hardware contains multiple subdevices.
+ - Add many new attributes to describe device type, and the
+ numbers of slices, subslices, execution units and threads.
+ - Expose the memory information as LevelZeroHBM/DDR/MemorySize infos.
+ + Ignore the max frequencies of cores in Linux cpukinds when the
+ base frequencies are available (to avoid exposing hybrid CPUs
+ when Intel Turbo Boost Max 3.0 gives slightly different max
+ frequencies to CPU cores).
+ - May be reverted by setting HWLOC_CPUKINDS_MAXFREQ=1 in the environment.
+* Tools
+ + Add --grey and --palette options to switch lstopo to greyscale or
+ white-background-only graphics, or to tune individual colors.
+* Build
+ + Windows CMake builds now support non-MSVC compilers, detect several
+ features at build time, can build/run tests, etc.
+ Thanks to Michael Hirsch and Alexander Neumann .
+
+
+Version 2.6.0
+-------------
+* Backends
+ + Expose two cpukinds for energy-efficient cores (icestorm) and
+ high-performance cores (firestorm) on Apple M1 on Mac OS X.
+ + Use sysfs CPU "capacity" to rank hybrid cores by efficiency
+ on Linux when available (mostly on recent ARM platforms for now).
+ + Improve HWLOC_MEMBIND_BIND (without the STRICT flag) on Linux kernel
+ >= 5.15: If more than one node is given, the kernel may now use all
+ of them instead of only the first one before falling back to others.
+ + Expose cache os_index when available on Linux, it may be needed
+ when using resctrl to configure cache partitioning, memory bandwidth
+ monitoring, etc.
+ + Add a "XGMIHops" distances matrix in the RSMI backend for AMD GPU
+ interconnected through XGMI links.
+ + Expose AMD GPU memory information (VRAM and GTT) in the RSMI backend.
+ + Add OS devices such as "bxi0" for Atos/Bull BXI HCAs on Linux.
+* Tools
+ + lstopo has a better placement algorithm with respect to I/O
+ objects, see --children-order in the manpage for details.
+ + hwloc-annotate may now change object subtypes and cache or memory
+ sizes.
+* Build
+ + Allow to specify the ROCm installation for building the RSMI backend:
+ - Use a custom installation path if specified with --with-rocm=
.
+ - Use /opt/rocm- if specified with --with-rocm-version=
+ or the ROCM_VERSION environment variable.
+ - Try /opt/rocm if it exists.
+ - See "How do I enable ROCm SMI and select which version to use?"
+ in the FAQ for details.
+ + Add a CMakeLists for Windows under contrib/windows-cmake/ .
+* Documentation
+ + Add FAQ entry "How do I create a custom heterogeneous and
+ asymmetric topology?"
+
+
Version 2.5.0
-------------
* API
diff --git a/src/3rdparty/hwloc/VERSION b/src/3rdparty/hwloc/VERSION
index a74f0a53e6..7486ae04f3 100644
--- a/src/3rdparty/hwloc/VERSION
+++ b/src/3rdparty/hwloc/VERSION
@@ -8,7 +8,7 @@
# Please update HWLOC_VERSION* in contrib/windows/hwloc_config.h too.
major=2
-minor=5
+minor=7
release=0
# greek is used for alpha or beta release tags. If it is non-empty,
@@ -22,7 +22,7 @@ greek=
# The date when this release was created
-date="Jun 14, 2021"
+date="Dec 06, 2021"
# If snapshot=1, then use the value from snapshot_version as the
# entire hwloc version (i.e., ignore major, minor, release, and
@@ -41,7 +41,7 @@ snapshot_version=${major}.${minor}.${release}${greek}-git
# 2. Version numbers are described in the Libtool current:revision:age
# format.
-libhwloc_so_version=20:0:5
+libhwloc_so_version=20:2:5
libnetloc_so_version=0:0:0
# Please also update the lines in contrib/windows/libhwloc.vcxproj
diff --git a/src/3rdparty/hwloc/include/hwloc.h b/src/3rdparty/hwloc/include/hwloc.h
index 88fac968e7..b5f0f48a15 100644
--- a/src/3rdparty/hwloc/include/hwloc.h
+++ b/src/3rdparty/hwloc/include/hwloc.h
@@ -346,7 +346,8 @@ typedef enum hwloc_obj_osdev_type_e {
* For instance the "eth0" interface on Linux. */
HWLOC_OBJ_OSDEV_OPENFABRICS, /**< \brief Operating system openfabrics device.
* For instance the "mlx4_0" InfiniBand HCA,
- * or "hfi1_0" Omni-Path interface on Linux. */
+ * "hfi1_0" Omni-Path interface,
+ * or "bxi0" Atos/Bull BXI HCA on Linux. */
HWLOC_OBJ_OSDEV_DMA, /**< \brief Operating system dma engine device.
* For instance the "dma0chan0" DMA channel on Linux. */
HWLOC_OBJ_OSDEV_COPROC /**< \brief Operating system co-processor device.
@@ -1212,8 +1213,9 @@ HWLOC_DECLSPEC int hwloc_set_cpubind(hwloc_topology_t topology, hwloc_const_cpus
/** \brief Get current process or thread binding.
*
- * Writes into \p set the physical cpuset which the process or thread (according to \e
- * flags) was last bound to.
+ * The CPU-set \p set (previously allocated by the caller)
+ * is filled with the list of PUs which the process or
+ * thread (according to \e flags) was last bound to.
*/
HWLOC_DECLSPEC int hwloc_get_cpubind(hwloc_topology_t topology, hwloc_cpuset_t set, int flags);
@@ -1231,6 +1233,10 @@ HWLOC_DECLSPEC int hwloc_get_cpubind(hwloc_topology_t topology, hwloc_cpuset_t s
HWLOC_DECLSPEC int hwloc_set_proc_cpubind(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_const_cpuset_t set, int flags);
/** \brief Get the current physical binding of process \p pid.
+ *
+ * The CPU-set \p set (previously allocated by the caller)
+ * is filled with the list of PUs which the process
+ * was last bound to.
*
* \note \p hwloc_pid_t is \p pid_t on Unix platforms,
* and \p HANDLE on native Windows platforms.
@@ -1256,6 +1262,10 @@ HWLOC_DECLSPEC int hwloc_set_thread_cpubind(hwloc_topology_t topology, hwloc_thr
#ifdef hwloc_thread_t
/** \brief Get the current physical binding of thread \p tid.
+ *
+ * The CPU-set \p set (previously allocated by the caller)
+ * is filled with the list of PUs which the thread
+ * was last bound to.
*
* \note \p hwloc_thread_t is \p pthread_t on Unix platforms,
* and \p HANDLE on native Windows platforms.
@@ -1266,6 +1276,10 @@ HWLOC_DECLSPEC int hwloc_get_thread_cpubind(hwloc_topology_t topology, hwloc_thr
#endif
/** \brief Get the last physical CPU where the current process or thread ran.
+ *
+ * The CPU-set \p set (previously allocated by the caller)
+ * is filled with the list of PUs which the process or
+ * thread (according to \e flags) last ran on.
*
* The operating system may move some tasks from one processor
* to another at any time according to their binding,
@@ -1281,6 +1295,10 @@ HWLOC_DECLSPEC int hwloc_get_thread_cpubind(hwloc_topology_t topology, hwloc_thr
HWLOC_DECLSPEC int hwloc_get_last_cpu_location(hwloc_topology_t topology, hwloc_cpuset_t set, int flags);
/** \brief Get the last physical CPU where a process ran.
+ *
+ * The CPU-set \p set (previously allocated by the caller)
+ * is filled with the list of PUs which the process
+ * last ran on.
*
* The operating system may move some tasks from one processor
* to another at any time according to their binding,
@@ -1511,6 +1529,9 @@ HWLOC_DECLSPEC int hwloc_set_membind(hwloc_topology_t topology, hwloc_const_bitm
/** \brief Query the default memory binding policy and physical locality of the
* current process or thread.
*
+ * The bitmap \p set (previously allocated by the caller)
+ * is filled with the process or thread memory binding.
+ *
* This function has two output parameters: \p set and \p policy.
* The values returned in these parameters depend on both the \p flags
* passed in and the current memory binding policies and nodesets in
@@ -1571,6 +1592,9 @@ HWLOC_DECLSPEC int hwloc_set_proc_membind(hwloc_topology_t topology, hwloc_pid_t
/** \brief Query the default memory binding policy and physical locality of the
* specified process.
*
+ * The bitmap \p set (previously allocated by the caller)
+ * is filled with the process memory binding.
+ *
* This function has two output parameters: \p set and \p policy.
* The values returned in these parameters depend on both the \p flags
* passed in and the current memory binding policies and nodesets in
@@ -1624,6 +1648,9 @@ HWLOC_DECLSPEC int hwloc_set_area_membind(hwloc_topology_t topology, const void
/** \brief Query the CPUs near the physical NUMA node(s) and binding policy of
* the memory identified by (\p addr, \p len ).
*
+ * The bitmap \p set (previously allocated by the caller)
+ * is filled with the memory area binding.
+ *
* This function has two output parameters: \p set and \p policy.
* The values returned in these parameters depend on both the \p flags
* passed in and the memory binding policies and nodesets of the pages
@@ -1652,7 +1679,8 @@ HWLOC_DECLSPEC int hwloc_get_area_membind(hwloc_topology_t topology, const void
/** \brief Get the NUMA nodes where memory identified by (\p addr, \p len ) is physically allocated.
*
- * Fills \p set according to the NUMA nodes where the memory area pages
+ * The bitmap \p set (previously allocated by the caller)
+ * is filled according to the NUMA nodes where the memory area pages
* are physically allocated. If no page is actually allocated yet,
* \p set may be empty.
*
@@ -1698,9 +1726,12 @@ HWLOC_DECLSPEC void *hwloc_alloc_membind(hwloc_topology_t topology, size_t len,
/** \brief Allocate some memory on NUMA memory nodes specified by \p set
*
- * This is similar to hwloc_alloc_membind_nodeset() except that it is allowed to change
- * the current memory binding policy, thus providing more binding support, at
- * the expense of changing the current state.
+ * First, try to allocate properly with hwloc_alloc_membind().
+ * On failure, the current process or thread memory binding policy
+ * is changed with hwloc_set_membind() before allocating memory.
+ * Thus this function works in more cases, at the expense of changing
+ * the current state (possibly affecting future allocations that
+ * would not specify any policy).
*
* If ::HWLOC_MEMBIND_BYNODESET is specified, set is considered a nodeset.
* Otherwise it's a cpuset.
diff --git a/src/3rdparty/hwloc/include/hwloc/autogen/config.h b/src/3rdparty/hwloc/include/hwloc/autogen/config.h
index eb70ba490f..8d89fa2538 100644
--- a/src/3rdparty/hwloc/include/hwloc/autogen/config.h
+++ b/src/3rdparty/hwloc/include/hwloc/autogen/config.h
@@ -1,6 +1,6 @@
/*
* Copyright © 2009 CNRS
- * Copyright © 2009-2020 Inria. All rights reserved.
+ * Copyright © 2009-2021 Inria. All rights reserved.
* Copyright © 2009-2012 Université Bordeaux
* Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved.
* See COPYING in top-level directory.
@@ -11,9 +11,9 @@
#ifndef HWLOC_CONFIG_H
#define HWLOC_CONFIG_H
-#define HWLOC_VERSION "2.5.0"
+#define HWLOC_VERSION "2.7.0"
#define HWLOC_VERSION_MAJOR 2
-#define HWLOC_VERSION_MINOR 5
+#define HWLOC_VERSION_MINOR 7
#define HWLOC_VERSION_RELEASE 0
#define HWLOC_VERSION_GREEK ""
diff --git a/src/3rdparty/hwloc/include/hwloc/cpukinds.h b/src/3rdparty/hwloc/include/hwloc/cpukinds.h
index f240baf390..524a05afe8 100644
--- a/src/3rdparty/hwloc/include/hwloc/cpukinds.h
+++ b/src/3rdparty/hwloc/include/hwloc/cpukinds.h
@@ -1,5 +1,5 @@
/*
- * Copyright © 2020 Inria. All rights reserved.
+ * Copyright © 2020-2021 Inria. All rights reserved.
* See COPYING in top-level directory.
*/
@@ -42,18 +42,23 @@ extern "C" {
* (for instance the "CoreType" and "FrequencyMaxMHz",
* see \ref topoattrs_cpukinds).
*
- * A higher efficiency value means intrinsic greater performance
+ * A higher efficiency value means greater intrinsic performance
* (and possibly less performance/power efficiency).
- * Kinds with lower efficiency are ranked first:
+ * Kinds with lower efficiency values are ranked first:
* Passing 0 as \p kind_index to hwloc_cpukinds_get_info() will
- * return information about the less efficient CPU kind.
- *
- * When available, efficiency values are gathered from the operating
- * system (when \p cpukind_efficiency is set in the
- * struct hwloc_topology_discovery_support array, only on Windows 10 for now).
- * Otherwise hwloc tries to compute efficiencies
- * by comparing CPU kinds using frequencies (on ARM),
- * or core types and frequencies (on other architectures).
+ * return information about the CPU kind with lower performance
+ * but higher energy-efficiency.
+ * Higher \p kind_index values would rather return information
+ * about power-hungry high-performance cores.
+ *
+ * When available, efficiency values are gathered from the operating system.
+ * If so, \p cpukind_efficiency is set in the struct hwloc_topology_discovery_support array.
+ * This is currently available on Windows 10, Mac OS X (Darwin),
+ * and on some Linux platforms where core "capacity" is exposed in sysfs.
+ *
+ * If the operating system does not expose core efficiencies natively,
+ * hwloc tries to compute efficiencies by comparing CPU kinds using
+ * frequencies (on ARM), or core types and frequencies (on other architectures).
* The environment variable HWLOC_CPUKINDS_RANKING may be used
* to change this heuristics, see \ref envvar.
*
diff --git a/src/3rdparty/hwloc/include/hwloc/distances.h b/src/3rdparty/hwloc/include/hwloc/distances.h
index 6eac94e975..44cd7ea1fa 100644
--- a/src/3rdparty/hwloc/include/hwloc/distances.h
+++ b/src/3rdparty/hwloc/include/hwloc/distances.h
@@ -35,7 +35,8 @@ extern "C" {
* from a core in another node.
* The corresponding kind is ::HWLOC_DISTANCES_KIND_FROM_OS | ::HWLOC_DISTANCES_KIND_FROM_USER.
* The name of this distances structure is "NUMALatency".
- * Others distance structures include and "XGMIBandwidth" and "NVLinkBandwidth".
+ * Others distance structures include and "XGMIBandwidth", "XGMIHops"
+ * and "NVLinkBandwidth".
*
* The matrix may also contain bandwidths between random sets of objects,
* possibly provided by the user, as specified in the \p kind attribute.
@@ -159,7 +160,7 @@ hwloc_distances_get_by_type(hwloc_topology_t topology, hwloc_obj_type_t type,
* Usually only one distances structure may match a given name.
*
* The name of the most common structure is "NUMALatency".
- * Others include "XGMIBandwidth" and "NVLinkBandwidth".
+ * Others include "XGMIBandwidth", "XGMIHops" and "NVLinkBandwidth".
*/
HWLOC_DECLSPEC int
hwloc_distances_get_by_name(hwloc_topology_t topology, const char *name,
diff --git a/src/3rdparty/hwloc/include/hwloc/linux.h b/src/3rdparty/hwloc/include/hwloc/linux.h
index ecc86be3df..d76633b0f6 100644
--- a/src/3rdparty/hwloc/include/hwloc/linux.h
+++ b/src/3rdparty/hwloc/include/hwloc/linux.h
@@ -1,6 +1,6 @@
/*
* Copyright © 2009 CNRS
- * Copyright © 2009-2016 Inria. All rights reserved.
+ * Copyright © 2009-2021 Inria. All rights reserved.
* Copyright © 2009-2011 Université Bordeaux
* See COPYING in top-level directory.
*/
@@ -44,6 +44,10 @@ extern "C" {
HWLOC_DECLSPEC int hwloc_linux_set_tid_cpubind(hwloc_topology_t topology, pid_t tid, hwloc_const_cpuset_t set);
/** \brief Get the current binding of thread \p tid
+ *
+ * The CPU-set \p set (previously allocated by the caller)
+ * is filled with the list of PUs which the thread
+ * was last bound to.
*
* The behavior is exactly the same as the Linux sched_getaffinity system call,
* but uses a hwloc cpuset.
@@ -54,6 +58,9 @@ HWLOC_DECLSPEC int hwloc_linux_set_tid_cpubind(hwloc_topology_t topology, pid_t
HWLOC_DECLSPEC int hwloc_linux_get_tid_cpubind(hwloc_topology_t topology, pid_t tid, hwloc_cpuset_t set);
/** \brief Get the last physical CPU where thread \p tid ran.
+ *
+ * The CPU-set \p set (previously allocated by the caller)
+ * is filled with the PU which the thread last ran on.
*
* \note This is equivalent to calling hwloc_get_proc_last_cpu_location() with
* ::HWLOC_CPUBIND_THREAD as flags.
diff --git a/src/3rdparty/hwloc/include/hwloc/plugins.h b/src/3rdparty/hwloc/include/hwloc/plugins.h
index 6e4f129156..ed4b833d84 100644
--- a/src/3rdparty/hwloc/include/hwloc/plugins.h
+++ b/src/3rdparty/hwloc/include/hwloc/plugins.h
@@ -497,6 +497,7 @@ hwloc_filter_check_pcidev_subtype_important(unsigned classid)
return (baseclass == 0x03 /* PCI_BASE_CLASS_DISPLAY */
|| baseclass == 0x02 /* PCI_BASE_CLASS_NETWORK */
|| baseclass == 0x01 /* PCI_BASE_CLASS_STORAGE */
+ || baseclass == 0x00 /* Unclassified, for Atos/Bull BXI */
|| baseclass == 0x0b /* PCI_BASE_CLASS_PROCESSOR */
|| classid == 0x0c04 /* PCI_CLASS_SERIAL_FIBER */
|| classid == 0x0c06 /* PCI_CLASS_SERIAL_INFINIBAND */
diff --git a/src/3rdparty/hwloc/include/private/autogen/config.h b/src/3rdparty/hwloc/include/private/autogen/config.h
index 687e82bc4b..5bf22fac85 100644
--- a/src/3rdparty/hwloc/include/private/autogen/config.h
+++ b/src/3rdparty/hwloc/include/private/autogen/config.h
@@ -1,6 +1,6 @@
/*
* Copyright © 2009, 2011, 2012 CNRS. All rights reserved.
- * Copyright © 2009-2020 Inria. All rights reserved.
+ * Copyright © 2009-2021 Inria. All rights reserved.
* Copyright © 2009, 2011, 2012, 2015 Université Bordeaux. All rights reserved.
* Copyright © 2009-2020 Cisco Systems, Inc. All rights reserved.
* $COPYRIGHT$
@@ -290,10 +290,6 @@
/* Define to '1' if sysctlbyname is present and usable */
/* #undef HAVE_SYSCTLBYNAME */
-/* Define to 1 if the system has the type
- `SYSTEM_LOGICAL_PROCESSOR_INFORMATION'. */
-#define HAVE_SYSTEM_LOGICAL_PROCESSOR_INFORMATION 1
-
/* Define to 1 if the system has the type
`SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX'. */
#define HAVE_SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX 1
diff --git a/src/3rdparty/hwloc/include/private/misc.h b/src/3rdparty/hwloc/include/private/misc.h
index 6c02d793bb..bc57e98ec8 100644
--- a/src/3rdparty/hwloc/include/private/misc.h
+++ b/src/3rdparty/hwloc/include/private/misc.h
@@ -504,7 +504,7 @@ hwloc__obj_type_is_icache(hwloc_obj_type_t type)
} \
} while(0)
#else /* HAVE_USELOCALE */
-#if __HWLOC_HAVE_ATTRIBUTE_UNUSED
+#if HWLOC_HAVE_ATTRIBUTE_UNUSED
#define hwloc_localeswitch_declare int __dummy_nolocale __hwloc_attribute_unused
#define hwloc_localeswitch_init()
#else
diff --git a/src/3rdparty/hwloc/include/private/private.h b/src/3rdparty/hwloc/include/private/private.h
index 5e216632f8..131b079650 100644
--- a/src/3rdparty/hwloc/include/private/private.h
+++ b/src/3rdparty/hwloc/include/private/private.h
@@ -480,6 +480,7 @@ extern char * hwloc_progname(struct hwloc_topology *topology);
#define HWLOC_GROUP_KIND_AIX_SDL_UNKNOWN 210 /* subkind is SDL level */
#define HWLOC_GROUP_KIND_WINDOWS_PROCESSOR_GROUP 220 /* no subkind */
#define HWLOC_GROUP_KIND_WINDOWS_RELATIONSHIP_UNKNOWN 221 /* no subkind */
+#define HWLOC_GROUP_KIND_LINUX_CLUSTER 222 /* no subkind */
/* distance groups */
#define HWLOC_GROUP_KIND_DISTANCE 900 /* subkind is round of adding these groups during distance based grouping */
/* finally, hwloc-specific groups required to insert something else, should disappear as soon as possible */
diff --git a/src/3rdparty/hwloc/include/private/windows.h b/src/3rdparty/hwloc/include/private/windows.h
new file mode 100644
index 0000000000..0a061b0942
--- /dev/null
+++ b/src/3rdparty/hwloc/include/private/windows.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright © 2009 Université Bordeaux
+ * Copyright © 2020 Inria. All rights reserved.
+ *
+ * See COPYING in top-level directory.
+ */
+
+#ifndef HWLOC_PRIVATE_WINDOWS_H
+#define HWLOC_PRIVATE_WINDOWS_H
+
+#ifdef __GNUC__
+#define _ANONYMOUS_UNION __extension__
+#define _ANONYMOUS_STRUCT __extension__
+#else
+#define _ANONYMOUS_UNION
+#define _ANONYMOUS_STRUCT
+#endif /* __GNUC__ */
+#define DUMMYUNIONNAME
+#define DUMMYSTRUCTNAME
+
+#endif /* HWLOC_PRIVATE_WINDOWS_H */
diff --git a/src/3rdparty/hwloc/src/cpukinds.c b/src/3rdparty/hwloc/src/cpukinds.c
index 074b7a732f..fc05f17ee9 100644
--- a/src/3rdparty/hwloc/src/cpukinds.c
+++ b/src/3rdparty/hwloc/src/cpukinds.c
@@ -42,6 +42,9 @@ hwloc_internal_cpukinds_dup(hwloc_topology_t new, hwloc_topology_t old)
struct hwloc_internal_cpukind_s *kinds;
unsigned i;
+ if (!old->nr_cpukinds)
+ return 0;
+
kinds = hwloc_tma_malloc(tma, old->nr_cpukinds * sizeof(*kinds));
if (!kinds)
return -1;
@@ -445,7 +448,9 @@ static int hwloc__cpukinds_compare_ranking_values(const void *_a, const void *_b
{
const struct hwloc_internal_cpukind_s *a = _a;
const struct hwloc_internal_cpukind_s *b = _b;
- return a->ranking_value - b->ranking_value;
+ uint64_t arv = a->ranking_value;
+ uint64_t brv = b->ranking_value;
+ return arv < brv ? -1 : arv > brv ? 1 : 0;
}
/* this function requires ranking values to be unique */
diff --git a/src/3rdparty/hwloc/src/memattrs.c b/src/3rdparty/hwloc/src/memattrs.c
index 16e9896ed8..92efe5757d 100644
--- a/src/3rdparty/hwloc/src/memattrs.c
+++ b/src/3rdparty/hwloc/src/memattrs.c
@@ -1,5 +1,5 @@
/*
- * Copyright © 2020 Inria. All rights reserved.
+ * Copyright © 2020-2021 Inria. All rights reserved.
* See COPYING in top-level directory.
*/
@@ -127,6 +127,8 @@ hwloc_internal_memattrs_dup(struct hwloc_topology *new, struct hwloc_topology *o
struct hwloc_internal_memattr_s *imattrs;
hwloc_memattr_id_t id;
+ /* old->nr_memattrs is always > 0 thanks to default memattrs */
+
imattrs = hwloc_tma_malloc(tma, old->nr_memattrs * sizeof(*imattrs));
if (!imattrs)
return -1;
diff --git a/src/3rdparty/hwloc/src/pci-common.c b/src/3rdparty/hwloc/src/pci-common.c
index 24626860a2..977475ebda 100644
--- a/src/3rdparty/hwloc/src/pci-common.c
+++ b/src/3rdparty/hwloc/src/pci-common.c
@@ -810,13 +810,14 @@ hwloc_pcidisc_find_linkspeed(const unsigned char *config,
* PCIe Gen3 = 8 GT/s signal-rate per lane with 128/130 encoding = 1 GB/s data-rate per lane
* PCIe Gen4 = 16 GT/s signal-rate per lane with 128/130 encoding = 2 GB/s data-rate per lane
* PCIe Gen5 = 32 GT/s signal-rate per lane with 128/130 encoding = 4 GB/s data-rate per lane
+ * PCIe Gen6 = 64 GT/s signal-rate per lane with 128/130 encoding = 8 GB/s data-rate per lane
*/
/* lanespeed in Gbit/s */
if (speed <= 2)
lanespeed = 2.5f * speed * 0.8f;
else
- lanespeed = 8.0f * (1<<(speed-3)) * 128/130; /* assume Gen6 will be 64 GT/s and so on */
+ lanespeed = 8.0f * (1<<(speed-3)) * 128/130; /* assume Gen7 will be 128 GT/s and so on */
/* linkspeed in GB/s */
*linkspeed = lanespeed * width / 8;
diff --git a/src/3rdparty/hwloc/src/topology-windows.c b/src/3rdparty/hwloc/src/topology-windows.c
index d67c6b994c..df93c5e9c8 100644
--- a/src/3rdparty/hwloc/src/topology-windows.c
+++ b/src/3rdparty/hwloc/src/topology-windows.c
@@ -13,6 +13,7 @@
#include "hwloc.h"
#include "hwloc/windows.h"
#include "private/private.h"
+#include "private/windows.h" /* must be before windows.h */
#include "private/debug.h"
#include
@@ -65,26 +66,6 @@ typedef enum _LOGICAL_PROCESSOR_RELATIONSHIP {
# endif /* HAVE_RELATIONPROCESSORPACKAGE */
#endif /* HAVE_LOGICAL_PROCESSOR_RELATIONSHIP */
-#ifndef HAVE_SYSTEM_LOGICAL_PROCESSOR_INFORMATION
-typedef struct _SYSTEM_LOGICAL_PROCESSOR_INFORMATION {
- ULONG_PTR ProcessorMask;
- LOGICAL_PROCESSOR_RELATIONSHIP Relationship;
- _ANONYMOUS_UNION
- union {
- struct {
- BYTE flags;
- } ProcessorCore;
- struct {
- DWORD NodeNumber;
- } NumaNode;
- CACHE_DESCRIPTOR Cache;
- ULONGLONG Reserved[2];
- } DUMMYUNIONNAME;
-} SYSTEM_LOGICAL_PROCESSOR_INFORMATION, *PSYSTEM_LOGICAL_PROCESSOR_INFORMATION;
-#endif
-
-/* Extended interface, for group support */
-
#ifndef HAVE_GROUP_AFFINITY
typedef struct _GROUP_AFFINITY {
KAFFINITY Mask;
@@ -93,35 +74,40 @@ typedef struct _GROUP_AFFINITY {
} GROUP_AFFINITY, *PGROUP_AFFINITY;
#endif
-#ifndef HAVE_PROCESSOR_RELATIONSHIP
+/* always use our own structure because the EfficiencyClass field didn't exist before Win10 */
typedef struct HWLOC_PROCESSOR_RELATIONSHIP {
BYTE Flags;
- BYTE EfficiencyClass; /* for RelationProcessorCore, higher means greater performance but less efficiency, only available in Win10+ */
+ BYTE EfficiencyClass; /* for RelationProcessorCore, higher means greater performance but less efficiency */
BYTE Reserved[20];
WORD GroupCount;
GROUP_AFFINITY GroupMask[ANYSIZE_ARRAY];
-} PROCESSOR_RELATIONSHIP, *PPROCESSOR_RELATIONSHIP;
-#endif
+} HWLOC_PROCESSOR_RELATIONSHIP;
-#ifndef HAVE_NUMA_NODE_RELATIONSHIP
-typedef struct _NUMA_NODE_RELATIONSHIP {
+/* always use our own structure because the GroupCount and GroupMasks fields didn't exist in some Win10 */
+typedef struct HWLOC_NUMA_NODE_RELATIONSHIP {
DWORD NodeNumber;
- BYTE Reserved[20];
- GROUP_AFFINITY GroupMask;
-} NUMA_NODE_RELATIONSHIP, *PNUMA_NODE_RELATIONSHIP;
-#endif
+ BYTE Reserved[18];
+ WORD GroupCount;
+ _ANONYMOUS_UNION
+ union {
+ GROUP_AFFINITY GroupMask;
+ GROUP_AFFINITY GroupMasks[ANYSIZE_ARRAY];
+ } DUMMYUNIONNAME;
+} HWLOC_NUMA_NODE_RELATIONSHIP;
-#ifndef HAVE_CACHE_RELATIONSHIP
-typedef struct _CACHE_RELATIONSHIP {
+typedef struct HWLOC_CACHE_RELATIONSHIP {
BYTE Level;
BYTE Associativity;
WORD LineSize;
DWORD CacheSize;
PROCESSOR_CACHE_TYPE Type;
- BYTE Reserved[20];
- GROUP_AFFINITY GroupMask;
-} CACHE_RELATIONSHIP, *PCACHE_RELATIONSHIP;
-#endif
+ BYTE Reserved[18];
+ WORD GroupCount;
+ union {
+ GROUP_AFFINITY GroupMask;
+ GROUP_AFFINITY GroupMasks[ANYSIZE_ARRAY];
+ } DUMMYUNIONNAME;
+} HWLOC_CACHE_RELATIONSHIP;
#ifndef HAVE_PROCESSOR_GROUP_INFO
typedef struct _PROCESSOR_GROUP_INFO {
@@ -141,20 +127,19 @@ typedef struct _GROUP_RELATIONSHIP {
} GROUP_RELATIONSHIP, *PGROUP_RELATIONSHIP;
#endif
-#ifndef HAVE_SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
-typedef struct _SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX {
+/* always use our own structure because we need our own HWLOC_PROCESSOR/CACHE/NUMA_NODE_RELATIONSHIP */
+typedef struct HWLOC_SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX {
LOGICAL_PROCESSOR_RELATIONSHIP Relationship;
DWORD Size;
_ANONYMOUS_UNION
union {
- PROCESSOR_RELATIONSHIP Processor;
- NUMA_NODE_RELATIONSHIP NumaNode;
- CACHE_RELATIONSHIP Cache;
+ HWLOC_PROCESSOR_RELATIONSHIP Processor;
+ HWLOC_NUMA_NODE_RELATIONSHIP NumaNode;
+ HWLOC_CACHE_RELATIONSHIP Cache;
GROUP_RELATIONSHIP Group;
/* Odd: no member to tell the cpu mask of the package... */
} DUMMYUNIONNAME;
-} SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, *PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX;
-#endif
+} HWLOC_SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX;
#ifndef HAVE_PSAPI_WORKING_SET_EX_BLOCK
typedef union _PSAPI_WORKING_SET_EX_BLOCK {
@@ -200,10 +185,7 @@ static PFN_GETCURRENTPROCESSORNUMBER GetCurrentProcessorNumberProc;
typedef VOID (WINAPI *PFN_GETCURRENTPROCESSORNUMBEREX)(PPROCESSOR_NUMBER);
static PFN_GETCURRENTPROCESSORNUMBEREX GetCurrentProcessorNumberExProc;
-typedef BOOL (WINAPI *PFN_GETLOGICALPROCESSORINFORMATION)(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION Buffer, PDWORD ReturnLength);
-static PFN_GETLOGICALPROCESSORINFORMATION GetLogicalProcessorInformationProc;
-
-typedef BOOL (WINAPI *PFN_GETLOGICALPROCESSORINFORMATIONEX)(LOGICAL_PROCESSOR_RELATIONSHIP relationship, PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX Buffer, PDWORD ReturnLength);
+typedef BOOL (WINAPI *PFN_GETLOGICALPROCESSORINFORMATIONEX)(LOGICAL_PROCESSOR_RELATIONSHIP relationship, HWLOC_SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *Buffer, PDWORD ReturnLength);
static PFN_GETLOGICALPROCESSORINFORMATIONEX GetLogicalProcessorInformationExProc;
typedef BOOL (WINAPI *PFN_SETTHREADGROUPAFFINITY)(HANDLE hThread, const GROUP_AFFINITY *GroupAffinity, PGROUP_AFFINITY PreviousGroupAffinity);
@@ -244,8 +226,6 @@ static void hwloc_win_get_function_ptrs(void)
(PFN_GETACTIVEPROCESSORGROUPCOUNT) GetProcAddress(kernel32, "GetActiveProcessorGroupCount");
GetActiveProcessorCountProc =
(PFN_GETACTIVEPROCESSORCOUNT) GetProcAddress(kernel32, "GetActiveProcessorCount");
- GetLogicalProcessorInformationProc =
- (PFN_GETLOGICALPROCESSORINFORMATION) GetProcAddress(kernel32, "GetLogicalProcessorInformation");
GetCurrentProcessorNumberProc =
(PFN_GETCURRENTPROCESSORNUMBER) GetProcAddress(kernel32, "GetCurrentProcessorNumber");
GetCurrentProcessorNumberExProc =
@@ -370,13 +350,13 @@ static hwloc_cpuset_t * processor_group_cpusets = NULL;
static void
hwloc_win_get_processor_groups(void)
{
- PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX procInfoTotal, tmpprocInfoTotal, procInfo;
+ HWLOC_SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *procInfoTotal, *tmpprocInfoTotal, *procInfo;
DWORD length;
unsigned i;
hwloc_debug("querying windows processor groups\n");
- if (!GetActiveProcessorGroupCountProc || !GetLogicalProcessorInformationExProc)
+ if (!GetLogicalProcessorInformationExProc)
goto error;
nr_processor_groups = GetActiveProcessorGroupCountProc();
@@ -415,6 +395,8 @@ hwloc_win_get_processor_groups(void)
assert(procInfo->Relationship == RelationGroup);
+ hwloc_debug("Found %u active windows processor groups\n",
+ (unsigned) procInfo->Group.ActiveGroupCount);
for (id = 0; id < procInfo->Group.ActiveGroupCount; id++) {
KAFFINITY mask;
hwloc_bitmap_t set;
@@ -424,8 +406,8 @@ hwloc_win_get_processor_groups(void)
goto error_with_cpusets;
mask = procInfo->Group.GroupInfo[id].ActiveProcessorMask;
- hwloc_debug("group %u %d cpus mask %lx\n", id,
- procInfo->Group.GroupInfo[id].ActiveProcessorCount, mask);
+ hwloc_debug("group %u with %u cpus mask 0x%llx\n", id,
+ (unsigned) procInfo->Group.GroupInfo[id].ActiveProcessorCount, (unsigned long long) mask);
/* KAFFINITY is ULONG_PTR */
hwloc_bitmap_set_ith_ULONG_PTR(set, id, mask);
/* FIXME: what if running 32bits on a 64bits windows with 64-processor groups?
@@ -1008,6 +990,8 @@ hwloc_look_windows(struct hwloc_backend *backend, struct hwloc_disc_status *dsta
unsigned hostname_size = sizeof(hostname);
int has_efficiencyclass = 0;
struct hwloc_win_efficiency_classes eclasses;
+ char *env = getenv("HWLOC_WINDOWS_PROCESSOR_GROUP_OBJS");
+ int keep_pgroup_objs = (env && atoi(env));
assert(dstatus->phase == HWLOC_DISC_PHASE_CPU);
@@ -1038,137 +1022,8 @@ hwloc_look_windows(struct hwloc_backend *backend, struct hwloc_disc_status *dsta
GetSystemInfo(&SystemInfo);
- if (!GetLogicalProcessorInformationExProc && GetLogicalProcessorInformationProc) {
- PSYSTEM_LOGICAL_PROCESSOR_INFORMATION procInfo, tmpprocInfo;
- unsigned id;
- unsigned i;
- struct hwloc_obj *obj;
- hwloc_obj_type_t type;
-
- length = 0;
- procInfo = NULL;
-
- while (1) {
- if (GetLogicalProcessorInformationProc(procInfo, &length))
- break;
- if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
- return -1;
- tmpprocInfo = realloc(procInfo, length);
- if (!tmpprocInfo) {
- free(procInfo);
- goto out;
- }
- procInfo = tmpprocInfo;
- }
-
- assert(!length || procInfo);
-
- for (i = 0; i < length / sizeof(*procInfo); i++) {
-
- /* Ignore unknown caches */
- if (procInfo->Relationship == RelationCache
- && procInfo->Cache.Type != CacheUnified
- && procInfo->Cache.Type != CacheData
- && procInfo->Cache.Type != CacheInstruction)
- continue;
-
- id = HWLOC_UNKNOWN_INDEX;
- switch (procInfo[i].Relationship) {
- case RelationNumaNode:
- type = HWLOC_OBJ_NUMANODE;
- id = procInfo[i].NumaNode.NodeNumber;
- gotnuma++;
- if (id > max_numanode_index)
- max_numanode_index = id;
- break;
- case RelationProcessorPackage:
- type = HWLOC_OBJ_PACKAGE;
- break;
- case RelationCache:
- type = (procInfo[i].Cache.Type == CacheInstruction ? HWLOC_OBJ_L1ICACHE : HWLOC_OBJ_L1CACHE) + procInfo[i].Cache.Level - 1;
- break;
- case RelationProcessorCore:
- type = HWLOC_OBJ_CORE;
- break;
- case RelationGroup:
- default:
- type = HWLOC_OBJ_GROUP;
- break;
- }
-
- if (!hwloc_filter_check_keep_object_type(topology, type))
- continue;
-
- obj = hwloc_alloc_setup_object(topology, type, id);
- obj->cpuset = hwloc_bitmap_alloc();
- hwloc_debug("%s#%u mask %llx\n", hwloc_obj_type_string(type), id, (unsigned long long) procInfo[i].ProcessorMask);
- /* ProcessorMask is a ULONG_PTR */
- hwloc_bitmap_set_ith_ULONG_PTR(obj->cpuset, 0, procInfo[i].ProcessorMask);
- hwloc_debug_2args_bitmap("%s#%u bitmap %s\n", hwloc_obj_type_string(type), id, obj->cpuset);
-
- switch (type) {
- case HWLOC_OBJ_NUMANODE:
- {
- ULONGLONG avail;
- obj->nodeset = hwloc_bitmap_alloc();
- hwloc_bitmap_set(obj->nodeset, id);
- if ((GetNumaAvailableMemoryNodeExProc && GetNumaAvailableMemoryNodeExProc(id, &avail))
- || (GetNumaAvailableMemoryNodeProc && GetNumaAvailableMemoryNodeProc(id, &avail))) {
- obj->attr->numanode.local_memory = avail;
- gotnumamemory++;
- }
- obj->attr->numanode.page_types_len = 2;
- obj->attr->numanode.page_types = malloc(2 * sizeof(*obj->attr->numanode.page_types));
- memset(obj->attr->numanode.page_types, 0, 2 * sizeof(*obj->attr->numanode.page_types));
- obj->attr->numanode.page_types_len = 1;
- obj->attr->numanode.page_types[0].size = SystemInfo.dwPageSize;
-#if HAVE_DECL__SC_LARGE_PAGESIZE
- obj->attr->numanode.page_types_len++;
- obj->attr->numanode.page_types[1].size = sysconf(_SC_LARGE_PAGESIZE);
-#endif
- break;
- }
- case HWLOC_OBJ_L1CACHE:
- case HWLOC_OBJ_L2CACHE:
- case HWLOC_OBJ_L3CACHE:
- case HWLOC_OBJ_L4CACHE:
- case HWLOC_OBJ_L5CACHE:
- case HWLOC_OBJ_L1ICACHE:
- case HWLOC_OBJ_L2ICACHE:
- case HWLOC_OBJ_L3ICACHE:
- obj->attr->cache.size = procInfo[i].Cache.Size;
- obj->attr->cache.associativity = procInfo[i].Cache.Associativity == CACHE_FULLY_ASSOCIATIVE ? -1 : procInfo[i].Cache.Associativity ;
- obj->attr->cache.linesize = procInfo[i].Cache.LineSize;
- obj->attr->cache.depth = procInfo[i].Cache.Level;
- switch (procInfo->Cache.Type) {
- case CacheUnified:
- obj->attr->cache.type = HWLOC_OBJ_CACHE_UNIFIED;
- break;
- case CacheData:
- obj->attr->cache.type = HWLOC_OBJ_CACHE_DATA;
- break;
- case CacheInstruction:
- obj->attr->cache.type = HWLOC_OBJ_CACHE_INSTRUCTION;
- break;
- default:
- hwloc_free_unlinked_object(obj);
- continue;
- }
- break;
- case HWLOC_OBJ_GROUP:
- obj->attr->group.kind = procInfo[i].Relationship == RelationGroup ? HWLOC_GROUP_KIND_WINDOWS_PROCESSOR_GROUP : HWLOC_GROUP_KIND_WINDOWS_RELATIONSHIP_UNKNOWN;
- break;
- default:
- break;
- }
- hwloc__insert_object_by_cpuset(topology, NULL, obj, "windows:GetLogicalProcessorInformation");
- }
-
- free(procInfo);
- }
-
if (GetLogicalProcessorInformationExProc) {
- PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX procInfoTotal, tmpprocInfoTotal, procInfo;
+ HWLOC_SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *procInfoTotal, *tmpprocInfoTotal, *procInfo;
unsigned id;
struct hwloc_obj *obj;
hwloc_obj_type_t type;
@@ -1207,8 +1062,16 @@ hwloc_look_windows(struct hwloc_backend *backend, struct hwloc_disc_status *dsta
switch (procInfo->Relationship) {
case RelationNumaNode:
type = HWLOC_OBJ_NUMANODE;
- num = 1;
- GroupMask = &procInfo->NumaNode.GroupMask;
+ /* Starting with Windows 11 and Server 2022, the GroupCount field is valid and >=1
+ * and we may read GroupMasks[]. Older releases have GroupCount==0 and we must read GroupMask.
+ */
+ if (procInfo->NumaNode.GroupCount) {
+ num = procInfo->NumaNode.GroupCount;
+ GroupMask = procInfo->NumaNode.GroupMasks;
+ } else {
+ num = 1;
+ GroupMask = &procInfo->NumaNode.GroupMask;
+ }
id = procInfo->NumaNode.NodeNumber;
gotnuma++;
if (id > max_numanode_index)
@@ -1221,18 +1084,20 @@ hwloc_look_windows(struct hwloc_backend *backend, struct hwloc_disc_status *dsta
break;
case RelationCache:
type = (procInfo->Cache.Type == CacheInstruction ? HWLOC_OBJ_L1ICACHE : HWLOC_OBJ_L1CACHE) + procInfo->Cache.Level - 1;
- num = 1;
- GroupMask = &procInfo->Cache.GroupMask;
+ /* GroupCount added approximately with NumaNode.GroupCount above */
+ if (procInfo->Cache.GroupCount) {
+ num = procInfo->Cache.GroupCount;
+ GroupMask = procInfo->Cache.GroupMasks;
+ } else {
+ num = 1;
+ GroupMask = &procInfo->Cache.GroupMask;
+ }
break;
case RelationProcessorCore:
type = HWLOC_OBJ_CORE;
num = procInfo->Processor.GroupCount;
GroupMask = procInfo->Processor.GroupMask;
- if (has_efficiencyclass)
- /* the EfficiencyClass field didn't exist before Windows10 and recent MSVC headers,
- * so just access it manually instead of trying to detect it.
- */
- efficiency_class = * ((&procInfo->Processor.Flags) + 1);
+ efficiency_class = procInfo->Processor.EfficiencyClass;
break;
case RelationGroup:
/* So strange an interface... */
@@ -1257,11 +1122,12 @@ hwloc_look_windows(struct hwloc_backend *backend, struct hwloc_disc_status *dsta
groups_pu_set = hwloc_bitmap_alloc();
hwloc_bitmap_or(groups_pu_set, groups_pu_set, set);
- if (hwloc_filter_check_keep_object_type(topology, HWLOC_OBJ_GROUP)) {
+ /* Ignore processor groups unless requested and filtered-in */
+ if (keep_pgroup_objs && hwloc_filter_check_keep_object_type(topology, HWLOC_OBJ_GROUP)) {
obj = hwloc_alloc_setup_object(topology, HWLOC_OBJ_GROUP, id);
obj->cpuset = set;
obj->attr->group.kind = HWLOC_GROUP_KIND_WINDOWS_PROCESSOR_GROUP;
- hwloc__insert_object_by_cpuset(topology, NULL, obj, "windows:GetLogicalProcessorInformation:ProcessorGroup");
+ hwloc__insert_object_by_cpuset(topology, NULL, obj, "windows:GetLogicalProcessorInformationEx:ProcessorGroup");
} else
hwloc_bitmap_free(set);
}
diff --git a/src/3rdparty/hwloc/src/topology-x86.c b/src/3rdparty/hwloc/src/topology-x86.c
index 94f9d45368..42172eca5d 100644
--- a/src/3rdparty/hwloc/src/topology-x86.c
+++ b/src/3rdparty/hwloc/src/topology-x86.c
@@ -500,7 +500,8 @@ static void read_amd_cores_topoext(struct procinfo *infos, unsigned long flags,
nodes_per_proc = ((ecx >> 8) & 7) + 1;
}
if ((infos->cpufamilynumber == 0x15 && nodes_per_proc > 2)
- || ((infos->cpufamilynumber == 0x17 || infos->cpufamilynumber == 0x18) && nodes_per_proc > 4)) {
+ || ((infos->cpufamilynumber == 0x17 || infos->cpufamilynumber == 0x18) && nodes_per_proc > 4)
+ || (infos->cpufamilynumber == 0x19 && nodes_per_proc > 1)) {
hwloc_debug("warning: undefined nodes_per_proc value %u, assuming it means %u\n", nodes_per_proc, nodes_per_proc);
}
}
@@ -775,13 +776,19 @@ static void look_proc(struct hwloc_backend *backend, struct procinfo *infos, uns
} else if (cpuid_type == amd) {
/* AMD quirks */
- if (infos->cpufamilynumber == 0x17
- && cache->level == 3 && cache->nbthreads_sharing == 6) {
- /* AMD family 0x17 always shares L3 between 8 APIC ids,
- * even when only 6 APIC ids are enabled and reported in nbthreads_sharing
- * (on 24-core CPUs).
+ if (infos->cpufamilynumber >= 0x17 && cache->level == 3) {
+ /* AMD family 0x19 always shares L3 between 16 APIC ids (8 HT cores).
+ * while Family 0x17 shares between 8 APIC ids (4 HT cores).
+ * But many models have less APIC ids enabled and reported in nbthreads_sharing.
+ * It means we must round-up nbthreads_sharing to the nearest power of 2
+ * before computing cacheid.
*/
- cache->cacheid = infos->apicid / 8;
+ unsigned nbapics_sharing = cache->nbthreads_sharing;
+ if (nbapics_sharing & (nbapics_sharing-1))
+ /* not a power of two, round-up */
+ nbapics_sharing = 1U<<(1+hwloc_ffsl(nbapics_sharing));
+
+ cache->cacheid = infos->apicid / nbapics_sharing;
} else if (infos->cpufamilynumber== 0x10 && infos->cpumodelnumber == 0x9
&& cache->level == 3
@@ -807,7 +814,7 @@ static void look_proc(struct hwloc_backend *backend, struct procinfo *infos, uns
} else if (infos->cpufamilynumber == 0x15
&& (infos->cpumodelnumber == 0x1 /* Bulldozer */ || infos->cpumodelnumber == 0x2 /* Piledriver */)
&& cache->level == 3 && cache->nbthreads_sharing == 6) {
- /* AMD Bulldozer and Piledriver 12-core processors have same APIC ids as Magny-Cours below,
+ /* AMD Bulldozer and Piledriver 12-core processors have same APIC ids as Magny-Cours above,
* but we can't merge the checks because the original nbthreads_sharing must be exactly 6 here.
*/
cache->cacheid = (infos->apicid % legacy_max_log_proc) / cache->nbthreads_sharing /* cacheid within the package */
@@ -1231,6 +1238,18 @@ static void summarize(struct hwloc_backend *backend, struct procinfo *infos, uns
}
}
cache = hwloc_alloc_setup_object(topology, otype, HWLOC_UNKNOWN_INDEX);
+ /* We don't specify the os_index of caches because we want to be
+ * 100% sure they are identical to what the Linux kernel reports
+ * (so that things like resctrl work).
+ * However, vendor/model-specific quirks in the x86 code above
+ * make this difficult.
+ *
+ * Caveat: if the x86 backend is used on Linux to avoid kernel bugs,
+ * IDs won't be available to resctrl users. But resctrl heavily
+ * relies on the kernel x86 discovery being non-buggy anyway.
+ *
+ * TODO: make this optional? or only disable it on Linux?
+ */
cache->attr->cache.depth = level;
cache->attr->cache.size = infos[i].cache[l].size;
cache->attr->cache.linesize = infos[i].cache[l].linesize;
@@ -1688,7 +1707,7 @@ hwloc_x86_check_cpuiddump_input(const char *src_cpuiddump_path, hwloc_bitmap_t s
char line [32];
dir = opendir(src_cpuiddump_path);
- if (!dir)
+ if (!dir)
return -1;
path = malloc(strlen(src_cpuiddump_path) + strlen("/hwloc-cpuid-info") + 1);
diff --git a/src/3rdparty/hwloc/src/topology-xml.c b/src/3rdparty/hwloc/src/topology-xml.c
index 87e91010c9..2075d6fa6f 100644
--- a/src/3rdparty/hwloc/src/topology-xml.c
+++ b/src/3rdparty/hwloc/src/topology-xml.c
@@ -243,7 +243,7 @@ hwloc__xml_import_object_attr(struct hwloc_topology *topology,
else if (!strcmp(name, "dont_merge")) {
unsigned long lvalue = strtoul(value, NULL, 10);
if (obj->type == HWLOC_OBJ_GROUP)
- obj->attr->group.dont_merge = lvalue;
+ obj->attr->group.dont_merge = (unsigned char) lvalue;
else if (hwloc__xml_verbose())
fprintf(stderr, "%s: ignoring dont_merge attribute for non-group object type\n",
state->global->msgprefix);
@@ -2825,6 +2825,7 @@ hwloc__xml_v1export_object_with_memory(hwloc__xml_export_state_t parentstate, hw
/* child has sibling, we must add a Group around those memory children */
hwloc_obj_t group = parentstate->global->v1_memory_group;
parentstate->new_child(parentstate, &gstate, "object");
+ group->parent = obj->parent;
group->cpuset = obj->cpuset;
group->complete_cpuset = obj->complete_cpuset;
group->nodeset = obj->nodeset;
diff --git a/src/3rdparty/hwloc/src/topology.c b/src/3rdparty/hwloc/src/topology.c
index 01e5a863c1..c0f39c77ac 100644
--- a/src/3rdparty/hwloc/src/topology.c
+++ b/src/3rdparty/hwloc/src/topology.c
@@ -69,7 +69,7 @@
* it will break in cygwin, we'll have to use both putenv() and SetEnvironmentVariable().
* Hopefully L0 will be provide a way to enable Sysman without env vars before it happens.
*/
-#ifdef HWLOC_HAVE_ATTRIBUTE_CONSTRUCTOR
+#if HWLOC_HAVE_ATTRIBUTE_CONSTRUCTOR
static void hwloc_constructor(void) __attribute__((constructor));
static void hwloc_constructor(void)
{
@@ -1901,6 +1901,9 @@ hwloc_topology_alloc_group_object(struct hwloc_topology *topology)
static void hwloc_propagate_symmetric_subtree(hwloc_topology_t topology, hwloc_obj_t root);
static void propagate_total_memory(hwloc_obj_t obj);
static void hwloc_set_group_depth(hwloc_topology_t topology);
+static void hwloc_connect_children(hwloc_obj_t parent);
+static int hwloc_connect_levels(hwloc_topology_t topology);
+static int hwloc_connect_special_levels(hwloc_topology_t topology);
hwloc_obj_t
hwloc_topology_insert_group_object(struct hwloc_topology *topology, hwloc_obj_t obj)
@@ -2474,13 +2477,26 @@ hwloc_compare_levels_structure(hwloc_topology_t topology, unsigned i)
return 0;
}
-/* return > 0 if any level was removed, which means reconnect is needed */
-static void
+/* return > 0 if any level was removed.
+ * performs its own reconnect internally if needed
+ */
+static int
hwloc_filter_levels_keep_structure(hwloc_topology_t topology)
{
unsigned i, j;
int res = 0;
+ if (topology->modified) {
+ /* WARNING: hwloc_topology_reconnect() is duplicated partially here
+ * and at the end of this function:
+ * - we need normal levels before merging.
+ * - and we'll need to update special levels after merging.
+ */
+ hwloc_connect_children(topology->levels[0][0]);
+ if (hwloc_connect_levels(topology) < 0)
+ return -1;
+ }
+
/* start from the bottom since we'll remove intermediate levels */
for(i=topology->nb_levels-1; i>0; i--) {
int replacechild = 0, replaceparent = 0;
@@ -2646,6 +2662,22 @@ hwloc_filter_levels_keep_structure(hwloc_topology_t topology)
topology->type_depth[type] = HWLOC_TYPE_DEPTH_MULTIPLE;
}
}
+
+
+ if (res > 0 || topology-> modified) {
+ /* WARNING: hwloc_topology_reconnect() is duplicated partially here
+ * and at the beginning of this function.
+ * If we merged some levels, some child+parent special children lisst
+ * may have been merged, hence specials level might need reordering,
+ * So reconnect special levels only here at the end
+ * (it's not needed at the beginning of this function).
+ */
+ if (hwloc_connect_special_levels(topology) < 0)
+ return -1;
+ topology->modified = 0;
+ }
+
+ return 0;
}
static void
@@ -2963,9 +2995,9 @@ hwloc_list_special_objects(hwloc_topology_t topology, hwloc_obj_t obj)
}
}
-/* Build I/O levels */
+/* Build Memory, I/O and Misc levels */
static int
-hwloc_connect_io_misc_levels(hwloc_topology_t topology)
+hwloc_connect_special_levels(hwloc_topology_t topology)
{
unsigned i;
@@ -3176,6 +3208,10 @@ hwloc_connect_levels(hwloc_topology_t topology)
int
hwloc_topology_reconnect(struct hwloc_topology *topology, unsigned long flags)
{
+ /* WARNING: when updating this function, the replicated code must
+ * also be updated inside hwloc_filter_levels_keep_structure()
+ */
+
if (flags) {
errno = EINVAL;
return -1;
@@ -3188,7 +3224,7 @@ hwloc_topology_reconnect(struct hwloc_topology *topology, unsigned long flags)
if (hwloc_connect_levels(topology) < 0)
return -1;
- if (hwloc_connect_io_misc_levels(topology) < 0)
+ if (hwloc_connect_special_levels(topology) < 0)
return -1;
topology->modified = 0;
@@ -3529,15 +3565,12 @@ hwloc_discover(struct hwloc_topology *topology,
}
hwloc_debug_print_objects(0, topology->levels[0][0]);
- /* Reconnect things after all these changes.
- * Often needed because of Groups inserted for I/Os.
- * And required for KEEP_STRUCTURE below.
- */
- if (hwloc_topology_reconnect(topology, 0) < 0)
- return -1;
-
hwloc_debug("%s", "\nRemoving levels with HWLOC_TYPE_FILTER_KEEP_STRUCTURE\n");
- hwloc_filter_levels_keep_structure(topology);
+ if (hwloc_filter_levels_keep_structure(topology) < 0)
+ return -1;
+ /* takes care of reconnecting children/levels internally,
+ * because it needs normal levels.
+ * and it's often needed below because of Groups inserted for I/Os anyway */
hwloc_debug_print_objects(0, topology->levels[0][0]);
/* accumulate children memory in total_memory fields (only once parent is set) */
@@ -4360,14 +4393,13 @@ hwloc_topology_restrict(struct hwloc_topology *topology, hwloc_const_bitmap_t se
hwloc_bitmap_free(droppedcpuset);
hwloc_bitmap_free(droppednodeset);
- if (hwloc_topology_reconnect(topology, 0) < 0)
+ if (hwloc_filter_levels_keep_structure(topology) < 0) /* takes care of reconnecting internally */
goto out;
/* some objects may have disappeared, we need to update distances objs arrays */
hwloc_internal_distances_invalidate_cached_objs(topology);
hwloc_internal_memattrs_need_refresh(topology);
- hwloc_filter_levels_keep_structure(topology);
hwloc_propagate_symmetric_subtree(topology, topology->levels[0][0]);
propagate_total_memory(topology->levels[0][0]);
hwloc_internal_cpukinds_restrict(topology);
diff --git a/src/Summary.cpp b/src/Summary.cpp
index 6b12e62f39..7682398f92 100644
--- a/src/Summary.cpp
+++ b/src/Summary.cpp
@@ -1,12 +1,6 @@
/* XMRig
- * Copyright 2010 Jeff Garzik
- * Copyright 2012-2014 pooler
- * Copyright 2014 Lucas Jones
- * Copyright 2014-2016 Wolf9466
- * Copyright 2016 Jay D Dee
- * Copyright 2017-2019 XMR-Stak ,
- * Copyright 2018-2021 SChernykh
- * Copyright 2016-2021 XMRig
+ * Copyright (c) 2018-2022 SChernykh
+ * Copyright (c) 2016-2022 XMRig
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -22,7 +16,6 @@
* along with this program. If not, see .
*/
-
#include
#include
#include
@@ -158,7 +151,7 @@ static void print_memory(const Config *config)
"", memory.id().data(), memory.size() / oneGiB, memory.type(), memory.speed() / 1000000ULL, memory.product().data());
}
else if (printEmpty) {
- Log::print(WHITE_BOLD(" %-13s") "%s: " BLACK_BOLD(""), "", memory.slot().data());
+ Log::print(WHITE_BOLD(" %-13s") "%s: " BLACK_BOLD(""), "", memory.id().data());
}
}
diff --git a/src/Summary.h b/src/Summary.h
index 0b03f67591..906aabf581 100644
--- a/src/Summary.h
+++ b/src/Summary.h
@@ -1,12 +1,6 @@
/* XMRig
- * Copyright 2010 Jeff Garzik
- * Copyright 2012-2014 pooler
- * Copyright 2014 Lucas Jones
- * Copyright 2014-2016 Wolf9466
- * Copyright 2016 Jay D Dee
- * Copyright 2017-2018 XMR-Stak ,
- * Copyright 2018-2021 SChernykh
- * Copyright 2016-2021 XMRig ,
+ * Copyright (c) 2018-2022 SChernykh
+ * Copyright (c) 2016-2022 XMRig
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/backend/cpu/CpuConfig_gen.h b/src/backend/cpu/CpuConfig_gen.h
index 5ba1073808..6698861af1 100644
--- a/src/backend/cpu/CpuConfig_gen.h
+++ b/src/backend/cpu/CpuConfig_gen.h
@@ -157,7 +157,15 @@ size_t inline generate(Threads &threads, uint32_t
template<>
size_t inline generate(Threads& threads, uint32_t limit)
{
- return generate(Algorithm::kASTROBWT, threads, Algorithm::ASTROBWT_DERO, limit);
+ size_t count = 0;
+
+ if (!threads.isExist(Algorithm::ASTROBWT_DERO_2)) {
+ auto v2 = Cpu::info()->threads(Algorithm::ASTROBWT_DERO_2, limit);
+ count += threads.move(Algorithm::kASTROBWT_DERO_2, std::move(v2));
+ }
+
+ count += generate(Algorithm::kASTROBWT, threads, Algorithm::ASTROBWT_DERO, limit);
+ return count;
}
#endif
diff --git a/src/backend/cpu/CpuWorker.cpp b/src/backend/cpu/CpuWorker.cpp
index 86201e5069..4109a6cf24 100644
--- a/src/backend/cpu/CpuWorker.cpp
+++ b/src/backend/cpu/CpuWorker.cpp
@@ -224,9 +224,8 @@ bool xmrig::CpuWorker::selfTest()
# endif
# ifdef XMRIG_ALGO_ASTROBWT
- if (m_algorithm.family() == Algorithm::ASTROBWT) {
- return verify(Algorithm::ASTROBWT_DERO, astrobwt_dero_test_out);
- }
+ if (m_algorithm.id() == Algorithm::ASTROBWT_DERO) return verify(Algorithm::ASTROBWT_DERO, astrobwt_dero_test_out);
+ if (m_algorithm.id() == Algorithm::ASTROBWT_DERO_2) return verify(Algorithm::ASTROBWT_DERO_2, astrobwt_dero_2_test_out);
# endif
return false;
@@ -320,8 +319,15 @@ void xmrig::CpuWorker::start()
# ifdef XMRIG_ALGO_ASTROBWT
case Algorithm::ASTROBWT:
- if (!astrobwt::astrobwt_dero(m_job.blob(), job.size(), m_ctx[0]->memory, m_hash, m_astrobwtMaxSize, m_astrobwtAVX2)) {
- valid = false;
+ if (job.algorithm().id() == Algorithm::ASTROBWT_DERO) {
+ if (!astrobwt::astrobwt_dero(m_job.blob(), job.size(), m_ctx[0]->memory, m_hash, m_astrobwtMaxSize, m_astrobwtAVX2)) {
+ valid = false;
+ }
+ }
+ else {
+ if (!astrobwt::astrobwt_dero_v2(m_job.blob(), job.size(), m_ctx[0]->memory, m_hash)) {
+ valid = false;
+ }
}
break;
# endif
diff --git a/src/backend/cuda/CudaBackend.cpp b/src/backend/cuda/CudaBackend.cpp
index 0ef59981ea..fd6ec3d953 100644
--- a/src/backend/cuda/CudaBackend.cpp
+++ b/src/backend/cuda/CudaBackend.cpp
@@ -221,7 +221,7 @@ class CudaBackendPrivate
size_t algo_l3 = algo.l3();
# ifdef XMRIG_ALGO_ASTROBWT
- if (algo.family() == Algorithm::ASTROBWT) {
+ if (algo.id() == Algorithm::ASTROBWT_DERO) {
algo_l3 = CudaAstroBWTRunner::BWT_DATA_STRIDE * 17 + 1024;
}
# endif
diff --git a/src/backend/cuda/CudaConfig_gen.h b/src/backend/cuda/CudaConfig_gen.h
index d92b052608..73c77e48dd 100644
--- a/src/backend/cuda/CudaConfig_gen.h
+++ b/src/backend/cuda/CudaConfig_gen.h
@@ -139,7 +139,14 @@ size_t inline generate(Threads &threads, const
template<>
size_t inline generate(Threads &threads, const std::vector &devices)
{
- return generate(Algorithm::kASTROBWT, threads, Algorithm::ASTROBWT_DERO, devices);
+ size_t count = 0;
+
+ if (!threads.isExist(Algorithm::ASTROBWT_DERO_2)) {
+ count += threads.move(Algorithm::kASTROBWT_DERO_2, CudaThreads(devices, Algorithm::ASTROBWT_DERO_2));
+ }
+
+ count += generate(Algorithm::kASTROBWT, threads, Algorithm::ASTROBWT_DERO, devices);
+ return count;
}
#endif
diff --git a/src/backend/cuda/runners/CudaAstroBWTRunner.cpp b/src/backend/cuda/runners/CudaAstroBWTRunner.cpp
index 43431aac45..6b078e4f85 100644
--- a/src/backend/cuda/runners/CudaAstroBWTRunner.cpp
+++ b/src/backend/cuda/runners/CudaAstroBWTRunner.cpp
@@ -32,11 +32,17 @@
constexpr uint32_t xmrig::CudaAstroBWTRunner::BWT_DATA_STRIDE;
-xmrig::CudaAstroBWTRunner::CudaAstroBWTRunner(size_t index, const CudaLaunchData &data) :
- CudaBaseRunner(index, data)
+xmrig::CudaAstroBWTRunner::CudaAstroBWTRunner(size_t index, const CudaLaunchData &data)
+ : CudaBaseRunner(index, data)
+ , m_algorithm(data.algorithm)
{
m_intensity = m_data.thread.threads() * m_data.thread.blocks();
m_intensity -= m_intensity % 32;
+
+ // Dero HE has very fast blocks, so we can't use high intensity
+ if ((m_algorithm == Algorithm::ASTROBWT_DERO_2) && (m_intensity > 4096)) {
+ m_intensity = 4096;
+ }
}
@@ -58,10 +64,14 @@ bool xmrig::CudaAstroBWTRunner::set(const Job &job, uint8_t *blob)
size_t xmrig::CudaAstroBWTRunner::roundSize() const
{
+ if (m_algorithm == Algorithm::ASTROBWT_DERO_2) {
+ return m_intensity;
+ }
+
constexpr uint32_t STAGE1_SIZE = 147253;
constexpr uint32_t STAGE1_DATA_STRIDE = (STAGE1_SIZE + 256 + 255) & ~255U;
- const uint32_t BATCH2_SIZE = m_intensity;
+ const uint32_t BATCH2_SIZE = static_cast(m_intensity);
const uint32_t BWT_ALLOCATION_SIZE = BATCH2_SIZE * BWT_DATA_STRIDE;
const uint32_t BATCH1_SIZE = (BWT_ALLOCATION_SIZE / STAGE1_DATA_STRIDE) & ~255U;
diff --git a/src/backend/cuda/runners/CudaAstroBWTRunner.h b/src/backend/cuda/runners/CudaAstroBWTRunner.h
index 0afee8c1cf..d217d65a50 100644
--- a/src/backend/cuda/runners/CudaAstroBWTRunner.h
+++ b/src/backend/cuda/runners/CudaAstroBWTRunner.h
@@ -27,6 +27,7 @@
#include "backend/cuda/runners/CudaBaseRunner.h"
+#include "base/crypto/Algorithm.h"
namespace xmrig {
@@ -50,6 +51,7 @@ class CudaAstroBWTRunner : public CudaBaseRunner
private:
size_t m_intensity = 0;
+ Algorithm m_algorithm;
};
diff --git a/src/backend/opencl/OclBackend.cpp b/src/backend/opencl/OclBackend.cpp
index 18b8892a13..6f9543b818 100644
--- a/src/backend/opencl/OclBackend.cpp
+++ b/src/backend/opencl/OclBackend.cpp
@@ -205,7 +205,7 @@ class OclBackendPrivate
size_t algo_l3 = algo.l3();
# ifdef XMRIG_ALGO_ASTROBWT
- if (algo.family() == Algorithm::ASTROBWT) {
+ if (algo.id() == Algorithm::ASTROBWT_DERO) {
algo_l3 = OclAstroBWTRunner::BWT_DATA_STRIDE * 17 + 324;
}
# endif
diff --git a/src/backend/opencl/OclConfig_gen.h b/src/backend/opencl/OclConfig_gen.h
index e4024ca631..aedd3983f5 100644
--- a/src/backend/opencl/OclConfig_gen.h
+++ b/src/backend/opencl/OclConfig_gen.h
@@ -133,7 +133,14 @@ size_t inline generate(Threads &threads, const
template<>
size_t inline generate(Threads& threads, const std::vector& devices)
{
- return generate(Algorithm::kASTROBWT, threads, Algorithm::ASTROBWT_DERO, devices);
+ size_t count = 0;
+
+ if (!threads.isExist(Algorithm::ASTROBWT_DERO_2)) {
+ count += threads.move(Algorithm::kASTROBWT_DERO_2, OclThreads(devices, Algorithm::ASTROBWT_DERO_2));
+ }
+
+ count += generate(Algorithm::kASTROBWT, threads, Algorithm::ASTROBWT_DERO, devices);
+ return count;
}
#endif
diff --git a/src/backend/opencl/OclWorker.cpp b/src/backend/opencl/OclWorker.cpp
index d9977a4037..cd49a50e9c 100644
--- a/src/backend/opencl/OclWorker.cpp
+++ b/src/backend/opencl/OclWorker.cpp
@@ -37,6 +37,7 @@
#ifdef XMRIG_ALGO_ASTROBWT
# include "backend/opencl/runners/OclAstroBWTRunner.h"
+# include "backend/opencl/runners/OclAstroBWT_v2_Runner.h"
#endif
#ifdef XMRIG_ALGO_KAWPOW
@@ -92,7 +93,12 @@ xmrig::OclWorker::OclWorker(size_t id, const OclLaunchData &data) :
case Algorithm::ASTROBWT:
# ifdef XMRIG_ALGO_ASTROBWT
- m_runner = new OclAstroBWTRunner(id, data);
+ if (m_algorithm.id() == Algorithm::ASTROBWT_DERO_2) {
+ m_runner = new OclAstroBWT_v2_Runner(id, data);
+ }
+ else {
+ m_runner = new OclAstroBWTRunner(id, data);
+ }
# endif
break;
diff --git a/src/backend/opencl/cl/OclSource.cpp b/src/backend/opencl/cl/OclSource.cpp
index facb2bdcb9..c55fda8f6b 100644
--- a/src/backend/opencl/cl/OclSource.cpp
+++ b/src/backend/opencl/cl/OclSource.cpp
@@ -34,6 +34,7 @@
#ifdef XMRIG_ALGO_ASTROBWT
# include "backend/opencl/cl/astrobwt/astrobwt_cl.h"
+# include "backend/opencl/cl/astrobwt_v2/astrobwt_v2_cl.h"
#endif
#ifdef XMRIG_ALGO_KAWPOW
@@ -52,7 +53,7 @@ const char *xmrig::OclSource::get(const Algorithm &algorithm)
# ifdef XMRIG_ALGO_ASTROBWT
if (algorithm.family() == Algorithm::ASTROBWT) {
- return astrobwt_cl;
+ return (algorithm.id() == Algorithm::ASTROBWT_DERO_2) ? astrobwt_v2_cl : astrobwt_cl;
}
# endif
diff --git a/src/backend/opencl/cl/astrobwt_v2/BWT.cl b/src/backend/opencl/cl/astrobwt_v2/BWT.cl
new file mode 100644
index 0000000000..5ecbed22bd
--- /dev/null
+++ b/src/backend/opencl/cl/astrobwt_v2/BWT.cl
@@ -0,0 +1,179 @@
+/* XMRig
+ * Copyright 2010 Jeff Garzik
+ * Copyright 2012-2014 pooler
+ * Copyright 2014 Lucas Jones
+ * Copyright 2014-2016 Wolf9466
+ * Copyright 2016 Jay D Dee
+ * Copyright 2017-2018 XMR-Stak ,
+ * Copyright 2018-2022 SChernykh
+ * Copyright 2016-2022 XMRig ,
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#define BLOCK_SIZE 1024
+#define DATA_SIZE 9973
+#define DATA_STRIDE 10240
+#define BITS 14
+#define COUNTERS_SIZE (1 << BITS)
+
+inline uint16_t atomic_inc16(__local uint16_t* value)
+{
+ const size_t k = (size_t) value;
+ if ((k & 3) == 0) {
+ return atomic_add((__local uint32_t*) value, 1);
+ }
+ return atomic_add((__local uint32_t*)(k - 2), 0x10000) >> 16;
+}
+
+__attribute__((reqd_work_group_size(BLOCK_SIZE, 1, 1)))
+__kernel void BWT_preprocess(__global const uint8_t* datas, __global uint32_t* keys)
+{
+ const uint32_t data_offset = get_group_id(0) * DATA_STRIDE;
+ const uint32_t tid = get_local_id(0);
+
+ __local uint32_t counters_buf[COUNTERS_SIZE / 2];
+ __local uint16_t* counters = (__local uint16_t*) counters_buf;
+ for (uint32_t i = tid; i < COUNTERS_SIZE / 2; i += BLOCK_SIZE) {
+ counters_buf[i] = 0;
+ }
+ barrier(CLK_LOCAL_MEM_FENCE);
+
+ datas += data_offset;
+ keys += data_offset;
+
+ for (uint32_t i = tid; i < DATA_SIZE; i += BLOCK_SIZE) {
+ const uint32_t k0 = datas[i];
+ const uint32_t k1 = datas[i + 1];
+ const uint32_t k = ((k0 << 8) | k1) >> (16 - BITS);
+ atomic_inc16(counters + k);
+ }
+ barrier(CLK_LOCAL_MEM_FENCE);
+
+ #pragma unroll BITS
+ for (int k = 0; k < BITS; ++k) {
+ for (uint32_t t1 = tid; t1 < ((COUNTERS_SIZE / 2) >> k); t1 += BLOCK_SIZE) {
+ const uint32_t i = (t1 << (k + 1)) + ((1 << (k + 1)) - 1);
+ counters[i] += counters[i - (1 << k)];
+ }
+ barrier(CLK_LOCAL_MEM_FENCE);
+ }
+
+ if (tid == 0) {
+ counters[COUNTERS_SIZE - 1] = 0;
+ }
+ barrier(CLK_LOCAL_MEM_FENCE);
+
+ #pragma unroll BITS
+ for (int k = BITS - 1; k >= 0; --k) {
+ for (uint32_t t1 = tid; t1 < ((COUNTERS_SIZE / 2) >> k); t1 += BLOCK_SIZE) {
+ const uint32_t i = (t1 << (k + 1)) + ((1 << (k + 1)) - 1);
+ const uint16_t old = counters[i];
+ counters[i] = old + counters[i - (1 << k)];
+ counters[i - (1 << k)] = old;
+ }
+ barrier(CLK_LOCAL_MEM_FENCE);
+ }
+
+ for (uint32_t i = tid; i < DATA_SIZE; i += BLOCK_SIZE) {
+ const uint32_t k0 = datas[i];
+ const uint32_t k1 = datas[i + 1];
+ const uint32_t k = (k0 << 8) | k1;
+ const uint32_t index = atomic_inc16(counters + (k >> (16 - BITS)));
+ keys[index] = (k << 16) | i;
+ }
+}
+
+inline void fix_order(__global const uint8_t* input, uint32_t a, uint32_t b, __global uint32_t* keys)
+{
+ const uint32_t ka = keys[a];
+ const uint32_t kb = keys[b];
+ const uint32_t index_a = ka & 0xFFFF;
+ const uint32_t index_b = kb & 0xFFFF;
+
+ const uint32_t value_a =
+ (((uint32_t)input[index_a + 1]) << 24) |
+ (((uint32_t)input[index_a + 2]) << 16) |
+ (((uint32_t)input[index_a + 3]) << 8) |
+ ((uint32_t)input[index_a + 4]);
+
+ const uint32_t value_b =
+ (((uint32_t)input[index_b + 1]) << 24) |
+ (((uint32_t)input[index_b + 2]) << 16) |
+ (((uint32_t)input[index_b + 3]) << 8) |
+ ((uint32_t)input[index_b + 4]);
+
+ if (value_a > value_b)
+ {
+ keys[a] = kb;
+ keys[b] = ka;
+ }
+}
+
+__attribute__((reqd_work_group_size(BLOCK_SIZE, 1, 1)))
+__kernel void BWT_fix_order(__global const uint8_t* datas, __global uint32_t* keys, __global uint16_t* values)
+{
+ const uint32_t tid = get_local_id(0);
+ const uint32_t gid = get_group_id(0);
+
+ const uint32_t data_offset = gid * 10240;
+
+ const uint32_t N = 9973;
+
+ datas += data_offset;
+ keys += data_offset;
+ values += data_offset;
+
+ for (uint32_t i = tid, N1 = N - 1; i < N1; i += BLOCK_SIZE)
+ {
+ const uint32_t value = keys[i] >> (32 - BITS);
+ if (value == (keys[i + 1] >> (32 - BITS)))
+ {
+ if (i && (value == (keys[i - 1] >> (32 - BITS))))
+ continue;
+
+ uint32_t n = i + 2;
+ while ((n < N) && (value == (keys[n] >> (32 - BITS))))
+ ++n;
+
+ for (uint32_t j = i; j < n; ++j)
+ for (uint32_t k = j + 1; k < n; ++k)
+ fix_order(datas, j, k, keys);
+ }
+ }
+ barrier(CLK_GLOBAL_MEM_FENCE);
+
+ for (uint32_t i = tid; i < N; i += BLOCK_SIZE) {
+ values[i] = keys[i];
+ }
+}
+
+__kernel void find_shares(__global const uint64_t* hashes, uint64_t target, __global uint32_t* shares)
+{
+ const uint32_t global_index = get_global_id(0);
+
+ if (hashes[global_index * 4 + 3] >= target) {
+ return;
+ }
+
+ const uint32_t idx = atomic_inc(shares + 0xFF);
+ if (idx < 0xFF)
+ shares[idx] = global_index;
+}
+
+#undef BLOCK_SIZE
+#undef DATA_SIZE
+#undef DATA_STRIDE
+#undef BITS
+#undef COUNTERS_SIZE
diff --git a/src/backend/opencl/cl/astrobwt_v2/astrobwt_v2.cl b/src/backend/opencl/cl/astrobwt_v2/astrobwt_v2.cl
new file mode 100644
index 0000000000..915c16a69e
--- /dev/null
+++ b/src/backend/opencl/cl/astrobwt_v2/astrobwt_v2.cl
@@ -0,0 +1,35 @@
+/* XMRig
+ * Copyright 2010 Jeff Garzik
+ * Copyright 2012-2014 pooler
+ * Copyright 2014 Lucas Jones
+ * Copyright 2014-2016 Wolf9466
+ * Copyright 2016 Jay D Dee
+ * Copyright 2017-2018 XMR-Stak ,
+ * Copyright 2018-2022 SChernykh
+ * Copyright 2016-2022 XMRig ,
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+typedef uchar uint8_t;
+typedef ushort uint16_t;
+typedef uint uint32_t;
+typedef ulong uint64_t;
+
+typedef int int32_t;
+typedef long int64_t;
+
+#include "BWT.cl"
+#include "salsa20.cl"
+#include "sha3.cl"
diff --git a/src/backend/opencl/cl/astrobwt_v2/astrobwt_v2_cl.h b/src/backend/opencl/cl/astrobwt_v2/astrobwt_v2_cl.h
new file mode 100644
index 0000000000..62a600661f
--- /dev/null
+++ b/src/backend/opencl/cl/astrobwt_v2/astrobwt_v2_cl.h
@@ -0,0 +1,388 @@
+#pragma once
+
+namespace xmrig {
+
+static const char astrobwt_v2_cl[12139] = {
+ 0x74,0x79,0x70,0x65,0x64,0x65,0x66,0x20,0x75,0x63,0x68,0x61,0x72,0x20,0x75,0x69,0x6e,0x74,0x38,0x5f,0x74,0x3b,0x0a,0x74,0x79,0x70,0x65,0x64,0x65,0x66,0x20,0x75,
+ 0x73,0x68,0x6f,0x72,0x74,0x20,0x75,0x69,0x6e,0x74,0x31,0x36,0x5f,0x74,0x3b,0x0a,0x74,0x79,0x70,0x65,0x64,0x65,0x66,0x20,0x75,0x69,0x6e,0x74,0x20,0x75,0x69,0x6e,
+ 0x74,0x33,0x32,0x5f,0x74,0x3b,0x0a,0x74,0x79,0x70,0x65,0x64,0x65,0x66,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x3b,0x0a,0x74,
+ 0x79,0x70,0x65,0x64,0x65,0x66,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x3b,0x0a,0x74,0x79,0x70,0x65,0x64,0x65,0x66,0x20,0x6c,0x6f,0x6e,0x67,
+ 0x20,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x3b,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x42,0x4c,0x4f,0x43,0x4b,0x5f,0x53,0x49,0x5a,0x45,0x20,0x31,0x30,0x32,
+ 0x34,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x44,0x41,0x54,0x41,0x5f,0x53,0x49,0x5a,0x45,0x20,0x39,0x39,0x37,0x33,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,
+ 0x20,0x44,0x41,0x54,0x41,0x5f,0x53,0x54,0x52,0x49,0x44,0x45,0x20,0x31,0x30,0x32,0x34,0x30,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x42,0x49,0x54,0x53,0x20,
+ 0x31,0x34,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x43,0x4f,0x55,0x4e,0x54,0x45,0x52,0x53,0x5f,0x53,0x49,0x5a,0x45,0x20,0x28,0x31,0x20,0x3c,0x3c,0x20,0x42,
+ 0x49,0x54,0x53,0x29,0x0a,0x69,0x6e,0x6c,0x69,0x6e,0x65,0x20,0x75,0x69,0x6e,0x74,0x31,0x36,0x5f,0x74,0x20,0x61,0x74,0x6f,0x6d,0x69,0x63,0x5f,0x69,0x6e,0x63,0x31,
+ 0x36,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x31,0x36,0x5f,0x74,0x2a,0x20,0x76,0x61,0x6c,0x75,0x65,0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,
+ 0x73,0x74,0x20,0x73,0x69,0x7a,0x65,0x5f,0x74,0x20,0x6b,0x3d,0x28,0x73,0x69,0x7a,0x65,0x5f,0x74,0x29,0x20,0x76,0x61,0x6c,0x75,0x65,0x3b,0x0a,0x69,0x66,0x28,0x28,
+ 0x6b,0x26,0x33,0x29,0x3d,0x3d,0x30,0x29,0x20,0x7b,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x61,0x74,0x6f,0x6d,0x69,0x63,0x5f,0x61,0x64,0x64,0x28,0x28,0x5f,0x5f,
+ 0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x2a,0x29,0x20,0x76,0x61,0x6c,0x75,0x65,0x2c,0x31,0x29,0x3b,0x0a,0x7d,0x0a,0x72,0x65,0x74,
+ 0x75,0x72,0x6e,0x20,0x61,0x74,0x6f,0x6d,0x69,0x63,0x5f,0x61,0x64,0x64,0x28,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,
+ 0x2a,0x29,0x28,0x6b,0x2d,0x32,0x29,0x2c,0x30,0x78,0x31,0x30,0x30,0x30,0x30,0x29,0x3e,0x3e,0x31,0x36,0x3b,0x0a,0x7d,0x0a,0x5f,0x5f,0x61,0x74,0x74,0x72,0x69,0x62,
+ 0x75,0x74,0x65,0x5f,0x5f,0x28,0x28,0x72,0x65,0x71,0x64,0x5f,0x77,0x6f,0x72,0x6b,0x5f,0x67,0x72,0x6f,0x75,0x70,0x5f,0x73,0x69,0x7a,0x65,0x28,0x42,0x4c,0x4f,0x43,
+ 0x4b,0x5f,0x53,0x49,0x5a,0x45,0x2c,0x31,0x2c,0x31,0x29,0x29,0x29,0x0a,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x42,0x57,0x54,0x5f,
+ 0x70,0x72,0x65,0x70,0x72,0x6f,0x63,0x65,0x73,0x73,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x38,0x5f,
+ 0x74,0x2a,0x20,0x64,0x61,0x74,0x61,0x73,0x2c,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x2a,0x20,0x6b,0x65,0x79,0x73,
+ 0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x64,0x61,0x74,0x61,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x3d,0x67,
+ 0x65,0x74,0x5f,0x67,0x72,0x6f,0x75,0x70,0x5f,0x69,0x64,0x28,0x30,0x29,0x2a,0x44,0x41,0x54,0x41,0x5f,0x53,0x54,0x52,0x49,0x44,0x45,0x3b,0x0a,0x63,0x6f,0x6e,0x73,
+ 0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x74,0x69,0x64,0x3d,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0x0a,
+ 0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x63,0x6f,0x75,0x6e,0x74,0x65,0x72,0x73,0x5f,0x62,0x75,0x66,0x5b,0x43,0x4f,
+ 0x55,0x4e,0x54,0x45,0x52,0x53,0x5f,0x53,0x49,0x5a,0x45,0x2f,0x32,0x5d,0x3b,0x0a,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x31,0x36,0x5f,0x74,
+ 0x2a,0x20,0x63,0x6f,0x75,0x6e,0x74,0x65,0x72,0x73,0x3d,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x31,0x36,0x5f,0x74,0x2a,0x29,0x20,0x63,
+ 0x6f,0x75,0x6e,0x74,0x65,0x72,0x73,0x5f,0x62,0x75,0x66,0x3b,0x0a,0x66,0x6f,0x72,0x20,0x28,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x69,0x3d,0x74,0x69,0x64,
+ 0x3b,0x20,0x69,0x3c,0x43,0x4f,0x55,0x4e,0x54,0x45,0x52,0x53,0x5f,0x53,0x49,0x5a,0x45,0x2f,0x32,0x3b,0x20,0x69,0x2b,0x3d,0x42,0x4c,0x4f,0x43,0x4b,0x5f,0x53,0x49,
+ 0x5a,0x45,0x29,0x20,0x7b,0x0a,0x63,0x6f,0x75,0x6e,0x74,0x65,0x72,0x73,0x5f,0x62,0x75,0x66,0x5b,0x69,0x5d,0x3d,0x30,0x3b,0x0a,0x7d,0x0a,0x62,0x61,0x72,0x72,0x69,
+ 0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0x0a,0x64,0x61,0x74,0x61,0x73,0x2b,0x3d,
+ 0x64,0x61,0x74,0x61,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x3b,0x0a,0x6b,0x65,0x79,0x73,0x2b,0x3d,0x64,0x61,0x74,0x61,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x3b,0x0a,
+ 0x66,0x6f,0x72,0x20,0x28,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x69,0x3d,0x74,0x69,0x64,0x3b,0x20,0x69,0x3c,0x44,0x41,0x54,0x41,0x5f,0x53,0x49,0x5a,0x45,
+ 0x3b,0x20,0x69,0x2b,0x3d,0x42,0x4c,0x4f,0x43,0x4b,0x5f,0x53,0x49,0x5a,0x45,0x29,0x20,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,
+ 0x74,0x20,0x6b,0x30,0x3d,0x64,0x61,0x74,0x61,0x73,0x5b,0x69,0x5d,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6b,0x31,
+ 0x3d,0x64,0x61,0x74,0x61,0x73,0x5b,0x69,0x2b,0x31,0x5d,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6b,0x3d,0x28,0x28,
+ 0x6b,0x30,0x3c,0x3c,0x38,0x29,0x7c,0x6b,0x31,0x29,0x3e,0x3e,0x28,0x31,0x36,0x2d,0x42,0x49,0x54,0x53,0x29,0x3b,0x0a,0x61,0x74,0x6f,0x6d,0x69,0x63,0x5f,0x69,0x6e,
+ 0x63,0x31,0x36,0x28,0x63,0x6f,0x75,0x6e,0x74,0x65,0x72,0x73,0x2b,0x6b,0x29,0x3b,0x0a,0x7d,0x0a,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,
+ 0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0x0a,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x20,
+ 0x42,0x49,0x54,0x53,0x0a,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x6b,0x3d,0x30,0x3b,0x20,0x6b,0x3c,0x42,0x49,0x54,0x53,0x3b,0x20,0x2b,0x2b,0x6b,0x29,0x20,
+ 0x7b,0x0a,0x66,0x6f,0x72,0x20,0x28,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x74,0x31,0x3d,0x74,0x69,0x64,0x3b,0x20,0x74,0x31,0x3c,0x28,0x28,0x43,0x4f,0x55,
+ 0x4e,0x54,0x45,0x52,0x53,0x5f,0x53,0x49,0x5a,0x45,0x2f,0x32,0x29,0x3e,0x3e,0x6b,0x29,0x3b,0x20,0x74,0x31,0x2b,0x3d,0x42,0x4c,0x4f,0x43,0x4b,0x5f,0x53,0x49,0x5a,
+ 0x45,0x29,0x20,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x69,0x3d,0x28,0x74,0x31,0x3c,0x3c,0x28,0x6b,0x2b,0x31,0x29,
+ 0x29,0x2b,0x28,0x28,0x31,0x3c,0x3c,0x28,0x6b,0x2b,0x31,0x29,0x29,0x2d,0x31,0x29,0x3b,0x0a,0x63,0x6f,0x75,0x6e,0x74,0x65,0x72,0x73,0x5b,0x69,0x5d,0x2b,0x3d,0x63,
+ 0x6f,0x75,0x6e,0x74,0x65,0x72,0x73,0x5b,0x69,0x2d,0x28,0x31,0x3c,0x3c,0x6b,0x29,0x5d,0x3b,0x0a,0x7d,0x0a,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,
+ 0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0x0a,0x7d,0x0a,0x69,0x66,0x28,0x74,0x69,0x64,0x3d,0x3d,0x30,0x29,0x20,
+ 0x7b,0x0a,0x63,0x6f,0x75,0x6e,0x74,0x65,0x72,0x73,0x5b,0x43,0x4f,0x55,0x4e,0x54,0x45,0x52,0x53,0x5f,0x53,0x49,0x5a,0x45,0x2d,0x31,0x5d,0x3d,0x30,0x3b,0x0a,0x7d,
+ 0x0a,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0x0a,0x23,
+ 0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x20,0x42,0x49,0x54,0x53,0x0a,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x6b,0x3d,0x42,0x49,
+ 0x54,0x53,0x2d,0x31,0x3b,0x20,0x6b,0x3e,0x3d,0x30,0x3b,0x20,0x2d,0x2d,0x6b,0x29,0x20,0x7b,0x0a,0x66,0x6f,0x72,0x20,0x28,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,
+ 0x20,0x74,0x31,0x3d,0x74,0x69,0x64,0x3b,0x20,0x74,0x31,0x3c,0x28,0x28,0x43,0x4f,0x55,0x4e,0x54,0x45,0x52,0x53,0x5f,0x53,0x49,0x5a,0x45,0x2f,0x32,0x29,0x3e,0x3e,
+ 0x6b,0x29,0x3b,0x20,0x74,0x31,0x2b,0x3d,0x42,0x4c,0x4f,0x43,0x4b,0x5f,0x53,0x49,0x5a,0x45,0x29,0x20,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,
+ 0x33,0x32,0x5f,0x74,0x20,0x69,0x3d,0x28,0x74,0x31,0x3c,0x3c,0x28,0x6b,0x2b,0x31,0x29,0x29,0x2b,0x28,0x28,0x31,0x3c,0x3c,0x28,0x6b,0x2b,0x31,0x29,0x29,0x2d,0x31,
+ 0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x31,0x36,0x5f,0x74,0x20,0x6f,0x6c,0x64,0x3d,0x63,0x6f,0x75,0x6e,0x74,0x65,0x72,0x73,0x5b,0x69,
+ 0x5d,0x3b,0x0a,0x63,0x6f,0x75,0x6e,0x74,0x65,0x72,0x73,0x5b,0x69,0x5d,0x3d,0x6f,0x6c,0x64,0x2b,0x63,0x6f,0x75,0x6e,0x74,0x65,0x72,0x73,0x5b,0x69,0x2d,0x28,0x31,
+ 0x3c,0x3c,0x6b,0x29,0x5d,0x3b,0x0a,0x63,0x6f,0x75,0x6e,0x74,0x65,0x72,0x73,0x5b,0x69,0x2d,0x28,0x31,0x3c,0x3c,0x6b,0x29,0x5d,0x3d,0x6f,0x6c,0x64,0x3b,0x0a,0x7d,
+ 0x0a,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0x0a,0x7d,
+ 0x0a,0x66,0x6f,0x72,0x20,0x28,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x69,0x3d,0x74,0x69,0x64,0x3b,0x20,0x69,0x3c,0x44,0x41,0x54,0x41,0x5f,0x53,0x49,0x5a,
+ 0x45,0x3b,0x20,0x69,0x2b,0x3d,0x42,0x4c,0x4f,0x43,0x4b,0x5f,0x53,0x49,0x5a,0x45,0x29,0x20,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,
+ 0x5f,0x74,0x20,0x6b,0x30,0x3d,0x64,0x61,0x74,0x61,0x73,0x5b,0x69,0x5d,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6b,
+ 0x31,0x3d,0x64,0x61,0x74,0x61,0x73,0x5b,0x69,0x2b,0x31,0x5d,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6b,0x3d,0x28,
+ 0x6b,0x30,0x3c,0x3c,0x38,0x29,0x7c,0x6b,0x31,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x69,0x6e,0x64,0x65,0x78,0x3d,
+ 0x61,0x74,0x6f,0x6d,0x69,0x63,0x5f,0x69,0x6e,0x63,0x31,0x36,0x28,0x63,0x6f,0x75,0x6e,0x74,0x65,0x72,0x73,0x2b,0x28,0x6b,0x3e,0x3e,0x28,0x31,0x36,0x2d,0x42,0x49,
+ 0x54,0x53,0x29,0x29,0x29,0x3b,0x0a,0x6b,0x65,0x79,0x73,0x5b,0x69,0x6e,0x64,0x65,0x78,0x5d,0x3d,0x28,0x6b,0x3c,0x3c,0x31,0x36,0x29,0x7c,0x69,0x3b,0x0a,0x7d,0x0a,
+ 0x7d,0x0a,0x69,0x6e,0x6c,0x69,0x6e,0x65,0x20,0x76,0x6f,0x69,0x64,0x20,0x66,0x69,0x78,0x5f,0x6f,0x72,0x64,0x65,0x72,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,
+ 0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x38,0x5f,0x74,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x2c,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x61,
+ 0x2c,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x62,0x2c,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x2a,0x20,0x6b,
+ 0x65,0x79,0x73,0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6b,0x61,0x3d,0x6b,0x65,0x79,0x73,0x5b,0x61,0x5d,
+ 0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6b,0x62,0x3d,0x6b,0x65,0x79,0x73,0x5b,0x62,0x5d,0x3b,0x0a,0x63,0x6f,0x6e,
+ 0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x69,0x6e,0x64,0x65,0x78,0x5f,0x61,0x3d,0x6b,0x61,0x26,0x30,0x78,0x46,0x46,0x46,0x46,0x3b,0x0a,0x63,
+ 0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x69,0x6e,0x64,0x65,0x78,0x5f,0x62,0x3d,0x6b,0x62,0x26,0x30,0x78,0x46,0x46,0x46,0x46,0x3b,
+ 0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x76,0x61,0x6c,0x75,0x65,0x5f,0x61,0x20,0x3d,0x0a,0x28,0x28,0x28,0x75,0x69,0x6e,
+ 0x74,0x33,0x32,0x5f,0x74,0x29,0x69,0x6e,0x70,0x75,0x74,0x5b,0x69,0x6e,0x64,0x65,0x78,0x5f,0x61,0x2b,0x31,0x5d,0x29,0x3c,0x3c,0x32,0x34,0x29,0x20,0x7c,0x0a,0x28,
+ 0x28,0x28,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x29,0x69,0x6e,0x70,0x75,0x74,0x5b,0x69,0x6e,0x64,0x65,0x78,0x5f,0x61,0x2b,0x32,0x5d,0x29,0x3c,0x3c,0x31,0x36,
+ 0x29,0x20,0x7c,0x0a,0x28,0x28,0x28,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x29,0x69,0x6e,0x70,0x75,0x74,0x5b,0x69,0x6e,0x64,0x65,0x78,0x5f,0x61,0x2b,0x33,0x5d,
+ 0x29,0x3c,0x3c,0x38,0x29,0x20,0x7c,0x0a,0x28,0x28,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x29,0x69,0x6e,0x70,0x75,0x74,0x5b,0x69,0x6e,0x64,0x65,0x78,0x5f,0x61,
+ 0x2b,0x34,0x5d,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x76,0x61,0x6c,0x75,0x65,0x5f,0x62,0x20,0x3d,0x0a,0x28,
+ 0x28,0x28,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x29,0x69,0x6e,0x70,0x75,0x74,0x5b,0x69,0x6e,0x64,0x65,0x78,0x5f,0x62,0x2b,0x31,0x5d,0x29,0x3c,0x3c,0x32,0x34,
+ 0x29,0x20,0x7c,0x0a,0x28,0x28,0x28,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x29,0x69,0x6e,0x70,0x75,0x74,0x5b,0x69,0x6e,0x64,0x65,0x78,0x5f,0x62,0x2b,0x32,0x5d,
+ 0x29,0x3c,0x3c,0x31,0x36,0x29,0x20,0x7c,0x0a,0x28,0x28,0x28,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x29,0x69,0x6e,0x70,0x75,0x74,0x5b,0x69,0x6e,0x64,0x65,0x78,
+ 0x5f,0x62,0x2b,0x33,0x5d,0x29,0x3c,0x3c,0x38,0x29,0x20,0x7c,0x0a,0x28,0x28,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x29,0x69,0x6e,0x70,0x75,0x74,0x5b,0x69,0x6e,
+ 0x64,0x65,0x78,0x5f,0x62,0x2b,0x34,0x5d,0x29,0x3b,0x0a,0x69,0x66,0x28,0x76,0x61,0x6c,0x75,0x65,0x5f,0x61,0x3e,0x76,0x61,0x6c,0x75,0x65,0x5f,0x62,0x29,0x0a,0x7b,
+ 0x0a,0x6b,0x65,0x79,0x73,0x5b,0x61,0x5d,0x3d,0x6b,0x62,0x3b,0x0a,0x6b,0x65,0x79,0x73,0x5b,0x62,0x5d,0x3d,0x6b,0x61,0x3b,0x0a,0x7d,0x0a,0x7d,0x0a,0x5f,0x5f,0x61,
+ 0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x5f,0x5f,0x28,0x28,0x72,0x65,0x71,0x64,0x5f,0x77,0x6f,0x72,0x6b,0x5f,0x67,0x72,0x6f,0x75,0x70,0x5f,0x73,0x69,0x7a,0x65,
+ 0x28,0x42,0x4c,0x4f,0x43,0x4b,0x5f,0x53,0x49,0x5a,0x45,0x2c,0x31,0x2c,0x31,0x29,0x29,0x29,0x0a,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,
+ 0x20,0x42,0x57,0x54,0x5f,0x66,0x69,0x78,0x5f,0x6f,0x72,0x64,0x65,0x72,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,
+ 0x6e,0x74,0x38,0x5f,0x74,0x2a,0x20,0x64,0x61,0x74,0x61,0x73,0x2c,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x2a,0x20,
+ 0x6b,0x65,0x79,0x73,0x2c,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x31,0x36,0x5f,0x74,0x2a,0x20,0x76,0x61,0x6c,0x75,0x65,0x73,0x29,0x0a,
+ 0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x74,0x69,0x64,0x3d,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,
+ 0x64,0x28,0x30,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x67,0x69,0x64,0x3d,0x67,0x65,0x74,0x5f,0x67,0x72,0x6f,
+ 0x75,0x70,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x64,0x61,0x74,0x61,0x5f,0x6f,0x66,
+ 0x66,0x73,0x65,0x74,0x3d,0x67,0x69,0x64,0x2a,0x31,0x30,0x32,0x34,0x30,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x4e,
+ 0x3d,0x39,0x39,0x37,0x33,0x3b,0x0a,0x64,0x61,0x74,0x61,0x73,0x2b,0x3d,0x64,0x61,0x74,0x61,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x3b,0x0a,0x6b,0x65,0x79,0x73,0x2b,
+ 0x3d,0x64,0x61,0x74,0x61,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x3b,0x0a,0x76,0x61,0x6c,0x75,0x65,0x73,0x2b,0x3d,0x64,0x61,0x74,0x61,0x5f,0x6f,0x66,0x66,0x73,0x65,
+ 0x74,0x3b,0x0a,0x66,0x6f,0x72,0x20,0x28,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x69,0x3d,0x74,0x69,0x64,0x2c,0x4e,0x31,0x3d,0x4e,0x2d,0x31,0x3b,0x20,0x69,
+ 0x3c,0x4e,0x31,0x3b,0x20,0x69,0x2b,0x3d,0x42,0x4c,0x4f,0x43,0x4b,0x5f,0x53,0x49,0x5a,0x45,0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,
+ 0x33,0x32,0x5f,0x74,0x20,0x76,0x61,0x6c,0x75,0x65,0x3d,0x6b,0x65,0x79,0x73,0x5b,0x69,0x5d,0x3e,0x3e,0x28,0x33,0x32,0x2d,0x42,0x49,0x54,0x53,0x29,0x3b,0x0a,0x69,
+ 0x66,0x28,0x76,0x61,0x6c,0x75,0x65,0x3d,0x3d,0x28,0x6b,0x65,0x79,0x73,0x5b,0x69,0x2b,0x31,0x5d,0x3e,0x3e,0x28,0x33,0x32,0x2d,0x42,0x49,0x54,0x53,0x29,0x29,0x29,
+ 0x0a,0x7b,0x0a,0x69,0x66,0x28,0x69,0x26,0x26,0x28,0x76,0x61,0x6c,0x75,0x65,0x3d,0x3d,0x28,0x6b,0x65,0x79,0x73,0x5b,0x69,0x2d,0x31,0x5d,0x3e,0x3e,0x28,0x33,0x32,
+ 0x2d,0x42,0x49,0x54,0x53,0x29,0x29,0x29,0x29,0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6e,0x3d,0x69,
+ 0x2b,0x32,0x3b,0x0a,0x77,0x68,0x69,0x6c,0x65,0x20,0x28,0x28,0x6e,0x3c,0x4e,0x29,0x26,0x26,0x28,0x76,0x61,0x6c,0x75,0x65,0x3d,0x3d,0x28,0x6b,0x65,0x79,0x73,0x5b,
+ 0x6e,0x5d,0x3e,0x3e,0x28,0x33,0x32,0x2d,0x42,0x49,0x54,0x53,0x29,0x29,0x29,0x29,0x0a,0x2b,0x2b,0x6e,0x3b,0x0a,0x66,0x6f,0x72,0x20,0x28,0x75,0x69,0x6e,0x74,0x33,
+ 0x32,0x5f,0x74,0x20,0x6a,0x3d,0x69,0x3b,0x20,0x6a,0x3c,0x6e,0x3b,0x20,0x2b,0x2b,0x6a,0x29,0x0a,0x66,0x6f,0x72,0x20,0x28,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,
+ 0x20,0x6b,0x3d,0x6a,0x2b,0x31,0x3b,0x20,0x6b,0x3c,0x6e,0x3b,0x20,0x2b,0x2b,0x6b,0x29,0x0a,0x66,0x69,0x78,0x5f,0x6f,0x72,0x64,0x65,0x72,0x28,0x64,0x61,0x74,0x61,
+ 0x73,0x2c,0x6a,0x2c,0x6b,0x2c,0x6b,0x65,0x79,0x73,0x29,0x3b,0x0a,0x7d,0x0a,0x7d,0x0a,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x47,0x4c,0x4f,
+ 0x42,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0x0a,0x66,0x6f,0x72,0x20,0x28,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x69,0x3d,
+ 0x74,0x69,0x64,0x3b,0x20,0x69,0x3c,0x4e,0x3b,0x20,0x69,0x2b,0x3d,0x42,0x4c,0x4f,0x43,0x4b,0x5f,0x53,0x49,0x5a,0x45,0x29,0x20,0x7b,0x0a,0x76,0x61,0x6c,0x75,0x65,
+ 0x73,0x5b,0x69,0x5d,0x3d,0x6b,0x65,0x79,0x73,0x5b,0x69,0x5d,0x3b,0x0a,0x7d,0x0a,0x7d,0x0a,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,
+ 0x66,0x69,0x6e,0x64,0x5f,0x73,0x68,0x61,0x72,0x65,0x73,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x36,
+ 0x34,0x5f,0x74,0x2a,0x20,0x68,0x61,0x73,0x68,0x65,0x73,0x2c,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x20,0x74,0x61,0x72,0x67,0x65,0x74,0x2c,0x5f,0x5f,0x67,0x6c,
+ 0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x2a,0x20,0x73,0x68,0x61,0x72,0x65,0x73,0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,
+ 0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3d,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,
+ 0x69,0x64,0x28,0x30,0x29,0x3b,0x0a,0x69,0x66,0x28,0x68,0x61,0x73,0x68,0x65,0x73,0x5b,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x6e,0x64,0x65,0x78,0x2a,0x34,0x2b,
+ 0x33,0x5d,0x3e,0x3d,0x74,0x61,0x72,0x67,0x65,0x74,0x29,0x20,0x7b,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x3b,0x0a,0x7d,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,
+ 0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x69,0x64,0x78,0x3d,0x61,0x74,0x6f,0x6d,0x69,0x63,0x5f,0x69,0x6e,0x63,0x28,0x73,0x68,0x61,0x72,0x65,0x73,0x2b,0x30,0x78,0x46,
+ 0x46,0x29,0x3b,0x0a,0x69,0x66,0x28,0x69,0x64,0x78,0x3c,0x30,0x78,0x46,0x46,0x29,0x0a,0x73,0x68,0x61,0x72,0x65,0x73,0x5b,0x69,0x64,0x78,0x5d,0x3d,0x67,0x6c,0x6f,
+ 0x62,0x61,0x6c,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3b,0x0a,0x7d,0x0a,0x23,0x75,0x6e,0x64,0x65,0x66,0x20,0x42,0x4c,0x4f,0x43,0x4b,0x5f,0x53,0x49,0x5a,0x45,0x0a,0x23,
+ 0x75,0x6e,0x64,0x65,0x66,0x20,0x44,0x41,0x54,0x41,0x5f,0x53,0x49,0x5a,0x45,0x0a,0x23,0x75,0x6e,0x64,0x65,0x66,0x20,0x44,0x41,0x54,0x41,0x5f,0x53,0x54,0x52,0x49,
+ 0x44,0x45,0x0a,0x23,0x75,0x6e,0x64,0x65,0x66,0x20,0x42,0x49,0x54,0x53,0x0a,0x23,0x75,0x6e,0x64,0x65,0x66,0x20,0x43,0x4f,0x55,0x4e,0x54,0x45,0x52,0x53,0x5f,0x53,
+ 0x49,0x5a,0x45,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x4f,0x54,0x41,0x54,0x45,0x28,0x76,0x2c,0x63,0x29,0x20,0x28,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,
+ 0x76,0x2c,0x28,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x29,0x63,0x29,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x58,0x4f,0x52,0x28,0x76,0x2c,0x77,0x29,
+ 0x20,0x28,0x28,0x76,0x29,0x20,0x5e,0x20,0x28,0x77,0x29,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x50,0x4c,0x55,0x53,0x28,0x76,0x2c,0x77,0x29,0x20,0x28,
+ 0x28,0x76,0x29,0x20,0x2b,0x20,0x28,0x77,0x29,0x29,0x0a,0x5f,0x5f,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x5f,0x5f,0x28,0x28,0x72,0x65,0x71,0x64,0x5f,0x77,
+ 0x6f,0x72,0x6b,0x5f,0x67,0x72,0x6f,0x75,0x70,0x5f,0x73,0x69,0x7a,0x65,0x28,0x53,0x41,0x4c,0x53,0x41,0x32,0x30,0x5f,0x47,0x52,0x4f,0x55,0x50,0x5f,0x53,0x49,0x5a,
+ 0x45,0x2c,0x31,0x2c,0x31,0x29,0x29,0x29,0x0a,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x53,0x61,0x6c,0x73,0x61,0x32,0x30,0x5f,0x58,
+ 0x4f,0x52,0x4b,0x65,0x79,0x53,0x74,0x72,0x65,0x61,0x6d,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,
+ 0x32,0x5f,0x74,0x2a,0x20,0x6b,0x65,0x79,0x73,0x2c,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x2a,0x20,0x6f,0x75,0x74,
+ 0x70,0x75,0x74,0x73,0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x74,0x3d,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,
+ 0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x67,0x3d,0x67,0x65,0x74,0x5f,0x67,
+ 0x72,0x6f,0x75,0x70,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,
+ 0x74,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x3d,0x67,0x2a,0x31,0x30,0x32,0x34,0x30,0x3b,0x0a,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,
+ 0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x2a,0x20,0x6b,0x3d,0x6b,0x65,0x79,0x73,0x2b,0x67,0x2a,0x38,0x3b,0x0a,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,
+ 0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x2a,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x3d,0x6f,0x75,0x74,0x70,0x75,0x74,0x73,0x2b,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,
+ 0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x2b,0x28,0x74,0x2a,0x36,0x34,0x29,0x29,0x2f,0x73,0x69,0x7a,0x65,0x6f,0x66,0x28,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x29,
+ 0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x73,0x69,0x7a,0x65,0x3d,0x39,0x39,0x37,
+ 0x33,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6a,0x31,0x3d,0x6b,0x5b,0x30,0x5d,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,
+ 0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6a,0x32,0x3d,0x6b,0x5b,0x31,0x5d,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,
+ 0x74,0x20,0x6a,0x33,0x3d,0x6b,0x5b,0x32,0x5d,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6a,0x34,0x3d,0x6b,0x5b,0x33,
+ 0x5d,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6a,0x31,0x31,0x3d,0x6b,0x5b,0x34,0x5d,0x3b,0x0a,0x63,0x6f,0x6e,0x73,
+ 0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6a,0x31,0x32,0x3d,0x6b,0x5b,0x35,0x5d,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,
+ 0x32,0x5f,0x74,0x20,0x6a,0x31,0x33,0x3d,0x6b,0x5b,0x36,0x5d,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6a,0x31,0x34,
+ 0x3d,0x6b,0x5b,0x37,0x5d,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6a,0x30,0x3d,0x30,0x78,0x36,0x31,0x37,0x30,0x37,
+ 0x38,0x36,0x35,0x55,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6a,0x35,0x3d,0x30,0x78,0x33,0x33,0x32,0x30,0x36,0x34,
+ 0x36,0x45,0x55,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6a,0x31,0x30,0x3d,0x30,0x78,0x37,0x39,0x36,0x32,0x32,0x44,
+ 0x33,0x32,0x55,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6a,0x31,0x35,0x3d,0x30,0x78,0x36,0x42,0x32,0x30,0x36,0x35,
+ 0x37,0x34,0x55,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6a,0x36,0x3d,0x30,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,
+ 0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6a,0x37,0x3d,0x30,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6a,0x38,
+ 0x3d,0x30,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6a,0x39,0x3d,0x30,0x3b,0x0a,0x66,0x6f,0x72,0x20,0x28,0x75,0x69,
+ 0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x69,0x3d,0x74,0x2a,0x36,0x34,0x3b,0x20,0x69,0x3c,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x73,0x69,0x7a,0x65,0x3b,0x20,0x69,0x2b,
+ 0x3d,0x53,0x41,0x4c,0x53,0x41,0x32,0x30,0x5f,0x47,0x52,0x4f,0x55,0x50,0x5f,0x53,0x49,0x5a,0x45,0x2a,0x36,0x34,0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,
+ 0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6a,0x38,0x5f,0x31,0x3d,0x6a,0x38,0x2b,0x28,0x69,0x2f,0x36,0x34,0x29,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,
+ 0x74,0x20,0x78,0x30,0x3d,0x6a,0x30,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x78,0x31,0x3d,0x6a,0x31,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,
+ 0x74,0x20,0x78,0x32,0x3d,0x6a,0x32,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x78,0x33,0x3d,0x6a,0x33,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,
+ 0x74,0x20,0x78,0x34,0x3d,0x6a,0x34,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x78,0x35,0x3d,0x6a,0x35,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,
+ 0x74,0x20,0x78,0x36,0x3d,0x6a,0x36,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x78,0x37,0x3d,0x6a,0x37,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,
+ 0x74,0x20,0x78,0x38,0x3d,0x6a,0x38,0x5f,0x31,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x78,0x39,0x3d,0x6a,0x39,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x33,
+ 0x32,0x5f,0x74,0x20,0x78,0x31,0x30,0x3d,0x6a,0x31,0x30,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x78,0x31,0x31,0x3d,0x6a,0x31,0x31,0x3b,0x0a,0x75,
+ 0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x78,0x31,0x32,0x3d,0x6a,0x31,0x32,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x78,0x31,0x33,0x3d,0x6a,0x31,
+ 0x33,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x78,0x31,0x34,0x3d,0x6a,0x31,0x34,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x78,0x31,
+ 0x35,0x3d,0x6a,0x31,0x35,0x3b,0x0a,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x20,0x35,0x0a,0x66,0x6f,0x72,0x20,0x28,0x75,0x69,0x6e,
+ 0x74,0x33,0x32,0x5f,0x74,0x20,0x6a,0x3d,0x30,0x3b,0x20,0x6a,0x3c,0x31,0x30,0x3b,0x20,0x2b,0x2b,0x6a,0x29,0x0a,0x7b,0x0a,0x78,0x34,0x3d,0x58,0x4f,0x52,0x28,0x20,
+ 0x78,0x34,0x2c,0x52,0x4f,0x54,0x41,0x54,0x45,0x28,0x50,0x4c,0x55,0x53,0x28,0x20,0x78,0x30,0x2c,0x78,0x31,0x32,0x29,0x2c,0x37,0x29,0x29,0x3b,0x0a,0x78,0x38,0x3d,
+ 0x58,0x4f,0x52,0x28,0x20,0x78,0x38,0x2c,0x52,0x4f,0x54,0x41,0x54,0x45,0x28,0x50,0x4c,0x55,0x53,0x28,0x20,0x78,0x34,0x2c,0x78,0x30,0x29,0x2c,0x39,0x29,0x29,0x3b,
+ 0x0a,0x78,0x31,0x32,0x3d,0x58,0x4f,0x52,0x28,0x78,0x31,0x32,0x2c,0x52,0x4f,0x54,0x41,0x54,0x45,0x28,0x50,0x4c,0x55,0x53,0x28,0x20,0x78,0x38,0x2c,0x78,0x34,0x29,
+ 0x2c,0x31,0x33,0x29,0x29,0x3b,0x0a,0x78,0x30,0x3d,0x58,0x4f,0x52,0x28,0x20,0x78,0x30,0x2c,0x52,0x4f,0x54,0x41,0x54,0x45,0x28,0x50,0x4c,0x55,0x53,0x28,0x78,0x31,
+ 0x32,0x2c,0x78,0x38,0x29,0x2c,0x31,0x38,0x29,0x29,0x3b,0x0a,0x78,0x39,0x3d,0x58,0x4f,0x52,0x28,0x20,0x78,0x39,0x2c,0x52,0x4f,0x54,0x41,0x54,0x45,0x28,0x50,0x4c,
+ 0x55,0x53,0x28,0x20,0x78,0x35,0x2c,0x78,0x31,0x29,0x2c,0x37,0x29,0x29,0x3b,0x0a,0x78,0x31,0x33,0x3d,0x58,0x4f,0x52,0x28,0x78,0x31,0x33,0x2c,0x52,0x4f,0x54,0x41,
+ 0x54,0x45,0x28,0x50,0x4c,0x55,0x53,0x28,0x20,0x78,0x39,0x2c,0x78,0x35,0x29,0x2c,0x39,0x29,0x29,0x3b,0x0a,0x78,0x31,0x3d,0x58,0x4f,0x52,0x28,0x20,0x78,0x31,0x2c,
+ 0x52,0x4f,0x54,0x41,0x54,0x45,0x28,0x50,0x4c,0x55,0x53,0x28,0x78,0x31,0x33,0x2c,0x78,0x39,0x29,0x2c,0x31,0x33,0x29,0x29,0x3b,0x0a,0x78,0x35,0x3d,0x58,0x4f,0x52,
+ 0x28,0x20,0x78,0x35,0x2c,0x52,0x4f,0x54,0x41,0x54,0x45,0x28,0x50,0x4c,0x55,0x53,0x28,0x20,0x78,0x31,0x2c,0x78,0x31,0x33,0x29,0x2c,0x31,0x38,0x29,0x29,0x3b,0x0a,
+ 0x78,0x31,0x34,0x3d,0x58,0x4f,0x52,0x28,0x78,0x31,0x34,0x2c,0x52,0x4f,0x54,0x41,0x54,0x45,0x28,0x50,0x4c,0x55,0x53,0x28,0x78,0x31,0x30,0x2c,0x78,0x36,0x29,0x2c,
+ 0x37,0x29,0x29,0x3b,0x0a,0x78,0x32,0x3d,0x58,0x4f,0x52,0x28,0x20,0x78,0x32,0x2c,0x52,0x4f,0x54,0x41,0x54,0x45,0x28,0x50,0x4c,0x55,0x53,0x28,0x78,0x31,0x34,0x2c,
+ 0x78,0x31,0x30,0x29,0x2c,0x39,0x29,0x29,0x3b,0x0a,0x78,0x36,0x3d,0x58,0x4f,0x52,0x28,0x20,0x78,0x36,0x2c,0x52,0x4f,0x54,0x41,0x54,0x45,0x28,0x50,0x4c,0x55,0x53,
+ 0x28,0x20,0x78,0x32,0x2c,0x78,0x31,0x34,0x29,0x2c,0x31,0x33,0x29,0x29,0x3b,0x0a,0x78,0x31,0x30,0x3d,0x58,0x4f,0x52,0x28,0x78,0x31,0x30,0x2c,0x52,0x4f,0x54,0x41,
+ 0x54,0x45,0x28,0x50,0x4c,0x55,0x53,0x28,0x20,0x78,0x36,0x2c,0x78,0x32,0x29,0x2c,0x31,0x38,0x29,0x29,0x3b,0x0a,0x78,0x33,0x3d,0x58,0x4f,0x52,0x28,0x20,0x78,0x33,
+ 0x2c,0x52,0x4f,0x54,0x41,0x54,0x45,0x28,0x50,0x4c,0x55,0x53,0x28,0x78,0x31,0x35,0x2c,0x78,0x31,0x31,0x29,0x2c,0x37,0x29,0x29,0x3b,0x0a,0x78,0x37,0x3d,0x58,0x4f,
+ 0x52,0x28,0x20,0x78,0x37,0x2c,0x52,0x4f,0x54,0x41,0x54,0x45,0x28,0x50,0x4c,0x55,0x53,0x28,0x20,0x78,0x33,0x2c,0x78,0x31,0x35,0x29,0x2c,0x39,0x29,0x29,0x3b,0x0a,
+ 0x78,0x31,0x31,0x3d,0x58,0x4f,0x52,0x28,0x78,0x31,0x31,0x2c,0x52,0x4f,0x54,0x41,0x54,0x45,0x28,0x50,0x4c,0x55,0x53,0x28,0x20,0x78,0x37,0x2c,0x78,0x33,0x29,0x2c,
+ 0x31,0x33,0x29,0x29,0x3b,0x0a,0x78,0x31,0x35,0x3d,0x58,0x4f,0x52,0x28,0x78,0x31,0x35,0x2c,0x52,0x4f,0x54,0x41,0x54,0x45,0x28,0x50,0x4c,0x55,0x53,0x28,0x78,0x31,
+ 0x31,0x2c,0x78,0x37,0x29,0x2c,0x31,0x38,0x29,0x29,0x3b,0x0a,0x78,0x31,0x3d,0x58,0x4f,0x52,0x28,0x20,0x78,0x31,0x2c,0x52,0x4f,0x54,0x41,0x54,0x45,0x28,0x50,0x4c,
+ 0x55,0x53,0x28,0x20,0x78,0x30,0x2c,0x78,0x33,0x29,0x2c,0x37,0x29,0x29,0x3b,0x0a,0x78,0x32,0x3d,0x58,0x4f,0x52,0x28,0x20,0x78,0x32,0x2c,0x52,0x4f,0x54,0x41,0x54,
+ 0x45,0x28,0x50,0x4c,0x55,0x53,0x28,0x20,0x78,0x31,0x2c,0x78,0x30,0x29,0x2c,0x39,0x29,0x29,0x3b,0x0a,0x78,0x33,0x3d,0x58,0x4f,0x52,0x28,0x20,0x78,0x33,0x2c,0x52,
+ 0x4f,0x54,0x41,0x54,0x45,0x28,0x50,0x4c,0x55,0x53,0x28,0x20,0x78,0x32,0x2c,0x78,0x31,0x29,0x2c,0x31,0x33,0x29,0x29,0x3b,0x0a,0x78,0x30,0x3d,0x58,0x4f,0x52,0x28,
+ 0x20,0x78,0x30,0x2c,0x52,0x4f,0x54,0x41,0x54,0x45,0x28,0x50,0x4c,0x55,0x53,0x28,0x20,0x78,0x33,0x2c,0x78,0x32,0x29,0x2c,0x31,0x38,0x29,0x29,0x3b,0x0a,0x78,0x36,
+ 0x3d,0x58,0x4f,0x52,0x28,0x20,0x78,0x36,0x2c,0x52,0x4f,0x54,0x41,0x54,0x45,0x28,0x50,0x4c,0x55,0x53,0x28,0x20,0x78,0x35,0x2c,0x78,0x34,0x29,0x2c,0x37,0x29,0x29,
+ 0x3b,0x0a,0x78,0x37,0x3d,0x58,0x4f,0x52,0x28,0x20,0x78,0x37,0x2c,0x52,0x4f,0x54,0x41,0x54,0x45,0x28,0x50,0x4c,0x55,0x53,0x28,0x20,0x78,0x36,0x2c,0x78,0x35,0x29,
+ 0x2c,0x39,0x29,0x29,0x3b,0x0a,0x78,0x34,0x3d,0x58,0x4f,0x52,0x28,0x20,0x78,0x34,0x2c,0x52,0x4f,0x54,0x41,0x54,0x45,0x28,0x50,0x4c,0x55,0x53,0x28,0x20,0x78,0x37,
+ 0x2c,0x78,0x36,0x29,0x2c,0x31,0x33,0x29,0x29,0x3b,0x0a,0x78,0x35,0x3d,0x58,0x4f,0x52,0x28,0x20,0x78,0x35,0x2c,0x52,0x4f,0x54,0x41,0x54,0x45,0x28,0x50,0x4c,0x55,
+ 0x53,0x28,0x20,0x78,0x34,0x2c,0x78,0x37,0x29,0x2c,0x31,0x38,0x29,0x29,0x3b,0x0a,0x78,0x31,0x31,0x3d,0x58,0x4f,0x52,0x28,0x78,0x31,0x31,0x2c,0x52,0x4f,0x54,0x41,
+ 0x54,0x45,0x28,0x50,0x4c,0x55,0x53,0x28,0x78,0x31,0x30,0x2c,0x78,0x39,0x29,0x2c,0x37,0x29,0x29,0x3b,0x0a,0x78,0x38,0x3d,0x58,0x4f,0x52,0x28,0x20,0x78,0x38,0x2c,
+ 0x52,0x4f,0x54,0x41,0x54,0x45,0x28,0x50,0x4c,0x55,0x53,0x28,0x78,0x31,0x31,0x2c,0x78,0x31,0x30,0x29,0x2c,0x39,0x29,0x29,0x3b,0x0a,0x78,0x39,0x3d,0x58,0x4f,0x52,
+ 0x28,0x20,0x78,0x39,0x2c,0x52,0x4f,0x54,0x41,0x54,0x45,0x28,0x50,0x4c,0x55,0x53,0x28,0x20,0x78,0x38,0x2c,0x78,0x31,0x31,0x29,0x2c,0x31,0x33,0x29,0x29,0x3b,0x0a,
+ 0x78,0x31,0x30,0x3d,0x58,0x4f,0x52,0x28,0x78,0x31,0x30,0x2c,0x52,0x4f,0x54,0x41,0x54,0x45,0x28,0x50,0x4c,0x55,0x53,0x28,0x20,0x78,0x39,0x2c,0x78,0x38,0x29,0x2c,
+ 0x31,0x38,0x29,0x29,0x3b,0x0a,0x78,0x31,0x32,0x3d,0x58,0x4f,0x52,0x28,0x78,0x31,0x32,0x2c,0x52,0x4f,0x54,0x41,0x54,0x45,0x28,0x50,0x4c,0x55,0x53,0x28,0x78,0x31,
+ 0x35,0x2c,0x78,0x31,0x34,0x29,0x2c,0x37,0x29,0x29,0x3b,0x0a,0x78,0x31,0x33,0x3d,0x58,0x4f,0x52,0x28,0x78,0x31,0x33,0x2c,0x52,0x4f,0x54,0x41,0x54,0x45,0x28,0x50,
+ 0x4c,0x55,0x53,0x28,0x78,0x31,0x32,0x2c,0x78,0x31,0x35,0x29,0x2c,0x39,0x29,0x29,0x3b,0x0a,0x78,0x31,0x34,0x3d,0x58,0x4f,0x52,0x28,0x78,0x31,0x34,0x2c,0x52,0x4f,
+ 0x54,0x41,0x54,0x45,0x28,0x50,0x4c,0x55,0x53,0x28,0x78,0x31,0x33,0x2c,0x78,0x31,0x32,0x29,0x2c,0x31,0x33,0x29,0x29,0x3b,0x0a,0x78,0x31,0x35,0x3d,0x58,0x4f,0x52,
+ 0x28,0x78,0x31,0x35,0x2c,0x52,0x4f,0x54,0x41,0x54,0x45,0x28,0x50,0x4c,0x55,0x53,0x28,0x78,0x31,0x34,0x2c,0x78,0x31,0x33,0x29,0x2c,0x31,0x38,0x29,0x29,0x3b,0x0a,
+ 0x7d,0x0a,0x6f,0x75,0x74,0x70,0x75,0x74,0x5b,0x30,0x5d,0x3d,0x50,0x4c,0x55,0x53,0x28,0x78,0x30,0x2c,0x6a,0x30,0x29,0x3b,0x0a,0x6f,0x75,0x74,0x70,0x75,0x74,0x5b,
+ 0x31,0x5d,0x3d,0x50,0x4c,0x55,0x53,0x28,0x78,0x31,0x2c,0x6a,0x31,0x29,0x3b,0x0a,0x6f,0x75,0x74,0x70,0x75,0x74,0x5b,0x32,0x5d,0x3d,0x50,0x4c,0x55,0x53,0x28,0x78,
+ 0x32,0x2c,0x6a,0x32,0x29,0x3b,0x0a,0x6f,0x75,0x74,0x70,0x75,0x74,0x5b,0x33,0x5d,0x3d,0x50,0x4c,0x55,0x53,0x28,0x78,0x33,0x2c,0x6a,0x33,0x29,0x3b,0x0a,0x6f,0x75,
+ 0x74,0x70,0x75,0x74,0x5b,0x34,0x5d,0x3d,0x50,0x4c,0x55,0x53,0x28,0x78,0x34,0x2c,0x6a,0x34,0x29,0x3b,0x0a,0x6f,0x75,0x74,0x70,0x75,0x74,0x5b,0x35,0x5d,0x3d,0x50,
+ 0x4c,0x55,0x53,0x28,0x78,0x35,0x2c,0x6a,0x35,0x29,0x3b,0x0a,0x6f,0x75,0x74,0x70,0x75,0x74,0x5b,0x36,0x5d,0x3d,0x50,0x4c,0x55,0x53,0x28,0x78,0x36,0x2c,0x6a,0x36,
+ 0x29,0x3b,0x0a,0x6f,0x75,0x74,0x70,0x75,0x74,0x5b,0x37,0x5d,0x3d,0x50,0x4c,0x55,0x53,0x28,0x78,0x37,0x2c,0x6a,0x37,0x29,0x3b,0x0a,0x6f,0x75,0x74,0x70,0x75,0x74,
+ 0x5b,0x38,0x5d,0x3d,0x50,0x4c,0x55,0x53,0x28,0x78,0x38,0x2c,0x6a,0x38,0x5f,0x31,0x29,0x3b,0x0a,0x6f,0x75,0x74,0x70,0x75,0x74,0x5b,0x39,0x5d,0x3d,0x50,0x4c,0x55,
+ 0x53,0x28,0x78,0x39,0x2c,0x6a,0x39,0x29,0x3b,0x0a,0x6f,0x75,0x74,0x70,0x75,0x74,0x5b,0x31,0x30,0x5d,0x3d,0x50,0x4c,0x55,0x53,0x28,0x78,0x31,0x30,0x2c,0x6a,0x31,
+ 0x30,0x29,0x3b,0x0a,0x6f,0x75,0x74,0x70,0x75,0x74,0x5b,0x31,0x31,0x5d,0x3d,0x50,0x4c,0x55,0x53,0x28,0x78,0x31,0x31,0x2c,0x6a,0x31,0x31,0x29,0x3b,0x0a,0x6f,0x75,
+ 0x74,0x70,0x75,0x74,0x5b,0x31,0x32,0x5d,0x3d,0x50,0x4c,0x55,0x53,0x28,0x78,0x31,0x32,0x2c,0x6a,0x31,0x32,0x29,0x3b,0x0a,0x6f,0x75,0x74,0x70,0x75,0x74,0x5b,0x31,
+ 0x33,0x5d,0x3d,0x50,0x4c,0x55,0x53,0x28,0x78,0x31,0x33,0x2c,0x6a,0x31,0x33,0x29,0x3b,0x0a,0x6f,0x75,0x74,0x70,0x75,0x74,0x5b,0x31,0x34,0x5d,0x3d,0x50,0x4c,0x55,
+ 0x53,0x28,0x78,0x31,0x34,0x2c,0x6a,0x31,0x34,0x29,0x3b,0x0a,0x6f,0x75,0x74,0x70,0x75,0x74,0x5b,0x31,0x35,0x5d,0x3d,0x50,0x4c,0x55,0x53,0x28,0x78,0x31,0x35,0x2c,
+ 0x6a,0x31,0x35,0x29,0x3b,0x0a,0x6f,0x75,0x74,0x70,0x75,0x74,0x2b,0x3d,0x28,0x53,0x41,0x4c,0x53,0x41,0x32,0x30,0x5f,0x47,0x52,0x4f,0x55,0x50,0x5f,0x53,0x49,0x5a,
+ 0x45,0x2a,0x36,0x34,0x29,0x2f,0x73,0x69,0x7a,0x65,0x6f,0x66,0x28,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x29,0x3b,0x0a,0x7d,0x0a,0x62,0x61,0x72,0x72,0x69,0x65,
+ 0x72,0x28,0x43,0x4c,0x4b,0x5f,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0x0a,0x69,0x66,0x28,0x74,0x3c,0x31,0x36,
+ 0x29,0x0a,0x7b,0x0a,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x2a,0x20,0x70,0x3d,0x6f,0x75,0x74,0x70,0x75,0x74,0x73,
+ 0x2b,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x2b,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x73,0x69,0x7a,0x65,0x2b,0x33,0x29,0x2f,0x73,
+ 0x69,0x7a,0x65,0x6f,0x66,0x28,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x29,0x3b,0x0a,0x70,0x5b,0x74,0x5d,0x3d,0x30,0x3b,0x0a,0x7d,0x0a,0x69,0x66,0x28,0x28,0x74,
+ 0x3d,0x3d,0x30,0x29,0x26,0x26,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x73,0x69,0x7a,0x65,0x26,0x33,0x29,0x29,0x0a,0x6f,0x75,0x74,0x70,0x75,0x74,0x73,0x5b,0x28,
+ 0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x2b,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x73,0x69,0x7a,0x65,0x29,0x2f,0x73,0x69,0x7a,0x65,0x6f,
+ 0x66,0x28,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x29,0x5d,0x20,0x26,0x3d,0x20,0x30,0x78,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x55,0x3e,0x3e,0x28,0x28,0x34,
+ 0x2d,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x73,0x69,0x7a,0x65,0x26,0x33,0x29,0x29,0x3c,0x3c,0x33,0x29,0x3b,0x0a,0x7d,0x0a,0x23,0x75,0x6e,0x64,0x65,0x66,0x20,
+ 0x52,0x4f,0x54,0x41,0x54,0x45,0x0a,0x23,0x75,0x6e,0x64,0x65,0x66,0x20,0x58,0x4f,0x52,0x0a,0x23,0x75,0x6e,0x64,0x65,0x66,0x20,0x50,0x4c,0x55,0x53,0x0a,0x23,0x64,
+ 0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x4f,0x55,0x4e,0x44,0x53,0x20,0x32,0x34,0x0a,0x5f,0x5f,0x63,0x6f,0x6e,0x73,0x74,0x61,0x6e,0x74,0x20,0x63,0x6f,0x6e,0x73,0x74,
+ 0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x20,0x72,0x63,0x5b,0x32,0x34,0x5d,0x3d,0x7b,0x0a,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,
+ 0x30,0x30,0x30,0x30,0x31,0x55,0x4c,0x2c,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x38,0x32,0x55,0x4c,0x2c,0x30,0x78,0x38,
+ 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x38,0x41,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,
+ 0x30,0x38,0x30,0x30,0x30,0x55,0x4c,0x2c,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x38,0x42,0x55,0x4c,0x2c,0x30,0x78,0x30,
+ 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x31,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,
+ 0x30,0x38,0x30,0x38,0x31,0x55,0x4c,0x2c,0x30,0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,0x39,0x55,0x4c,0x2c,0x30,0x78,0x30,
+ 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x41,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,
+ 0x30,0x30,0x30,0x38,0x38,0x55,0x4c,0x2c,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,0x30,0x38,0x30,0x30,0x39,0x55,0x4c,0x2c,0x30,0x78,0x30,
+ 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x41,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,
+ 0x30,0x38,0x30,0x38,0x42,0x55,0x4c,0x2c,0x30,0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x42,0x55,0x4c,0x2c,0x30,0x78,0x38,
+ 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x38,0x39,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,
+ 0x30,0x38,0x30,0x30,0x33,0x55,0x4c,0x2c,0x30,0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,0x32,0x55,0x4c,0x2c,0x30,0x78,0x38,
+ 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,
+ 0x30,0x38,0x30,0x30,0x41,0x55,0x4c,0x2c,0x30,0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x41,0x55,0x4c,0x2c,0x30,0x78,0x38,
+ 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,0x30,0x38,0x30,0x38,0x31,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,
+ 0x30,0x38,0x30,0x38,0x30,0x55,0x4c,0x2c,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x31,0x55,0x4c,0x2c,0x30,0x78,0x38,
+ 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,0x30,0x38,0x30,0x30,0x38,0x55,0x4c,0x0a,0x7d,0x3b,0x0a,0x5f,0x5f,0x63,0x6f,0x6e,0x73,0x74,0x61,0x6e,0x74,0x20,
+ 0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x63,0x5b,0x32,0x35,0x5d,0x5b,0x32,0x5d,0x3d,0x7b,0x0a,0x7b,0x20,0x31,0x2c,0x32,0x7d,0x2c,0x7b,0x20,0x32,0x2c,
+ 0x33,0x7d,0x2c,0x7b,0x20,0x33,0x2c,0x34,0x7d,0x2c,0x7b,0x20,0x34,0x2c,0x30,0x7d,0x2c,0x7b,0x20,0x30,0x2c,0x31,0x7d,0x2c,0x0a,0x7b,0x20,0x36,0x2c,0x37,0x7d,0x2c,
+ 0x7b,0x20,0x37,0x2c,0x38,0x7d,0x2c,0x7b,0x20,0x38,0x2c,0x39,0x7d,0x2c,0x7b,0x20,0x39,0x2c,0x35,0x7d,0x2c,0x7b,0x20,0x35,0x2c,0x36,0x7d,0x2c,0x0a,0x7b,0x31,0x31,
+ 0x2c,0x31,0x32,0x7d,0x2c,0x7b,0x31,0x32,0x2c,0x31,0x33,0x7d,0x2c,0x7b,0x31,0x33,0x2c,0x31,0x34,0x7d,0x2c,0x7b,0x31,0x34,0x2c,0x31,0x30,0x7d,0x2c,0x7b,0x31,0x30,
+ 0x2c,0x31,0x31,0x7d,0x2c,0x0a,0x7b,0x31,0x36,0x2c,0x31,0x37,0x7d,0x2c,0x7b,0x31,0x37,0x2c,0x31,0x38,0x7d,0x2c,0x7b,0x31,0x38,0x2c,0x31,0x39,0x7d,0x2c,0x7b,0x31,
+ 0x39,0x2c,0x31,0x35,0x7d,0x2c,0x7b,0x31,0x35,0x2c,0x31,0x36,0x7d,0x2c,0x0a,0x7b,0x32,0x31,0x2c,0x32,0x32,0x7d,0x2c,0x7b,0x32,0x32,0x2c,0x32,0x33,0x7d,0x2c,0x7b,
+ 0x32,0x33,0x2c,0x32,0x34,0x7d,0x2c,0x7b,0x32,0x34,0x2c,0x32,0x30,0x7d,0x2c,0x7b,0x32,0x30,0x2c,0x32,0x31,0x7d,0x0a,0x7d,0x3b,0x0a,0x5f,0x5f,0x63,0x6f,0x6e,0x73,
+ 0x74,0x61,0x6e,0x74,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x70,0x70,0x69,0x5b,0x32,0x35,0x5d,0x5b,0x32,0x5d,0x3d,0x7b,0x0a,0x7b,0x30,0x2c,0x30,
+ 0x7d,0x2c,0x7b,0x36,0x2c,0x34,0x34,0x7d,0x2c,0x7b,0x31,0x32,0x2c,0x34,0x33,0x7d,0x2c,0x7b,0x31,0x38,0x2c,0x32,0x31,0x7d,0x2c,0x7b,0x32,0x34,0x2c,0x31,0x34,0x7d,
+ 0x2c,0x7b,0x33,0x2c,0x32,0x38,0x7d,0x2c,0x7b,0x39,0x2c,0x32,0x30,0x7d,0x2c,0x7b,0x31,0x30,0x2c,0x33,0x7d,0x2c,0x7b,0x31,0x36,0x2c,0x34,0x35,0x7d,0x2c,0x0a,0x7b,
+ 0x32,0x32,0x2c,0x36,0x31,0x7d,0x2c,0x7b,0x31,0x2c,0x31,0x7d,0x2c,0x7b,0x37,0x2c,0x36,0x7d,0x2c,0x7b,0x31,0x33,0x2c,0x32,0x35,0x7d,0x2c,0x7b,0x31,0x39,0x2c,0x38,
+ 0x7d,0x2c,0x7b,0x32,0x30,0x2c,0x31,0x38,0x7d,0x2c,0x7b,0x34,0x2c,0x32,0x37,0x7d,0x2c,0x7b,0x35,0x2c,0x33,0x36,0x7d,0x2c,0x7b,0x31,0x31,0x2c,0x31,0x30,0x7d,0x2c,
+ 0x0a,0x7b,0x31,0x37,0x2c,0x31,0x35,0x7d,0x2c,0x7b,0x32,0x33,0x2c,0x35,0x36,0x7d,0x2c,0x7b,0x32,0x2c,0x36,0x32,0x7d,0x2c,0x7b,0x38,0x2c,0x35,0x35,0x7d,0x2c,0x7b,
+ 0x31,0x34,0x2c,0x33,0x39,0x7d,0x2c,0x7b,0x31,0x35,0x2c,0x34,0x31,0x7d,0x2c,0x7b,0x32,0x31,0x2c,0x32,0x7d,0x0a,0x7d,0x3b,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,
+ 0x20,0x52,0x36,0x34,0x28,0x61,0x2c,0x62,0x2c,0x63,0x29,0x20,0x28,0x28,0x28,0x61,0x29,0x20,0x3c,0x3c,0x20,0x62,0x29,0x20,0x7c,0x20,0x28,0x28,0x61,0x29,0x20,0x3e,
+ 0x3e,0x20,0x63,0x29,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x4f,0x55,0x4e,0x44,0x28,0x6b,0x29,0x20,0x5c,0x0a,0x64,0x6f,0x20,0x7b,0x20,0x5c,0x0a,
+ 0x43,0x5b,0x74,0x5d,0x3d,0x41,0x5b,0x73,0x5d,0x5e,0x41,0x5b,0x73,0x2b,0x35,0x5d,0x5e,0x41,0x5b,0x73,0x2b,0x31,0x30,0x5d,0x5e,0x41,0x5b,0x73,0x2b,0x31,0x35,0x5d,
+ 0x5e,0x41,0x5b,0x73,0x2b,0x32,0x30,0x5d,0x3b,0x20,0x5c,0x0a,0x41,0x5b,0x74,0x5d,0x20,0x5e,0x3d,0x20,0x43,0x5b,0x73,0x2b,0x34,0x5d,0x5e,0x52,0x36,0x34,0x28,0x43,
+ 0x5b,0x73,0x2b,0x31,0x5d,0x2c,0x31,0x2c,0x36,0x33,0x29,0x3b,0x20,0x5c,0x0a,0x43,0x5b,0x74,0x5d,0x3d,0x52,0x36,0x34,0x28,0x41,0x5b,0x61,0x74,0x5d,0x2c,0x72,0x6f,
+ 0x30,0x2c,0x72,0x6f,0x31,0x29,0x3b,0x20,0x5c,0x0a,0x41,0x5b,0x74,0x5d,0x3d,0x28,0x43,0x5b,0x74,0x5d,0x5e,0x28,0x28,0x7e,0x43,0x5b,0x63,0x31,0x5d,0x29,0x26,0x43,
+ 0x5b,0x63,0x32,0x5d,0x29,0x29,0x5e,0x28,0x6b,0x31,0x26,0x28,0x6b,0x29,0x29,0x3b,0x20,0x5c,0x0a,0x7d,0x20,0x77,0x68,0x69,0x6c,0x65,0x20,0x28,0x30,0x29,0x0a,0x5f,
+ 0x5f,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x5f,0x5f,0x28,0x28,0x72,0x65,0x71,0x64,0x5f,0x77,0x6f,0x72,0x6b,0x5f,0x67,0x72,0x6f,0x75,0x70,0x5f,0x73,0x69,
+ 0x7a,0x65,0x28,0x33,0x32,0x2c,0x31,0x2c,0x31,0x29,0x29,0x29,0x0a,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x73,0x68,0x61,0x33,0x28,
+ 0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x38,0x5f,0x74,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x73,0x2c,0x5f,
+ 0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x2a,0x20,0x68,0x61,0x73,0x68,0x65,0x73,0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73,
+ 0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x74,0x3d,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0x0a,0x69,0x66,
+ 0x28,0x74,0x3e,0x3d,0x32,0x35,0x29,0x20,0x7b,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x3b,0x0a,0x7d,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,
+ 0x5f,0x74,0x20,0x67,0x3d,0x67,0x65,0x74,0x5f,0x67,0x72,0x6f,0x75,0x70,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,
+ 0x36,0x34,0x5f,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x3d,0x31,0x30,0x32,0x34,0x30,0x2a,0x32,0x2a,0x67,0x3b,0x0a,0x5f,0x5f,0x67,
+ 0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x3d,0x28,0x5f,0x5f,0x67,
+ 0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x2a,0x29,0x28,0x69,0x6e,0x70,0x75,0x74,0x73,0x2b,0x69,0x6e,
+ 0x70,0x75,0x74,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0x0a,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x20,0x41,0x5b,
+ 0x32,0x35,0x5d,0x3b,0x0a,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x20,0x43,0x5b,0x32,0x35,0x5d,0x3b,0x0a,0x41,0x5b,0x74,
+ 0x5d,0x3d,0x30,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x73,0x3d,0x74,0x20,0x25,0x20,0x35,0x3b,0x0a,0x63,0x6f,0x6e,
+ 0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x61,0x74,0x3d,0x70,0x70,0x69,0x5b,0x74,0x5d,0x5b,0x30,0x5d,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x72,
+ 0x6f,0x30,0x3d,0x70,0x70,0x69,0x5b,0x74,0x5d,0x5b,0x31,0x5d,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x72,0x6f,0x31,0x3d,0x36,0x34,0x2d,0x72,
+ 0x6f,0x30,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x63,0x31,0x3d,0x63,0x5b,0x74,0x5d,0x5b,0x30,0x5d,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,
+ 0x69,0x6e,0x74,0x20,0x63,0x32,0x3d,0x63,0x5b,0x74,0x5d,0x5b,0x31,0x5d,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x20,0x6b,
+ 0x31,0x3d,0x28,0x74,0x3d,0x3d,0x30,0x29,0x3f,0x30,0x78,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x55,0x4c,0x3a,0x30,0x55,
+ 0x4c,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x73,0x69,0x7a,0x65,0x3d,0x39,0x39,0x37,
+ 0x33,0x2a,0x32,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x77,0x6f,0x72,0x64,0x73,0x3d,
+ 0x69,0x6e,0x70,0x75,0x74,0x5f,0x73,0x69,0x7a,0x65,0x2f,0x73,0x69,0x7a,0x65,0x6f,0x66,0x28,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x29,0x3b,0x0a,0x5f,0x5f,0x67,
+ 0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x2a,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x70,0x75,
+ 0x74,0x5f,0x65,0x6e,0x64,0x31,0x37,0x3d,0x69,0x6e,0x70,0x75,0x74,0x2b,0x28,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x77,0x6f,0x72,0x64,0x73,0x2f,0x31,0x37,0x29,0x2a,
+ 0x31,0x37,0x29,0x3b,0x0a,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x2a,0x20,0x63,0x6f,
+ 0x6e,0x73,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x65,0x6e,0x64,0x3d,0x69,0x6e,0x70,0x75,0x74,0x2b,0x69,0x6e,0x70,0x75,0x74,0x5f,0x77,0x6f,0x72,0x64,0x73,0x3b,
+ 0x0a,0x66,0x6f,0x72,0x20,0x28,0x3b,0x20,0x69,0x6e,0x70,0x75,0x74,0x3c,0x69,0x6e,0x70,0x75,0x74,0x5f,0x65,0x6e,0x64,0x31,0x37,0x3b,0x20,0x69,0x6e,0x70,0x75,0x74,
+ 0x2b,0x3d,0x31,0x37,0x29,0x20,0x7b,0x0a,0x69,0x66,0x28,0x74,0x3c,0x31,0x37,0x29,0x20,0x41,0x5b,0x74,0x5d,0x20,0x5e,0x3d,0x20,0x69,0x6e,0x70,0x75,0x74,0x5b,0x74,
+ 0x5d,0x3b,0x0a,0x52,0x4f,0x55,0x4e,0x44,0x28,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x31,0x55,0x4c,0x29,0x3b,0x20,
+ 0x52,0x4f,0x55,0x4e,0x44,0x28,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x38,0x32,0x55,0x4c,0x29,0x3b,0x20,0x52,0x4f,0x55,
+ 0x4e,0x44,0x28,0x30,0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x38,0x41,0x55,0x4c,0x29,0x3b,0x0a,0x52,0x4f,0x55,0x4e,0x44,0x28,
+ 0x30,0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,0x30,0x38,0x30,0x30,0x30,0x55,0x4c,0x29,0x3b,0x20,0x52,0x4f,0x55,0x4e,0x44,0x28,0x30,0x78,0x30,
+ 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x38,0x42,0x55,0x4c,0x29,0x3b,0x20,0x52,0x4f,0x55,0x4e,0x44,0x28,0x30,0x78,0x30,0x30,0x30,0x30,
+ 0x30,0x30,0x30,0x30,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x31,0x55,0x4c,0x29,0x3b,0x0a,0x52,0x4f,0x55,0x4e,0x44,0x28,0x30,0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30,
+ 0x30,0x38,0x30,0x30,0x30,0x38,0x30,0x38,0x31,0x55,0x4c,0x29,0x3b,0x20,0x52,0x4f,0x55,0x4e,0x44,0x28,0x30,0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,
+ 0x30,0x30,0x38,0x30,0x30,0x39,0x55,0x4c,0x29,0x3b,0x20,0x52,0x4f,0x55,0x4e,0x44,0x28,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,
+ 0x30,0x38,0x41,0x55,0x4c,0x29,0x3b,0x0a,0x52,0x4f,0x55,0x4e,0x44,0x28,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x38,
+ 0x55,0x4c,0x29,0x3b,0x20,0x52,0x4f,0x55,0x4e,0x44,0x28,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,0x30,0x38,0x30,0x30,0x39,0x55,0x4c,0x29,
+ 0x3b,0x20,0x52,0x4f,0x55,0x4e,0x44,0x28,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x41,0x55,0x4c,0x29,0x3b,0x0a,0x52,
+ 0x4f,0x55,0x4e,0x44,0x28,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,0x30,0x38,0x30,0x38,0x42,0x55,0x4c,0x29,0x3b,0x20,0x52,0x4f,0x55,0x4e,
+ 0x44,0x28,0x30,0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x42,0x55,0x4c,0x29,0x3b,0x20,0x52,0x4f,0x55,0x4e,0x44,0x28,0x30,
+ 0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x38,0x39,0x55,0x4c,0x29,0x3b,0x0a,0x52,0x4f,0x55,0x4e,0x44,0x28,0x30,0x78,0x38,0x30,
+ 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,0x33,0x55,0x4c,0x29,0x3b,0x20,0x52,0x4f,0x55,0x4e,0x44,0x28,0x30,0x78,0x38,0x30,0x30,0x30,0x30,
+ 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,0x32,0x55,0x4c,0x29,0x3b,0x20,0x52,0x4f,0x55,0x4e,0x44,0x28,0x30,0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,
+ 0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x55,0x4c,0x29,0x3b,0x0a,0x52,0x4f,0x55,0x4e,0x44,0x28,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,
+ 0x30,0x38,0x30,0x30,0x41,0x55,0x4c,0x29,0x3b,0x20,0x52,0x4f,0x55,0x4e,0x44,0x28,0x30,0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,0x30,0x30,0x30,
+ 0x30,0x41,0x55,0x4c,0x29,0x3b,0x20,0x52,0x4f,0x55,0x4e,0x44,0x28,0x30,0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,0x30,0x38,0x30,0x38,0x31,0x55,
+ 0x4c,0x29,0x3b,0x0a,0x52,0x4f,0x55,0x4e,0x44,0x28,0x30,0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x38,0x30,0x55,0x4c,0x29,0x3b,
+ 0x20,0x52,0x4f,0x55,0x4e,0x44,0x28,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x31,0x55,0x4c,0x29,0x3b,0x20,0x52,0x4f,
+ 0x55,0x4e,0x44,0x28,0x30,0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,0x30,0x38,0x30,0x30,0x38,0x55,0x4c,0x29,0x3b,0x0a,0x7d,0x0a,0x63,0x6f,0x6e,
+ 0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x77,0x6f,0x72,0x64,0x49,0x6e,0x64,0x65,0x78,0x3d,0x69,0x6e,0x70,0x75,0x74,0x5f,0x65,0x6e,0x64,0x2d,
+ 0x69,0x6e,0x70,0x75,0x74,0x3b,0x0a,0x69,0x66,0x28,0x74,0x3c,0x77,0x6f,0x72,0x64,0x49,0x6e,0x64,0x65,0x78,0x29,0x20,0x41,0x5b,0x74,0x5d,0x20,0x5e,0x3d,0x20,0x69,
+ 0x6e,0x70,0x75,0x74,0x5b,0x74,0x5d,0x3b,0x0a,0x69,0x66,0x28,0x74,0x3d,0x3d,0x30,0x29,0x20,0x7b,0x0a,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x20,0x74,0x61,0x69,
+ 0x6c,0x3d,0x30,0x3b,0x0a,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x38,0x5f,0x74,0x2a,0x20,0x70,0x3d,0x28,
+ 0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x38,0x5f,0x74,0x2a,0x29,0x69,0x6e,0x70,0x75,0x74,0x5f,0x65,0x6e,
+ 0x64,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x74,0x61,0x69,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x3d,0x69,0x6e,0x70,0x75,
+ 0x74,0x5f,0x73,0x69,0x7a,0x65,0x20,0x25,0x20,0x73,0x69,0x7a,0x65,0x6f,0x66,0x28,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x29,0x3b,0x0a,0x66,0x6f,0x72,0x20,0x28,
+ 0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x74,0x61,0x69,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,
+ 0x7b,0x0a,0x74,0x61,0x69,0x6c,0x7c,0x3d,0x28,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x29,0x28,0x70,0x5b,0x69,0x5d,0x29,0x3c,0x3c,0x28,0x69,0x2a,0x38,0x29,0x3b,
+ 0x0a,0x7d,0x0a,0x41,0x5b,0x77,0x6f,0x72,0x64,0x49,0x6e,0x64,0x65,0x78,0x5d,0x20,0x5e,0x3d,0x20,0x74,0x61,0x69,0x6c,0x5e,0x28,0x28,0x75,0x69,0x6e,0x74,0x36,0x34,
+ 0x5f,0x74,0x29,0x28,0x28,0x28,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x29,0x28,0x30,0x78,0x30,0x32,0x7c,0x28,0x31,0x3c,0x3c,0x32,0x29,0x29,0x29,0x3c,0x3c,0x28,
+ 0x74,0x61,0x69,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x2a,0x38,0x29,0x29,0x29,0x3b,0x0a,0x41,0x5b,0x31,0x36,0x5d,0x20,0x5e,0x3d,0x20,0x30,0x78,0x38,0x30,0x30,0x30,0x30,
+ 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x55,0x4c,0x3b,0x0a,0x7d,0x0a,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,
+ 0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0x0a,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x20,0x31,0x0a,
+ 0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x52,0x4f,0x55,0x4e,0x44,0x53,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x7b,0x0a,0x43,
+ 0x5b,0x74,0x5d,0x3d,0x41,0x5b,0x73,0x5d,0x5e,0x41,0x5b,0x73,0x2b,0x35,0x5d,0x5e,0x41,0x5b,0x73,0x2b,0x31,0x30,0x5d,0x5e,0x41,0x5b,0x73,0x2b,0x31,0x35,0x5d,0x5e,
+ 0x41,0x5b,0x73,0x2b,0x32,0x30,0x5d,0x3b,0x0a,0x41,0x5b,0x74,0x5d,0x20,0x5e,0x3d,0x20,0x43,0x5b,0x73,0x2b,0x34,0x5d,0x5e,0x52,0x36,0x34,0x28,0x43,0x5b,0x73,0x2b,
+ 0x31,0x5d,0x2c,0x31,0x2c,0x36,0x33,0x29,0x3b,0x0a,0x43,0x5b,0x74,0x5d,0x3d,0x52,0x36,0x34,0x28,0x41,0x5b,0x61,0x74,0x5d,0x2c,0x72,0x6f,0x30,0x2c,0x72,0x6f,0x31,
+ 0x29,0x3b,0x0a,0x41,0x5b,0x74,0x5d,0x3d,0x28,0x43,0x5b,0x74,0x5d,0x5e,0x28,0x28,0x7e,0x43,0x5b,0x63,0x31,0x5d,0x29,0x26,0x43,0x5b,0x63,0x32,0x5d,0x29,0x29,0x5e,
+ 0x28,0x72,0x63,0x5b,0x69,0x5d,0x26,0x6b,0x31,0x29,0x3b,0x0a,0x7d,0x0a,0x69,0x66,0x28,0x74,0x3c,0x34,0x29,0x20,0x7b,0x0a,0x68,0x61,0x73,0x68,0x65,0x73,0x5b,0x67,
+ 0x2a,0x34,0x2b,0x74,0x5d,0x3d,0x41,0x5b,0x74,0x5d,0x3b,0x0a,0x7d,0x0a,0x7d,0x0a,0x5f,0x5f,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x5f,0x5f,0x28,0x28,0x72,
+ 0x65,0x71,0x64,0x5f,0x77,0x6f,0x72,0x6b,0x5f,0x67,0x72,0x6f,0x75,0x70,0x5f,0x73,0x69,0x7a,0x65,0x28,0x33,0x32,0x2c,0x31,0x2c,0x31,0x29,0x29,0x29,0x0a,0x5f,0x5f,
+ 0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x73,0x68,0x61,0x33,0x5f,0x69,0x6e,0x69,0x74,0x69,0x61,0x6c,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,
+ 0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x38,0x5f,0x74,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2c,0x75,0x69,0x6e,0x74,
+ 0x33,0x32,0x5f,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x73,0x69,0x7a,0x65,0x2c,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6e,0x6f,0x6e,0x63,0x65,0x2c,0x5f,
+ 0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x2a,0x20,0x68,0x61,0x73,0x68,0x65,0x73,0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73,
+ 0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x74,0x3d,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0x0a,0x63,0x6f,
+ 0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x67,0x3d,0x67,0x65,0x74,0x5f,0x67,0x72,0x6f,0x75,0x70,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0x0a,
+ 0x69,0x66,0x28,0x74,0x3e,0x3d,0x32,0x35,0x29,0x20,0x7b,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x3b,0x0a,0x7d,0x0a,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,
+ 0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x3d,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,
+ 0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x2a,0x29,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x29,0x3b,0x0a,0x5f,0x5f,0x6c,
+ 0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x20,0x41,0x5b,0x32,0x35,0x5d,0x3b,0x0a,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,
+ 0x74,0x36,0x34,0x5f,0x74,0x20,0x43,0x5b,0x32,0x35,0x5d,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x69,0x6e,0x70,0x75,
+ 0x74,0x5f,0x77,0x6f,0x72,0x64,0x73,0x3d,0x69,0x6e,0x70,0x75,0x74,0x5f,0x73,0x69,0x7a,0x65,0x2f,0x73,0x69,0x7a,0x65,0x6f,0x66,0x28,0x75,0x69,0x6e,0x74,0x36,0x34,
+ 0x5f,0x74,0x29,0x3b,0x0a,0x41,0x5b,0x74,0x5d,0x3d,0x28,0x74,0x3c,0x69,0x6e,0x70,0x75,0x74,0x5f,0x77,0x6f,0x72,0x64,0x73,0x29,0x3f,0x69,0x6e,0x70,0x75,0x74,0x5b,
+ 0x74,0x5d,0x3a,0x30,0x3b,0x0a,0x69,0x66,0x28,0x74,0x3d,0x3d,0x30,0x29,0x20,0x7b,0x0a,0x28,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x33,
+ 0x32,0x5f,0x74,0x2a,0x29,0x41,0x29,0x5b,0x31,0x31,0x5d,0x3d,0x6e,0x6f,0x6e,0x63,0x65,0x2b,0x67,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,
+ 0x32,0x5f,0x74,0x20,0x74,0x61,0x69,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x3d,0x69,0x6e,0x70,0x75,0x74,0x5f,0x73,0x69,0x7a,0x65,0x20,0x25,0x20,0x73,0x69,0x7a,0x65,0x6f,
+ 0x66,0x28,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x29,0x3b,0x0a,0x41,0x5b,0x69,0x6e,0x70,0x75,0x74,0x5f,0x77,0x6f,0x72,0x64,0x73,0x5d,0x20,0x5e,0x3d,0x20,0x28,
+ 0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x29,0x28,0x28,0x28,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x29,0x28,0x30,0x78,0x30,0x32,0x7c,0x28,0x31,0x3c,0x3c,0x32,
+ 0x29,0x29,0x29,0x3c,0x3c,0x28,0x74,0x61,0x69,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x2a,0x38,0x29,0x29,0x3b,0x0a,0x41,0x5b,0x31,0x36,0x5d,0x20,0x5e,0x3d,0x20,0x30,0x78,
+ 0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x55,0x4c,0x3b,0x0a,0x7d,0x0a,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,
+ 0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,
+ 0x5f,0x74,0x20,0x73,0x3d,0x74,0x20,0x25,0x20,0x35,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x61,0x74,0x3d,0x70,0x70,0x69,0x5b,0x74,0x5d,0x5b,
+ 0x30,0x5d,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x72,0x6f,0x30,0x3d,0x70,0x70,0x69,0x5b,0x74,0x5d,0x5b,0x31,0x5d,0x3b,0x0a,0x63,0x6f,0x6e,
+ 0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x72,0x6f,0x31,0x3d,0x36,0x34,0x2d,0x72,0x6f,0x30,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x63,0x31,0x3d,
+ 0x63,0x5b,0x74,0x5d,0x5b,0x30,0x5d,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x63,0x32,0x3d,0x63,0x5b,0x74,0x5d,0x5b,0x31,0x5d,0x3b,0x0a,0x63,
+ 0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x20,0x6b,0x31,0x3d,0x28,0x74,0x3d,0x3d,0x30,0x29,0x3f,0x28,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,
+ 0x74,0x29,0x28,0x2d,0x31,0x29,0x3a,0x30,0x3b,0x0a,0x52,0x4f,0x55,0x4e,0x44,0x28,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,
+ 0x30,0x31,0x55,0x4c,0x29,0x3b,0x20,0x52,0x4f,0x55,0x4e,0x44,0x28,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x38,0x32,0x55,
+ 0x4c,0x29,0x3b,0x20,0x52,0x4f,0x55,0x4e,0x44,0x28,0x30,0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x38,0x41,0x55,0x4c,0x29,0x3b,
+ 0x0a,0x52,0x4f,0x55,0x4e,0x44,0x28,0x30,0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,0x30,0x38,0x30,0x30,0x30,0x55,0x4c,0x29,0x3b,0x20,0x52,0x4f,
+ 0x55,0x4e,0x44,0x28,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x38,0x42,0x55,0x4c,0x29,0x3b,0x20,0x52,0x4f,0x55,0x4e,0x44,
+ 0x28,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x31,0x55,0x4c,0x29,0x3b,0x0a,0x52,0x4f,0x55,0x4e,0x44,0x28,0x30,0x78,
+ 0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,0x30,0x38,0x30,0x38,0x31,0x55,0x4c,0x29,0x3b,0x20,0x52,0x4f,0x55,0x4e,0x44,0x28,0x30,0x78,0x38,0x30,0x30,
+ 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,0x39,0x55,0x4c,0x29,0x3b,0x20,0x52,0x4f,0x55,0x4e,0x44,0x28,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,
+ 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x41,0x55,0x4c,0x29,0x3b,0x0a,0x52,0x4f,0x55,0x4e,0x44,0x28,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,
+ 0x30,0x30,0x30,0x30,0x30,0x38,0x38,0x55,0x4c,0x29,0x3b,0x20,0x52,0x4f,0x55,0x4e,0x44,0x28,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,0x30,
+ 0x38,0x30,0x30,0x39,0x55,0x4c,0x29,0x3b,0x20,0x52,0x4f,0x55,0x4e,0x44,0x28,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,0x30,0x30,0x30,0x30,
+ 0x41,0x55,0x4c,0x29,0x3b,0x0a,0x52,0x4f,0x55,0x4e,0x44,0x28,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,0x30,0x38,0x30,0x38,0x42,0x55,0x4c,
+ 0x29,0x3b,0x20,0x52,0x4f,0x55,0x4e,0x44,0x28,0x30,0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x42,0x55,0x4c,0x29,0x3b,0x20,
+ 0x52,0x4f,0x55,0x4e,0x44,0x28,0x30,0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x38,0x39,0x55,0x4c,0x29,0x3b,0x0a,0x52,0x4f,0x55,
+ 0x4e,0x44,0x28,0x30,0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,0x33,0x55,0x4c,0x29,0x3b,0x20,0x52,0x4f,0x55,0x4e,0x44,0x28,
+ 0x30,0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,0x32,0x55,0x4c,0x29,0x3b,0x20,0x52,0x4f,0x55,0x4e,0x44,0x28,0x30,0x78,0x38,
+ 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x55,0x4c,0x29,0x3b,0x0a,0x52,0x4f,0x55,0x4e,0x44,0x28,0x30,0x78,0x30,0x30,0x30,0x30,
+ 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,0x41,0x55,0x4c,0x29,0x3b,0x20,0x52,0x4f,0x55,0x4e,0x44,0x28,0x30,0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30,
+ 0x30,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x41,0x55,0x4c,0x29,0x3b,0x20,0x52,0x4f,0x55,0x4e,0x44,0x28,0x30,0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,
+ 0x30,0x30,0x38,0x30,0x38,0x31,0x55,0x4c,0x29,0x3b,0x0a,0x52,0x4f,0x55,0x4e,0x44,0x28,0x30,0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,
+ 0x30,0x38,0x30,0x55,0x4c,0x29,0x3b,0x20,0x52,0x4f,0x55,0x4e,0x44,0x28,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x31,
+ 0x55,0x4c,0x29,0x3b,0x20,0x52,0x4f,0x55,0x4e,0x44,0x28,0x30,0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,0x30,0x38,0x30,0x30,0x38,0x55,0x4c,0x29,
+ 0x3b,0x0a,0x69,0x66,0x28,0x74,0x3c,0x34,0x29,0x20,0x7b,0x0a,0x68,0x61,0x73,0x68,0x65,0x73,0x5b,0x67,0x2a,0x34,0x2b,0x74,0x5d,0x3d,0x41,0x5b,0x74,0x5d,0x3b,0x0a,
+ 0x7d,0x0a,0x7d,0x0a,0x23,0x75,0x6e,0x64,0x65,0x66,0x20,0x52,0x4f,0x55,0x4e,0x44,0x53,0x0a,0x23,0x75,0x6e,0x64,0x65,0x66,0x20,0x52,0x36,0x34,0x0a,0x23,0x75,0x6e,
+ 0x64,0x65,0x66,0x20,0x52,0x4f,0x55,0x4e,0x44,0x0a,0x00
+};
+
+} // namespace xmrig
diff --git a/src/backend/opencl/cl/astrobwt_v2/salsa20.cl b/src/backend/opencl/cl/astrobwt_v2/salsa20.cl
new file mode 100644
index 0000000000..8dd9374aea
--- /dev/null
+++ b/src/backend/opencl/cl/astrobwt_v2/salsa20.cl
@@ -0,0 +1,151 @@
+/* XMRig
+ * Copyright 2010 Jeff Garzik
+ * Copyright 2012-2014 pooler
+ * Copyright 2014 Lucas Jones
+ * Copyright 2014-2016 Wolf9466
+ * Copyright 2016 Jay D Dee
+ * Copyright 2017-2018 XMR-Stak ,
+ * Copyright 2018-2022 SChernykh
+ * Copyright 2016-2022 XMRig ,
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#define ROTATE(v,c) (rotate(v,(uint32_t)c))
+#define XOR(v,w) ((v) ^ (w))
+#define PLUS(v,w) ((v) + (w))
+
+__attribute__((reqd_work_group_size(SALSA20_GROUP_SIZE, 1, 1)))
+__kernel void Salsa20_XORKeyStream(__global const uint32_t* keys, __global uint32_t* outputs)
+{
+ const uint32_t t = get_local_id(0);
+ const uint32_t g = get_group_id(0);
+
+ const uint64_t output_offset = g * 10240;
+
+ __global const uint32_t* k = keys + g * 8;
+ __global uint32_t* output = outputs + (output_offset + (t * 64)) / sizeof(uint32_t);
+ const uint32_t output_size = 9973;
+
+ const uint32_t j1 = k[0];
+ const uint32_t j2 = k[1];
+ const uint32_t j3 = k[2];
+ const uint32_t j4 = k[3];
+ const uint32_t j11 = k[4];
+ const uint32_t j12 = k[5];
+ const uint32_t j13 = k[6];
+ const uint32_t j14 = k[7];
+ const uint32_t j0 = 0x61707865U;
+ const uint32_t j5 = 0x3320646EU;
+ const uint32_t j10 = 0x79622D32U;
+ const uint32_t j15 = 0x6B206574U;
+ const uint32_t j6 = 0;
+ const uint32_t j7 = 0;
+ const uint32_t j8 = 0;
+ const uint32_t j9 = 0;
+
+ for (uint32_t i = t * 64; i < output_size; i += SALSA20_GROUP_SIZE * 64)
+ {
+ const uint32_t j8_1 = j8 + (i / 64);
+
+ uint32_t x0 = j0;
+ uint32_t x1 = j1;
+ uint32_t x2 = j2;
+ uint32_t x3 = j3;
+ uint32_t x4 = j4;
+ uint32_t x5 = j5;
+ uint32_t x6 = j6;
+ uint32_t x7 = j7;
+ uint32_t x8 = j8_1;
+ uint32_t x9 = j9;
+ uint32_t x10 = j10;
+ uint32_t x11 = j11;
+ uint32_t x12 = j12;
+ uint32_t x13 = j13;
+ uint32_t x14 = j14;
+ uint32_t x15 = j15;
+
+ #pragma unroll 5
+ for (uint32_t j = 0; j < 10; ++j)
+ {
+ x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7));
+ x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9));
+ x12 = XOR(x12,ROTATE(PLUS( x8, x4),13));
+ x0 = XOR( x0,ROTATE(PLUS(x12, x8),18));
+ x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7));
+ x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9));
+ x1 = XOR( x1,ROTATE(PLUS(x13, x9),13));
+ x5 = XOR( x5,ROTATE(PLUS( x1,x13),18));
+ x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7));
+ x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9));
+ x6 = XOR( x6,ROTATE(PLUS( x2,x14),13));
+ x10 = XOR(x10,ROTATE(PLUS( x6, x2),18));
+ x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9));
+ x11 = XOR(x11,ROTATE(PLUS( x7, x3),13));
+ x15 = XOR(x15,ROTATE(PLUS(x11, x7),18));
+ x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7));
+ x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9));
+ x3 = XOR( x3,ROTATE(PLUS( x2, x1),13));
+ x0 = XOR( x0,ROTATE(PLUS( x3, x2),18));
+ x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9));
+ x4 = XOR( x4,ROTATE(PLUS( x7, x6),13));
+ x5 = XOR( x5,ROTATE(PLUS( x4, x7),18));
+ x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7));
+ x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9));
+ x9 = XOR( x9,ROTATE(PLUS( x8,x11),13));
+ x10 = XOR(x10,ROTATE(PLUS( x9, x8),18));
+ x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7));
+ x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9));
+ x14 = XOR(x14,ROTATE(PLUS(x13,x12),13));
+ x15 = XOR(x15,ROTATE(PLUS(x14,x13),18));
+ }
+
+ output[0] = PLUS(x0, j0);
+ output[1] = PLUS(x1, j1);
+ output[2] = PLUS(x2, j2);
+ output[3] = PLUS(x3, j3);
+ output[4] = PLUS(x4, j4);
+ output[5] = PLUS(x5, j5);
+ output[6] = PLUS(x6, j6);
+ output[7] = PLUS(x7, j7);
+ output[8] = PLUS(x8, j8_1);
+ output[9] = PLUS(x9, j9);
+ output[10] = PLUS(x10,j10);
+ output[11] = PLUS(x11,j11);
+ output[12] = PLUS(x12,j12);
+ output[13] = PLUS(x13,j13);
+ output[14] = PLUS(x14,j14);
+ output[15] = PLUS(x15,j15);
+
+ output += (SALSA20_GROUP_SIZE * 64) / sizeof(uint32_t);
+ }
+
+ barrier(CLK_GLOBAL_MEM_FENCE);
+
+ // Put zeroes after output's end
+ if (t < 16)
+ {
+ __global uint32_t* p = outputs + (output_offset + output_size + 3) / sizeof(uint32_t);
+ p[t] = 0;
+ }
+
+ if ((t == 0) && (output_size & 3))
+ outputs[(output_offset + output_size) / sizeof(uint32_t)] &= 0xFFFFFFFFU >> ((4 - (output_size & 3)) << 3);
+}
+
+#undef ROTATE
+#undef XOR
+#undef PLUS
diff --git a/src/backend/opencl/cl/astrobwt_v2/sha3.cl b/src/backend/opencl/cl/astrobwt_v2/sha3.cl
new file mode 100644
index 0000000000..ddd32a7c51
--- /dev/null
+++ b/src/backend/opencl/cl/astrobwt_v2/sha3.cl
@@ -0,0 +1,188 @@
+/* XMRig
+ * Copyright 2010 Jeff Garzik
+ * Copyright 2012-2014 pooler
+ * Copyright 2014 Lucas Jones
+ * Copyright 2014-2016 Wolf9466
+ * Copyright 2016 Jay D Dee
+ * Copyright 2017-2018 XMR-Stak ,
+ * Copyright 2018-2022 SChernykh
+ * Copyright 2016-2022 XMRig ,
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#define ROUNDS 24
+
+__constant const uint64_t rc[24] = {
+ 0x0000000000000001UL, 0x0000000000008082UL, 0x800000000000808AUL,
+ 0x8000000080008000UL, 0x000000000000808BUL, 0x0000000080000001UL,
+ 0x8000000080008081UL, 0x8000000000008009UL, 0x000000000000008AUL,
+ 0x0000000000000088UL, 0x0000000080008009UL, 0x000000008000000AUL,
+ 0x000000008000808BUL, 0x800000000000008BUL, 0x8000000000008089UL,
+ 0x8000000000008003UL, 0x8000000000008002UL, 0x8000000000000080UL,
+ 0x000000000000800AUL, 0x800000008000000AUL, 0x8000000080008081UL,
+ 0x8000000000008080UL, 0x0000000080000001UL, 0x8000000080008008UL
+};
+
+__constant const int c[25][2] = {
+ { 1, 2}, { 2, 3}, { 3, 4}, { 4, 0}, { 0, 1},
+ { 6, 7}, { 7, 8}, { 8, 9}, { 9, 5}, { 5, 6},
+ {11,12}, {12,13}, {13,14}, {14,10}, {10,11},
+ {16,17}, {17,18}, {18,19}, {19,15}, {15,16},
+ {21,22}, {22,23}, {23,24}, {24,20}, {20,21}
+};
+
+__constant const int ppi[25][2] = {
+ {0, 0}, {6, 44}, {12, 43}, {18, 21}, {24, 14}, {3, 28}, {9, 20}, {10, 3}, {16, 45},
+ {22, 61}, {1, 1}, {7, 6}, {13, 25}, {19, 8}, {20, 18}, {4, 27}, {5, 36}, {11, 10},
+ {17, 15}, {23, 56}, {2, 62}, {8, 55}, {14, 39}, {15, 41}, {21, 2}
+};
+
+#define R64(a,b,c) (((a) << b) | ((a) >> c))
+
+#define ROUND(k) \
+do { \
+ C[t] = A[s] ^ A[s + 5] ^ A[s + 10] ^ A[s + 15] ^ A[s + 20]; \
+ A[t] ^= C[s + 4] ^ R64(C[s + 1], 1, 63); \
+ C[t] = R64(A[at], ro0, ro1); \
+ A[t] = (C[t] ^ ((~C[c1]) & C[c2])) ^ (k1 & (k)); \
+} while (0)
+
+__attribute__((reqd_work_group_size(32, 1, 1)))
+__kernel void sha3(__global const uint8_t* inputs, __global uint64_t* hashes)
+{
+ const uint32_t t = get_local_id(0);
+
+ if (t >= 25) {
+ return;
+ }
+
+ const uint32_t g = get_group_id(0);
+ const uint64_t input_offset = 10240 * 2 * g;
+ __global const uint64_t* input = (__global const uint64_t*)(inputs + input_offset);
+
+ __local uint64_t A[25];
+ __local uint64_t C[25];
+
+ A[t] = 0;
+
+ const uint32_t s = t % 5;
+ const int at = ppi[t][0];
+ const int ro0 = ppi[t][1];
+ const int ro1 = 64 - ro0;
+ const int c1 = c[t][0];
+ const int c2 = c[t][1];
+ const uint64_t k1 = (t == 0) ? 0xFFFFFFFFFFFFFFFFUL : 0UL;
+
+ const uint32_t input_size = 9973 * 2;
+ const uint32_t input_words = input_size / sizeof(uint64_t);
+ __global const uint64_t* const input_end17 = input + ((input_words / 17) * 17);
+ __global const uint64_t* const input_end = input + input_words;
+
+ for (; input < input_end17; input += 17) {
+ if (t < 17) A[t] ^= input[t];
+
+ ROUND(0x0000000000000001UL); ROUND(0x0000000000008082UL); ROUND(0x800000000000808AUL);
+ ROUND(0x8000000080008000UL); ROUND(0x000000000000808BUL); ROUND(0x0000000080000001UL);
+ ROUND(0x8000000080008081UL); ROUND(0x8000000000008009UL); ROUND(0x000000000000008AUL);
+ ROUND(0x0000000000000088UL); ROUND(0x0000000080008009UL); ROUND(0x000000008000000AUL);
+ ROUND(0x000000008000808BUL); ROUND(0x800000000000008BUL); ROUND(0x8000000000008089UL);
+ ROUND(0x8000000000008003UL); ROUND(0x8000000000008002UL); ROUND(0x8000000000000080UL);
+ ROUND(0x000000000000800AUL); ROUND(0x800000008000000AUL); ROUND(0x8000000080008081UL);
+ ROUND(0x8000000000008080UL); ROUND(0x0000000080000001UL); ROUND(0x8000000080008008UL);
+ }
+
+ const uint32_t wordIndex = input_end - input;
+ if (t < wordIndex) A[t] ^= input[t];
+
+ if (t == 0) {
+ uint64_t tail = 0;
+ __global const uint8_t* p = (__global const uint8_t*)input_end;
+ const uint32_t tail_size = input_size % sizeof(uint64_t);
+ for (uint32_t i = 0; i < tail_size; ++i) {
+ tail |= (uint64_t)(p[i]) << (i * 8);
+ }
+
+ A[wordIndex] ^= tail ^ ((uint64_t)(((uint64_t)(0x02 | (1 << 2))) << (tail_size * 8)));
+ A[16] ^= 0x8000000000000000UL;
+ }
+
+ barrier(CLK_LOCAL_MEM_FENCE);
+
+ #pragma unroll 1
+ for (int i = 0; i < ROUNDS; ++i) {
+ C[t] = A[s] ^ A[s + 5] ^ A[s + 10] ^ A[s + 15] ^ A[s + 20];
+ A[t] ^= C[s + 4] ^ R64(C[s + 1], 1, 63);
+ C[t] = R64(A[at], ro0, ro1);
+ A[t] = (C[t] ^ ((~C[c1]) & C[c2])) ^ (rc[i] & k1);
+ }
+
+ if (t < 4) {
+ hashes[g * 4 + t] = A[t];
+ }
+}
+
+__attribute__((reqd_work_group_size(32, 1, 1)))
+__kernel void sha3_initial(__global const uint8_t* input_data, uint32_t input_size, uint32_t nonce, __global uint64_t* hashes)
+{
+ const uint32_t t = get_local_id(0);
+ const uint32_t g = get_group_id(0);
+
+ if (t >= 25) {
+ return;
+ }
+
+ __global const uint64_t* input = (__global const uint64_t*)(input_data);
+
+ __local uint64_t A[25];
+ __local uint64_t C[25];
+
+ const uint32_t input_words = input_size / sizeof(uint64_t);
+ A[t] = (t < input_words) ? input[t] : 0;
+
+ if (t == 0) {
+ ((__local uint32_t*)A)[11] = nonce + g;
+
+ const uint32_t tail_size = input_size % sizeof(uint64_t);
+ A[input_words] ^= (uint64_t)(((uint64_t)(0x02 | (1 << 2))) << (tail_size * 8));
+ A[16] ^= 0x8000000000000000UL;
+ }
+
+ barrier(CLK_LOCAL_MEM_FENCE);
+
+ const uint32_t s = t % 5;
+ const int at = ppi[t][0];
+ const int ro0 = ppi[t][1];
+ const int ro1 = 64 - ro0;
+ const int c1 = c[t][0];
+ const int c2 = c[t][1];
+ const uint64_t k1 = (t == 0) ? (uint64_t)(-1) : 0;
+
+ ROUND(0x0000000000000001UL); ROUND(0x0000000000008082UL); ROUND(0x800000000000808AUL);
+ ROUND(0x8000000080008000UL); ROUND(0x000000000000808BUL); ROUND(0x0000000080000001UL);
+ ROUND(0x8000000080008081UL); ROUND(0x8000000000008009UL); ROUND(0x000000000000008AUL);
+ ROUND(0x0000000000000088UL); ROUND(0x0000000080008009UL); ROUND(0x000000008000000AUL);
+ ROUND(0x000000008000808BUL); ROUND(0x800000000000008BUL); ROUND(0x8000000000008089UL);
+ ROUND(0x8000000000008003UL); ROUND(0x8000000000008002UL); ROUND(0x8000000000000080UL);
+ ROUND(0x000000000000800AUL); ROUND(0x800000008000000AUL); ROUND(0x8000000080008081UL);
+ ROUND(0x8000000000008080UL); ROUND(0x0000000080000001UL); ROUND(0x8000000080008008UL);
+
+ if (t < 4) {
+ hashes[g * 4 + t] = A[t];
+ }
+}
+
+#undef ROUNDS
+#undef R64
+#undef ROUND
diff --git a/src/backend/opencl/generators/ocl_generic_astrobwt_generator.cpp b/src/backend/opencl/generators/ocl_generic_astrobwt_generator.cpp
index 95dffd5b83..fdc0518074 100644
--- a/src/backend/opencl/generators/ocl_generic_astrobwt_generator.cpp
+++ b/src/backend/opencl/generators/ocl_generic_astrobwt_generator.cpp
@@ -40,6 +40,15 @@ bool ocl_generic_astrobwt_generator(const OclDevice &device, const Algorithm &al
return false;
}
+ if (algorithm.id() == Algorithm::ASTROBWT_DERO_2) {
+ uint32_t intensity = device.computeUnits() * 128;
+ if (!intensity || (intensity > 4096)) {
+ intensity = 4096;
+ }
+ threads.add(OclThread(device.index(), intensity, 1));
+ return true;
+ }
+
const size_t mem = device.globalMemSize();
uint32_t per_thread_mem = 10 << 20;
diff --git a/src/backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_BWT_FixOrderKernel.cpp b/src/backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_BWT_FixOrderKernel.cpp
new file mode 100644
index 0000000000..5cc812f8bf
--- /dev/null
+++ b/src/backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_BWT_FixOrderKernel.cpp
@@ -0,0 +1,42 @@
+/* XMRig
+ * Copyright 2010 Jeff Garzik
+ * Copyright 2012-2014 pooler
+ * Copyright 2014 Lucas Jones
+ * Copyright 2014-2016 Wolf9466
+ * Copyright 2016 Jay D Dee
+ * Copyright 2017-2018 XMR-Stak ,
+ * Copyright 2018-2020 SChernykh
+ * Copyright 2016-2020 XMRig ,
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+
+#include "backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_BWT_FixOrderKernel.h"
+#include "backend/opencl/wrappers/OclLib.h"
+
+
+void xmrig::AstroBWT_v2_BWT_FixOrderKernel::enqueue(cl_command_queue queue, size_t threads, size_t workgroup_size)
+{
+ const size_t gthreads = threads * workgroup_size;
+ enqueueNDRange(queue, 1, nullptr, >hreads, &workgroup_size);
+}
+
+
+void xmrig::AstroBWT_v2_BWT_FixOrderKernel::setArgs(cl_mem datas, cl_mem keys, cl_mem temp_storage)
+{
+ setArg(0, sizeof(cl_mem), &datas);
+ setArg(1, sizeof(cl_mem), &keys);
+ setArg(2, sizeof(cl_mem), &temp_storage);
+}
diff --git a/src/backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_BWT_FixOrderKernel.h b/src/backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_BWT_FixOrderKernel.h
new file mode 100644
index 0000000000..7859e666f3
--- /dev/null
+++ b/src/backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_BWT_FixOrderKernel.h
@@ -0,0 +1,44 @@
+/* XMRig
+ * Copyright 2010 Jeff Garzik
+ * Copyright 2012-2014 pooler
+ * Copyright 2014 Lucas Jones
+ * Copyright 2014-2016 Wolf9466
+ * Copyright 2016 Jay D Dee
+ * Copyright 2017-2018 XMR-Stak ,
+ * Copyright 2018-2020 SChernykh
+ * Copyright 2016-2020 XMRig ,
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#pragma once
+
+
+#include "backend/opencl/wrappers/OclKernel.h"
+
+
+namespace xmrig {
+
+
+class AstroBWT_v2_BWT_FixOrderKernel : public OclKernel
+{
+public:
+ inline AstroBWT_v2_BWT_FixOrderKernel(cl_program program) : OclKernel(program, "BWT_fix_order") {}
+
+ void enqueue(cl_command_queue queue, size_t threads, size_t workgroup_size);
+ void setArgs(cl_mem datas, cl_mem keys, cl_mem temp_storage);
+};
+
+
+} // namespace xmrig
diff --git a/src/backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_BWT_PreprocessKernel.cpp b/src/backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_BWT_PreprocessKernel.cpp
new file mode 100644
index 0000000000..aade283167
--- /dev/null
+++ b/src/backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_BWT_PreprocessKernel.cpp
@@ -0,0 +1,41 @@
+/* XMRig
+ * Copyright 2010 Jeff Garzik
+ * Copyright 2012-2014 pooler
+ * Copyright 2014 Lucas Jones
+ * Copyright 2014-2016 Wolf9466
+ * Copyright 2016 Jay D Dee
+ * Copyright 2017-2018 XMR-Stak ,
+ * Copyright 2018-2020 SChernykh
+ * Copyright 2016-2020 XMRig ,
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+
+#include "backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_BWT_PreprocessKernel.h"
+#include "backend/opencl/wrappers/OclLib.h"
+
+
+void xmrig::AstroBWT_v2_BWT_PreprocessKernel::enqueue(cl_command_queue queue, size_t threads, size_t workgroup_size)
+{
+ const size_t gthreads = threads * workgroup_size;
+ enqueueNDRange(queue, 1, nullptr, >hreads, &workgroup_size);
+}
+
+
+void xmrig::AstroBWT_v2_BWT_PreprocessKernel::setArgs(cl_mem datas, cl_mem keys)
+{
+ setArg(0, sizeof(cl_mem), &datas);
+ setArg(1, sizeof(cl_mem), &keys);
+}
diff --git a/src/backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_BWT_PreprocessKernel.h b/src/backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_BWT_PreprocessKernel.h
new file mode 100644
index 0000000000..dc41fce072
--- /dev/null
+++ b/src/backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_BWT_PreprocessKernel.h
@@ -0,0 +1,44 @@
+/* XMRig
+ * Copyright 2010 Jeff Garzik
+ * Copyright 2012-2014 pooler
+ * Copyright 2014 Lucas Jones
+ * Copyright 2014-2016 Wolf9466
+ * Copyright 2016 Jay D Dee
+ * Copyright 2017-2018 XMR-Stak ,
+ * Copyright 2018-2020 SChernykh
+ * Copyright 2016-2020 XMRig ,
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#pragma once
+
+
+#include "backend/opencl/wrappers/OclKernel.h"
+
+
+namespace xmrig {
+
+
+class AstroBWT_v2_BWT_PreprocessKernel : public OclKernel
+{
+public:
+ inline AstroBWT_v2_BWT_PreprocessKernel(cl_program program) : OclKernel(program, "BWT_preprocess") {}
+
+ void enqueue(cl_command_queue queue, size_t threads, size_t workgroup_size);
+ void setArgs(cl_mem datas, cl_mem keys);
+};
+
+
+} // namespace xmrig
diff --git a/src/backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_FindSharesKernel.cpp b/src/backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_FindSharesKernel.cpp
new file mode 100644
index 0000000000..8ca0185a08
--- /dev/null
+++ b/src/backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_FindSharesKernel.cpp
@@ -0,0 +1,46 @@
+/* XMRig
+ * Copyright 2010 Jeff Garzik
+ * Copyright 2012-2014 pooler
+ * Copyright 2014 Lucas Jones
+ * Copyright 2014-2016 Wolf9466
+ * Copyright 2016 Jay D Dee
+ * Copyright 2017-2018 XMR-Stak ,
+ * Copyright 2018-2019 SChernykh
+ * Copyright 2016-2019 XMRig ,
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+
+#include "backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_FindSharesKernel.h"
+#include "backend/opencl/wrappers/OclLib.h"
+
+
+void xmrig::AstroBWT_v2_FindSharesKernel::enqueue(cl_command_queue queue, size_t threads, size_t workgroup_size)
+{
+ enqueueNDRange(queue, 1, nullptr, &threads, &workgroup_size);
+}
+
+
+void xmrig::AstroBWT_v2_FindSharesKernel::setArgs(cl_mem hashes, cl_mem shares)
+{
+ setArg(0, sizeof(cl_mem), &hashes);
+ setArg(2, sizeof(cl_mem), &shares);
+}
+
+
+void xmrig::AstroBWT_v2_FindSharesKernel::setTarget(uint64_t target)
+{
+ setArg(1, sizeof(uint64_t), &target);
+}
diff --git a/src/backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_FindSharesKernel.h b/src/backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_FindSharesKernel.h
new file mode 100644
index 0000000000..4b585216e6
--- /dev/null
+++ b/src/backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_FindSharesKernel.h
@@ -0,0 +1,45 @@
+/* XMRig
+ * Copyright 2010 Jeff Garzik
+ * Copyright 2012-2014 pooler
+ * Copyright 2014 Lucas Jones
+ * Copyright 2014-2016 Wolf9466
+ * Copyright 2016 Jay D Dee
+ * Copyright 2017-2018 XMR-Stak ,
+ * Copyright 2018-2019 SChernykh
+ * Copyright 2016-2019 XMRig ,
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#pragma once
+
+
+#include "backend/opencl/wrappers/OclKernel.h"
+
+
+namespace xmrig {
+
+
+class AstroBWT_v2_FindSharesKernel : public OclKernel
+{
+public:
+ inline AstroBWT_v2_FindSharesKernel(cl_program program) : OclKernel(program, "find_shares") {}
+
+ void enqueue(cl_command_queue queue, size_t threads, size_t workgroup_size);
+ void setArgs(cl_mem hashes, cl_mem shares);
+ void setTarget(uint64_t target);
+};
+
+
+} // namespace xmrig
diff --git a/src/backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_SHA3InitialKernel.cpp b/src/backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_SHA3InitialKernel.cpp
new file mode 100644
index 0000000000..5ba0e27523
--- /dev/null
+++ b/src/backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_SHA3InitialKernel.cpp
@@ -0,0 +1,44 @@
+/* XMRig
+ * Copyright 2010 Jeff Garzik
+ * Copyright 2012-2014 pooler
+ * Copyright 2014 Lucas Jones
+ * Copyright 2014-2016 Wolf9466
+ * Copyright 2016 Jay D Dee
+ * Copyright 2017-2018 XMR-Stak ,
+ * Copyright 2018-2020 SChernykh
+ * Copyright 2016-2020 XMRig ,
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+
+#include "backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_SHA3InitialKernel.h"
+#include "backend/opencl/wrappers/OclLib.h"
+
+
+void xmrig::AstroBWT_v2_SHA3InitialKernel::enqueue(cl_command_queue queue, size_t threads)
+{
+ const size_t workgroup_size = 32;
+ const size_t gthreads = threads * workgroup_size;
+ enqueueNDRange(queue, 1, nullptr, >hreads, &workgroup_size);
+}
+
+
+void xmrig::AstroBWT_v2_SHA3InitialKernel::setArgs(cl_mem input, uint32_t input_size, uint32_t nonce, cl_mem output_salsa20_keys)
+{
+ setArg(0, sizeof(cl_mem), &input);
+ setArg(1, sizeof(uint32_t), &input_size);
+ setArg(2, sizeof(uint32_t), &nonce);
+ setArg(3, sizeof(cl_mem), &output_salsa20_keys);
+}
diff --git a/src/backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_SHA3InitialKernel.h b/src/backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_SHA3InitialKernel.h
new file mode 100644
index 0000000000..1e7d142331
--- /dev/null
+++ b/src/backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_SHA3InitialKernel.h
@@ -0,0 +1,44 @@
+/* XMRig
+ * Copyright 2010 Jeff Garzik
+ * Copyright 2012-2014 pooler
+ * Copyright 2014 Lucas Jones
+ * Copyright 2014-2016 Wolf9466
+ * Copyright 2016 Jay D Dee
+ * Copyright 2017-2018 XMR-Stak ,
+ * Copyright 2018-2020 SChernykh
+ * Copyright 2016-2020 XMRig ,
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#pragma once
+
+
+#include "backend/opencl/wrappers/OclKernel.h"
+
+
+namespace xmrig {
+
+
+class AstroBWT_v2_SHA3InitialKernel : public OclKernel
+{
+public:
+ inline AstroBWT_v2_SHA3InitialKernel(cl_program program) : OclKernel(program, "sha3_initial") {}
+
+ void enqueue(cl_command_queue queue, size_t threads);
+ void setArgs(cl_mem input, uint32_t input_size, uint32_t nonce, cl_mem output_salsa20_keys);
+};
+
+
+} // namespace xmrig
diff --git a/src/backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_SHA3Kernel.cpp b/src/backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_SHA3Kernel.cpp
new file mode 100644
index 0000000000..346e0dc167
--- /dev/null
+++ b/src/backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_SHA3Kernel.cpp
@@ -0,0 +1,42 @@
+/* XMRig
+ * Copyright 2010 Jeff Garzik
+ * Copyright 2012-2014 pooler
+ * Copyright 2014 Lucas Jones
+ * Copyright 2014-2016 Wolf9466
+ * Copyright 2016 Jay D Dee
+ * Copyright 2017-2018 XMR-Stak ,
+ * Copyright 2018-2020 SChernykh
+ * Copyright 2016-2020 XMRig ,
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+
+#include "backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_SHA3Kernel.h"
+#include "backend/opencl/wrappers/OclLib.h"
+
+
+void xmrig::AstroBWT_v2_SHA3Kernel::enqueue(cl_command_queue queue, size_t threads)
+{
+ const size_t workgroup_size = 32;
+ const size_t gthreads = threads * workgroup_size;
+ enqueueNDRange(queue, 1, nullptr, >hreads, &workgroup_size);
+}
+
+
+void xmrig::AstroBWT_v2_SHA3Kernel::setArgs(cl_mem temp_storage, cl_mem hashes)
+{
+ setArg(0, sizeof(cl_mem), &temp_storage);
+ setArg(1, sizeof(cl_mem), &hashes);
+}
diff --git a/src/backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_SHA3Kernel.h b/src/backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_SHA3Kernel.h
new file mode 100644
index 0000000000..622abcccde
--- /dev/null
+++ b/src/backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_SHA3Kernel.h
@@ -0,0 +1,44 @@
+/* XMRig
+ * Copyright 2010 Jeff Garzik
+ * Copyright 2012-2014 pooler
+ * Copyright 2014 Lucas Jones
+ * Copyright 2014-2016 Wolf9466
+ * Copyright 2016 Jay D Dee
+ * Copyright 2017-2018 XMR-Stak ,
+ * Copyright 2018-2020 SChernykh
+ * Copyright 2016-2020 XMRig ,
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#pragma once
+
+
+#include "backend/opencl/wrappers/OclKernel.h"
+
+
+namespace xmrig {
+
+
+class AstroBWT_v2_SHA3Kernel : public OclKernel
+{
+public:
+ inline AstroBWT_v2_SHA3Kernel(cl_program program) : OclKernel(program, "sha3") {}
+
+ void enqueue(cl_command_queue queue, size_t threads);
+ void setArgs(cl_mem temp_storage, cl_mem hashes);
+};
+
+
+} // namespace xmrig
diff --git a/src/backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_Salsa20Kernel.cpp b/src/backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_Salsa20Kernel.cpp
new file mode 100644
index 0000000000..902f818cc4
--- /dev/null
+++ b/src/backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_Salsa20Kernel.cpp
@@ -0,0 +1,41 @@
+/* XMRig
+ * Copyright 2010 Jeff Garzik
+ * Copyright 2012-2014 pooler
+ * Copyright 2014 Lucas Jones
+ * Copyright 2014-2016 Wolf9466
+ * Copyright 2016 Jay D Dee
+ * Copyright 2017-2018 XMR-Stak ,
+ * Copyright 2018-2020 SChernykh
+ * Copyright 2016-2020 XMRig ,
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+
+#include "backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_Salsa20Kernel.h"
+#include "backend/opencl/wrappers/OclLib.h"
+
+
+void xmrig::AstroBWT_v2_Salsa20Kernel::enqueue(cl_command_queue queue, size_t threads, size_t workgroup_size)
+{
+ const size_t gthreads = threads * workgroup_size;
+ enqueueNDRange(queue, 1, nullptr, >hreads, &workgroup_size);
+}
+
+
+void xmrig::AstroBWT_v2_Salsa20Kernel::setArgs(cl_mem salsa20_keys, cl_mem outputs)
+{
+ setArg(0, sizeof(cl_mem), &salsa20_keys);
+ setArg(1, sizeof(cl_mem), &outputs);
+}
diff --git a/src/backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_Salsa20Kernel.h b/src/backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_Salsa20Kernel.h
new file mode 100644
index 0000000000..85fa522298
--- /dev/null
+++ b/src/backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_Salsa20Kernel.h
@@ -0,0 +1,44 @@
+/* XMRig
+ * Copyright 2010 Jeff Garzik
+ * Copyright 2012-2014 pooler
+ * Copyright 2014 Lucas Jones
+ * Copyright 2014-2016 Wolf9466
+ * Copyright 2016 Jay D Dee
+ * Copyright 2017-2018 XMR-Stak ,
+ * Copyright 2018-2020 SChernykh
+ * Copyright 2016-2020 XMRig ,
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#pragma once
+
+
+#include "backend/opencl/wrappers/OclKernel.h"
+
+
+namespace xmrig {
+
+
+class AstroBWT_v2_Salsa20Kernel : public OclKernel
+{
+public:
+ inline AstroBWT_v2_Salsa20Kernel(cl_program program) : OclKernel(program, "Salsa20_XORKeyStream") {}
+
+ void enqueue(cl_command_queue queue, size_t threads, size_t workgroup_size);
+ void setArgs(cl_mem salsa20_keys, cl_mem outputs);
+};
+
+
+} // namespace xmrig
diff --git a/src/backend/opencl/opencl.cmake b/src/backend/opencl/opencl.cmake
index 49134df78f..e9e69e8cce 100644
--- a/src/backend/opencl/opencl.cmake
+++ b/src/backend/opencl/opencl.cmake
@@ -119,7 +119,14 @@ if (WITH_OPENCL)
src/backend/opencl/kernels/astrobwt/AstroBWT_Salsa20Kernel.h
src/backend/opencl/kernels/astrobwt/AstroBWT_SHA3InitialKernel.h
src/backend/opencl/kernels/astrobwt/AstroBWT_SHA3Kernel.h
+ src/backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_BWT_FixOrderKernel.h
+ src/backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_BWT_PreprocessKernel.h
+ src/backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_FindSharesKernel.h
+ src/backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_Salsa20Kernel.h
+ src/backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_SHA3InitialKernel.h
+ src/backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_SHA3Kernel.h
src/backend/opencl/runners/OclAstroBWTRunner.h
+ src/backend/opencl/runners/OclAstroBWT_v2_Runner.h
)
list(APPEND SOURCES_BACKEND_OPENCL
@@ -131,7 +138,14 @@ if (WITH_OPENCL)
src/backend/opencl/kernels/astrobwt/AstroBWT_Salsa20Kernel.cpp
src/backend/opencl/kernels/astrobwt/AstroBWT_SHA3InitialKernel.cpp
src/backend/opencl/kernels/astrobwt/AstroBWT_SHA3Kernel.cpp
+ src/backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_BWT_FixOrderKernel.cpp
+ src/backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_BWT_PreprocessKernel.cpp
+ src/backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_FindSharesKernel.cpp
+ src/backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_Salsa20Kernel.cpp
+ src/backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_SHA3InitialKernel.cpp
+ src/backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_SHA3Kernel.cpp
src/backend/opencl/runners/OclAstroBWTRunner.cpp
+ src/backend/opencl/runners/OclAstroBWT_v2_Runner.cpp
)
endif()
diff --git a/src/backend/opencl/runners/OclAstroBWT_v2_Runner.cpp b/src/backend/opencl/runners/OclAstroBWT_v2_Runner.cpp
new file mode 100644
index 0000000000..f369d0d723
--- /dev/null
+++ b/src/backend/opencl/runners/OclAstroBWT_v2_Runner.cpp
@@ -0,0 +1,155 @@
+/* XMRig
+ * Copyright (c) 2018-2021 SChernykh
+ * Copyright (c) 2016-2021 XMRig ,
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "backend/opencl/runners/OclAstroBWT_v2_Runner.h"
+#include "backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_FindSharesKernel.h"
+#include "backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_BWT_FixOrderKernel.h"
+#include "backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_BWT_PreprocessKernel.h"
+#include "backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_Salsa20Kernel.h"
+#include "backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_SHA3InitialKernel.h"
+#include "backend/opencl/kernels/astrobwt_v2/AstroBWT_v2_SHA3Kernel.h"
+#include "backend/opencl/OclLaunchData.h"
+#include "backend/opencl/wrappers/OclLib.h"
+#include "base/io/log/Log.h"
+#include "base/net/stratum/Job.h"
+
+
+xmrig::OclAstroBWT_v2_Runner::OclAstroBWT_v2_Runner(size_t index, const OclLaunchData &data) : OclBaseRunner(index, data)
+{
+ switch (data.device.type())
+ {
+ case OclDevice::Baffin:
+ case OclDevice::Ellesmere:
+ case OclDevice::Polaris:
+ case OclDevice::Lexa:
+ case OclDevice::Vega_10:
+ case OclDevice::Vega_20:
+ case OclDevice::Raven:
+ m_workgroup_size = 64;
+ break;
+
+ default:
+ m_workgroup_size = 32;
+ break;
+ }
+
+ m_options += " -DSALSA20_GROUP_SIZE=" + std::to_string(m_workgroup_size);
+ m_bwt_allocation_size = m_intensity * BWT_DATA_STRIDE;
+}
+
+
+xmrig::OclAstroBWT_v2_Runner::~OclAstroBWT_v2_Runner()
+{
+ delete m_find_shares_kernel;
+ delete m_bwt_fix_order_kernel;
+ delete m_bwt_preprocess_kernel;
+ delete m_salsa20_kernel;
+ delete m_sha3_initial_kernel;
+ delete m_sha3_kernel;
+
+ OclLib::release(m_input);
+ OclLib::release(m_hashes);
+ OclLib::release(m_data);
+ OclLib::release(m_keys);
+ OclLib::release(m_temp_storage);
+}
+
+
+size_t xmrig::OclAstroBWT_v2_Runner::bufferSize() const
+{
+ return OclBaseRunner::bufferSize() +
+ align(m_intensity * 32) + // m_hashes
+ align(m_bwt_allocation_size) + // m_data
+ align(m_bwt_allocation_size * 4) + // m_keys
+ align(m_bwt_allocation_size * 2); // m_temp_storage
+}
+
+
+void xmrig::OclAstroBWT_v2_Runner::run(uint32_t nonce, uint32_t *hashOutput)
+{
+ const uint32_t zero = 0;
+ enqueueWriteBuffer(m_output, CL_FALSE, sizeof(cl_uint) * 0xFF, sizeof(uint32_t), &zero);
+
+ m_sha3_initial_kernel->setArg(2, sizeof(nonce), &nonce);
+ m_sha3_initial_kernel->enqueue(m_queue, m_intensity);
+
+ m_salsa20_kernel->enqueue(m_queue, m_intensity, m_workgroup_size);
+
+ m_bwt_preprocess_kernel->enqueue(m_queue, m_intensity, 1024);
+ m_bwt_fix_order_kernel->enqueue(m_queue, m_intensity, 1024);
+
+ m_sha3_kernel->enqueue(m_queue, m_intensity);
+
+ m_find_shares_kernel->enqueue(m_queue, m_intensity, m_workgroup_size);
+
+ finalize(hashOutput);
+
+ OclLib::finish(m_queue);
+
+ for (uint32_t i = 0; i < hashOutput[0xFF]; ++i) {
+ hashOutput[i] += nonce;
+ }
+}
+
+
+void xmrig::OclAstroBWT_v2_Runner::set(const Job &job, uint8_t *blob)
+{
+ if (job.size() > (Job::kMaxBlobSize - 4)) {
+ throw std::length_error("job size too big");
+ }
+
+ if (job.size() < Job::kMaxBlobSize) {
+ memset(blob + job.size(), 0, Job::kMaxBlobSize - job.size());
+ }
+
+ enqueueWriteBuffer(m_input, CL_TRUE, 0, Job::kMaxBlobSize, blob);
+
+ m_sha3_initial_kernel->setArgs(m_input, static_cast(job.size()), *job.nonce(), m_hashes);
+ m_salsa20_kernel->setArgs(m_hashes, m_data);
+ m_bwt_preprocess_kernel->setArgs(m_data, m_keys);
+ m_bwt_fix_order_kernel->setArgs(m_data, m_keys, m_temp_storage);
+ m_sha3_kernel->setArgs(m_temp_storage, m_hashes);
+ m_find_shares_kernel->setArgs(m_hashes, m_output);
+ m_find_shares_kernel->setTarget(job.target());
+}
+
+
+void xmrig::OclAstroBWT_v2_Runner::build()
+{
+ OclBaseRunner::build();
+
+ m_find_shares_kernel = new AstroBWT_v2_FindSharesKernel(m_program);
+ m_bwt_fix_order_kernel = new AstroBWT_v2_BWT_FixOrderKernel(m_program);
+ m_bwt_preprocess_kernel = new AstroBWT_v2_BWT_PreprocessKernel(m_program);
+ m_salsa20_kernel = new AstroBWT_v2_Salsa20Kernel(m_program);
+ m_sha3_initial_kernel = new AstroBWT_v2_SHA3InitialKernel(m_program);
+ m_sha3_kernel = new AstroBWT_v2_SHA3Kernel(m_program);
+}
+
+
+void xmrig::OclAstroBWT_v2_Runner::init()
+{
+ OclBaseRunner::init();
+
+ const cl_mem_flags f = CL_MEM_READ_WRITE | CL_MEM_HOST_NO_ACCESS;
+
+ m_hashes = createSubBuffer(f, m_intensity * 32);
+ m_data = createSubBuffer(f, m_bwt_allocation_size);
+ m_keys = createSubBuffer(f, m_bwt_allocation_size * 4);
+ m_temp_storage = createSubBuffer(f, m_bwt_allocation_size * 2);
+}
diff --git a/src/backend/opencl/runners/OclAstroBWT_v2_Runner.h b/src/backend/opencl/runners/OclAstroBWT_v2_Runner.h
new file mode 100644
index 0000000000..722a0545a8
--- /dev/null
+++ b/src/backend/opencl/runners/OclAstroBWT_v2_Runner.h
@@ -0,0 +1,78 @@
+/* XMRig
+ * Copyright (c) 2018-2021 SChernykh
+ * Copyright (c) 2016-2021 XMRig ,
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#ifndef XMRIG_OclAstroBWT_v2_Runner_H
+#define XMRIG_OclAstroBWT_v2_Runner_H
+
+
+#include "backend/opencl/runners/OclBaseRunner.h"
+
+namespace xmrig {
+
+
+class AstroBWT_v2_FindSharesKernel;
+class AstroBWT_v2_BWT_FixOrderKernel;
+class AstroBWT_v2_BWT_PreprocessKernel;
+class AstroBWT_v2_Salsa20Kernel;
+class AstroBWT_v2_SHA3InitialKernel;
+class AstroBWT_v2_SHA3Kernel;
+
+
+class OclAstroBWT_v2_Runner : public OclBaseRunner
+{
+public:
+ static constexpr uint32_t BWT_DATA_SIZE = 9973;
+ static constexpr uint32_t BWT_DATA_STRIDE = 10240;
+
+ XMRIG_DISABLE_COPY_MOVE_DEFAULT(OclAstroBWT_v2_Runner)
+
+ OclAstroBWT_v2_Runner(size_t index, const OclLaunchData &data);
+ ~OclAstroBWT_v2_Runner() override;
+
+ inline uint32_t roundSize() const override { return m_intensity; }
+ inline uint32_t processedHashes() const override { return m_intensity; }
+
+protected:
+ size_t bufferSize() const override;
+ void run(uint32_t nonce, uint32_t *hashOutput) override;
+ void set(const Job &job, uint8_t *blob) override;
+ void build() override;
+ void init() override;
+
+private:
+ AstroBWT_v2_FindSharesKernel* m_find_shares_kernel = nullptr;
+ AstroBWT_v2_BWT_FixOrderKernel* m_bwt_fix_order_kernel = nullptr;
+ AstroBWT_v2_BWT_PreprocessKernel* m_bwt_preprocess_kernel = nullptr;
+ AstroBWT_v2_Salsa20Kernel* m_salsa20_kernel = nullptr;
+ AstroBWT_v2_SHA3InitialKernel* m_sha3_initial_kernel = nullptr;
+ AstroBWT_v2_SHA3Kernel* m_sha3_kernel = nullptr;
+
+ cl_mem m_hashes = nullptr;
+ cl_mem m_data = nullptr;
+ cl_mem m_keys = nullptr;
+ cl_mem m_temp_storage = nullptr;
+
+ uint32_t m_workgroup_size = 0;
+ uint32_t m_bwt_allocation_size = 0;
+};
+
+
+} /* namespace xmrig */
+
+
+#endif // XMRIG_OclAstroBWT_v2_Runner_H
diff --git a/src/base/crypto/Algorithm.cpp b/src/base/crypto/Algorithm.cpp
index 636a638cd4..6a20a5b513 100644
--- a/src/base/crypto/Algorithm.cpp
+++ b/src/base/crypto/Algorithm.cpp
@@ -94,6 +94,7 @@ const char *Algorithm::kAR2_WRKZ = "argon2/ninja";
#ifdef XMRIG_ALGO_ASTROBWT
const char *Algorithm::kASTROBWT = "astrobwt";
const char *Algorithm::kASTROBWT_DERO = "astrobwt";
+const char *Algorithm::kASTROBWT_DERO_2 = "astrobwt/v2";
#endif
#ifdef XMRIG_ALGO_KAWPOW
@@ -163,6 +164,7 @@ static const std::map kAlgorithmNames = {
# ifdef XMRIG_ALGO_ASTROBWT
ALGO_NAME(ASTROBWT_DERO),
+ ALGO_NAME(ASTROBWT_DERO_2),
# endif
# ifdef XMRIG_ALGO_KAWPOW
@@ -282,6 +284,9 @@ static const std::map kAlgorithmAlias
# ifdef XMRIG_ALGO_ASTROBWT
ALGO_ALIAS_AUTO(ASTROBWT_DERO), ALGO_ALIAS(ASTROBWT_DERO, "astrobwt/dero"),
+ ALGO_ALIAS_AUTO(ASTROBWT_DERO_2), ALGO_ALIAS(ASTROBWT_DERO_2, "astrobwt/v2"),
+ ALGO_ALIAS_AUTO(ASTROBWT_DERO_2), ALGO_ALIAS(ASTROBWT_DERO_2, "astrobwt/dero_he"),
+ ALGO_ALIAS_AUTO(ASTROBWT_DERO_2), ALGO_ALIAS(ASTROBWT_DERO_2, "astrobwt/derohe"),
# endif
# ifdef XMRIG_ALGO_KAWPOW
@@ -365,7 +370,7 @@ std::vector xmrig::Algorithm::all(const std::function
+#endif
+
+
#include
#include
+#include
namespace xmrig {
@@ -58,7 +64,9 @@ namespace xmrig {
Storage DaemonClient::m_storage;
-static const char* kBlocktemplateBlob = "blocktemplate_blob";
+static const char* kBlocktemplateBlob = "blocktemplate_blob";
+static const char* kBlockhashingBlob = "blockhashing_blob";
+static const char* kLastError = "lasterror";
static const char *kGetHeight = "/getheight";
static const char *kGetInfo = "/getinfo";
static const char *kHash = "hash";
@@ -73,6 +81,14 @@ static constexpr size_t kZMQGreetingSize1 = 11;
static const char kZMQHandshake[] = "\4\x19\5READY\xbSocket-Type\0\0\0\3SUB";
static const char kZMQSubscribe[] = "\0\x18\1json-minimal-chain_main";
+static const char kWSSLogin[] = "\
+GET /ws/%s HTTP/1.1\r\n\
+Host: %s\r\n\
+Upgrade: websocket\r\n\
+Connection: Upgrade\r\n\
+Sec-WebSocket-Key: %s\r\n\
+Sec-WebSocket-Version: 13\r\n\r\n";
+
} // namespace xmrig
@@ -89,11 +105,20 @@ xmrig::DaemonClient::~DaemonClient()
{
delete m_timer;
delete m_ZMQSocket;
+# ifdef XMRIG_FEATURE_TLS
+ delete m_wss.m_socket;
+# endif
}
void xmrig::DaemonClient::deleteLater()
{
+# ifdef XMRIG_FEATURE_TLS
+ if (m_pool.isWSS()) {
+ WSSClose(true);
+ }
+ else
+# endif
if (m_pool.zmq_port() >= 0) {
ZMQClose(true);
}
@@ -123,6 +148,12 @@ bool xmrig::DaemonClient::isTLS() const
}
+bool xmrig::DaemonClient::isWSS() const
+{
+ return m_pool.isWSS();
+}
+
+
int64_t xmrig::DaemonClient::submit(const JobResult &result)
{
if (result.jobId != m_currentJobId) {
@@ -151,6 +182,17 @@ int64_t xmrig::DaemonClient::submit(const JobResult &result)
Cvt::toHex(data + m_job.nonceOffset() * 2, 8, reinterpret_cast(&result.nonce), 4);
+# ifdef XMRIG_FEATURE_TLS
+ if (m_pool.isWSS() && (m_apiVersion == API_DERO) && (m_pool.algorithm().id() == Algorithm::ASTROBWT_DERO_2)) {
+ char buf[256];
+ const int n = snprintf(buf, sizeof(buf), "{\"jobid\":\"%s\",\"mbl_blob\":\"%s\"}", m_job.id().data(), data);
+ if (0 <= n && n < static_cast(sizeof(buf))) {
+ return WSSWrite(buf, n) ? 1 : -1;
+ }
+ return -1;
+ }
+# endif
+
if (m_blocktemplate.hasMinerSignature()) {
Cvt::toHex(data + sig_offset * 2, 128, result.minerSignature(), 64);
}
@@ -193,19 +235,24 @@ void xmrig::DaemonClient::connect()
setState(ConnectingState);
- if (!m_walletAddress.isValid()) {
- return connectError("Invalid wallet address.");
- }
-
if (!m_coin.isValid() && !m_pool.algorithm().isValid()) {
return connectError("Invalid algorithm.");
}
- if ((m_pool.algorithm() == Algorithm::ASTROBWT_DERO) || (m_coin == Coin::DERO)) {
+ if (!m_pool.algorithm().isValid()) {
+ m_pool.setAlgo(m_coin.algorithm());
+ }
+
+ const xmrig::Algorithm algo = m_pool.algorithm();
+ if ((algo == Algorithm::ASTROBWT_DERO) || (algo == Algorithm::ASTROBWT_DERO_2) || (m_coin == Coin::DERO) || (m_coin == Coin::DERO_HE)) {
m_apiVersion = API_DERO;
}
- if (m_pool.zmq_port() >= 0) {
+ if ((m_apiVersion == API_MONERO) && !m_walletAddress.isValid()) {
+ return connectError("Invalid wallet address.");
+ }
+
+ if ((m_pool.zmq_port() >= 0) || m_pool.isWSS()) {
m_dns = Dns::resolve(m_pool.host(), this);
}
else {
@@ -306,6 +353,9 @@ void xmrig::DaemonClient::onTimer(const Timer *)
connect();
}
else if (m_state == ConnectedState) {
+ if (m_pool.isWSS()) {
+ return;
+ }
if (m_apiVersion == API_DERO) {
rpcSend(JsonRequest::create(m_sequence, "get_info"));
}
@@ -330,26 +380,35 @@ void xmrig::DaemonClient::onResolved(const DnsRecords &records, int status, cons
}
- delete m_ZMQSocket;
-
-
const auto &record = records.get();
m_ip = record.ip();
auto req = new uv_connect_t;
req->data = m_storage.ptr(m_key);
- m_ZMQSocket = new uv_tcp_t;
- m_ZMQSocket->data = m_storage.ptr(m_key);
+ uv_tcp_t* s = new uv_tcp_t;
+ s->data = m_storage.ptr(m_key);
- uv_tcp_init(uv_default_loop(), m_ZMQSocket);
- uv_tcp_nodelay(m_ZMQSocket, 1);
+ uv_tcp_init(uv_default_loop(), s);
+ uv_tcp_nodelay(s, 1);
# ifndef WIN32
- uv_tcp_keepalive(m_ZMQSocket, 1, 60);
+ uv_tcp_keepalive(s, 1, 60);
# endif
- uv_tcp_connect(req, m_ZMQSocket, record.addr(m_pool.zmq_port()), onZMQConnect);
+# ifdef XMRIG_FEATURE_TLS
+ if (m_pool.isWSS()) {
+ delete m_wss.m_socket;
+ m_wss.m_socket = s;
+ uv_tcp_connect(req, s, record.addr(m_pool.port()), onWSSConnect);
+ }
+ else
+# endif
+ if (m_pool.zmq_port() > 0) {
+ delete m_ZMQSocket;
+ m_ZMQSocket = s;
+ uv_tcp_connect(req, s, record.addr(m_pool.zmq_port()), onZMQConnect);
+ }
}
@@ -396,7 +455,7 @@ bool xmrig::DaemonClient::parseJob(const rapidjson::Value ¶ms, int *code)
);
# endif
- m_blockhashingblob = Json::getString(params, "blockhashing_blob");
+ m_blockhashingblob = Json::getString(params, kBlockhashingBlob);
if (m_blocktemplate.hasMinerSignature()) {
if (m_pool.spendSecretKey().isEmpty()) {
@@ -589,6 +648,12 @@ void xmrig::DaemonClient::retry()
setState(ConnectingState);
}
+# ifdef XMRIG_FEATURE_TLS
+ if (m_wss.m_socket) {
+ uv_close(reinterpret_cast(m_wss.m_socket), onWSSClose);
+ }
+ else
+# endif
if ((m_ZMQConnectionState != ZMQ_NOT_CONNECTED) && (m_ZMQConnectionState != ZMQ_DISCONNECTING)) {
uv_close(reinterpret_cast(m_ZMQSocket), onZMQClose);
}
@@ -913,3 +978,377 @@ bool xmrig::DaemonClient::ZMQClose(bool shutdown)
return false;
}
+
+
+#ifdef XMRIG_FEATURE_TLS
+void xmrig::DaemonClient::onWSSConnect(uv_connect_t* req, int status)
+{
+ DaemonClient* client = getClient(req->data);
+ delete req;
+
+ if (!client) {
+ return;
+ }
+
+ if (status < 0) {
+ LOG_ERR("%s " RED("WSS connect error: ") RED_BOLD("\"%s\""), client->tag(), uv_strerror(status));
+ client->retry();
+ return;
+ }
+
+ client->WSSConnected();
+}
+
+
+void xmrig::DaemonClient::onWSSRead(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf)
+{
+ DaemonClient* client = getClient(stream->data);
+ if (client) {
+ client->WSSRead(nread, buf);
+ }
+
+ NetBuffer::release(buf);
+}
+
+
+void xmrig::DaemonClient::onWSSClose(uv_handle_t* handle)
+{
+ DaemonClient* client = getClient(handle->data);
+ if (client) {
+# ifdef APP_DEBUG
+ LOG_DEBUG(CYAN("%s") BLACK_BOLD(" disconnected"), client->m_pool.url().data());
+# endif
+ client->m_wss.cleanup();
+ client->retry();
+ }
+}
+
+
+void xmrig::DaemonClient::onWSSShutdown(uv_handle_t* handle)
+{
+ DaemonClient* client = getClient(handle->data);
+ if (client) {
+# ifdef APP_DEBUG
+ LOG_DEBUG(CYAN("%s") BLACK_BOLD(" shutdown"), client->m_pool.url().data());
+# endif
+ client->m_wss.cleanup();
+ m_storage.remove(client->m_key);
+ }
+}
+
+
+void xmrig::DaemonClient::WSSConnected()
+{
+ m_wss.m_ctx = SSL_CTX_new(SSLv23_method());
+ m_wss.m_write = BIO_new(BIO_s_mem());
+ m_wss.m_read = BIO_new(BIO_s_mem());
+
+ SSL_CTX_set_options(m_wss.m_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
+ m_wss.m_ssl = SSL_new(m_wss.m_ctx);
+ SSL_set_connect_state(m_wss.m_ssl);
+ SSL_set_bio(m_wss.m_ssl, m_wss.m_read, m_wss.m_write);
+ SSL_do_handshake(m_wss.m_ssl);
+
+ if (WSSWrite(nullptr, 0)) {
+ uv_read_start(reinterpret_cast(m_wss.m_socket), NetBuffer::onAlloc, onWSSRead);
+ }
+}
+
+
+bool xmrig::DaemonClient::WSSWrite(const char* data, size_t size)
+{
+ if (!m_wss.m_socket) {
+ return false;
+ }
+
+ if (data && size) {
+# ifdef APP_DEBUG
+ LOG_DEBUG(CYAN("%s") BLACK_BOLD(" write ") CYAN_BOLD("%zu") BLACK_BOLD(" bytes") " %s", m_pool.url().data(), size, data);
+# endif
+
+ if (!m_wss.m_handshake) {
+ WSS::Header h{};
+ h.fin = 1;
+ h.mask = 1;
+ h.opcode = 1;
+
+ uint8_t size_buf[8];
+ if (size < 126) {
+ h.payload_len = static_cast(size);
+ }
+ else if (size < 65536) {
+ h.payload_len = 126;
+ size_buf[0] = static_cast(size >> 8);
+ size_buf[1] = static_cast(size & 0xFF);
+ }
+ else {
+ h.payload_len = 127;
+ uint64_t k = size;
+ for (int i = 7; i >= 0; --i, k >>= 8) {
+ size_buf[i] = static_cast(k & 0xFF);
+ }
+ }
+
+ // Header
+ SSL_write(m_wss.m_ssl, &h, sizeof(h));
+
+ // Optional extended payload length
+ if (h.payload_len == 126) SSL_write(m_wss.m_ssl, size_buf, 2);
+ if (h.payload_len == 127) SSL_write(m_wss.m_ssl, size_buf, 8);
+
+ // Masking-key
+ SSL_write(m_wss.m_ssl, "\0\0\0\0", 4);
+ }
+
+ SSL_write(m_wss.m_ssl, data, static_cast(size));
+ }
+
+ uv_buf_t buf;
+ buf.len = BIO_get_mem_data(m_wss.m_write, &buf.base);
+
+ if (buf.len == 0) {
+ return true;
+ }
+
+ const int rc = uv_try_write(reinterpret_cast(m_wss.m_socket), &buf, 1);
+
+ BIO_reset(m_wss.m_write);
+
+ if (static_cast(rc) == buf.len) {
+ return true;
+ }
+
+ LOG_ERR("%s " RED("WSS write failed, rc = %d"), tag(), rc);
+ WSSClose();
+ return false;
+}
+
+
+void xmrig::DaemonClient::WSSRead(ssize_t nread, const uv_buf_t* read_buf)
+{
+ if (nread <= 0) {
+ LOG_ERR("%s " RED("WSS read failed, nread = %" PRId64), tag(), nread);
+ WSSClose();
+ return;
+ }
+
+ BIO_write(m_wss.m_read, read_buf->base, static_cast(nread));
+
+ if (!SSL_is_init_finished(m_wss.m_ssl)) {
+ const int rc = SSL_connect(m_wss.m_ssl);
+
+ if ((rc < 0) && (SSL_get_error(m_wss.m_ssl, rc) == SSL_ERROR_WANT_READ)) {
+ WSSWrite(nullptr, 0);
+ }
+ else if (rc == 1) {
+ // login
+ static constexpr char Base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+ char key[25];
+ std::random_device r;
+
+ for (int i = 0; i < 21; ++i) {
+ key[i] = Base64[r() % 64];
+ }
+
+ key[21] = Base64[0];
+ key[22] = '=';
+ key[23] = '=';
+ key[24] = '\0';
+
+ const int n = snprintf(m_wss.m_buf, sizeof(m_wss.m_buf), kWSSLogin, m_pool.user().data(), m_pool.host().data(), key);
+ if (0 <= n && n < static_cast(sizeof(m_wss.m_buf))) {
+ WSSWrite(m_wss.m_buf, n);
+ }
+ else {
+ WSSClose();
+ }
+ }
+
+ return;
+ }
+
+ int n = 0;
+ while ((n = SSL_read(m_wss.m_ssl, m_wss.m_buf, sizeof(m_wss.m_buf))) > 0) {
+ m_wss.m_data.insert(m_wss.m_data.end(), m_wss.m_buf, m_wss.m_buf + n);
+
+ // Skip the first message (HTTP upgrade response)
+ if (m_wss.m_handshake) {
+ const size_t len = m_wss.m_data.size();
+ if (len >= 4) {
+ for (size_t k = 0; k <= len - 4; ++k) {
+ if (memcmp(m_wss.m_data.data() + k, "\r\n\r\n", 4) == 0) {
+ m_wss.m_handshake = false;
+ m_wss.m_data.erase(m_wss.m_data.begin(), m_wss.m_data.begin() + k + 4);
+ break;
+ }
+ }
+ }
+ continue;
+ }
+
+ const uint8_t* p0 = reinterpret_cast(m_wss.m_data.data());
+ const uint8_t* p = p0;
+ const uint8_t* e = p0 + m_wss.m_data.size();
+
+ if (e - p < static_cast(sizeof(WSS::Header)))
+ continue;
+
+ const WSS::Header* h = reinterpret_cast(p);
+ p += sizeof(WSS::Header);
+
+ uint64_t len = h->payload_len;
+
+ if (len == 126) {
+ if (e - p < static_cast(sizeof(uint16_t))) {
+ continue;
+ }
+ len = 0;
+ for (size_t i = 0; i < sizeof(uint16_t); ++i, ++p) {
+ len = (len << 8) | *p;
+ }
+ }
+ else if (len == 127) {
+ if (e - p < static_cast(sizeof(uint64_t))) {
+ continue;
+ }
+ len = 0;
+ for (size_t i = 0; i < sizeof(uint64_t); ++i, ++p) {
+ len = (len << 8) | *p;
+ }
+ }
+
+ uint8_t mask_key[4] = {};
+ if (h->mask) {
+ if (e - p < 4)
+ continue;
+ memcpy(mask_key, p, 4);
+ p += 4;
+ }
+
+ if (static_cast(e - p) < len)
+ continue;
+
+ for (uint64_t i = 0; i < len; ++i) {
+ m_wss.m_message.push_back(p[i] ^ mask_key[i % 4]);
+ }
+ p += len;
+
+ m_wss.m_data.erase(m_wss.m_data.begin(), m_wss.m_data.begin() + (p - p0));
+
+ if (h->fin) {
+ if (m_wss.m_message.back() == '\n') {
+ m_wss.m_message.back() = '\0';
+ }
+ else {
+ m_wss.m_message.push_back('\0');
+ }
+ WSSParse();
+ m_wss.m_message.clear();
+ }
+ }
+}
+
+
+void xmrig::DaemonClient::WSSParse()
+{
+# ifdef APP_DEBUG
+ LOG_DEBUG(CYAN("%s") BLACK_BOLD(" read ") CYAN_BOLD("%zu") BLACK_BOLD(" bytes") " %s", m_pool.url().data(), m_wss.m_message.size(), m_wss.m_message.data());
+# endif
+
+ using namespace rapidjson;
+
+ Document doc;
+ if (doc.ParseInsitu(m_wss.m_message.data()).HasParseError() || !doc.IsObject()) {
+ if (!isQuiet()) {
+ LOG_ERR("%s " RED("JSON decode failed: ") RED_BOLD("\"%s\""), tag(), GetParseError_En(doc.GetParseError()));
+ }
+
+ return retry();
+ }
+
+ if (doc.HasMember(kLastError)) {
+ String err = Json::getString(doc, kLastError, "");
+ if (!err.isEmpty()) {
+ LOG_ERR("%s " RED_BOLD("\"%s\""), tag(), err.data());
+ return;
+ }
+ }
+
+ if (doc.HasMember(kBlockhashingBlob)) {
+ Job job(false, m_pool.algorithm(), String());
+
+ m_blockhashingblob = Json::getString(doc, kBlockhashingBlob, "");
+ if (m_blockhashingblob.isEmpty()) {
+ LOG_ERR("%s " RED_BOLD("blockhashing_blob is empty"), tag());
+ return;
+ }
+ job.setBlob(m_blockhashingblob);
+ memset(job.blob() + job.nonceOffset(), 0, job.nonceSize());
+
+ const uint64_t height = Json::getUint64(doc, kHeight);
+
+ job.setHeight(height);
+ job.setDiff(Json::getUint64(doc, "difficultyuint64"));
+ //job.setDiff(100000);
+
+ m_currentJobId = Json::getString(doc, "jobid");
+ job.setId(m_currentJobId);
+
+ m_job = std::move(job);
+
+ if (m_state == ConnectingState) {
+ setState(ConnectedState);
+ }
+
+ const uint64_t blocks = Json::getUint64(doc, "blocks");
+ const uint64_t miniblocks = Json::getUint64(doc, "miniblocks");
+
+ if ((blocks != m_wss.m_blocks) || (miniblocks != m_wss.m_miniblocks) || (height != m_wss.m_height)) {
+ LOG_INFO("%s " GREEN_BOLD("%" PRIu64 " blocks, %" PRIu64 " mini blocks"), tag(), blocks, miniblocks);
+ m_wss.m_blocks = blocks;
+ m_wss.m_miniblocks = miniblocks;
+ m_wss.m_height = height;
+ }
+
+ m_listener->onJobReceived(this, m_job, doc);
+ return;
+ }
+}
+
+
+bool xmrig::DaemonClient::WSSClose(bool shutdown)
+{
+ if (m_wss.m_socket && (uv_is_closing(reinterpret_cast(m_wss.m_socket)) == 0)) {
+ uv_close(reinterpret_cast(m_wss.m_socket), shutdown ? onWSSShutdown : onWSSClose);
+ return true;
+ }
+
+ return false;
+}
+
+
+void xmrig::DaemonClient::WSS::cleanup()
+{
+ delete m_socket;
+ m_socket = nullptr;
+
+ if (m_ctx) {
+ SSL_CTX_free(m_ctx);
+ m_ctx = nullptr;
+ }
+ if (m_ssl) {
+ SSL_free(m_ssl);
+ m_ssl = nullptr;
+ }
+
+ m_read = nullptr;
+ m_write = nullptr;
+ m_handshake = true;
+ m_blocks = 0;
+ m_miniblocks = 0;
+ m_height = 0;
+ m_data.clear();
+ m_message.clear();
+}
+#endif
diff --git a/src/base/net/stratum/DaemonClient.h b/src/base/net/stratum/DaemonClient.h
index 5a6ca8ca8a..2cb6f8b815 100644
--- a/src/base/net/stratum/DaemonClient.h
+++ b/src/base/net/stratum/DaemonClient.h
@@ -39,6 +39,12 @@ using uv_handle_t = struct uv_handle_s;
using uv_stream_t = struct uv_stream_s;
using uv_tcp_t = struct uv_tcp_s;
+#ifdef XMRIG_FEATURE_TLS
+using BIO = struct bio_st;
+using SSL = struct ssl_st;
+using SSL_CTX = struct ssl_ctx_st;
+#endif
+
namespace xmrig {
@@ -57,6 +63,7 @@ class DaemonClient : public BaseClient, public IDnsListener, public ITimerListen
protected:
bool disconnect() override;
bool isTLS() const override;
+ bool isWSS() const override;
int64_t submit(const JobResult &result) override;
void connect() override;
void connect(const Pool &pool) override;
@@ -136,6 +143,45 @@ class DaemonClient : public BaseClient, public IDnsListener, public ITimerListen
std::vector m_ZMQSendBuf;
std::vector m_ZMQRecvBuf;
+
+# ifdef XMRIG_FEATURE_TLS
+ static void onWSSConnect(uv_connect_t* req, int status);
+ static void onWSSRead(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf);
+ static void onWSSClose(uv_handle_t* handle);
+ static void onWSSShutdown(uv_handle_t* handle);
+
+ void WSSConnected();
+ bool WSSWrite(const char* data, size_t size);
+ void WSSRead(ssize_t nread, const uv_buf_t* buf);
+ void WSSParse();
+ bool WSSClose(bool shutdown = false);
+
+ struct WSS {
+ struct Header
+ {
+ uint8_t opcode : 4;
+ uint8_t reserved : 3;
+ uint8_t fin : 1;
+ uint8_t payload_len : 7;
+ uint8_t mask : 1;
+ };
+
+ uv_tcp_t* m_socket = nullptr;
+ SSL_CTX* m_ctx = nullptr;
+ BIO* m_read = nullptr;
+ BIO* m_write = nullptr;
+ SSL* m_ssl = nullptr;
+ char m_buf[512] = {};
+ bool m_handshake = true;
+ uint64_t m_blocks = 0;
+ uint64_t m_miniblocks = 0;
+ uint64_t m_height = 0;
+ std::vector m_data;
+ std::vector m_message;
+
+ void cleanup();
+ } m_wss;
+# endif
};
diff --git a/src/base/net/stratum/Job.cpp b/src/base/net/stratum/Job.cpp
index 8465ec0bc3..fd002d0e3f 100644
--- a/src/base/net/stratum/Job.cpp
+++ b/src/base/net/stratum/Job.cpp
@@ -164,6 +164,18 @@ void xmrig::Job::setSigKey(const char *sig_key)
}
+int32_t xmrig::Job::nonceOffset() const
+{
+ auto f = algorithm().family();
+ if (f == Algorithm::KAWPOW) return 32;
+ if (f == Algorithm::GHOSTRIDER) return 76;
+
+ auto id = algorithm().id();
+ if (id == Algorithm::ASTROBWT_DERO_2) return 44;
+
+ return 39;
+}
+
uint32_t xmrig::Job::getNumTransactions() const
{
if (!(m_algorithm.isCN() || m_algorithm.family() == Algorithm::RANDOM_X)) {
diff --git a/src/base/net/stratum/Job.h b/src/base/net/stratum/Job.h
index 3bad33d539..3fb31baa5b 100644
--- a/src/base/net/stratum/Job.h
+++ b/src/base/net/stratum/Job.h
@@ -76,7 +76,7 @@ class Job
inline const String &poolWallet() const { return m_poolWallet; }
inline const uint32_t *nonce() const { return reinterpret_cast(m_blob + nonceOffset()); }
inline const uint8_t *blob() const { return m_blob; }
- inline int32_t nonceOffset() const { auto f = algorithm().family(); return (f == Algorithm::KAWPOW) ? 32 : ((f == Algorithm::GHOSTRIDER) ? 76 : 39); }
+ int32_t nonceOffset() const;
inline size_t nonceSize() const { return (algorithm().family() == Algorithm::KAWPOW) ? 8 : 4; }
inline size_t size() const { return m_size; }
inline uint32_t *nonce() { return reinterpret_cast(m_blob + nonceOffset()); }
diff --git a/src/base/net/stratum/Pool.cpp b/src/base/net/stratum/Pool.cpp
index 7a58f4cb52..e11e8717f7 100644
--- a/src/base/net/stratum/Pool.cpp
+++ b/src/base/net/stratum/Pool.cpp
@@ -76,6 +76,7 @@ const char *Pool::kSelfSelect = "self-select";
const char *Pool::kSOCKS5 = "socks5";
const char *Pool::kSubmitToOrigin = "submit-to-origin";
const char *Pool::kTls = "tls";
+const char *Pool::kWSS = "wss";
const char *Pool::kUrl = "url";
const char *Pool::kUser = "user";
const char *Pool::kSpendSecretKey = "spend-secret-key";
@@ -93,7 +94,7 @@ xmrig::Pool::Pool(const char *url) :
}
-xmrig::Pool::Pool(const char *host, uint16_t port, const char *user, const char *password, const char* spendSecretKey, int keepAlive, bool nicehash, bool tls, Mode mode) :
+xmrig::Pool::Pool(const char *host, uint16_t port, const char *user, const char *password, const char* spendSecretKey, int keepAlive, bool nicehash, bool tls, bool wss, Mode mode) :
m_keepAlive(keepAlive),
m_mode(mode),
m_flags(1 << FLAG_ENABLED),
@@ -105,6 +106,7 @@ xmrig::Pool::Pool(const char *host, uint16_t port, const char *user, const char
{
m_flags.set(FLAG_NICEHASH, nicehash || strstr(host, kNicehashHost));
m_flags.set(FLAG_TLS, tls);
+ m_flags.set(FLAG_WSS, wss);
}
@@ -132,6 +134,7 @@ xmrig::Pool::Pool(const rapidjson::Value &object) :
m_flags.set(FLAG_ENABLED, Json::getBool(object, kEnabled, true));
m_flags.set(FLAG_NICEHASH, Json::getBool(object, kNicehash) || m_url.host().contains(kNicehashHost));
m_flags.set(FLAG_TLS, Json::getBool(object, kTls) || m_url.isTLS());
+ m_flags.set(FLAG_WSS, Json::getBool(object, kWSS) || m_url.isWSS());
setKeepAlive(Json::getValue(object, kKeepalive));
@@ -293,6 +296,7 @@ rapidjson::Value xmrig::Pool::toJSON(rapidjson::Document &doc) const
obj.AddMember(StringRef(kEnabled), m_flags.test(FLAG_ENABLED), allocator);
obj.AddMember(StringRef(kTls), isTLS(), allocator);
+ obj.AddMember(StringRef(kWSS), isWSS(), allocator);
obj.AddMember(StringRef(kFingerprint), m_fingerprint.toJSON(), allocator);
obj.AddMember(StringRef(kDaemon), m_mode == MODE_DAEMON, allocator);
obj.AddMember(StringRef(kSOCKS5), m_proxy.toJSON(doc), allocator);
diff --git a/src/base/net/stratum/Pool.h b/src/base/net/stratum/Pool.h
index 78684510f0..54e38f8dc8 100644
--- a/src/base/net/stratum/Pool.h
+++ b/src/base/net/stratum/Pool.h
@@ -69,10 +69,12 @@ class Pool
static const char *kSOCKS5;
static const char *kSubmitToOrigin;
static const char *kTls;
+ static const char* kWSS;
static const char *kUrl;
static const char *kUser;
static const char* kSpendSecretKey;
static const char* kDaemonZMQPort;
+ static const char* kDaemonWSSPort;
static const char *kNicehashHost;
constexpr static int kKeepAliveTimeout = 60;
@@ -80,7 +82,7 @@ class Pool
constexpr static uint64_t kDefaultPollInterval = 1000;
Pool() = default;
- Pool(const char *host, uint16_t port, const char *user, const char *password, const char* spendSecretKey, int keepAlive, bool nicehash, bool tls, Mode mode);
+ Pool(const char *host, uint16_t port, const char *user, const char *password, const char* spendSecretKey, int keepAlive, bool nicehash, bool tls, bool wss, Mode mode);
Pool(const char *url);
Pool(const rapidjson::Value &object);
@@ -93,6 +95,7 @@ class Pool
inline bool isNicehash() const { return m_flags.test(FLAG_NICEHASH); }
inline bool isTLS() const { return m_flags.test(FLAG_TLS) || m_url.isTLS(); }
+ inline bool isWSS() const { return m_flags.test(FLAG_WSS) || m_url.isWSS(); }
inline bool isValid() const { return m_url.isValid(); }
inline const Algorithm &algorithm() const { return m_algorithm; }
inline const Coin &coin() const { return m_coin; }
@@ -135,6 +138,7 @@ class Pool
FLAG_ENABLED,
FLAG_NICEHASH,
FLAG_TLS,
+ FLAG_WSS,
FLAG_MAX
};
diff --git a/src/base/net/stratum/SelfSelectClient.h b/src/base/net/stratum/SelfSelectClient.h
index c73198a5a2..a68dbcfc2a 100644
--- a/src/base/net/stratum/SelfSelectClient.h
+++ b/src/base/net/stratum/SelfSelectClient.h
@@ -49,6 +49,7 @@ class SelfSelectClient : public IClient, public IClientListener, public IHttpLis
inline bool hasExtension(Extension extension) const noexcept override { return m_client->hasExtension(extension); }
inline bool isEnabled() const override { return m_client->isEnabled(); }
inline bool isTLS() const override { return m_client->isTLS(); }
+ inline bool isWSS() const override { return m_client->isWSS(); }
inline const char *mode() const override { return m_client->mode(); }
inline const char *tag() const override { return m_client->tag(); }
inline const char *tlsFingerprint() const override { return m_client->tlsFingerprint(); }
diff --git a/src/base/net/stratum/Url.cpp b/src/base/net/stratum/Url.cpp
index 7904a445dc..3bb47db1e9 100644
--- a/src/base/net/stratum/Url.cpp
+++ b/src/base/net/stratum/Url.cpp
@@ -39,6 +39,7 @@ static const char kSOCKS5[] = "socks5://";
#ifdef XMRIG_FEATURE_HTTP
static const char kDaemonHttp[] = "daemon+http://";
static const char kDaemonHttps[] = "daemon+https://";
+static const char kDaemonWss[] = "daemon+wss://";
#endif
} // namespace xmrig
@@ -103,6 +104,11 @@ bool xmrig::Url::parse(const char *url)
m_scheme = DAEMON;
m_tls = false;
}
+ else if (strncasecmp(url, kDaemonWss, sizeof(kDaemonWss) - 1) == 0) {
+ m_scheme = DAEMON;
+ m_tls = true;
+ m_wss = true;
+ }
# endif
else {
return false;
diff --git a/src/base/net/stratum/Url.h b/src/base/net/stratum/Url.h
index 6882631e25..f8ccf7693b 100644
--- a/src/base/net/stratum/Url.h
+++ b/src/base/net/stratum/Url.h
@@ -41,6 +41,7 @@ class Url
Url(const char *host, uint16_t port, bool tls = false, Scheme scheme = UNSPECIFIED);
inline bool isTLS() const { return m_tls; }
+ inline bool isWSS() const { return m_wss; }
inline bool isValid() const { return !m_host.isNull() && m_port > 0; }
inline const String &host() const { return m_host; }
inline const String &url() const { return m_url; }
@@ -57,6 +58,7 @@ class Url
bool parseIPv6(const char *addr);
bool m_tls = false;
+ bool m_wss = false;
Scheme m_scheme = UNSPECIFIED;
String m_host;
String m_url;
diff --git a/src/base/net/stratum/benchmark/BenchClient.h b/src/base/net/stratum/benchmark/BenchClient.h
index c29e42e005..1bd2816145 100644
--- a/src/base/net/stratum/benchmark/BenchClient.h
+++ b/src/base/net/stratum/benchmark/BenchClient.h
@@ -41,6 +41,7 @@ class BenchClient : public IClient, public IHttpListener, public IBenchListener,
inline bool hasExtension(Extension) const noexcept override { return false; }
inline bool isEnabled() const override { return true; }
inline bool isTLS() const override { return false; }
+ inline bool isWSS() const override { return false; }
inline const char *mode() const override { return "benchmark"; }
inline const char *tlsFingerprint() const override { return nullptr; }
inline const char *tlsVersion() const override { return nullptr; }
diff --git a/src/base/tools/bswap_64.h b/src/base/tools/bswap_64.h
index 96335c64e4..462a335531 100644
--- a/src/base/tools/bswap_64.h
+++ b/src/base/tools/bswap_64.h
@@ -23,10 +23,12 @@
#include