Merge branch 'dev'

This commit is contained in:
XMRig 2022-04-05 21:45:26 +07:00
commit eadf272425
No known key found for this signature in database
GPG key ID: 446A53638BE94409
88 changed files with 3091 additions and 367 deletions

View file

@ -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 # v6.16.4
- [#2904](https://github.com/xmrig/xmrig/pull/2904) Fixed unaligned memory accesses. - [#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`. - [#2908](https://github.com/xmrig/xmrig/pull/2908) Added MSVC/2022 to `version.h`.

View file

@ -3,10 +3,12 @@ if (WITH_ASTROBWT)
list(APPEND HEADERS_CRYPTO list(APPEND HEADERS_CRYPTO
src/crypto/astrobwt/AstroBWT.h src/crypto/astrobwt/AstroBWT.h
src/crypto/astrobwt/sort_indices2.h
) )
list(APPEND SOURCES_CRYPTO list(APPEND SOURCES_CRYPTO
src/crypto/astrobwt/AstroBWT.cpp src/crypto/astrobwt/AstroBWT.cpp
src/crypto/astrobwt/sort_indices2.cpp
) )
if (XMRIG_ARM) if (XMRIG_ARM)
@ -21,6 +23,10 @@ if (WITH_ASTROBWT)
src/crypto/astrobwt/salsa20_ref/salsa20.c src/crypto/astrobwt/salsa20_ref/salsa20.c
) )
else() 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) if (CMAKE_SIZEOF_VOID_P EQUAL 8)
add_definitions(/DASTROBWT_AVX2) add_definitions(/DASTROBWT_AVX2)
list(APPEND SOURCES_CRYPTO src/crypto/astrobwt/xmm6int/salsa20_xmm6int-avx2.c) list(APPEND SOURCES_CRYPTO src/crypto/astrobwt/xmm6int/salsa20_xmm6int-avx2.c)

View file

@ -1,6 +1,10 @@
#!/bin/bash -e #!/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
mkdir -p deps/include mkdir -p deps/include
@ -8,7 +12,7 @@ mkdir -p deps/lib
mkdir -p build && cd build 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 tar -xzf hwloc-${HWLOC_VERSION}.tar.gz
cd hwloc-${HWLOC_VERSION} cd hwloc-${HWLOC_VERSION}
@ -16,4 +20,4 @@ cd hwloc-${HWLOC_VERSION}
make -j$(nproc || sysctl -n hw.ncpu || sysctl -n hw.logicalcpu) make -j$(nproc || sysctl -n hw.ncpu || sysctl -n hw.logicalcpu)
cp -fr include ../../deps cp -fr include ../../deps
cp hwloc/.libs/libhwloc.a ../../deps/lib cp hwloc/.libs/libhwloc.a ../../deps/lib
cd .. cd ..

View file

@ -1,6 +1,6 @@
#!/bin/bash -e #!/bin/bash -e
LIBRESSL_VERSION="3.0.2" LIBRESSL_VERSION="3.4.2"
mkdir -p deps mkdir -p deps
mkdir -p deps/include mkdir -p deps/include
@ -17,4 +17,4 @@ make -j$(nproc || sysctl -n hw.ncpu || sysctl -n hw.logicalcpu)
cp -fr include ../../deps cp -fr include ../../deps
cp crypto/.libs/libcrypto.a ../../deps/lib cp crypto/.libs/libcrypto.a ../../deps/lib
cp ssl/.libs/libssl.a ../../deps/lib cp ssl/.libs/libssl.a ../../deps/lib
cd .. cd ..

View file

@ -1,6 +1,6 @@
#!/bin/bash -e #!/bin/bash -e
OPENSSL_VERSION="1.1.1l" OPENSSL_VERSION="1.1.1m"
mkdir -p deps mkdir -p deps
mkdir -p deps/include mkdir -p deps/include

20
scripts/build.openssl3.sh Executable file
View file

@ -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 ..

View file

@ -1,6 +1,6 @@
#!/bin/bash -e #!/bin/bash -e
UV_VERSION="1.42.0" UV_VERSION="1.43.0"
mkdir -p deps mkdir -p deps
mkdir -p deps/include mkdir -p deps/include
@ -17,4 +17,4 @@ sh autogen.sh
make -j$(nproc || sysctl -n hw.ncpu || sysctl -n hw.logicalcpu) make -j$(nproc || sysctl -n hw.ncpu || sysctl -n hw.logicalcpu)
cp -fr include ../../deps cp -fr include ../../deps
cp .libs/libuv.a ../../deps/lib cp .libs/libuv.a ../../deps/lib
cd .. cd ..

View file

