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 #define bswap_64(x) _byteswap_uint64(x) +#define bswap_32(x) _byteswap_ulong(x) #elif defined __GNUC__ #define bswap_64(x) __builtin_bswap64(x) +#define bswap_32(x) __builtin_bswap32(x) #else diff --git a/src/crypto/astrobwt/AstroBWT.cpp b/src/crypto/astrobwt/AstroBWT.cpp index 9fd2db60b5..2ae649b2f8 100644 --- a/src/crypto/astrobwt/AstroBWT.cpp +++ b/src/crypto/astrobwt/AstroBWT.cpp @@ -25,6 +25,7 @@ #include "base/crypto/sha3.h" #include "base/tools/bswap_64.h" #include "crypto/cn/CryptoNight.h" +#include "crypto/astrobwt/sort_indices2.h" #include @@ -433,6 +434,45 @@ bool xmrig::astrobwt::astrobwt_dero(const void* input_data, uint32_t input_size, } +bool xmrig::astrobwt::astrobwt_dero_v2(const void* input_data, uint32_t input_size, void* scratchpad, uint8_t* output_hash) +{ + constexpr size_t N = 9973; + constexpr size_t STRIDE = 10240; + + alignas(8) uint8_t key[32]; + uint8_t* scratchpad_ptr = (uint8_t*)(scratchpad) + 64; + uint8_t* v = scratchpad_ptr; + uint32_t* indices = (uint32_t*)(scratchpad_ptr + STRIDE); + uint32_t* tmp_indices = (uint32_t*)(scratchpad_ptr + STRIDE * 5); + +#ifdef ASTROBWT_AVX2 + if (hasAVX2) { + SHA3_256_AVX2_ASM(input_data, input_size, key); + Salsa20_XORKeyStream_AVX256(key, v, N); + } + else +#endif + { + sha3_HashBuffer(256, SHA3_FLAGS_NONE, input_data, input_size, key, sizeof(key)); + Salsa20_XORKeyStream(key, v, N); + } + + sort_indices_astrobwt_v2(N, v, indices, tmp_indices); + +#ifdef ASTROBWT_AVX2 + if (hasAVX2) { + SHA3_256_AVX2_ASM(indices, N * 2, output_hash); + } + else +#endif + { + sha3_HashBuffer(256, SHA3_FLAGS_NONE, indices, N * 2, output_hash, 32); + } + + return true; +} + + void xmrig::astrobwt::init() { if (!astrobwtInitialized) { @@ -450,3 +490,10 @@ void xmrig::astrobwt::single_hash(const uint8_t { astrobwt_dero(input, static_cast(size), ctx[0]->memory, output, std::numeric_limits::max(), true); } + + +template<> +void xmrig::astrobwt::single_hash(const uint8_t* input, size_t size, uint8_t* output, cryptonight_ctx** ctx, uint64_t) +{ + astrobwt_dero_v2(input, static_cast(size), ctx[0]->memory, output); +} diff --git a/src/crypto/astrobwt/AstroBWT.h b/src/crypto/astrobwt/AstroBWT.h index 236b3ce474..15dfa361ee 100644 --- a/src/crypto/astrobwt/AstroBWT.h +++ b/src/crypto/astrobwt/AstroBWT.h @@ -32,6 +32,7 @@ namespace xmrig { namespace astrobwt { bool astrobwt_dero(const void* input_data, uint32_t input_size, void* scratchpad, uint8_t* output_hash, int stage2_max_size, bool avx2); +bool astrobwt_dero_v2(const void* input_data, uint32_t input_size, void* scratchpad, uint8_t* output_hash); void init(); template @@ -40,5 +41,7 @@ void single_hash(const uint8_t* input, size_t size, uint8_t* output, cryptonight template<> void single_hash(const uint8_t* input, size_t size, uint8_t* output, cryptonight_ctx** ctx, uint64_t); +template<> +void single_hash(const uint8_t* input, size_t size, uint8_t* output, cryptonight_ctx** ctx, uint64_t); }} // namespace xmrig::astrobwt diff --git a/src/crypto/astrobwt/sort_indices2.cpp b/src/crypto/astrobwt/sort_indices2.cpp new file mode 100644 index 0000000000..2d86d4624d --- /dev/null +++ b/src/crypto/astrobwt/sort_indices2.cpp @@ -0,0 +1,208 @@ +/* XMRig + * Copyright (c) 2018 Lee Clagett + * Copyright (c) 2018-2019 tevador + * Copyright (c) 2000 Transmeta Corporation + * Copyright (c) 2004-2008 H. Peter Anvin + * 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 "crypto/astrobwt/sort_indices2.h" +#include "base/tools/bswap_64.h" +#include + + +#ifdef __GNUC__ +#define NOINLINE __attribute__((noinline)) +#define RESTRICT __restrict__ +#elif _MSC_VER +#define NOINLINE __declspec(noinline) +#define RESTRICT __restrict +#else +#define NOINLINE +#define RESTRICT +#endif + + +#if __has_cpp_attribute(unlikely) +#define UNLIKELY(X) (X) [[unlikely]] +#elif defined __GNUC__ +#define UNLIKELY(X) (__builtin_expect((X), 0)) +#else +#define UNLIKELY(X) (X) +#endif + + +static NOINLINE void fix(const uint8_t* RESTRICT v, uint32_t* RESTRICT indices, int32_t i) +{ + uint32_t prev_t = indices[i - 1]; + uint32_t t = indices[i]; + + const uint32_t data_a = bswap_32(*(const uint32_t*)(v + (t & 0xFFFF) + 2)); + if (data_a < bswap_32(*(const uint32_t*)(v + (prev_t & 0xFFFF) + 2))) + { + const uint32_t t2 = prev_t; + int32_t j = i - 1; + do + { + indices[j + 1] = prev_t; + --j; + + if (j < 0) { + break; + } + + prev_t = indices[j]; + } while (((t ^ prev_t) <= 0xFFFF) && (data_a < bswap_32(*(const uint32_t*)(v + (prev_t & 0xFFFF) + 2)))); + indices[j + 1] = t; + t = t2; + } +} + + +static NOINLINE void sort_indices(uint32_t N, const uint8_t* RESTRICT v, uint32_t* RESTRICT indices, uint32_t* RESTRICT tmp_indices) +{ + uint8_t byte_counters[2][256] = {}; + uint32_t counters[2][256]; + + { +#define ITER(X) ++byte_counters[1][v[i + X]]; + + enum { unroll = 12 }; + + uint32_t i = 0; + const uint32_t n = N - (unroll - 1); + for (; i < n; i += unroll) { + ITER(0); ITER(1); ITER(2); ITER(3); ITER(4); ITER(5); ITER(6); ITER(7); ITER(8); ITER(9); ITER(10); ITER(11); + } + for (; i < N; ++i) { + ITER(0); + } + memcpy(&byte_counters[0], &byte_counters[1], 256); + --byte_counters[0][v[0]]; + +#undef ITER + } + + { + uint32_t c0 = byte_counters[0][0]; + uint32_t c1 = byte_counters[1][0] - 1; + counters[0][0] = c0; + counters[1][0] = c1; + uint8_t* src = &byte_counters[0][0] + 1; + uint32_t* dst = &counters[0][0] + 1; + const uint8_t* const e = &byte_counters[0][0] + 256; + do { + c0 += src[0]; + c1 += src[256]; + dst[0] = c0; + dst[256] = c1; + ++src; + ++dst; + } while (src < e); + } + + { +#define ITER(X) \ + do { \ + const uint32_t byte0 = v[i - X + 0]; \ + const uint32_t byte1 = v[i - X + 1]; \ + tmp_indices[counters[0][byte1]--] = (byte0 << 24) | (byte1 << 16) | (i - X); \ + } while (0) + + enum { unroll = 8 }; + + uint32_t i = N; + for (; i >= unroll; i -= unroll) { + ITER(1); ITER(2); ITER(3); ITER(4); ITER(5); ITER(6); ITER(7); ITER(8); + } + for (; i > 0; --i) { + ITER(1); + } + +#undef ITER + } + + { +#define ITER(X) \ + do { \ + const uint32_t data = tmp_indices[i - X]; \ + indices[counters[1][data >> 24]--] = data; \ + } while (0) + + enum { unroll = 8 }; + + uint32_t i = N; + for (; i >= unroll; i -= unroll) { + ITER(1); ITER(2); ITER(3); ITER(4); ITER(5); ITER(6); ITER(7); ITER(8); + } + for (; i > 0; --i) { + ITER(1); + } + +#undef ITER + } + + { +#define ITER(X) do { if UNLIKELY(a[X * 2] == a[(X + 1) * 2]) fix(v, indices, i + X); } while (0) + + enum { unroll = 16 }; + + uint32_t i = 1; + const uint32_t n = N - (unroll - 1); + const uint16_t* a = ((const uint16_t*)indices) + 1; + + for (; i < n; i += unroll, a += unroll * 2) { + ITER(0); ITER(1); ITER(2); ITER(3); ITER(4); ITER(5); ITER(6); ITER(7); + ITER(8); ITER(9); ITER(10); ITER(11); ITER(12); ITER(13); ITER(14); ITER(15); + } + for (; i < N; ++i, a += 2) { + ITER(0); + } + +#undef ITER + } + + { +#define ITER(X) a[X] = b[X * 2]; + + enum { unroll = 32 }; + + uint16_t* a = (uint16_t*)indices; + uint16_t* b = (uint16_t*)indices; + uint16_t* e = ((uint16_t*)indices) + (N - (unroll - 1)); + + for (; a < e; a += unroll, b += unroll * 2) { + ITER(0); ITER(1); ITER(2); ITER(3); ITER(4); ITER(5); ITER(6); ITER(7); + ITER(8); ITER(9); ITER(10); ITER(11); ITER(12); ITER(13); ITER(14); ITER(15); + ITER(16); ITER(17); ITER(18); ITER(19); ITER(20); ITER(21); ITER(22); ITER(23); + ITER(24); ITER(25); ITER(26); ITER(27); ITER(28); ITER(29); ITER(30); ITER(31); + } + + e = ((uint16_t*)indices) + N; + for (; a < e; ++a, b += 2) { + ITER(0); + } + +#undef ITER + } +} + + +void sort_indices_astrobwt_v2(uint32_t N, const uint8_t* v, uint32_t* indices, uint32_t* tmp_indices) +{ + sort_indices(N, v, indices, tmp_indices); +} diff --git a/src/crypto/astrobwt/sort_indices2.h b/src/crypto/astrobwt/sort_indices2.h new file mode 100644 index 0000000000..3dd3a75157 --- /dev/null +++ b/src/crypto/astrobwt/sort_indices2.h @@ -0,0 +1,26 @@ +/* XMRig + * Copyright (c) 2018 Lee Clagett + * Copyright (c) 2018-2019 tevador + * Copyright (c) 2000 Transmeta Corporation + * Copyright (c) 2004-2008 H. Peter Anvin + * 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 + + +void sort_indices_astrobwt_v2(uint32_t N, const uint8_t* v, uint32_t* indices, uint32_t* tmp_indices); diff --git a/src/crypto/cn/CnHash.cpp b/src/crypto/cn/CnHash.cpp index a1ef901517..095b0eb0e0 100644 --- a/src/crypto/cn/CnHash.cpp +++ b/src/crypto/cn/CnHash.cpp @@ -379,6 +379,10 @@ xmrig::CnHash::CnHash() m_map[Algorithm::ASTROBWT_DERO] = new cn_hash_fun_array{}; m_map[Algorithm::ASTROBWT_DERO]->data[AV_SINGLE][Assembly::NONE] = astrobwt::single_hash; m_map[Algorithm::ASTROBWT_DERO]->data[AV_SINGLE_SOFT][Assembly::NONE] = astrobwt::single_hash; + + m_map[Algorithm::ASTROBWT_DERO_2] = new cn_hash_fun_array{}; + m_map[Algorithm::ASTROBWT_DERO_2]->data[AV_SINGLE][Assembly::NONE] = astrobwt::single_hash; + m_map[Algorithm::ASTROBWT_DERO_2]->data[AV_SINGLE_SOFT][Assembly::NONE] = astrobwt::single_hash; # endif # ifdef XMRIG_ALGO_GHOSTRIDER diff --git a/src/crypto/cn/CryptoNight_test.h b/src/crypto/cn/CryptoNight_test.h index 1df168e02b..9bec3cd825 100644 --- a/src/crypto/cn/CryptoNight_test.h +++ b/src/crypto/cn/CryptoNight_test.h @@ -447,6 +447,19 @@ const static uint8_t astrobwt_dero_test_out[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +// "astrobwt/v2" +const static uint8_t astrobwt_dero_2_test_out[256] = { + 0x48, 0x9E, 0xD2, 0x66, 0x14, 0x27, 0x98, 0x65, 0x03, 0xFB, 0x87, 0x25, 0xE1, 0xD3, 0x98, 0xDA, + 0x27, 0xEE, 0x25, 0x3D, 0xB4, 0x37, 0x87, 0x98, 0xBF, 0x5A, 0x5C, 0x94, 0xEE, 0x0C, 0xE2, 0x2A, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; #endif diff --git a/src/crypto/ghostrider/ghostrider.cpp b/src/crypto/ghostrider/ghostrider.cpp index 505378c02c..0ce0976eb8 100644 --- a/src/crypto/ghostrider/ghostrider.cpp +++ b/src/crypto/ghostrider/ghostrider.cpp @@ -773,6 +773,11 @@ void hash_octa(const uint8_t* data, size_t size, uint8_t* output, cryptonight_ct { constexpr uint32_t N = 8; + uint8_t* ctx_memory[N]; + for (size_t i = 0; i < N; ++i) { + ctx_memory[i] = ctx[i]->memory; + } + // PrevBlockHash (GhostRider's seed) is stored in bytes [4; 36) const uint8_t* seed = data + 4; @@ -800,30 +805,50 @@ void hash_octa(const uint8_t* data, size_t size, uint8_t* output, cryptonight_ct const CnHash::AlgoVariant* av = Cpu::info()->hasAES() ? av_hw_aes : av_soft_aes; - const cn_hash_fun f[3] = { - CnHash::fn(cn_hash[cn_indices[0]], av[step[cn_indices[0]]], Assembly::AUTO), - CnHash::fn(cn_hash[cn_indices[1]], av[step[cn_indices[1]]], Assembly::AUTO), - CnHash::fn(cn_hash[cn_indices[2]], av[step[cn_indices[2]]], Assembly::AUTO), - }; - uint8_t tmp[64 * N]; - for (uint64_t part = 0; part < 3; ++part) { - for (uint64_t i = 0; i < 5; ++i) { - for (uint64_t j = 0; j < N; ++j) { + for (size_t part = 0; part < 3; ++part) { + + // Allocate scratchpads + { + uint8_t* p = ctx_memory[0]; + + for (size_t i = 0, k = 0; i < N; ++i) { + if ((i % step[cn_indices[part]]) == 0) { + k = 0; + p = ctx_memory[0]; + } + else if (p - ctx_memory[k] >= (1 << 21)) { + ++k; + p = ctx_memory[k]; + } + ctx[i]->memory = p; + p += cn_sizes[cn_indices[part]]; + } + } + + for (size_t i = 0; i < 5; ++i) { + for (size_t j = 0; j < N; ++j) { core_hash[core_indices[part * 5 + i]](data + j * size, size, tmp + j * 64); - data = tmp; - size = 64; } + data = tmp; + size = 64; } - for (uint64_t j = 0, k = step[cn_indices[part]]; j < N; j += k) { - f[part](tmp + j * 64, 64, output + j * 32, ctx, 0); + + auto f = CnHash::fn(cn_hash[cn_indices[part]], av[step[cn_indices[part]]], Assembly::AUTO); + for (size_t j = 0; j < N; j += step[cn_indices[part]]) { + f(tmp + j * 64, 64, output + j * 32, ctx, 0); } - for (uint64_t j = 0; j < N; ++j) { + + for (size_t j = 0; j < N; ++j) { memcpy(tmp + j * 64, output + j * 32, 32); memset(tmp + j * 64 + 32, 0, 32); } } + + for (size_t i = 0; i < N; ++i) { + ctx[i]->memory = ctx_memory[i]; + } } diff --git a/src/net/strategies/DonateStrategy.cpp b/src/net/strategies/DonateStrategy.cpp index be9aad6a83..cdaf2258f1 100644 --- a/src/net/strategies/DonateStrategy.cpp +++ b/src/net/strategies/DonateStrategy.cpp @@ -1,6 +1,6 @@ /* XMRig - * Copyright (c) 2018-2021 SChernykh - * Copyright (c) 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 @@ -70,9 +70,9 @@ xmrig::DonateStrategy::DonateStrategy(Controller *controller, IStrategyListener # endif # ifdef XMRIG_FEATURE_TLS - m_pools.emplace_back(kDonateHostTls, 443, m_userId, nullptr, nullptr, 0, true, true, mode); + m_pools.emplace_back(kDonateHostTls, 443, m_userId, nullptr, nullptr, 0, true, true, false, mode); # endif - m_pools.emplace_back(kDonateHost, 3333, m_userId, nullptr, nullptr, 0, true, false, mode); + m_pools.emplace_back(kDonateHost, 3333, m_userId, nullptr, nullptr, 0, true, false, false, mode); if (m_pools.size() > 1) { m_strategy = new FailoverStrategy(m_pools, 10, 2, this, true); @@ -106,6 +106,12 @@ int64_t xmrig::DonateStrategy::submit(const JobResult &result) void xmrig::DonateStrategy::connect() { +# ifdef XMRIG_ALGO_ASTROBWT + if (m_algorithm == Algorithm::ASTROBWT_DERO_2) { + return; + } +# endif + m_proxy = createProxy(); if (m_proxy) { m_proxy->connect(); @@ -252,7 +258,7 @@ xmrig::IClient *xmrig::DonateStrategy::createProxy() const IClient *client = strategy->client(); m_tls = client->hasExtension(IClient::EXT_TLS); - Pool pool(client->pool().proxy().isValid() ? client->pool().host() : client->ip(), client->pool().port(), m_userId, client->pool().password(), client->pool().spendSecretKey(), 0, true, client->isTLS(), Pool::MODE_POOL); + Pool pool(client->pool().proxy().isValid() ? client->pool().host() : client->ip(), client->pool().port(), m_userId, client->pool().password(), client->pool().spendSecretKey(), 0, true, client->isTLS(), client->isWSS(), Pool::MODE_POOL); pool.setAlgo(client->pool().algorithm()); pool.setProxy(client->pool().proxy()); diff --git a/src/net/strategies/DonateStrategy.h b/src/net/strategies/DonateStrategy.h index fd3038bad8..56a0580ea4 100644 --- a/src/net/strategies/DonateStrategy.h +++ b/src/net/strategies/DonateStrategy.h @@ -1,6 +1,6 @@ /* XMRig - * Copyright (c) 2018-2021 SChernykh - * Copyright (c) 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/version.h b/src/version.h index 177daf92bd..381ed8193c 100644 --- a/src/version.h +++ b/src/version.h @@ -1,6 +1,6 @@ /* XMRig - * Copyright (c) 2018-2021 SChernykh - * Copyright (c) 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,15 +22,15 @@ #define APP_ID "xmrig" #define APP_NAME "XMRig" #define APP_DESC "XMRig miner" -#define APP_VERSION "6.16.4" +#define APP_VERSION "6.17.0" #define APP_DOMAIN "xmrig.com" #define APP_SITE "www.xmrig.com" -#define APP_COPYRIGHT "Copyright (C) 2016-2021 xmrig.com" +#define APP_COPYRIGHT "Copyright (C) 2016-2022 xmrig.com" #define APP_KIND "miner" #define APP_VER_MAJOR 6 -#define APP_VER_MINOR 16 -#define APP_VER_PATCH 4 +#define APP_VER_MINOR 17 +#define APP_VER_PATCH 0 #ifdef _MSC_VER # if (_MSC_VER >= 1930)