Sfoglia il codice sorgente

Merge branch 'jtgrassie-affinity'

tevador 7 anni fa
parent
commit
77f809e8db

+ 9 - 3
makefile

@@ -2,6 +2,7 @@
 #CC=gcc-8
 AR=gcc-ar
 PLATFORM=$(shell uname -m)
+OS=$(shell uname -s)
 CXXFLAGS=-std=c++11
 CCFLAGS=-std=c99
 ARFLAGS=rcs
@@ -21,6 +22,9 @@ ifeq ($(PLATFORM),x86_64)
     RXOBJS += $(addprefix $(OBJDIR)/,jit_compiler_x86_static.o jit_compiler_x86.o)
     CXXFLAGS += -maes
 endif
+ifeq ($(OS),Darwin)
+    AR=ar
+endif
 
 ifeq ($(PLATFORM),ppc64)
     CXXFLAGS += -mcpu=native
@@ -61,11 +65,13 @@ $(OBJDIR):
 	mkdir $(OBJDIR)
 $(BINDIR):
 	mkdir $(BINDIR)
+$(OBJDIR)/affinity.o: $(TESTDIR)/affinity.cpp $(TESTDIR)/affinity.hpp
+	$(CXX) $(CXXFLAGS) -c $< -o $@
 $(OBJDIR)/benchmark.o: $(TESTDIR)/benchmark.cpp $(TESTDIR)/stopwatch.hpp \
- $(TESTDIR)/utility.hpp $(SRCDIR)/randomx.h $(SRCDIR)/blake2/endian.h
+ $(TESTDIR)/utility.hpp $(SRCDIR)/randomx.h $(SRCDIR)/blake2/endian.h $(TESTDIR)/affinity.hpp
 	$(CXX) $(CXXFLAGS) -pthread -c $< -o $@
-$(BINDIR)/randomx-benchmark: $(OBJDIR)/benchmark.o $(RXA)
-	$(CXX) $(LDFLAGS) -pthread $< $(RXA) -o $@
+$(BINDIR)/randomx-benchmark: $(OBJDIR)/benchmark.o $(OBJDIR)/affinity.o $(RXA)
+	$(CXX) $(LDFLAGS) -pthread $< $(OBJDIR)/affinity.o $(RXA) -o $@
 $(OBJDIR)/code-generator.o: $(TESTDIR)/code-generator.cpp $(TESTDIR)/utility.hpp \
  $(SRCDIR)/common.hpp $(SRCDIR)/blake2/endian.h \
  $(SRCDIR)/configuration.h $(SRCDIR)/randomx.h \

+ 117 - 0
src/tests/affinity.cpp

