Prechádzať zdrojové kódy

Getting cache line width on MS-Windows.

David Piuva 10 mesiacov pred
rodič
commit
c8339878af
2 zmenil súbory, kde vykonal 50 pridanie a 41 odobranie
  1. 8 2
      Source/DFPSR/base/SafePointer.h
  2. 42 39
      Source/DFPSR/base/heap.cpp

+ 8 - 2
Source/DFPSR/base/SafePointer.h

@@ -143,14 +143,20 @@ public:
 	}
 	}
 	inline T& operator*() const {
 	inline T& operator*() const {
 		#ifdef SAFE_POINTER_CHECKS
 		#ifdef SAFE_POINTER_CHECKS
-		assertInside("operator*");
+		assertInside("operator *");
 		#endif
 		#endif
 		return *(this->data);
 		return *(this->data);
 	}
 	}
+	inline T* operator ->() const {
+		#ifdef SAFE_POINTER_CHECKS
+		assertInside("operator ->");
+		#endif
+		return this->data;
+	}
 	inline T& operator[] (intptr_t index) const {
 	inline T& operator[] (intptr_t index) const {
 		T* address = this->data + index;
 		T* address = this->data + index;
 		#ifdef SAFE_POINTER_CHECKS
 		#ifdef SAFE_POINTER_CHECKS
-		assertInside("operator[]", address);
+		assertInside("operator []", address);
 		#endif
 		#endif
 		return *address;
 		return *address;
 	}
 	}

+ 42 - 39
Source/DFPSR/base/heap.cpp

@@ -59,7 +59,7 @@ namespace dsr {
 	// There is no point in using a heap alignment smaller than the allocation heads, so we align to at least 64 bytes.
 	// There is no point in using a heap alignment smaller than the allocation heads, so we align to at least 64 bytes.
 	static const uintptr_t minimumHeapAlignment = 64;
 	static const uintptr_t minimumHeapAlignment = 64;
 	#if defined(USE_LINUX)
 	#if defined(USE_LINUX)
-		static int32_t getCacheLineSizeFromIndices(int32_t cpuIndex, int32_t cacheLevel) {
+		static uintptr_t getCacheLineSizeFromIndices(uintptr_t cpuIndex, uintptr_t cacheLevel) {
 			char path[256];
 			char path[256];
 			snprintf(path, sizeof(path), "/sys/devices/system/cpu/cpu%i/cache/index%i/coherency_line_size", (int)cpuIndex, (int)cacheLevel);
 			snprintf(path, sizeof(path), "/sys/devices/system/cpu/cpu%i/cache/index%i/coherency_line_size", (int)cpuIndex, (int)cacheLevel);
 			FILE *file = fopen(path, "r");
 			FILE *file = fopen(path, "r");
@@ -71,14 +71,14 @@ namespace dsr {
 				cacheLineSize = -1;
 				cacheLineSize = -1;
 			}
 			}
 			fclose(file);
 			fclose(file);
-			return int32_t(cacheLineSize);
+			return uintptr_t(cacheLineSize);
 		}
 		}
