949f45ac / xmr-stak-hip

Monero HIP miner with custom optimizations – Development continues at xmrig-HIP
GNU General Public License v3.0
9 stars 1 forks source link

Development continues elsewhere

https://github.com/949f45ac/xmrig-HIP

This repo contains

Fully functional miner that runs with a proof of concept for a ~3% optimization in the core CryptoNight algorithm. This optimization could theoretically be implemented on every GPU compute platform/framework.

This miner, however, currently works only on Linux. It can run:

The code is based on xmr-stak-nvidia, i.e. the original CUDA part of xmr-stak. I have ported it to HIP, which is a framework developed by AMD that allows writing GPU compute code that can be built for both Nvidia GPUs (where it will be cross-compiled via CUDA and hence run with barely any performance impact) and AMD GPUs (where it uses the new "ROCm" driver stack).

If you aren't technically literate/interested, I would not recommend trying to use this miner. It is relatively complicated to set up, and for little gain. If the optimization turns out to be useful and stable, it can be incorporated into the normal xmr-stak anyway. (If you run only Nvidia cards, you may check out the pre-built binary I’ve put up in the "releases" section. The only GPU lib it requires to run is libcudart, so it’s pretty portable across Linux systems.)

Build environment

Building

Make sure you export the HIP_PLATFORM variable correctly in each case. I think if you paste all lines into the terminal at once, it might not work properly on some shells.

To build for target AMD:

mkdir build && cd build
export HIP_PLATFORM=hcc
cmake .. -DCUDA_COMPILER=/opt/rocm/bin/hipcc -DHIP_PLATFORM=hcc -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DHIP_ROOT_DIR=/opt/rocm/hip -DMICROHTTPD_REQUIRED=OFF
make

When you build for AMD, an executable named xmr-stak-test will also be created in the binary output folder, allowing quick validation of the miner.

To build for target CUDA:

mkdir cuda_build && cd cuda_build
export HIP_PLATFORM=nvcc
cmake .. -DCUDA_COMPILER=/opt/rocm/bin/hipcc -DHIP_PLATFORM=nvcc -DCUDA_ARCH=30 -DCUDA_PATH=/usr -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DHIP_ROOT_DIR=/opt/rocm/hip -DMICROHTTPD_REQUIRED=OFF
make

You may have to export CUDA_PATH into your shell environment so HIP can find it.

Running / configuring

Configuration is done CUDA-style with threads/blocks for both platforms.

I.e. threads * blocks * 2 must always be at least 200 less than available GPU memory in MB, and blocks should be a multiple of CU count for optimal performance.

As for threads:

Core-algo optimization brief summary

In the core loop of the CryptoNight algorithm, execution speed is basically directly dependant on the speed of scratchpad loads.

On AMD GCN ISA, memory operations are actually split in two: One operation to request the store/load, another operation – s_wait vmcnt(n) – to wait on outstanding memory operations.

We can use this to build "async" loads: First, schedule the load. Then do something else while the load runs. Finally, s_wait for the load to finish if it hasn’t yet.

Asynchronous loads introduce a new angle of optimization: Scheduling a load operation as early as possible maximizes the amount of work we can do while the load is executing, therefor reducing wasted time.

Until here, this could just be the compiler’s job, and I guess that AMD’s GPU compilers have some logic for this.

But the compiler cannot know we’re running an algorithm that is so extremely ill-fitted to GPU computing; it cannot know how important loads really are to us.

It turns out that loads are that narrow bottlenecks, it pays off to schedule them ahead of the normally preceding scratchpad-store operations.

This means we have to check whether we actually loaded stale data (small chance, but would corrupt our whole result) that was supposed to have been overwritten by the preceding store, and if so, use the value we just stored instead.

Doing this check introduces plenty of additional operations, but since they can mostly be executed while the load is still running, it still pays off.

On CUDA, memory operations cannot be run asynchronous like that. Instead we use prefetch to achieve a similar effect. Theoretically we wouldn’t have to execute stores and loads in the wrong order, with this method, but somehow the proper order was still slower, in testing.

Regarding donations

Please note that I haven’t changed the donation address after forking from xmr-stak-nvidia, hence you’ll still be donating to the original devs.

If you enjoyed this work and want to drop me some crypto coins, please use:

XMR: 45FbpewbfJf6wp7gkwAqtwNc7wqnpEeJdUH2QRgeLPhZ1Chhi2qs4sNQKJX4Ek2jm946zmyBYnH6SFVCdL5aMjqRHodYYsF

BTC: 181TVrHPjeVZuKdqEsz8n9maqFLJAzTLc

If you gave a star to this repository, I’d also be glad already. :)