@ -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() function kawpow()
{ {
const kawpow = opencl_minify(addIncludes('kawpow.cl', [ 'defs.h' ])); const kawpow = opencl_minify(addIncludes('kawpow.cl', [ 'defs.h' ]));
@ -102,6 +110,11 @@ process.chdir(path.resolve('src/backend/opencl/cl/astrobwt'));
astrobwt(); astrobwt();
process.chdir(cwd);
process.chdir(path.resolve('src/backend/opencl/cl/astrobwt_v2'));
astrobwt_v2();
process.chdir(cwd); process.chdir(cwd);
process.chdir(path.resolve('src/backend/opencl/cl/kawpow')); process.chdir(path.resolve('src/backend/opencl/cl/kawpow'));

View file

@ -17,6 +17,76 @@ bug fixes (and other actions) for each version of hwloc since version
0.9. 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=<dir>.
- Use /opt/rocm-<version> if specified with --with-rocm-version=<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 Version 2.5.0
------------- -------------
* API * API

View file

@ -8,7 +8,7 @@
# Please update HWLOC_VERSION* in contrib/windows/hwloc_config.h too. # Please update HWLOC_VERSION* in contrib/windows/hwloc_config.h too.
major=2 major=2
minor=5 minor=7
release=0 release=0
# greek is used for alpha or beta release tags. If it is non-empty, # 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 # 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 # If snapshot=1, then use the value from snapshot_version as the
# entire hwloc version (i.e., ignore major, minor, release, and # 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 # 2. Version numbers are described in the Libtool current:revision:age
# format. # format.
libhwloc_so_version=20:0:5 libhwloc_so_version=20:2:5
libnetloc_so_version=0:0:0 libnetloc_so_version=0:0:0
# Please also update the <TargetName> lines in contrib/windows/libhwloc.vcxproj # Please also update the <TargetName> lines in contrib/windows/libhwloc.vcxproj

View file

@ -346,7 +346,8 @@ typedef enum hwloc_obj_osdev_type_e {
* For instance the "eth0" interface on Linux. */ * For instance the "eth0" interface on Linux. */
HWLOC_OBJ_OSDEV_OPENFABRICS, /**< \brief Operating system openfabrics device. HWLOC_OBJ_OSDEV_OPENFABRICS, /**< \brief Operating system openfabrics device.
* For instance the "mlx4_0" InfiniBand HCA, * 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. HWLOC_OBJ_OSDEV_DMA, /**< \brief Operating system dma engine device.
* For instance the "dma0chan0" DMA channel on Linux. */ * For instance the "dma0chan0" DMA channel on Linux. */
HWLOC_OBJ_OSDEV_COPROC /**< \brief Operating system co-processor device. 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. /** \brief Get current process or thread binding.
* *
* Writes into \p set the physical cpuset which the process or thread (according to \e * The CPU-set \p set (previously allocated by the caller)
* flags) was last bound to. * 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); 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); 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. /** \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, * \note \p hwloc_pid_t is \p pid_t on Unix platforms,
* and \p HANDLE on native Windows 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 #ifdef hwloc_thread_t
/** \brief Get the current physical binding of thread \p tid. /** \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, * \note \p hwloc_thread_t is \p pthread_t on Unix platforms,
* and \p HANDLE on native Windows 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 #endif
/** \brief Get the last physical CPU where the current process or thread ran. /** \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 * The operating system may move some tasks from one processor
* to another at any time according to their binding, * 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); 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. /** \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 * The operating system may move some tasks from one processor
* to another at any time according to their binding, * 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 /** \brief Query the default memory binding policy and physical locality of the
* current process or thread. * 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. * This function has two output parameters: \p set and \p policy.
* The values returned in these parameters depend on both the \p flags * The values returned in these parameters depend on both the \p flags
* passed in and the current memory binding policies and nodesets in * 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 /** \brief Query the default memory binding policy and physical locality of the
* specified process. * 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. * This function has two output parameters: \p set and \p policy.
* The values returned in these parameters depend on both the \p flags * The values returned in these parameters depend on both the \p flags
* passed in and the current memory binding policies and nodesets in * 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 /** \brief Query the CPUs near the physical NUMA node(s) and binding policy of
* the memory identified by (\p addr, \p len ). * 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. * This function has two output parameters: \p set and \p policy.
* The values returned in these parameters depend on both the \p flags * The values returned in these parameters depend on both the \p flags
* passed in and the memory binding policies and nodesets of the pages * 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. /** \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, * are physically allocated. If no page is actually allocated yet,
* \p set may be empty. * \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 /** \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 * First, try to allocate properly with hwloc_alloc_membind().
* the current memory binding policy, thus providing more binding support, at * On failure, the current process or thread memory binding policy
* the expense of changing the current state. * 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. * If ::HWLOC_MEMBIND_BYNODESET is specified, set is considered a nodeset.
* Otherwise it's a cpuset. * Otherwise it's a cpuset.

View file

@ -1,6 +1,6 @@
/* /*
* Copyright © 2009 CNRS * Copyright © 2009 CNRS
* Copyright © 2009-2020 Inria. All rights reserved. * Copyright © 2009-2021 Inria. All rights reserved.
* Copyright © 2009-2012 Université Bordeaux * Copyright © 2009-2012 Université Bordeaux
* Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved. * Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved.
* See COPYING in top-level directory. * See COPYING in top-level directory.
@ -11,9 +11,9 @@
#ifndef HWLOC_CONFIG_H #ifndef HWLOC_CONFIG_H
#define 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_MAJOR 2
#define HWLOC_VERSION_MINOR 5 #define HWLOC_VERSION_MINOR 7
#define HWLOC_VERSION_RELEASE 0 #define HWLOC_VERSION_RELEASE 0
#define HWLOC_VERSION_GREEK "" #define HWLOC_VERSION_GREEK ""

View file

@ -1,5 +1,5 @@
/* /*
* Copyright © 2020 Inria. All rights reserved. * Copyright © 2020-2021 Inria. All rights reserved.
* See COPYING in top-level directory. * See COPYING in top-level directory.
*/ */
@ -42,18 +42,23 @@ extern "C" {
* (for instance the "CoreType" and "FrequencyMaxMHz", * (for instance the "CoreType" and "FrequencyMaxMHz",
* see \ref topoattrs_cpukinds). * 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). * (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 * Passing 0 as \p kind_index to hwloc_cpukinds_get_info() will
* return information about the less efficient CPU kind. * 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 * When available, efficiency values are gathered from the operating system.
* system (when \p cpukind_efficiency is set in the * If so, \p cpukind_efficiency is set in the struct hwloc_topology_discovery_support array.
* struct hwloc_topology_discovery_support array, only on Windows 10 for now). * This is currently available on Windows 10, Mac OS X (Darwin),
* Otherwise hwloc tries to compute efficiencies * and on some Linux platforms where core "capacity" is exposed in sysfs.
* by comparing CPU kinds using frequencies (on ARM), *
* or core types and frequencies (on other architectures). * 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 * The environment variable HWLOC_CPUKINDS_RANKING may be used
* to change this heuristics, see \ref envvar. * to change this heuristics, see \ref envvar.
* *

View file

@ -35,7 +35,8 @@ extern "C" {
* from a core in another node. * from a core in another node.
* The corresponding kind is ::HWLOC_DISTANCES_KIND_FROM_OS | ::HWLOC_DISTANCES_KIND_FROM_USER. * The corresponding kind is ::HWLOC_DISTANCES_KIND_FROM_OS | ::HWLOC_DISTANCES_KIND_FROM_USER.
* The name of this distances structure is "NUMALatency". * 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, * The matrix may also contain bandwidths between random sets of objects,
* possibly provided by the user, as specified in the \p kind attribute. * 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. * Usually only one distances structure may match a given name.
* *
* The name of the most common structure is "NUMALatency". * The name of the most common structure is "NUMALatency".
* Others include "XGMIBandwidth" and "NVLinkBandwidth". * Others include "XGMIBandwidth", "XGMIHops" and "NVLinkBandwidth".
*/ */
HWLOC_DECLSPEC int HWLOC_DECLSPEC int
hwloc_distances_get_by_name(hwloc_topology_t topology, const char *name, hwloc_distances_get_by_name(hwloc_topology_t topology, const char *name,

View file

@ -1,6 +1,6 @@
/* /*
* Copyright © 2009 CNRS * Copyright © 2009 CNRS
* Copyright © 2009-2016 Inria. All rights reserved. * Copyright © 2009-2021 Inria. All rights reserved.
* Copyright © 2009-2011 Université Bordeaux * Copyright © 2009-2011 Université Bordeaux
* See COPYING in top-level directory. * 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); 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 /** \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, * The behavior is exactly the same as the Linux sched_getaffinity system call,
* but uses a hwloc cpuset. * 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); 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. /** \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 * \note This is equivalent to calling hwloc_get_proc_last_cpu_location() with
* ::HWLOC_CPUBIND_THREAD as flags. * ::HWLOC_CPUBIND_THREAD as flags.

View file

@ -497,6 +497,7 @@ hwloc_filter_check_pcidev_subtype_important(unsigned classid)
return (baseclass == 0x03 /* PCI_BASE_CLASS_DISPLAY */ return (baseclass == 0x03 /* PCI_BASE_CLASS_DISPLAY */
|| baseclass == 0x02 /* PCI_BASE_CLASS_NETWORK */ || baseclass == 0x02 /* PCI_BASE_CLASS_NETWORK */
|| baseclass == 0x01 /* PCI_BASE_CLASS_STORAGE */ || baseclass == 0x01 /* PCI_BASE_CLASS_STORAGE */
|| baseclass == 0x00 /* Unclassified, for Atos/Bull BXI */
|| baseclass == 0x0b /* PCI_BASE_CLASS_PROCESSOR */ || baseclass == 0x0b /* PCI_BASE_CLASS_PROCESSOR */
|| classid == 0x0c04 /* PCI_CLASS_SERIAL_FIBER */ || classid == 0x0c04 /* PCI_CLASS_SERIAL_FIBER */
|| classid == 0x0c06 /* PCI_CLASS_SERIAL_INFINIBAND */ || classid == 0x0c06 /* PCI_CLASS_SERIAL_INFINIBAND */

View file

@ -1,6 +1,6 @@
/* /*
* Copyright © 2009, 2011, 2012 CNRS. All rights reserved. * 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, 2011, 2012, 2015 Université Bordeaux. All rights reserved.
* Copyright © 2009-2020 Cisco Systems, Inc. All rights reserved. * Copyright © 2009-2020 Cisco Systems, Inc. All rights reserved.
* $COPYRIGHT$ * $COPYRIGHT$
@ -290,10 +290,6 @@
/* Define to '1' if sysctlbyname is present and usable */ /* Define to '1' if sysctlbyname is present and usable */
/* #undef HAVE_SYSCTLBYNAME */ /* #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 /* Define to 1 if the system has the type
`SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX'. */ `SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX'. */
#define HAVE_SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX 1 #define HAVE_SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX 1

View file

@ -504,7 +504,7 @@ hwloc__obj_type_is_icache(hwloc_obj_type_t type)
} \ } \
} while(0) } while(0)
#else /* HAVE_USELOCALE */ #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_declare int __dummy_nolocale __hwloc_attribute_unused
#define hwloc_localeswitch_init() #define hwloc_localeswitch_init()
#else #else

View file

@ -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_AIX_SDL_UNKNOWN 210 /* subkind is SDL level */
#define HWLOC_GROUP_KIND_WINDOWS_PROCESSOR_GROUP 220 /* no subkind */ #define HWLOC_GROUP_KIND_WINDOWS_PROCESSOR_GROUP 220 /* no subkind */
#define HWLOC_GROUP_KIND_WINDOWS_RELATIONSHIP_UNKNOWN 221 /* no subkind */ #define HWLOC_GROUP_KIND_WINDOWS_RELATIONSHIP_UNKNOWN 221 /* no subkind */
#define HWLOC_GROUP_KIND_LINUX_CLUSTER 222 /* no subkind */
/* distance groups */ /* distance groups */
#define HWLOC_GROUP_KIND_DISTANCE 900 /* subkind is round of adding these groups during distance based grouping */ #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 */ /* finally, hwloc-specific groups required to insert something else, should disappear as soon as possible */

View file

@ -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 */

View file

@ -42,6 +42,9 @@ hwloc_internal_cpukinds_dup(hwloc_topology_t new, hwloc_topology_t old)
struct hwloc_internal_cpukind_s *kinds; struct hwloc_internal_cpukind_s *kinds;
unsigned i; unsigned i;
if (!old->nr_cpukinds)
return 0;
kinds = hwloc_tma_malloc(tma, old->nr_cpukinds * sizeof(*kinds)); kinds = hwloc_tma_malloc(tma, old->nr_cpukinds * sizeof(*kinds));
if (!kinds) if (!kinds)
return -1; 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 *a = _a;
const struct hwloc_internal_cpukind_s *b = _b; 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 */ /* this function requires ranking values to be unique */

View file

@ -1,5 +1,5 @@
/* /*
* Copyright © 2020 Inria. All rights reserved. * Copyright © 2020-2021 Inria. All rights reserved.
* See COPYING in top-level directory. * 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; struct hwloc_internal_memattr_s *imattrs;
hwloc_memattr_id_t id; 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)); imattrs = hwloc_tma_malloc(tma, old->nr_memattrs * sizeof(*imattrs));
if (!imattrs) if (!imattrs)
return -1; return -1;

View file

@ -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 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 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 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 */ /* lanespeed in Gbit/s */
if (speed <= 2) if (speed <= 2)
lanespeed = 2.5f * speed * 0.8f; lanespeed = 2.5f * speed * 0.8f;
else 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 in GB/s */
*linkspeed = lanespeed * width / 8; *linkspeed = lanespeed * width / 8;

View file

@ -13,6 +13,7 @@
#include "hwloc.h" #include "hwloc.h"
#include "hwloc/windows.h" #include "hwloc/windows.h"
#include "private/private.h" #include "private/private.h"
#include "private/windows.h" /* must be before windows.h */
#include "private/debug.h" #include "private/debug.h"
#include <windows.h> #include <windows.h>
@ -65,26 +66,6 @@ typedef enum _LOGICAL_PROCESSOR_RELATIONSHIP {
# endif /* HAVE_RELATIONPROCESSORPACKAGE */ # endif /* HAVE_RELATIONPROCESSORPACKAGE */
#endif /* HAVE_LOGICAL_PROCESSOR_RELATIONSHIP */ #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 #ifndef HAVE_GROUP_AFFINITY
typedef struct _GROUP_AFFINITY { typedef struct _GROUP_AFFINITY {
KAFFINITY Mask; KAFFINITY Mask;
@ -93,35 +74,40 @@ typedef struct _GROUP_AFFINITY {
} GROUP_AFFINITY, *PGROUP_AFFINITY; } GROUP_AFFINITY, *PGROUP_AFFINITY;
#endif #endif
#ifndef HAVE_PROCESSOR_RELATIONSHIP /* always use our own structure because the EfficiencyClass field didn't exist before Win10 */
typedef struct HWLOC_PROCESSOR_RELATIONSHIP { typedef struct HWLOC_PROCESSOR_RELATIONSHIP {
BYTE Flags; 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]; BYTE Reserved[20];
WORD GroupCount; WORD GroupCount;
GROUP_AFFINITY GroupMask[ANYSIZE_ARRAY]; GROUP_AFFINITY GroupMask[ANYSIZE_ARRAY];
} PROCESSOR_RELATIONSHIP, *PPROCESSOR_RELATIONSHIP; } HWLOC_PROCESSOR_RELATIONSHIP;
#endif
#ifndef HAVE_NUMA_NODE_RELATIONSHIP /* always use our own structure because the GroupCount and GroupMasks fields didn't exist in some Win10 */
typedef struct _NUMA_NODE_RELATIONSHIP { typedef struct HWLOC_NUMA_NODE_RELATIONSHIP {
DWORD NodeNumber; DWORD NodeNumber;
BYTE Reserved[20]; BYTE Reserved[18];
GROUP_AFFINITY GroupMask; WORD GroupCount;
} NUMA_NODE_RELATIONSHIP, *PNUMA_NODE_RELATIONSHIP; _ANONYMOUS_UNION
#endif union {
GROUP_AFFINITY GroupMask;
GROUP_AFFINITY GroupMasks[ANYSIZE_ARRAY];
} DUMMYUNIONNAME;
} HWLOC_NUMA_NODE_RELATIONSHIP;
#ifndef HAVE_CACHE_RELATIONSHIP typedef struct HWLOC_CACHE_RELATIONSHIP {
typedef struct _CACHE_RELATIONSHIP {
BYTE Level; BYTE Level;
BYTE Associativity; BYTE Associativity;
WORD LineSize; WORD LineSize;
DWORD CacheSize; DWORD CacheSize;
PROCESSOR_CACHE_TYPE Type; PROCESSOR_CACHE_TYPE Type;
BYTE Reserved[20]; BYTE Reserved[18];
GROUP_AFFINITY GroupMask; WORD GroupCount;
} CACHE_RELATIONSHIP, *PCACHE_RELATIONSHIP; union {
#endif GROUP_AFFINITY GroupMask;
GROUP_AFFINITY GroupMasks[ANYSIZE_ARRAY];
} DUMMYUNIONNAME;
} HWLOC_CACHE_RELATIONSHIP;
#ifndef HAVE_PROCESSOR_GROUP_INFO #ifndef HAVE_PROCESSOR_GROUP_INFO
typedef struct _PROCESSOR_GROUP_INFO { typedef struct _PROCESSOR_GROUP_INFO {
@ -141,20 +127,19 @@ typedef struct _GROUP_RELATIONSHIP {
} GROUP_RELATIONSHIP, *PGROUP_RELATIONSHIP; } GROUP_RELATIONSHIP, *PGROUP_RELATIONSHIP;
#endif #endif
#ifndef HAVE_SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX /* always use our own structure because we need our own HWLOC_PROCESSOR/CACHE/NUMA_NODE_RELATIONSHIP */
typedef struct _SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX { typedef struct HWLOC_SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX {
LOGICAL_PROCESSOR_RELATIONSHIP Relationship; LOGICAL_PROCESSOR_RELATIONSHIP Relationship;
DWORD Size; DWORD Size;
_ANONYMOUS_UNION _ANONYMOUS_UNION
union { union {
PROCESSOR_RELATIONSHIP Processor; HWLOC_PROCESSOR_RELATIONSHIP Processor;
NUMA_NODE_RELATIONSHIP NumaNode; HWLOC_NUMA_NODE_RELATIONSHIP NumaNode;
CACHE_RELATIONSHIP Cache; HWLOC_CACHE_RELATIONSHIP Cache;
GROUP_RELATIONSHIP Group; GROUP_RELATIONSHIP Group;
/* Odd: no member to tell the cpu mask of the package... */ /* Odd: no member to tell the cpu mask of the package... */
} DUMMYUNIONNAME; } DUMMYUNIONNAME;
} SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, *PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX; } HWLOC_SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX;
#endif
#ifndef HAVE_PSAPI_WORKING_SET_EX_BLOCK #ifndef HAVE_PSAPI_WORKING_SET_EX_BLOCK
typedef union _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); typedef VOID (WINAPI *PFN_GETCURRENTPROCESSORNUMBEREX)(PPROCESSOR_NUMBER);
static PFN_GETCURRENTPROCESSORNUMBEREX GetCurrentProcessorNumberExProc; static PFN_GETCURRENTPROCESSORNUMBEREX GetCurrentProcessorNumberExProc;
typedef BOOL (WINAPI *PFN_GETLOGICALPROCESSORINFORMATION)(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION Buffer, PDWORD ReturnLength); typedef BOOL (WINAPI *PFN_GETLOGICALPROCESSORINFORMATIONEX)(LOGICAL_PROCESSOR_RELATIONSHIP relationship, HWLOC_SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *Buffer, PDWORD ReturnLength);
static PFN_GETLOGICALPROCESSORINFORMATION GetLogicalProcessorInformationProc;
typedef BOOL (WINAPI *PFN_GETLOGICALPROCESSORINFORMATIONEX)(LOGICAL_PROCESSOR_RELATIONSHIP relationship, PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX Buffer, PDWORD ReturnLength);
static PFN_GETLOGICALPROCESSORINFORMATIONEX GetLogicalProcessorInformationExProc; static PFN_GETLOGICALPROCESSORINFORMATIONEX GetLogicalProcessorInformationExProc;
typedef BOOL (WINAPI *PFN_SETTHREADGROUPAFFINITY)(HANDLE hThread, const GROUP_AFFINITY *GroupAffinity, PGROUP_AFFINITY PreviousGroupAffinity); 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"); (PFN_GETACTIVEPROCESSORGROUPCOUNT) GetProcAddress(kernel32, "GetActiveProcessorGroupCount");
GetActiveProcessorCountProc = GetActiveProcessorCountProc =
(PFN_GETACTIVEPROCESSORCOUNT) GetProcAddress(kernel32, "GetActiveProcessorCount"); (PFN_GETACTIVEPROCESSORCOUNT) GetProcAddress(kernel32, "GetActiveProcessorCount");
GetLogicalProcessorInformationProc =
(PFN_GETLOGICALPROCESSORINFORMATION) GetProcAddress(kernel32, "GetLogicalProcessorInformation");
GetCurrentProcessorNumberProc = GetCurrentProcessorNumberProc =
(PFN_GETCURRENTPROCESSORNUMBER) GetProcAddress(kernel32, "GetCurrentProcessorNumber"); (PFN_GETCURRENTPROCESSORNUMBER) GetProcAddress(kernel32, "GetCurrentProcessorNumber");
GetCurrentProcessorNumberExProc = GetCurrentProcessorNumberExProc =
@ -370,13 +350,13 @@ static hwloc_cpuset_t * processor_group_cpusets = NULL;
static void static void
hwloc_win_get_processor_groups(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; DWORD length;
unsigned i; unsigned i;
hwloc_debug("querying windows processor groups\n"); hwloc_debug("querying windows processor groups\n");
if (!GetActiveProcessorGroupCountProc || !GetLogicalProcessorInformationExProc) if (!GetLogicalProcessorInformationExProc)
goto error; goto error;
nr_processor_groups = GetActiveProcessorGroupCountProc(); nr_processor_groups = GetActiveProcessorGroupCountProc();
@ -415,6 +395,8 @@ hwloc_win_get_processor_groups(void)
assert(procInfo->Relationship == RelationGroup); 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++) { for (id = 0; id < procInfo->Group.ActiveGroupCount; id++) {
KAFFINITY mask; KAFFINITY mask;
hwloc_bitmap_t set; hwloc_bitmap_t set;
@ -424,8 +406,8 @@ hwloc_win_get_processor_groups(void)
goto error_with_cpusets; goto error_with_cpusets;
mask = procInfo->Group.GroupInfo[id].ActiveProcessorMask; mask = procInfo->Group.GroupInfo[id].ActiveProcessorMask;
hwloc_debug("group %u %d cpus mask %lx\n", id, hwloc_debug("group %u with %u cpus mask 0x%llx\n", id,
procInfo->Group.GroupInfo[id].ActiveProcessorCount, mask); (unsigned) procInfo->Group.GroupInfo[id].ActiveProcessorCount, (unsigned long long) mask);
/* KAFFINITY is ULONG_PTR */ /* KAFFINITY is ULONG_PTR */
hwloc_bitmap_set_ith_ULONG_PTR(set, id, mask); hwloc_bitmap_set_ith_ULONG_PTR(set, id, mask);
/* FIXME: what if running 32bits on a 64bits windows with 64-processor groups? /* 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); unsigned hostname_size = sizeof(hostname);
int has_efficiencyclass = 0; int has_efficiencyclass = 0;
struct hwloc_win_efficiency_classes eclasses; 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); 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); 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) { if (GetLogicalProcessorInformationExProc) {
PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX procInfoTotal, tmpprocInfoTotal, procInfo; HWLOC_SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *procInfoTotal, *tmpprocInfoTotal, *procInfo;
unsigned id; unsigned id;
struct hwloc_obj *obj; struct hwloc_obj *obj;
hwloc_obj_type_t type; hwloc_obj_type_t type;
@ -1207,8 +1062,16 @@ hwloc_look_windows(struct hwloc_backend *backend, struct hwloc_disc_status *dsta
switch (procInfo->Relationship) { switch (procInfo->Relationship) {
case RelationNumaNode: case RelationNumaNode:
type = HWLOC_OBJ_NUMANODE; type = HWLOC_OBJ_NUMANODE;
num = 1; /* Starting with Windows 11 and Server 2022, the GroupCount field is valid and >=1
GroupMask = &procInfo->NumaNode.GroupMask; * 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; id = procInfo->NumaNode.NodeNumber;
gotnuma++; gotnuma++;
if (id > max_numanode_index) if (id > max_numanode_index)
@ -1221,18 +1084,20 @@ hwloc_look_windows(struct hwloc_backend *backend, struct hwloc_disc_status *dsta
break; break;
case RelationCache: case RelationCache:
type = (procInfo->Cache.Type == CacheInstruction ? HWLOC_OBJ_L1ICACHE : HWLOC_OBJ_L1CACHE) + procInfo->Cache.Level - 1; type = (procInfo->Cache.Type == CacheInstruction ? HWLOC_OBJ_L1ICACHE : HWLOC_OBJ_L1CACHE) + procInfo->Cache.Level - 1;
num = 1; /* GroupCount added approximately with NumaNode.GroupCount above */
GroupMask = &procInfo->Cache.GroupMask; if (procInfo->Cache.GroupCount) {
num = procInfo->Cache.GroupCount;
GroupMask = procInfo->Cache.GroupMasks;
} else {
num = 1;
GroupMask = &procInfo->Cache.GroupMask;
}
break; break;
case RelationProcessorCore: case RelationProcessorCore:
type = HWLOC_OBJ_CORE; type = HWLOC_OBJ_CORE;
num = procInfo->Processor.GroupCount; num = procInfo->Processor.GroupCount;
GroupMask = procInfo->Processor.GroupMask; GroupMask = procInfo->Processor.GroupMask;
if (has_efficiencyclass) efficiency_class = procInfo->Processor.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);
break; break;
case RelationGroup: case RelationGroup:
/* So strange an interface... */ /* 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(); groups_pu_set = hwloc_bitmap_alloc();
hwloc_bitmap_or(groups_pu_set, groups_pu_set, set); 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 = hwloc_alloc_setup_object(topology, HWLOC_OBJ_GROUP, id);
obj->cpuset = set; obj->cpuset = set;
obj->attr->group.kind = HWLOC_GROUP_KIND_WINDOWS_PROCESSOR_GROUP; 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 } else
hwloc_bitmap_free(set); hwloc_bitmap_free(set);
} }

View file

@ -500,7 +500,8 @@ static void read_amd_cores_topoext(struct procinfo *infos, unsigned long flags,
nodes_per_proc = ((ecx >> 8) & 7) + 1; nodes_per_proc = ((ecx >> 8) & 7) + 1;
} }
if ((infos->cpufamilynumber == 0x15 && nodes_per_proc > 2) 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); 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) { } else if (cpuid_type == amd) {
/* AMD quirks */ /* AMD quirks */
if (infos->cpufamilynumber == 0x17 if (infos->cpufamilynumber >= 0x17 && cache->level == 3) {
&& cache->level == 3 && cache->nbthreads_sharing == 6) { /* AMD family 0x19 always shares L3 between 16 APIC ids (8 HT cores).
/* AMD family 0x17 always shares L3 between 8 APIC ids, * while Family 0x17 shares between 8 APIC ids (4 HT cores).
* even when only 6 APIC ids are enabled and reported in nbthreads_sharing * But many models have less APIC ids enabled and reported in nbthreads_sharing.
* (on 24-core CPUs). * 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 } else if (infos->cpufamilynumber== 0x10 && infos->cpumodelnumber == 0x9
&& cache->level == 3 && cache->level == 3
@ -807,7 +814,7 @@ static void look_proc(struct hwloc_backend *backend, struct procinfo *infos, uns
} else if (infos->cpufamilynumber == 0x15 } else if (infos->cpufamilynumber == 0x15
&& (infos->cpumodelnumber == 0x1 /* Bulldozer */ || infos->cpumodelnumber == 0x2 /* Piledriver */) && (infos->cpumodelnumber == 0x1 /* Bulldozer */ || infos->cpumodelnumber == 0x2 /* Piledriver */)
&& cache->level == 3 && cache->nbthreads_sharing == 6) { && 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. * 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 */ 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); 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.depth = level;
cache->attr->cache.size = infos[i].cache[l].size; cache->attr->cache.size = infos[i].cache[l].size;
cache->attr->cache.linesize = infos[i].cache[l].linesize; 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]; char line [32];
dir = opendir(src_cpuiddump_path); dir = opendir(src_cpuiddump_path);
if (!dir) if (!dir)
return -1; return -1;
path = malloc(strlen(src_cpuiddump_path) + strlen("/hwloc-cpuid-info") + 1); path = malloc(strlen(src_cpuiddump_path) + strlen("/hwloc-cpuid-info") + 1);

View file

@ -243,7 +243,7 @@ hwloc__xml_import_object_attr(struct hwloc_topology *topology,
else if (!strcmp(name, "dont_merge")) { else if (!strcmp(name, "dont_merge")) {
unsigned long lvalue = strtoul(value, NULL, 10); unsigned long lvalue = strtoul(value, NULL, 10);
if (obj->type == HWLOC_OBJ_GROUP) 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()) else if (hwloc__xml_verbose())
fprintf(stderr, "%s: ignoring dont_merge attribute for non-group object type\n", fprintf(stderr, "%s: ignoring dont_merge attribute for non-group object type\n",
state->global->msgprefix); 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 */ /* child has sibling, we must add a Group around those memory children */
hwloc_obj_t group = parentstate->global->v1_memory_group; hwloc_obj_t group = parentstate->global->v1_memory_group;
parentstate->new_child(parentstate, &gstate, "object"); parentstate->new_child(parentstate, &gstate, "object");
group->parent = obj->parent;
group->cpuset = obj->cpuset; group->cpuset = obj->cpuset;
group->complete_cpuset = obj->complete_cpuset; group->complete_cpuset = obj->complete_cpuset;
group->nodeset = obj->nodeset; group->nodeset = obj->nodeset;

View file

@ -69,7 +69,7 @@
* it will break in cygwin, we'll have to use both putenv() and SetEnvironmentVariable(). * 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. * 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) __attribute__((constructor));
static void hwloc_constructor(void) 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 hwloc_propagate_symmetric_subtree(hwloc_topology_t topology, hwloc_obj_t root);
static void propagate_total_memory(hwloc_obj_t obj); static void propagate_total_memory(hwloc_obj_t obj);
static void hwloc_set_group_depth(hwloc_topology_t topology); 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_obj_t
hwloc_topology_insert_group_object(struct hwloc_topology *topology, hwloc_obj_t obj) 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;
} }
/* return > 0 if any level was removed, which means reconnect is needed */ /* return > 0 if any level was removed.
static void * performs its own reconnect internally if needed
*/
static int
hwloc_filter_levels_keep_structure(hwloc_topology_t topology) hwloc_filter_levels_keep_structure(hwloc_topology_t topology)
{ {
unsigned i, j; unsigned i, j;
int res = 0; 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 */ /* start from the bottom since we'll remove intermediate levels */
for(i=topology->nb_levels-1; i>0; i--) { for(i=topology->nb_levels-1; i>0; i--) {
int replacechild = 0, replaceparent = 0; 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; 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 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 static int
hwloc_connect_io_misc_levels(hwloc_topology_t topology) hwloc_connect_special_levels(hwloc_topology_t topology)
{ {
unsigned i; unsigned i;
@ -3176,6 +3208,10 @@ hwloc_connect_levels(hwloc_topology_t topology)
int int
hwloc_topology_reconnect(struct hwloc_topology *topology, unsigned long flags) 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) { if (flags) {
errno = EINVAL; errno = EINVAL;
return -1; return -1;
@ -3188,7 +3224,7 @@ hwloc_topology_reconnect(struct hwloc_topology *topology, unsigned long flags)
if (hwloc_connect_levels(topology) < 0) if (hwloc_connect_levels(topology) < 0)
return -1; return -1;
if (hwloc_connect_io_misc_levels(topology) < 0) if (hwloc_connect_special_levels(topology) < 0)
return -1; return -1;
topology->modified = 0; topology->modified = 0;
@ -3529,15 +3565,12 @@ hwloc_discover(struct hwloc_topology *topology,
} }
hwloc_debug_print_objects(0, topology->levels[0][0]); 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_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]); hwloc_debug_print_objects(0, topology->levels[0][0]);
/* accumulate children memory in total_memory fields (only once parent is set) */ /* 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(droppedcpuset);
hwloc_bitmap_free(droppednodeset); 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; goto out;
/* some objects may have disappeared, we need to update distances objs arrays */ /* some objects may have disappeared, we need to update distances objs arrays */
hwloc_internal_distances_invalidate_cached_objs(topology); hwloc_internal_distances_invalidate_cached_objs(topology);
hwloc_internal_memattrs_need_refresh(topology); hwloc_internal_memattrs_need_refresh(topology);
hwloc_filter_levels_keep_structure(topology);
hwloc_propagate_symmetric_subtree(topology, topology->levels[0][0]); hwloc_propagate_symmetric_subtree(topology, topology->levels[0][0]);
propagate_total_memory(topology->levels[0][0]); propagate_total_memory(topology->levels[0][0]);
hwloc_internal_cpukinds_restrict(topology); hwloc_internal_cpukinds_restrict(topology);

View file

@ -1,12 +1,6 @@
/* XMRig /* XMRig
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com> * Copyright (c) 2018-2022 SChernykh <https://github.com/SChernykh>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org> * Copyright (c) 2016-2022 XMRig <support@xmrig.com>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2019 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2018-2021 SChernykh <https://github.com/SChernykh>
* Copyright 2016-2021 XMRig <support@xmrig.com>
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -22,7 +16,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <cinttypes> #include <cinttypes>
#include <cstdio> #include <cstdio>
#include <uv.h> #include <uv.h>
@ -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()); "", memory.id().data(), memory.size() / oneGiB, memory.type(), memory.speed() / 1000000ULL, memory.product().data());
} }
else if (printEmpty) { else if (printEmpty) {
Log::print(WHITE_BOLD(" %-13s") "%s: " BLACK_BOLD("<empty>"), "", memory.slot().data()); Log::print(WHITE_BOLD(" %-13s") "%s: " BLACK_BOLD("<empty>"), "", memory.id().data());
} }
} }

View file

@ -1,12 +1,6 @@
/* XMRig /* XMRig
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com> * Copyright (c) 2018-2022 SChernykh <https://github.com/SChernykh>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org> * Copyright (c) 2016-2022 XMRig <support@xmrig.com>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2018-2021 SChernykh <https://github.com/SChernykh>
* Copyright 2016-2021 XMRig <https://github.com/xmrig>, <support@xmrig.com>
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View file

@ -157,7 +157,15 @@ size_t inline generate<Algorithm::ARGON2>(Threads<CpuThreads> &threads, uint32_t
template<> template<>
size_t inline generate<Algorithm::ASTROBWT>(Threads<CpuThreads>& threads, uint32_t limit) size_t inline generate<Algorithm::ASTROBWT>(Threads<CpuThreads>& 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 #endif

View file

@ -224,9 +224,8 @@ bool xmrig::CpuWorker<N>::selfTest()
# endif # endif
# ifdef XMRIG_ALGO_ASTROBWT # ifdef XMRIG_ALGO_ASTROBWT
if (m_algorithm.family() == Algorithm::ASTROBWT) { if (m_algorithm.id() == Algorithm::ASTROBWT_DERO) return verify(Algorithm::ASTROBWT_DERO, astrobwt_dero_test_out);
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 # endif
return false; return false;
@ -320,8 +319,15 @@ void xmrig::CpuWorker<N>::start()
# ifdef XMRIG_ALGO_ASTROBWT # ifdef XMRIG_ALGO_ASTROBWT
case Algorithm::ASTROBWT: case Algorithm::ASTROBWT:
if (!astrobwt::astrobwt_dero(m_job.blob(), job.size(), m_ctx[0]->memory, m_hash, m_astrobwtMaxSize, m_astrobwtAVX2)) { if (job.algorithm().id() == Algorithm::ASTROBWT_DERO) {
valid = false; 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; break;
# endif # endif

View file

@ -221,7 +221,7 @@ public:
size_t algo_l3 = algo.l3(); size_t algo_l3 = algo.l3();
# ifdef XMRIG_ALGO_ASTROBWT # ifdef XMRIG_ALGO_ASTROBWT
if (algo.family() == Algorithm::ASTROBWT) { if (algo.id() == Algorithm::ASTROBWT_DERO) {
algo_l3 = CudaAstroBWTRunner::BWT_DATA_STRIDE * 17 + 1024; algo_l3 = CudaAstroBWTRunner::BWT_DATA_STRIDE * 17 + 1024;
} }
# endif # endif

View file

@ -139,7 +139,14 @@ size_t inline generate<Algorithm::RANDOM_X>(Threads<CudaThreads> &threads, const
template<> template<>
size_t inline generate<Algorithm::ASTROBWT>(Threads<CudaThreads> &threads, const std::vector<CudaDevice> &devices) size_t inline generate<Algorithm::ASTROBWT>(Threads<CudaThreads> &threads, const std::vector<CudaDevice> &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 #endif

View file

@ -32,11 +32,17 @@
constexpr uint32_t xmrig::CudaAstroBWTRunner::BWT_DATA_STRIDE; constexpr uint32_t xmrig::CudaAstroBWTRunner::BWT_DATA_STRIDE;
xmrig::CudaAstroBWTRunner::CudaAstroBWTRunner(size_t index, const CudaLaunchData &data) : xmrig::CudaAstroBWTRunner::CudaAstroBWTRunner(size_t index, const CudaLaunchData &data)
CudaBaseRunner(index, data) : CudaBaseRunner(index, data)
, m_algorithm(data.algorithm)
{ {
m_intensity = m_data.thread.threads() * m_data.thread.blocks(); m_intensity = m_data.thread.threads() * m_data.thread.blocks();
m_intensity -= m_intensity % 32; 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 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_SIZE = 147253;
constexpr uint32_t STAGE1_DATA_STRIDE = (STAGE1_SIZE + 256 + 255) & ~255U; 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<uint32_t>(m_intensity);
const uint32_t BWT_ALLOCATION_SIZE = BATCH2_SIZE * BWT_DATA_STRIDE; const uint32_t BWT_ALLOCATION_SIZE = BATCH2_SIZE * BWT_DATA_STRIDE;
const uint32_t BATCH1_SIZE = (BWT_ALLOCATION_SIZE / STAGE1_DATA_STRIDE) & ~255U; const uint32_t BATCH1_SIZE = (BWT_ALLOCATION_SIZE / STAGE1_DATA_STRIDE) & ~255U;

View file

@ -27,6 +27,7 @@
#include "backend/cuda/runners/CudaBaseRunner.h" #include "backend/cuda/runners/CudaBaseRunner.h"
#include "base/crypto/Algorithm.h"
namespace xmrig { namespace xmrig {
@ -50,6 +51,7 @@ protected:
private: private:
size_t m_intensity = 0; size_t m_intensity = 0;
Algorithm m_algorithm;
}; };

View file

@ -205,7 +205,7 @@ public:
size_t algo_l3 = algo.l3(); size_t algo_l3 = algo.l3();
# ifdef XMRIG_ALGO_ASTROBWT # ifdef XMRIG_ALGO_ASTROBWT
if (algo.family() == Algorithm::ASTROBWT) { if (algo.id() == Algorithm::ASTROBWT_DERO) {
algo_l3 = OclAstroBWTRunner::BWT_DATA_STRIDE * 17 + 324; algo_l3 = OclAstroBWTRunner::BWT_DATA_STRIDE * 17 + 324;
} }
# endif # endif

View file

@ -133,7 +133,14 @@ size_t inline generate<Algorithm::RANDOM_X>(Threads<OclThreads> &threads, const
template<> template<>
size_t inline generate<Algorithm::ASTROBWT>(Threads<OclThreads>& threads, const std::vector<OclDevice>& devices) size_t inline generate<Algorithm::ASTROBWT>(Threads<OclThreads>& threads, const std::vector<OclDevice>& 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 #endif

View file

@ -37,6 +37,7 @@
#ifdef XMRIG_ALGO_ASTROBWT #ifdef XMRIG_ALGO_ASTROBWT
# include "backend/opencl/runners/OclAstroBWTRunner.h" # include "backend/opencl/runners/OclAstroBWTRunner.h"
# include "backend/opencl/runners/OclAstroBWT_v2_Runner.h"
#endif #endif
#ifdef XMRIG_ALGO_KAWPOW #ifdef XMRIG_ALGO_KAWPOW
@ -92,7 +93,12 @@ xmrig::OclWorker::OclWorker(size_t id, const OclLaunchData &data) :
case Algorithm::ASTROBWT: case Algorithm::ASTROBWT:
# ifdef XMRIG_ALGO_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 # endif
break; break;

View file

@ -34,6 +34,7 @@
#ifdef XMRIG_ALGO_ASTROBWT #ifdef XMRIG_ALGO_ASTROBWT
# include "backend/opencl/cl/astrobwt/astrobwt_cl.h" # include "backend/opencl/cl/astrobwt/astrobwt_cl.h"
# include "backend/opencl/cl/astrobwt_v2/astrobwt_v2_cl.h"
#endif #endif
#ifdef XMRIG_ALGO_KAWPOW #ifdef XMRIG_ALGO_KAWPOW
@ -52,7 +53,7 @@ const char *xmrig::OclSource::get(const Algorithm &algorithm)
# ifdef XMRIG_ALGO_ASTROBWT # ifdef XMRIG_ALGO_ASTROBWT
if (algorithm.family() == Algorithm::ASTROBWT) { if (algorithm.family() == Algorithm::ASTROBWT) {
return astrobwt_cl; return (algorithm.id() == Algorithm::ASTROBWT_DERO_2) ? astrobwt_v2_cl : astrobwt_cl;
} }
# endif # endif

View file

@ -0,0 +1,179 @@
/* XMRig
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2018-2022 SChernykh <https://github.com/SChernykh>
* Copyright 2016-2022 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#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

View file

@ -0,0 +1,35 @@
/* XMRig
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2018-2022 SChernykh <https://github.com/SChernykh>
* Copyright 2016-2022 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
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"

View file

@ -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

View file

@ -0,0 +1,151 @@
/* XMRig
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2018-2022 SChernykh <https://github.com/SChernykh>
* Copyright 2016-2022 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#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

View file

@ -0,0 +1,188 @@
/* XMRig
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2018-2022 SChernykh <https://github.com/SChernykh>
* Copyright 2016-2022 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#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

View file

@ -40,6 +40,15 @@ bool ocl_generic_astrobwt_generator(const OclDevice &device, const Algorithm &al
return false; 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(); const size_t mem = device.globalMemSize();
uint32_t per_thread_mem = 10 << 20; uint32_t per_thread_mem = 10 << 20;

View file

@ -0,0 +1,42 @@
/* XMRig
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2018-2020 SChernykh <https://github.com/SChernykh>
* Copyright 2016-2020 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#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, &gthreads, &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);
}

View file

@ -0,0 +1,44 @@
/* XMRig
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2018-2020 SChernykh <https://github.com/SChernykh>
* Copyright 2016-2020 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#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

View file

@ -0,0 +1,41 @@
/* XMRig
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2018-2020 SChernykh <https://github.com/SChernykh>
* Copyright 2016-2020 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#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, &gthreads, &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);
}

View file

@ -0,0 +1,44 @@
/* XMRig
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2018-2020 SChernykh <https://github.com/SChernykh>
* Copyright 2016-2020 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#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

View file

@ -0,0 +1,46 @@
/* XMRig
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2018-2019 SChernykh <https://github.com/SChernykh>
* Copyright 2016-2019 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#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);
}

View file

@ -0,0 +1,45 @@
/* XMRig
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2018-2019 SChernykh <https://github.com/SChernykh>
* Copyright 2016-2019 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#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

View file

@ -0,0 +1,44 @@
/* XMRig
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2018-2020 SChernykh <https://github.com/SChernykh>
* Copyright 2016-2020 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#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, &gthreads, &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);
}

View file

@ -0,0 +1,44 @@
/* XMRig
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2018-2020 SChernykh <https://github.com/SChernykh>
* Copyright 2016-2020 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#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

View file

@ -0,0 +1,42 @@
/* XMRig
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2018-2020 SChernykh <https://github.com/SChernykh>
* Copyright 2016-2020 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#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, &gthreads, &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);
}

View file

@ -0,0 +1,44 @@
/* XMRig
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2018-2020 SChernykh <https://github.com/SChernykh>
* Copyright 2016-2020 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#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

View file

@ -0,0 +1,41 @@
/* XMRig
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2018-2020 SChernykh <https://github.com/SChernykh>
* Copyright 2016-2020 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#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, &gthreads, &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);
}

View file

@ -0,0 +1,44 @@
/* XMRig
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2018-2020 SChernykh <https://github.com/SChernykh>
* Copyright 2016-2020 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#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

View file

@ -119,7 +119,14 @@ if (WITH_OPENCL)
src/backend/opencl/kernels/astrobwt/AstroBWT_Salsa20Kernel.h src/backend/opencl/kernels/astrobwt/AstroBWT_Salsa20Kernel.h
src/backend/opencl/kernels/astrobwt/AstroBWT_SHA3InitialKernel.h src/backend/opencl/kernels/astrobwt/AstroBWT_SHA3InitialKernel.h
src/backend/opencl/kernels/astrobwt/AstroBWT_SHA3Kernel.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/OclAstroBWTRunner.h
src/backend/opencl/runners/OclAstroBWT_v2_Runner.h
) )
list(APPEND SOURCES_BACKEND_OPENCL 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_Salsa20Kernel.cpp
src/backend/opencl/kernels/astrobwt/AstroBWT_SHA3InitialKernel.cpp src/backend/opencl/kernels/astrobwt/AstroBWT_SHA3InitialKernel.cpp
src/backend/opencl/kernels/astrobwt/AstroBWT_SHA3Kernel.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/OclAstroBWTRunner.cpp
src/backend/opencl/runners/OclAstroBWT_v2_Runner.cpp
) )
endif() endif()

View file

@ -0,0 +1,155 @@
/* XMRig
* Copyright (c) 2018-2021 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2016-2021 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#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<uint32_t>(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);
}

View file

@ -0,0 +1,78 @@
/* XMRig
* Copyright (c) 2018-2021 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2016-2021 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#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

View file

@ -94,6 +94,7 @@ const char *Algorithm::kAR2_WRKZ = "argon2/ninja";
#ifdef XMRIG_ALGO_ASTROBWT #ifdef XMRIG_ALGO_ASTROBWT
const char *Algorithm::kASTROBWT = "astrobwt"; const char *Algorithm::kASTROBWT = "astrobwt";
const char *Algorithm::kASTROBWT_DERO = "astrobwt"; const char *Algorithm::kASTROBWT_DERO = "astrobwt";
const char *Algorithm::kASTROBWT_DERO_2 = "astrobwt/v2";
#endif #endif
#ifdef XMRIG_ALGO_KAWPOW #ifdef XMRIG_ALGO_KAWPOW
@ -163,6 +164,7 @@ static const std::map<uint32_t, const char *> kAlgorithmNames = {
# ifdef XMRIG_ALGO_ASTROBWT # ifdef XMRIG_ALGO_ASTROBWT
ALGO_NAME(ASTROBWT_DERO), ALGO_NAME(ASTROBWT_DERO),
ALGO_NAME(ASTROBWT_DERO_2),
# endif # endif
# ifdef XMRIG_ALGO_KAWPOW # ifdef XMRIG_ALGO_KAWPOW
@ -282,6 +284,9 @@ static const std::map<const char *, Algorithm::Id, aliasCompare> kAlgorithmAlias
# ifdef XMRIG_ALGO_ASTROBWT # ifdef XMRIG_ALGO_ASTROBWT
ALGO_ALIAS_AUTO(ASTROBWT_DERO), ALGO_ALIAS(ASTROBWT_DERO, "astrobwt/dero"), 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 # endif
# ifdef XMRIG_ALGO_KAWPOW # ifdef XMRIG_ALGO_KAWPOW
@ -365,7 +370,7 @@ std::vector<xmrig::Algorithm> xmrig::Algorithm::all(const std::function<bool(con
CN_UPX2, CN_UPX2,
RX_0, RX_WOW, RX_ARQ, RX_GRAFT, RX_SFX, RX_KEVA, RX_0, RX_WOW, RX_ARQ, RX_GRAFT, RX_SFX, RX_KEVA,
AR2_CHUKWA, AR2_CHUKWA_V2, AR2_WRKZ, AR2_CHUKWA, AR2_CHUKWA_V2, AR2_WRKZ,
ASTROBWT_DERO, ASTROBWT_DERO, ASTROBWT_DERO_2,
KAWPOW_RVN, KAWPOW_RVN,
GHOSTRIDER_RTM GHOSTRIDER_RTM
}; };

View file

@ -82,6 +82,7 @@ public:
AR2_CHUKWA_V2 = 0x61140000, // "argon2/chukwav2" Argon2id (Chukwa v2). AR2_CHUKWA_V2 = 0x61140000, // "argon2/chukwav2" Argon2id (Chukwa v2).
AR2_WRKZ = 0x61120000, // "argon2/wrkz" Argon2id (WRKZ) AR2_WRKZ = 0x61120000, // "argon2/wrkz" Argon2id (WRKZ)
ASTROBWT_DERO = 0x41000000, // "astrobwt" AstroBWT (Dero) ASTROBWT_DERO = 0x41000000, // "astrobwt" AstroBWT (Dero)
ASTROBWT_DERO_2 = 0x41110000, // "astrobwt/v2" AstroBWT (Dero HE)
KAWPOW_RVN = 0x6b0f0000, // "kawpow/rvn" KawPow (RVN) KAWPOW_RVN = 0x6b0f0000, // "kawpow/rvn" KawPow (RVN)
}; };
@ -158,6 +159,7 @@ public:
# ifdef XMRIG_ALGO_ASTROBWT # ifdef XMRIG_ALGO_ASTROBWT
static const char *kASTROBWT; static const char *kASTROBWT;
static const char *kASTROBWT_DERO; static const char *kASTROBWT_DERO;
static const char* kASTROBWT_DERO_2;
# endif # endif
# ifdef XMRIG_ALGO_KAWPOW # ifdef XMRIG_ALGO_KAWPOW

View file

@ -45,15 +45,16 @@ struct CoinInfo
static const CoinInfo coinInfo[] = { static const CoinInfo coinInfo[] = {
{ Algorithm::INVALID, nullptr, nullptr, 0, 0, nullptr }, { Algorithm::INVALID, nullptr, nullptr, 0, 0, nullptr },
{ Algorithm::RX_0, "XMR", "Monero", 120, 1000000000000, YELLOW_BG_BOLD( WHITE_BOLD_S " monero ") }, { Algorithm::RX_0, "XMR", "Monero", 120, 1000000000000, YELLOW_BG_BOLD( WHITE_BOLD_S " monero ") },
{ Algorithm::CN_R, "SUMO", "Sumokoin", 240, 1000000000, BLUE_BG_BOLD( WHITE_BOLD_S " sumo ") }, { Algorithm::CN_R, "SUMO", "Sumokoin", 240, 1000000000, BLUE_BG_BOLD( WHITE_BOLD_S " sumo ") },
{ Algorithm::RX_ARQ, "ARQ", "ArQmA", 120, 1000000000, BLUE_BG_BOLD( WHITE_BOLD_S " arqma ") }, { Algorithm::RX_ARQ, "ARQ", "ArQmA", 120, 1000000000, BLUE_BG_BOLD( WHITE_BOLD_S " arqma ") },
{ Algorithm::ASTROBWT_DERO, "DERO", "DERO", 0, 0, BLUE_BG_BOLD( WHITE_BOLD_S " dero ") }, { Algorithm::ASTROBWT_DERO, "DERO", "DERO", 0, 0, BLUE_BG_BOLD( WHITE_BOLD_S " dero ") },
{ Algorithm::RX_GRAFT, "GRFT", "Graft", 120, 10000000000, BLUE_BG_BOLD( WHITE_BOLD_S " graft ") }, { Algorithm::ASTROBWT_DERO_2, "DERO_HE", "DERO_HE", 0, 0, BLUE_BG_BOLD( WHITE_BOLD_S " dero_he ") },
{ Algorithm::RX_KEVA, "KVA", "Kevacoin", 0, 0, MAGENTA_BG_BOLD(WHITE_BOLD_S " keva ") }, { Algorithm::RX_GRAFT, "GRFT", "Graft", 120, 10000000000, BLUE_BG_BOLD( WHITE_BOLD_S " graft ") },
{ Algorithm::KAWPOW_RVN, "RVN", "Ravencoin", 0, 0, BLUE_BG_BOLD( WHITE_BOLD_S " raven ") }, { Algorithm::RX_KEVA, "KVA", "Kevacoin", 0, 0, MAGENTA_BG_BOLD(WHITE_BOLD_S " keva ") },
{ Algorithm::RX_WOW, "WOW", "Wownero", 300, 100000000000, MAGENTA_BG_BOLD(WHITE_BOLD_S " wownero ") }, { Algorithm::KAWPOW_RVN, "RVN", "Ravencoin", 0, 0, BLUE_BG_BOLD( WHITE_BOLD_S " raven ") },
{ Algorithm::RX_WOW, "WOW", "Wownero", 300, 100000000000, MAGENTA_BG_BOLD(WHITE_BOLD_S " wownero ") },
}; };

View file

@ -36,6 +36,7 @@ public:
SUMO, SUMO,
ARQMA, ARQMA,
DERO, DERO,
DERO_HE,
GRAFT, GRAFT,
KEVA, KEVA,
RAVEN, RAVEN,

View file

@ -53,10 +53,8 @@ const uint64_t keccakf_rndc[24] =
void xmrig::keccakf(uint64_t st[25], int rounds) void xmrig::keccakf(uint64_t st[25], int rounds)
{ {
int i, j, round; for (int round = 0; round < rounds; ++round) {
uint64_t t, bc[5]; uint64_t bc[5];
for (round = 0; round < rounds; ++round) {
// Theta // Theta
bc[0] = st[0] ^ st[5] ^ st[10] ^ st[15] ^ st[20]; bc[0] = st[0] ^ st[5] ^ st[10] ^ st[15] ^ st[20];
@ -65,17 +63,21 @@ void xmrig::keccakf(uint64_t st[25], int rounds)
bc[3] = st[3] ^ st[8] ^ st[13] ^ st[18] ^ st[23]; bc[3] = st[3] ^ st[8] ^ st[13] ^ st[18] ^ st[23];
bc[4] = st[4] ^ st[9] ^ st[14] ^ st[19] ^ st[24]; bc[4] = st[4] ^ st[9] ^ st[14] ^ st[19] ^ st[24];
for (i = 0; i < 5; ++i) { #define X(i) { \
t = bc[(i + 4) % 5] ^ ROTL64(bc[(i + 1) % 5], 1); const uint64_t t = bc[(i + 4) % 5] ^ ROTL64(bc[(i + 1) % 5], 1); \
st[i ] ^= t; st[i ] ^= t; \
st[i + 5] ^= t; st[i + 5] ^= t; \
st[i + 10] ^= t; st[i + 10] ^= t; \
st[i + 15] ^= t; st[i + 15] ^= t; \
st[i + 20] ^= t; st[i + 20] ^= t; \
} }
X(0); X(1); X(2); X(3); X(4);
#undef X
// Rho Pi // Rho Pi
t = st[1]; const uint64_t t = st[1];
st[ 1] = ROTL64(st[ 6], 44); st[ 1] = ROTL64(st[ 6], 44);
st[ 6] = ROTL64(st[ 9], 20); st[ 6] = ROTL64(st[ 9], 20);
st[ 9] = ROTL64(st[22], 61); st[ 9] = ROTL64(st[22], 61);
@ -103,7 +105,7 @@ void xmrig::keccakf(uint64_t st[25], int rounds)
// Chi // Chi
// unrolled loop, where only last iteration is different // unrolled loop, where only last iteration is different
j = 0; int j = 0;
bc[0] = st[j ]; bc[0] = st[j ];
bc[1] = st[j + 1]; bc[1] = st[j + 1];

View file

@ -61,6 +61,7 @@ public:
virtual bool hasExtension(Extension extension) const noexcept = 0; virtual bool hasExtension(Extension extension) const noexcept = 0;
virtual bool isEnabled() const = 0; virtual bool isEnabled() const = 0;
virtual bool isTLS() const = 0; virtual bool isTLS() const = 0;
virtual bool isWSS() const = 0;
virtual const char *mode() const = 0; virtual const char *mode() const = 0;
virtual const char *tag() const = 0; virtual const char *tag() const = 0;
virtual const char *tlsFingerprint() const = 0; virtual const char *tlsFingerprint() const = 0;

View file

@ -59,6 +59,8 @@ protected:
void setPool(const Pool &pool) override; void setPool(const Pool &pool) override;
protected: protected:
bool isWSS() const override { return false; }
enum SocketState { enum SocketState {
UnconnectedState, UnconnectedState,
HostLookupState, HostLookupState,

View file

@ -48,8 +48,14 @@
#include "net/JobResult.h" #include "net/JobResult.h"
#ifdef XMRIG_FEATURE_TLS
#include <openssl/ssl.h>
#endif
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
#include <random>
namespace xmrig { namespace xmrig {
@ -58,7 +64,9 @@ namespace xmrig {
Storage<DaemonClient> DaemonClient::m_storage; Storage<DaemonClient> 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 *kGetHeight = "/getheight";
static const char *kGetInfo = "/getinfo"; static const char *kGetInfo = "/getinfo";
static const char *kHash = "hash"; 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 kZMQHandshake[] = "\4\x19\5READY\xbSocket-Type\0\0\0\3SUB";
static const char kZMQSubscribe[] = "\0\x18\1json-minimal-chain_main"; 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 } // namespace xmrig
@ -89,11 +105,20 @@ xmrig::DaemonClient::~DaemonClient()
{ {
delete m_timer; delete m_timer;
delete m_ZMQSocket; delete m_ZMQSocket;
# ifdef XMRIG_FEATURE_TLS
delete m_wss.m_socket;
# endif
} }
void xmrig::DaemonClient::deleteLater() void xmrig::DaemonClient::deleteLater()
{ {
# ifdef XMRIG_FEATURE_TLS
if (m_pool.isWSS()) {
WSSClose(true);
}
else
# endif
if (m_pool.zmq_port() >= 0) { if (m_pool.zmq_port() >= 0) {
ZMQClose(true); 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) int64_t xmrig::DaemonClient::submit(const JobResult &result)
{ {
if (result.jobId != m_currentJobId) { 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<const uint8_t*>(&result.nonce), 4); Cvt::toHex(data + m_job.nonceOffset() * 2, 8, reinterpret_cast<const uint8_t*>(&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<int>(sizeof(buf))) {
return WSSWrite(buf, n) ? 1 : -1;
}
return -1;
}
# endif
if (m_blocktemplate.hasMinerSignature()) { if (m_blocktemplate.hasMinerSignature()) {
Cvt::toHex(data + sig_offset * 2, 128, result.minerSignature(), 64); Cvt::toHex(data + sig_offset * 2, 128, result.minerSignature(), 64);
} }
@ -193,19 +235,24 @@ void xmrig::DaemonClient::connect()
setState(ConnectingState); setState(ConnectingState);
if (!m_walletAddress.isValid()) {
return connectError("Invalid wallet address.");
}
if (!m_coin.isValid() && !m_pool.algorithm().isValid()) { if (!m_coin.isValid() && !m_pool.algorithm().isValid()) {
return connectError("Invalid algorithm."); 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; 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); m_dns = Dns::resolve(m_pool.host(), this);
} }
else { else {
@ -306,6 +353,9 @@ void xmrig::DaemonClient::onTimer(const Timer *)
connect(); connect();
} }
else if (m_state == ConnectedState) { else if (m_state == ConnectedState) {
if (m_pool.isWSS()) {
return;
}
if (m_apiVersion == API_DERO) { if (m_apiVersion == API_DERO) {
rpcSend(JsonRequest::create(m_sequence, "get_info")); 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(); const auto &record = records.get();
m_ip = record.ip(); m_ip = record.ip();
auto req = new uv_connect_t; auto req = new uv_connect_t;
req->data = m_storage.ptr(m_key); req->data = m_storage.ptr(m_key);
m_ZMQSocket = new uv_tcp_t; uv_tcp_t* s = new uv_tcp_t;
m_ZMQSocket->data = m_storage.ptr(m_key); s->data = m_storage.ptr(m_key);
uv_tcp_init(uv_default_loop(), m_ZMQSocket); uv_tcp_init(uv_default_loop(), s);
uv_tcp_nodelay(m_ZMQSocket, 1); uv_tcp_nodelay(s, 1);
# ifndef WIN32 # ifndef WIN32
uv_tcp_keepalive(m_ZMQSocket, 1, 60); uv_tcp_keepalive(s, 1, 60);
# endif # 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 &params, int *code)
); );
# endif # endif
m_blockhashingblob = Json::getString(params, "blockhashing_blob"); m_blockhashingblob = Json::getString(params, kBlockhashingBlob);
if (m_blocktemplate.hasMinerSignature()) { if (m_blocktemplate.hasMinerSignature()) {
if (m_pool.spendSecretKey().isEmpty()) { if (m_pool.spendSecretKey().isEmpty()) {
@ -589,6 +648,12 @@ void xmrig::DaemonClient::retry()
setState(ConnectingState); setState(ConnectingState);
} }
# ifdef XMRIG_FEATURE_TLS
if (m_wss.m_socket) {
uv_close(reinterpret_cast<uv_handle_t*>(m_wss.m_socket), onWSSClose);
}
else
# endif
if ((m_ZMQConnectionState != ZMQ_NOT_CONNECTED) && (m_ZMQConnectionState != ZMQ_DISCONNECTING)) { if ((m_ZMQConnectionState != ZMQ_NOT_CONNECTED) && (m_ZMQConnectionState != ZMQ_DISCONNECTING)) {
uv_close(reinterpret_cast<uv_handle_t*>(m_ZMQSocket), onZMQClose); uv_close(reinterpret_cast<uv_handle_t*>(m_ZMQSocket), onZMQClose);
} }
@ -913,3 +978,377 @@ bool xmrig::DaemonClient::ZMQClose(bool shutdown)
return false; 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<uv_stream_t*>(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<uint8_t>(size);
}
else if (size < 65536) {
h.payload_len = 126;
size_buf[0] = static_cast<uint8_t>(size >> 8);
size_buf[1] = static_cast<uint8_t>(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<uint8_t>(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<int>(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<uv_stream_t*>(m_wss.m_socket), &buf, 1);
BIO_reset(m_wss.m_write);
if (static_cast<size_t>(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<int>(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<int>(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<uint8_t*>(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<int>(sizeof(WSS::Header)))
continue;
const WSS::Header* h = reinterpret_cast<const WSS::Header*>(p);
p += sizeof(WSS::Header);
uint64_t len = h->payload_len;
if (len == 126) {
if (e - p < static_cast<int>(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<int>(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<uint64_t>(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<uv_handle_t*>(m_wss.m_socket)) == 0)) {
uv_close(reinterpret_cast<uv_handle_t*>(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

View file

@ -39,6 +39,12 @@ using uv_handle_t = struct uv_handle_s;
using uv_stream_t = struct uv_stream_s; using uv_stream_t = struct uv_stream_s;
using uv_tcp_t = struct uv_tcp_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 { namespace xmrig {
@ -57,6 +63,7 @@ public:
protected: protected:
bool disconnect() override; bool disconnect() override;
bool isTLS() const override; bool isTLS() const override;
bool isWSS() const override;
int64_t submit(const JobResult &result) override; int64_t submit(const JobResult &result) override;
void connect() override; void connect() override;
void connect(const Pool &pool) override; void connect(const Pool &pool) override;
@ -136,6 +143,45 @@ private:
std::vector<char> m_ZMQSendBuf; std::vector<char> m_ZMQSendBuf;
std::vector<char> m_ZMQRecvBuf; std::vector<char> 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<char> m_data;
std::vector<char> m_message;
void cleanup();
} m_wss;
# endif
}; };

View file

@ -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 uint32_t xmrig::Job::getNumTransactions() const
{ {
if (!(m_algorithm.isCN() || m_algorithm.family() == Algorithm::RANDOM_X)) { if (!(m_algorithm.isCN() || m_algorithm.family() == Algorithm::RANDOM_X)) {

View file

@ -76,7 +76,7 @@ public:
inline const String &poolWallet() const { return m_poolWallet; } inline const String &poolWallet() const { return m_poolWallet; }
inline const uint32_t *nonce() const { return reinterpret_cast<const uint32_t*>(m_blob + nonceOffset()); } inline const uint32_t *nonce() const { return reinterpret_cast<const uint32_t*>(m_blob + nonceOffset()); }
inline const uint8_t *blob() const { return m_blob; } 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 nonceSize() const { return (algorithm().family() == Algorithm::KAWPOW) ? 8 : 4; }
inline size_t size() const { return m_size; } inline size_t size() const { return m_size; }
inline uint32_t *nonce() { return reinterpret_cast<uint32_t*>(m_blob + nonceOffset()); } inline uint32_t *nonce() { return reinterpret_cast<uint32_t*>(m_blob + nonceOffset()); }

View file

@ -76,6 +76,7 @@ const char *Pool::kSelfSelect = "self-select";
const char *Pool::kSOCKS5 = "socks5"; const char *Pool::kSOCKS5 = "socks5";
const char *Pool::kSubmitToOrigin = "submit-to-origin"; const char *Pool::kSubmitToOrigin = "submit-to-origin";
const char *Pool::kTls = "tls"; const char *Pool::kTls = "tls";
const char *Pool::kWSS = "wss";
const char *Pool::kUrl = "url"; const char *Pool::kUrl = "url";
const char *Pool::kUser = "user"; const char *Pool::kUser = "user";
const char *Pool::kSpendSecretKey = "spend-secret-key"; 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_keepAlive(keepAlive),
m_mode(mode), m_mode(mode),
m_flags(1 << FLAG_ENABLED), 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_NICEHASH, nicehash || strstr(host, kNicehashHost));
m_flags.set(FLAG_TLS, tls); 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_ENABLED, Json::getBool(object, kEnabled, true));
m_flags.set(FLAG_NICEHASH, Json::getBool(object, kNicehash) || m_url.host().contains(kNicehashHost)); 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_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)); 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(kEnabled), m_flags.test(FLAG_ENABLED), allocator);
obj.AddMember(StringRef(kTls), isTLS(), allocator); obj.AddMember(StringRef(kTls), isTLS(), allocator);
obj.AddMember(StringRef(kWSS), isWSS(), allocator);
obj.AddMember(StringRef(kFingerprint), m_fingerprint.toJSON(), allocator); obj.AddMember(StringRef(kFingerprint), m_fingerprint.toJSON(), allocator);
obj.AddMember(StringRef(kDaemon), m_mode == MODE_DAEMON, allocator); obj.AddMember(StringRef(kDaemon), m_mode == MODE_DAEMON, allocator);
obj.AddMember(StringRef(kSOCKS5), m_proxy.toJSON(doc), allocator); obj.AddMember(StringRef(kSOCKS5), m_proxy.toJSON(doc), allocator);

View file

@ -69,10 +69,12 @@ public:
static const char *kSOCKS5; static const char *kSOCKS5;
static const char *kSubmitToOrigin; static const char *kSubmitToOrigin;
static const char *kTls; static const char *kTls;
static const char* kWSS;
static const char *kUrl; static const char *kUrl;
static const char *kUser; static const char *kUser;
static const char* kSpendSecretKey; static const char* kSpendSecretKey;
static const char* kDaemonZMQPort; static const char* kDaemonZMQPort;
static const char* kDaemonWSSPort;
static const char *kNicehashHost; static const char *kNicehashHost;
constexpr static int kKeepAliveTimeout = 60; constexpr static int kKeepAliveTimeout = 60;
@ -80,7 +82,7 @@ public:
constexpr static uint64_t kDefaultPollInterval = 1000; constexpr static uint64_t kDefaultPollInterval = 1000;
Pool() = default; 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 char *url);
Pool(const rapidjson::Value &object); Pool(const rapidjson::Value &object);
@ -93,6 +95,7 @@ public:
inline bool isNicehash() const { return m_flags.test(FLAG_NICEHASH); } 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 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 bool isValid() const { return m_url.isValid(); }
inline const Algorithm &algorithm() const { return m_algorithm; } inline const Algorithm &algorithm() const { return m_algorithm; }
inline const Coin &coin() const { return m_coin; } inline const Coin &coin() const { return m_coin; }
@ -135,6 +138,7 @@ private:
FLAG_ENABLED, FLAG_ENABLED,
FLAG_NICEHASH, FLAG_NICEHASH,
FLAG_TLS, FLAG_TLS,
FLAG_WSS,
FLAG_MAX FLAG_MAX
}; };

View file

@ -49,6 +49,7 @@ protected:
inline bool hasExtension(Extension extension) const noexcept override { return m_client->hasExtension(extension); } inline bool hasExtension(Extension extension) const noexcept override { return m_client->hasExtension(extension); }
inline bool isEnabled() const override { return m_client->isEnabled(); } inline bool isEnabled() const override { return m_client->isEnabled(); }
inline bool isTLS() const override { return m_client->isTLS(); } 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 *mode() const override { return m_client->mode(); }
inline const char *tag() const override { return m_client->tag(); } inline const char *tag() const override { return m_client->tag(); }
inline const char *tlsFingerprint() const override { return m_client->tlsFingerprint(); } inline const char *tlsFingerprint() const override { return m_client->tlsFingerprint(); }

View file

@ -39,6 +39,7 @@ static const char kSOCKS5[] = "socks5://";
#ifdef XMRIG_FEATURE_HTTP #ifdef XMRIG_FEATURE_HTTP
static const char kDaemonHttp[] = "daemon+http://"; static const char kDaemonHttp[] = "daemon+http://";
static const char kDaemonHttps[] = "daemon+https://"; static const char kDaemonHttps[] = "daemon+https://";
static const char kDaemonWss[] = "daemon+wss://";
#endif #endif
} // namespace xmrig } // namespace xmrig
@ -103,6 +104,11 @@ bool xmrig::Url::parse(const char *url)
m_scheme = DAEMON; m_scheme = DAEMON;
m_tls = false; m_tls = false;
} }
else if (strncasecmp(url, kDaemonWss, sizeof(kDaemonWss) - 1) == 0) {
m_scheme = DAEMON;
m_tls = true;
m_wss = true;
}
# endif # endif
else { else {
return false; return false;

View file

@ -41,6 +41,7 @@ public:
Url(const char *host, uint16_t port, bool tls = false, Scheme scheme = UNSPECIFIED); Url(const char *host, uint16_t port, bool tls = false, Scheme scheme = UNSPECIFIED);
inline bool isTLS() const { return m_tls; } 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 bool isValid() const { return !m_host.isNull() && m_port > 0; }
inline const String &host() const { return m_host; } inline const String &host() const { return m_host; }
inline const String &url() const { return m_url; } inline const String &url() const { return m_url; }
@ -57,6 +58,7 @@ protected:
bool parseIPv6(const char *addr); bool parseIPv6(const char *addr);
bool m_tls = false; bool m_tls = false;
bool m_wss = false;
Scheme m_scheme = UNSPECIFIED; Scheme m_scheme = UNSPECIFIED;
String m_host; String m_host;
String m_url; String m_url;

View file

@ -41,6 +41,7 @@ public:
inline bool hasExtension(Extension) const noexcept override { return false; } inline bool hasExtension(Extension) const noexcept override { return false; }
inline bool isEnabled() const override { return true; } inline bool isEnabled() const override { return true; }
inline bool isTLS() const override { return false; } 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 *mode() const override { return "benchmark"; }
inline const char *tlsFingerprint() const override { return nullptr; } inline const char *tlsFingerprint() const override { return nullptr; }
inline const char *tlsVersion() const override { return nullptr; } inline const char *tlsVersion() const override { return nullptr; }

View file

@ -23,10 +23,12 @@
#include <stdlib.h> #include <stdlib.h>
#define bswap_64(x) _byteswap_uint64(x) #define bswap_64(x) _byteswap_uint64(x)
#define bswap_32(x) _byteswap_ulong(x)
#elif defined __GNUC__ #elif defined __GNUC__
#define bswap_64(x) __builtin_bswap64(x) #define bswap_64(x) __builtin_bswap64(x)
#define bswap_32(x) __builtin_bswap32(x)
#else #else

View file

@ -25,6 +25,7 @@
#include "base/crypto/sha3.h" #include "base/crypto/sha3.h"
#include "base/tools/bswap_64.h" #include "base/tools/bswap_64.h"
#include "crypto/cn/CryptoNight.h" #include "crypto/cn/CryptoNight.h"
#include "crypto/astrobwt/sort_indices2.h"
#include <limits> #include <limits>
@ -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() void xmrig::astrobwt::init()
{ {
if (!astrobwtInitialized) { if (!astrobwtInitialized) {
@ -450,3 +490,10 @@ void xmrig::astrobwt::single_hash<xmrig::Algorithm::ASTROBWT_DERO>(const uint8_t
{ {
astrobwt_dero(input, static_cast<uint32_t>(size), ctx[0]->memory, output, std::numeric_limits<int>::max(), true); astrobwt_dero(input, static_cast<uint32_t>(size), ctx[0]->memory, output, std::numeric_limits<int>::max(), true);
} }
template<>
void xmrig::astrobwt::single_hash<xmrig::Algorithm::ASTROBWT_DERO_2>(const uint8_t* input, size_t size, uint8_t* output, cryptonight_ctx** ctx, uint64_t)
{
astrobwt_dero_v2(input, static_cast<uint32_t>(size), ctx[0]->memory, output);
}

View file

@ -32,6 +32,7 @@ namespace xmrig {
namespace astrobwt { 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(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(); void init();
template<Algorithm::Id ALGO> template<Algorithm::Id ALGO>
@ -40,5 +41,7 @@ void single_hash(const uint8_t* input, size_t size, uint8_t* output, cryptonight
template<> template<>
void single_hash<Algorithm::ASTROBWT_DERO>(const uint8_t* input, size_t size, uint8_t* output, cryptonight_ctx** ctx, uint64_t); void single_hash<Algorithm::ASTROBWT_DERO>(const uint8_t* input, size_t size, uint8_t* output, cryptonight_ctx** ctx, uint64_t);
template<>
void single_hash<Algorithm::ASTROBWT_DERO_2>(const uint8_t* input, size_t size, uint8_t* output, cryptonight_ctx** ctx, uint64_t);
}} // namespace xmrig::astrobwt }} // namespace xmrig::astrobwt

View file

@ -0,0 +1,208 @@
/* XMRig
* Copyright (c) 2018 Lee Clagett <https://github.com/vtnerd>
* Copyright (c) 2018-2019 tevador <tevador@gmail.com>
* Copyright (c) 2000 Transmeta Corporation <https://github.com/intel/msr-tools>
* Copyright (c) 2004-2008 H. Peter Anvin <https://github.com/intel/msr-tools>
* Copyright (c) 2018-2021 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2016-2021 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "crypto/astrobwt/sort_indices2.h"
#include "base/tools/bswap_64.h"
#include <cstring>
#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);
}

View file

@ -0,0 +1,26 @@
/* XMRig
* Copyright (c) 2018 Lee Clagett <https://github.com/vtnerd>
* Copyright (c) 2018-2019 tevador <tevador@gmail.com>
* Copyright (c) 2000 Transmeta Corporation <https://github.com/intel/msr-tools>
* Copyright (c) 2004-2008 H. Peter Anvin <https://github.com/intel/msr-tools>
* Copyright (c) 2018-2021 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2016-2021 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <stdint.h>
void sort_indices_astrobwt_v2(uint32_t N, const uint8_t* v, uint32_t* indices, uint32_t* tmp_indices);

View file

@ -379,6 +379,10 @@ xmrig::CnHash::CnHash()
m_map[Algorithm::ASTROBWT_DERO] = new cn_hash_fun_array{}; m_map[Algorithm::ASTROBWT_DERO] = new cn_hash_fun_array{};
m_map[Algorithm::ASTROBWT_DERO]->data[AV_SINGLE][Assembly::NONE] = astrobwt::single_hash<Algorithm::ASTROBWT_DERO>; m_map[Algorithm::ASTROBWT_DERO]->data[AV_SINGLE][Assembly::NONE] = astrobwt::single_hash<Algorithm::ASTROBWT_DERO>;
m_map[Algorithm::ASTROBWT_DERO]->data[AV_SINGLE_SOFT][Assembly::NONE] = astrobwt::single_hash<Algorithm::ASTROBWT_DERO>; m_map[Algorithm::ASTROBWT_DERO]->data[AV_SINGLE_SOFT][Assembly::NONE] = astrobwt::single_hash<Algorithm::ASTROBWT_DERO>;
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<Algorithm::ASTROBWT_DERO_2>;
m_map[Algorithm::ASTROBWT_DERO_2]->data[AV_SINGLE_SOFT][Assembly::NONE] = astrobwt::single_hash<Algorithm::ASTROBWT_DERO_2>;
# endif # endif
# ifdef XMRIG_ALGO_GHOSTRIDER # ifdef XMRIG_ALGO_GHOSTRIDER

View file

@ -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 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 #endif

View file

@ -773,6 +773,11 @@ void hash_octa(const uint8_t* data, size_t size, uint8_t* output, cryptonight_ct
{ {
constexpr uint32_t N = 8; 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) // PrevBlockHash (GhostRider's seed) is stored in bytes [4; 36)
const uint8_t* seed = data + 4; 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 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]; uint8_t tmp[64 * N];
for (uint64_t part = 0; part < 3; ++part) { for (size_t part = 0; part < 3; ++part) {
for (uint64_t i = 0; i < 5; ++i) {
for (uint64_t j = 0; j < N; ++j) { // Allocate scratchpads
core_hash[core_indices[part * 5 + i]](data + j * size, size, tmp + j * 64); {
data = tmp; uint8_t* p = ctx_memory[0];
size = 64;
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 (uint64_t j = 0, k = step[cn_indices[part]]; j < N; j += k) {
f[part](tmp + j * 64, 64, output + j * 32, ctx, 0); 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;
} }
for (uint64_t j = 0; j < N; ++j) {
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 (size_t j = 0; j < N; ++j) {
memcpy(tmp + j * 64, output + j * 32, 32); memcpy(tmp + j * 64, output + j * 32, 32);
memset(tmp + j * 64 + 32, 0, 32); memset(tmp + j * 64 + 32, 0, 32);
} }
} }
for (size_t i = 0; i < N; ++i) {
ctx[i]->memory = ctx_memory[i];
}
} }

View file

@ -1,6 +1,6 @@
/* XMRig /* XMRig
* Copyright (c) 2018-2021 SChernykh <https://github.com/SChernykh> * Copyright (c) 2018-2022 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2016-2021 XMRig <https://github.com/xmrig>, <support@xmrig.com> * Copyright (c) 2016-2022 XMRig <https://github.com/xmrig>, <support@xmrig.com>
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -70,9 +70,9 @@ xmrig::DonateStrategy::DonateStrategy(Controller *controller, IStrategyListener
# endif # endif
# ifdef XMRIG_FEATURE_TLS # 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 # 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) { if (m_pools.size() > 1) {
m_strategy = new FailoverStrategy(m_pools, 10, 2, this, true); 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() void xmrig::DonateStrategy::connect()
{ {
# ifdef XMRIG_ALGO_ASTROBWT
if (m_algorithm == Algorithm::ASTROBWT_DERO_2) {
return;
}
# endif
m_proxy = createProxy(); m_proxy = createProxy();
if (m_proxy) { if (m_proxy) {
m_proxy->connect(); m_proxy->connect();
@ -252,7 +258,7 @@ xmrig::IClient *xmrig::DonateStrategy::createProxy()
const IClient *client = strategy->client(); const IClient *client = strategy->client();
m_tls = client->hasExtension(IClient::EXT_TLS); 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.setAlgo(client->pool().algorithm());
pool.setProxy(client->pool().proxy()); pool.setProxy(client->pool().proxy());

View file

@ -1,6 +1,6 @@
/* XMRig /* XMRig
* Copyright (c) 2018-2021 SChernykh <https://github.com/SChernykh> * Copyright (c) 2018-2022 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2016-2021 XMRig <https://github.com/xmrig>, <support@xmrig.com> * Copyright (c) 2016-2022 XMRig <https://github.com/xmrig>, <support@xmrig.com>
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/* XMRig /* XMRig
* Copyright (c) 2018-2021 SChernykh <https://github.com/SChernykh> * Copyright (c) 2018-2022 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2016-2021 XMRig <https://github.com/xmrig>, <support@xmrig.com> * Copyright (c) 2016-2022 XMRig <https://github.com/xmrig>, <support@xmrig.com>
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -22,15 +22,15 @@
#define APP_ID "xmrig" #define APP_ID "xmrig"
#define APP_NAME "XMRig" #define APP_NAME "XMRig"
#define APP_DESC "XMRig miner" #define APP_DESC "XMRig miner"
#define APP_VERSION "6.16.4" #define APP_VERSION "6.17.0-dev"
#define APP_DOMAIN "xmrig.com" #define APP_DOMAIN "xmrig.com"
#define APP_SITE "www.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_KIND "miner"
#define APP_VER_MAJOR 6 #define APP_VER_MAJOR 6
#define APP_VER_MINOR 16 #define APP_VER_MINOR 17
#define APP_VER_PATCH 4 #define APP_VER_PATCH 0
#ifdef _MSC_VER #ifdef _MSC_VER
# if (_MSC_VER >= 1930) # if (_MSC_VER >= 1930)