-		static int32_t getCacheLineSize() {
-			int32_t result = 0;
-			int32_t cpuIndex = 0;
-			int32_t cacheLevel = 0;
+		static uintptr_t getCacheLineSize() {
+			uintptr_t result = 0;
+			uintptr_t cpuIndex = 0;
+			uintptr_t cacheLevel = 0;
 			while (true) {
 			while (true) {
-				int32_t newSize = getCacheLineSizeFromIndices(cpuIndex, cacheLevel);
+				uintptr_t newSize = getCacheLineSizeFromIndices(cpuIndex, cacheLevel);
 				if (newSize == -1) {
 				if (newSize == -1) {
 					if (cacheLevel == 0) {
 					if (cacheLevel == 0) {
 						// CPU does not exist, so we are done.
 						// CPU does not exist, so we are done.
@@ -105,8 +105,8 @@ namespace dsr {
 			return result;
 			return result;
 		}
 		}
 	#elif defined(USE_MACOS)
 	#elif defined(USE_MACOS)
-		static int32_t getCacheLineSize() {
-			int32_t result = 0;
+		static uintptr_t getCacheLineSize() {
+			uintptr_t result = 0;
 			int cacheLine;
 			int cacheLine;
 			size_t size = sizeof(cacheLine);
 			size_t size = sizeof(cacheLine);
 			int mib[2] = {CTL_HW, HW_CACHELINE};
 			int mib[2] = {CTL_HW, HW_CACHELINE};
@@ -116,37 +116,48 @@ namespace dsr {
 				#ifdef DSR_PRINT_CACHE_LINE_SIZE
 				#ifdef DSR_PRINT_CACHE_LINE_SIZE
 					printf("Detected a cache line width of %i bytes on MacOS by asking for HW_CACHELINE with sysctl.\n", (int)result);
 					printf("Detected a cache line width of %i bytes on MacOS by asking for HW_CACHELINE with sysctl.\n", (int)result);
 				#endif
 				#endif
-			} else if(error == EFAULT) {
-				printf("WARNING! Failed to read HW_CACHELINE on MacOS because of a bad address error. The application might not be thread-safe.\n");
-			} else if(error == EINVAL) {
-				printf("WARNING! Failed to read HW_CACHELINE on MacOS because of a bad argument error. The application might not be thread-safe.\n");
-			} else if(error == ENOMEM) {
-				printf("WARNING! Failed to read HW_CACHELINE on MacOS because of an out of memory error. The application might not be thread-safe.\n");
-			} else if(error == ENOTDIR) {
-				printf("WARNING! Failed to read HW_CACHELINE on MacOS because of a not a directory error. The application might not be thread-safe.\n");
-			} else if(error == EISDIR) {
-				printf("WARNING! Failed to read HW_CACHELINE on MacOS because of a directory error. The application might not be thread-safe.\n");
-			} else if(error == EPERM) {
-				printf("WARNING! Failed to read HW_CACHELINE on MacOS because of a permission error. The application might not be thread-safe.\n");
 			} else {
 			} else {
 				result = defaultCacheLineSize;
 				result = defaultCacheLineSize;
-				printf("WARNING! Failed to read HW_CACHELINE on MacOS with an unknown error. The application might not be thread-safe.\n");
+				printf("WARNING! Failed to read HW_CACHELINE on MacOS. The application might not be thread-safe.\n");
 			}
 			}
 			return result;
 			return result;
 		}
 		}
-	/*
 	#elif defined(USE_MICROSOFT_WINDOWS)
 	#elif defined(USE_MICROSOFT_WINDOWS)
-		static int32_t getCacheLineSize() {
-			int32_t result = ?; // TODO: Implement
-			return result;
-		}*/
-	#else
-		static int32_t getCacheLineSize() {
-			int32_t result = 0;
+		static uintptr_t getCacheLineSize() {
+			DWORD bufferSize = 0;
+			GetLogicalProcessorInformation(nullptr, &bufferSize);
+			SYSTEM_LOGICAL_PROCESSOR_INFORMATION *buffer = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION *)malloc(bufferSize);
+			uintptr_t result = 0;
+			if (buffer == nullptr) {
+				result = defaultCacheLineSize;
+				printf("WARNING! Failed to allocate buffer for the call to GetLogicalProcessorInformation on MS-Windows. The application might not be thread-safe.\n");
+			} else if (GetLogicalProcessorInformation(buffer, &bufferSize)) {
+				SYSTEM_LOGICAL_PROCESSOR_INFORMATION *entry = buffer;
+				SYSTEM_LOGICAL_PROCESSOR_INFORMATION *lastEntry = buffer + (bufferSize / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION)) - 1;
+				while (entry <= lastEntry) {
+					if (entry->Relationship == RelationCache) {
+						uintptr_t currentLineSize = entry->Cache.LineSize;
+						if (currentLineSize > result) {
+							result = currentLineSize;
+						}
+					}
+					entry++;
+				}
+				#ifdef DSR_PRINT_CACHE_LINE_SIZE
+					printf("Detected a cache line width of %i bytes on MS-Windows by checking each RelationCache with GetLogicalProcessorInformation.\n", (int)result);
+				#endif
+			} else {
 				result = defaultCacheLineSize;
 				result = defaultCacheLineSize;
-				printf("WARNING! The target platform does not have a method for detecting cache line width in DFPSR/base/heap.cpp.\n");
+				printf("WARNING! The call to GetLogicalProcessorInformation failed to get the cache line size on MS-Windows. The application might not be thread-safe.\n");
+			}
+			free(buffer);
 			return result;
 			return result;
 		}
 		}
+	#else
+		static uintptr_t getCacheLineSize() {
+			printf("WARNING! The target platform does not have a method for detecting cache line width in DFPSR/base/heap.cpp.\n");
+			return defaultCacheLineSize;
+		}
 	#endif
 	#endif
 
 
 	static uintptr_t heapAlignmentAndMask = 0u;
 	static uintptr_t heapAlignmentAndMask = 0u;
@@ -317,14 +328,6 @@ namespace dsr {
 		};
 		};
 		HeapDestructor destructor;
 		HeapDestructor destructor;
 		uintptr_t useCount = 0; // How many handles that point to the data.
 		uintptr_t useCount = 0; // How many handles that point to the data.
-		// TODO: Allow placing a pointer to a singleton in another heap allocation, which will simply be freed using heap_free when the owner is freed.
-		//       This allow accessing any amount of additional information shared between all handles to the same payload.
-		//       Useful when you in hindsight realize that you need more information attached to something that is already created and shared, like a value allocated image needing a texture.
-		//       Check if it already exists. If it does not exist, lock the allocation mutex and check again if it still does not exist, before allocating the singleton.
-		//         Then there will only be a mutex overhead for accessing the singleton when accessed for the first time.
-		//         Once created, it can not go away until the allocation that knows about it is gone.
-		//       If using the reference counting, the singleton could also be reused between different allocations.
-		// void *singleton = nullptr;
 		// TODO: Allow the caller to access custom bit flags in allocations.
 		// TODO: Allow the caller to access custom bit flags in allocations.
 		// uint32_t userFlags = 0;
 		// uint32_t userFlags = 0;
 		HeapFlag flags = 0; // Flags use the heapFlag_ prefix.
 		HeapFlag flags = 0; // Flags use the heapFlag_ prefix.