@@ -0,0 +1,117 @@
+/*
+Copyright (c) 2019, jtgrassie
+Copyright (c) 2019, tevador <tevador@gmail.com>
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+	* Redistributions of source code must retain the above copyright
+	  notice, this list of conditions and the following disclaimer.
+	* Redistributions in binary form must reproduce the above copyright
+	  notice, this list of conditions and the following disclaimer in the
+	  documentation and/or other materials provided with the distribution.
+	* Neither the name of the copyright holder nor the
+	  names of its contributors may be used to endorse or promote products
+	  derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <sstream>
+
+#if defined(_WIN32) || defined(__CYGWIN__)
+  #include <windows.h>
+#else
+  #ifdef __APPLE__
+    #include <mach/thread_act.h>
+    #include <mach/thread_policy.h>
+  #endif
+  #include <pthread.h>
+#endif
+#include "affinity.hpp"
+
+int
+set_thread_affinity(const unsigned &cpuid)
+{
+    std::thread::native_handle_type thread;
+#if defined(_WIN32) || defined(__CYGWIN__)
+    thread = static_cast<std::thread::native_handle_type>(GetCurrentThread());
+#else
+    thread = static_cast<std::thread::native_handle_type>(pthread_self());
+#endif
+    return set_thread_affinity(thread, cpuid);
+}
+
+int
+set_thread_affinity(std::thread::native_handle_type thread,
+        const unsigned &cpuid)
+{
+    int rc = -1;
+#ifdef __APPLE__
+    thread_port_t mach_thread;
+    thread_affinity_policy_data_t policy = { static_cast<integer_t>(cpuid) };
+    mach_thread = pthread_mach_thread_np(thread);
+    rc = thread_policy_set(mach_thread, THREAD_AFFINITY_POLICY,
+            (thread_policy_t)&policy, 1);
+#elif defined(_WIN32) || defined(__CYGWIN__)
+    rc = SetThreadAffinityMask(thread, 1ULL << cpuid) == 0 ? -2 : 0;
+#else
+    cpu_set_t cs;
+    CPU_ZERO(&cs);
+    CPU_SET(cpuid, &cs);
+    rc = pthread_setaffinity_np(thread, sizeof(cpu_set_t), &cs);
+#endif
+    return rc;
+}
+
+unsigned
+cpuid_from_mask(uint64_t mask, const unsigned &thread_index)
+{
+    static unsigned lookup[64];
+    static bool init = false;
+    if (init)
+        return lookup[thread_index];
+    unsigned count_found = 0;
+    for (unsigned i=0; i<64; i++)
+    {
+        if (1ULL & mask)
+        {
+            lookup[count_found] = i;
+            count_found++;
+        }
+        mask >>= 1;
+    }
+    init = true;
+    return lookup[thread_index];
+}
+
+std::string
+mask_to_string(uint64_t mask)
+{
+	std::ostringstream ss;
+    unsigned len = 0;
+    unsigned v = 0;
+    unsigned i = 64;
+    while (i--)
+    {
+        v = mask >> i;
+		if (1ULL & v)
+		{
+			if (len == 0) len = i + 1;
+			ss << '1';
+		}
+		else
+			if (len > 0) ss << '0';
+    }
+    return ss.str();
+}

+ 39 - 0
src/tests/affinity.hpp

@@ -0,0 +1,39 @@
+/*
+Copyright (c) 2019, jtgrassie
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+	* Redistributions of source code must retain the above copyright
+	  notice, this list of conditions and the following disclaimer.
+	* Redistributions in binary form must reproduce the above copyright
+	  notice, this list of conditions and the following disclaimer in the
+	  documentation and/or other materials provided with the distribution.
+	* Neither the name of the copyright holder nor the
+	  names of its contributors may be used to endorse or promote products
+	  derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#pragma once
+
+#include <cstddef>
+#include <thread>
+#include <string>
+
+int set_thread_affinity(const unsigned &cpuid);
+int set_thread_affinity(std::thread::native_handle_type thread,
+        const unsigned &cpuid);
+unsigned cpuid_from_mask(uint64_t mask, const unsigned &thread_index);
+std::string mask_to_string(uint64_t mask);

+ 20 - 3
src/tests/benchmark.cpp

@@ -43,6 +43,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <windows.h>
 #include <VersionHelpers.h>
 #endif
+#include "affinity.hpp"
 
 const uint8_t blockTemplate_[] = {
 		0x07, 0x07, 0xf7, 0xa4, 0xf0, 0xd6, 0x05, 0xb3, 0x03, 0x26, 0x08, 0x16, 0xba, 0x3f, 0x10, 0x90, 0x2e, 0x1a, 0x14,
@@ -84,6 +85,7 @@ void printUsage(const char* executable) {
 	std::cout << "  --largePages  use large pages" << std::endl;
 	std::cout << "  --softAes     use software AES (default: x86 AES-NI)" << std::endl;
 	std::cout << "  --threads T   use T threads (default: 1)" << std::endl;
+	std::cout << "  --affinity A  thread affinity bitmask (default: 0)" << std::endl;
 	std::cout << "  --init Q      initialize dataset with Q threads (default: 1)" << std::endl;
 	std::cout << "  --nonces N    run N nonces (default: 1000)" << std::endl;
 	std::cout << "  --seed S      seed for cache initialization (default: 0)" << std::endl;
@@ -102,7 +104,13 @@ struct DatasetAllocException : public MemoryException {
 	}
 };
 
-void mine(randomx_vm* vm, std::atomic<uint32_t>& atomicNonce, AtomicHash& result, uint32_t noncesCount, int thread) {
+void mine(randomx_vm* vm, std::atomic<uint32_t>& atomicNonce, AtomicHash& result, uint32_t noncesCount, int thread, int cpuid=-1) {
+	if (cpuid >= 0) {
+		int rc = set_thread_affinity(cpuid);
+		if (rc) {
+			std::cerr << "Failed to set thread affinity for thread " << thread << " (error=" << rc << ")" <<  std::endl;
+		}
+	}
 	uint64_t hash[RANDOMX_HASH_SIZE / sizeof(uint64_t)];
 	uint8_t blockTemplate[sizeof(blockTemplate_)];
 	memcpy(blockTemplate, blockTemplate_, sizeof(blockTemplate));
@@ -120,6 +128,7 @@ void mine(randomx_vm* vm, std::atomic<uint32_t>& atomicNonce, AtomicHash& result
 int main(int argc, char** argv) {
 	bool softAes, miningMode, verificationMode, help, largePages, jit;
 	int noncesCount, threadCount, initThreadCount;
+	uint64_t threadAffinity;
 	int32_t seedValue;
 	char seed[4];
 
@@ -127,6 +136,7 @@ int main(int argc, char** argv) {
 	readOption("--mine", argc, argv, miningMode);
 	readOption("--verify", argc, argv, verificationMode);
 	readIntOption("--threads", argc, argv, threadCount, 1);
+	readUInt64Option("--affinity", argc, argv, threadAffinity, 0);
 	readIntOption("--nonces", argc, argv, noncesCount, 1000);
 	readIntOption("--init", argc, argv, initThreadCount, 1);
 	readIntOption("--seed", argc, argv, seedValue, 0);
@@ -183,6 +193,10 @@ int main(int argc, char** argv) {
 		std::cout << " - small pages mode" << std::endl;
 	}
 
+	if (threadAffinity) {
+		std::cout << " - thread affinity (" << mask_to_string(threadAffinity) << ")" << std::endl;
+	}
+
 	std::cout << "Initializing";
 	if (miningMode)
 		std::cout << " (" << initThreadCount << " thread" << (initThreadCount > 1 ? "s)" : ")");
@@ -237,10 +251,13 @@ int main(int argc, char** argv) {
 		sw.restart();
 		if (threadCount > 1) {
 			for (unsigned i = 0; i < vms.size(); ++i) {
+				int cpuid = -1;
+				if (threadAffinity)
+					cpuid = cpuid_from_mask(threadAffinity, i);
 				if (softAes)
-					threads.push_back(std::thread(&mine, vms[i], std::ref(atomicNonce), std::ref(result), noncesCount, i));
+					threads.push_back(std::thread(&mine, vms[i], std::ref(atomicNonce), std::ref(result), noncesCount, i, cpuid));
 				else
-					threads.push_back(std::thread(&mine, vms[i], std::ref(atomicNonce), std::ref(result), noncesCount, i));
+					threads.push_back(std::thread(&mine, vms[i], std::ref(atomicNonce), std::ref(result), noncesCount, i, cpuid));
 			}
 			for (unsigned i = 0; i < threads.size(); ++i) {
 				threads[i].join();

+ 9 - 0
src/tests/utility.hpp

@@ -96,6 +96,15 @@ inline void readIntOption(const char* option, int argc, char** argv, int& out, i
 	out = defaultValue;
 }
 
+inline void readUInt64Option(const char* option, int argc, char** argv, uint64_t& out, uint64_t defaultValue) {
+	for (int i = 0; i < argc - 1; ++i) {
+		if (strcmp(argv[i], option) == 0 && (out = std::strtoull(argv[i + 1], NULL, 0)) > 0) {
+			return;
+		}
+	}
+	out = defaultValue;
+}
+
 inline void readFloatOption(const char* option, int argc, char** argv, double& out, double defaultValue) {
 	for (int i = 0; i < argc - 1; ++i) {
 		if (strcmp(argv[i], option) == 0 && (out = atof(argv[i + 1])) > 0) {

+ 1 - 0
vcxproj/benchmark.vcxproj

@@ -115,6 +115,7 @@
     </Link>
   </ItemDefinitionGroup>
   <ItemGroup>
+    <ClCompile Include="..\src\tests\affinity.cpp" />
     <ClCompile Include="..\src\tests\benchmark.cpp" />
   </ItemGroup>
   <ItemGroup>

+ 3 - 0
vcxproj/benchmark.vcxproj.filters

@@ -18,6 +18,9 @@
     <ClCompile Include="..\src\tests\benchmark.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="..\src\tests\affinity.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\src\tests\utility.hpp">

+ 1 - 0
vcxproj/tests.vcxproj

@@ -109,6 +109,7 @@
       <IntrinsicFunctions>true</IntrinsicFunctions>
       <SDLCheck>true</SDLCheck>
       <ConformanceMode>true</ConformanceMode>
+      <EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
     </ClCompile>
     <Link>
       <EnableCOMDATFolding>true</EnableCOMDATFolding>