From 328a911379d445c9acef1b67f429e8c3454dda6c Mon Sep 17 00:00:00 2001 From: Michael Jones Date: Wed, 22 Jun 2022 22:32:34 +0100 Subject: Cycles: Distinguish Apple GPUs by core count This patch suffixes Apple GPU device names with `(GPU - # cores)` so that variant GPUs with the same chipset can be distinguished. Currently benchmark scores for these M1 family GPUs are being incorrectly merged: - M1: 7 or 8 cores - M1 Pro: 14 or 16 cores - M1 Max: 24 or 32 cores - M1 Ultra: 48 or 64 cores Reviewed By: brecht, sergey Differential Revision: https://developer.blender.org/D15257 --- intern/cycles/device/metal/device.mm | 14 +++----- intern/cycles/device/metal/device_impl.h | 1 - intern/cycles/device/metal/device_impl.mm | 6 ++-- intern/cycles/device/metal/util.h | 11 +++++- intern/cycles/device/metal/util.mm | 59 ++++++++++++++++++++++++++----- release/scripts/addons | 2 +- source/tools | 2 +- 7 files changed, 70 insertions(+), 25 deletions(-) diff --git a/intern/cycles/device/metal/device.mm b/intern/cycles/device/metal/device.mm index d7f190fc01e..51e3323370a 100644 --- a/intern/cycles/device/metal/device.mm +++ b/intern/cycles/device/metal/device.mm @@ -34,7 +34,8 @@ void device_metal_info(vector &devices) int device_index = 0; for (id &device : usable_devices) { /* Compute unique ID for persistent user preferences. */ - string device_name = [device.name UTF8String]; + string device_name = MetalInfo::get_device_name(device); + string id = string("METAL_") + device_name; /* Hardware ID might not be unique, add device number in that case. */ @@ -48,12 +49,6 @@ void device_metal_info(vector &devices) info.type = DEVICE_METAL; info.description = string_remove_trademark(string(device_name)); - /* Ensure unique naming on Apple Silicon / SoC devices which return the same string for CPU and - * GPU */ - if (info.description == system_cpu_brand_string()) { - info.description += " (GPU)"; - } - info.num = device_index; /* We don't know if it's used for display, but assume it is. */ info.display_device = true; @@ -69,14 +64,15 @@ string device_metal_capabilities() { string result = ""; auto allDevices = MTLCopyAllDevices(); - uint32_t num_devices = allDevices.count; + uint32_t num_devices = (uint32_t)allDevices.count; if (num_devices == 0) { return "No Metal devices found\n"; } result += string_printf("Number of devices: %u\n", num_devices); for (id device in allDevices) { - result += string_printf("\t\tDevice: %s\n", [device.name UTF8String]); + string device_name = MetalInfo::get_device_name(device); + result += string_printf("\t\tDevice: %s\n", device_name.c_str()); } return result; diff --git a/intern/cycles/device/metal/device_impl.h b/intern/cycles/device/metal/device_impl.h index 0e6817d94f8..4aea8d697a5 100644 --- a/intern/cycles/device/metal/device_impl.h +++ b/intern/cycles/device/metal/device_impl.h @@ -42,7 +42,6 @@ class MetalDevice : public Device { nil; /* encoder used for fetching device pointers from MTLAccelerationStructure */ /*---------------------------------------------------*/ - string device_name; MetalGPUVendor device_vendor; uint kernel_features; diff --git a/intern/cycles/device/metal/device_impl.mm b/intern/cycles/device/metal/device_impl.mm index 0a89055af34..0954f586d40 100644 --- a/intern/cycles/device/metal/device_impl.mm +++ b/intern/cycles/device/metal/device_impl.mm @@ -9,6 +9,7 @@ # include "util/debug.h" # include "util/md5.h" # include "util/path.h" +# include "util/time.h" CCL_NAMESPACE_BEGIN @@ -43,10 +44,9 @@ MetalDevice::MetalDevice(const DeviceInfo &info, Stats &stats, Profiler &profile auto usable_devices = MetalInfo::get_usable_devices(); assert(mtlDevId < usable_devices.size()); mtlDevice = usable_devices[mtlDevId]; - device_name = [mtlDevice.name UTF8String]; - device_vendor = MetalInfo::get_vendor_from_device_name(device_name); + device_vendor = MetalInfo::get_device_vendor(mtlDevice); assert(device_vendor != METAL_GPU_UNKNOWN); - metal_printf("Creating new Cycles device for Metal: %s\n", device_name.c_str()); + metal_printf("Creating new Cycles device for Metal: %s\n", info.description.c_str()); /* determine default storage mode based on whether UMA is supported */ diff --git a/intern/cycles/device/metal/util.h b/intern/cycles/device/metal/util.h index f728967835d..fd32d8a260f 100644 --- a/intern/cycles/device/metal/util.h +++ b/intern/cycles/device/metal/util.h @@ -25,10 +25,19 @@ enum MetalGPUVendor { METAL_GPU_INTEL = 3, }; +enum AppleGPUArchitecture { + APPLE_UNKNOWN, + APPLE_M1, + APPLE_M2, +}; + /* Contains static Metal helper functions. */ struct MetalInfo { static vector> const &get_usable_devices(); - static MetalGPUVendor get_vendor_from_device_name(string const &device_name); + static int get_apple_gpu_core_count(id device); + static MetalGPUVendor get_device_vendor(id device); + static AppleGPUArchitecture get_apple_gpu_architecture(id device); + static string get_device_name(id device); }; /* Pool of MTLBuffers whose lifetime is linked to a single MTLCommandBuffer */ diff --git a/intern/cycles/device/metal/util.mm b/intern/cycles/device/metal/util.mm index a6bd593bcb6..a7a5b596b8f 100644 --- a/intern/cycles/device/metal/util.mm +++ b/intern/cycles/device/metal/util.mm @@ -10,21 +10,63 @@ # include "util/string.h" # include "util/time.h" +# include # include # include # include CCL_NAMESPACE_BEGIN -MetalGPUVendor MetalInfo::get_vendor_from_device_name(string const &device_name) +string MetalInfo::get_device_name(id device) { - if (device_name.find("Intel") != string::npos) { + string device_name = [device.name UTF8String]; + if (get_device_vendor(device) == METAL_GPU_APPLE) { + /* Append the GPU core count so we can distinguish between GPU variants in benchmarks. */ + int gpu_core_count = get_apple_gpu_core_count(device); + device_name += string_printf(gpu_core_count ? " (GPU - %d cores)" : " (GPU)", gpu_core_count); + } + return device_name; +} + +int MetalInfo::get_apple_gpu_core_count(id device) +{ + int core_count = 0; + if (@available(macos 12.0, *)) { + io_service_t gpu_service = IOServiceGetMatchingService( + kIOMainPortDefault, IORegistryEntryIDMatching(device.registryID)); + if (CFNumberRef numberRef = (CFNumberRef)IORegistryEntryCreateCFProperty( + gpu_service, CFSTR("gpu-core-count"), 0, 0)) { + if (CFGetTypeID(numberRef) == CFNumberGetTypeID()) { + CFNumberGetValue(numberRef, kCFNumberSInt32Type, &core_count); + } + CFRelease(numberRef); + } + } + return core_count; +} + +AppleGPUArchitecture MetalInfo::get_apple_gpu_architecture(id device) +{ + const char *device_name = [device.name UTF8String]; + if (strstr(device_name, "M1")) { + return APPLE_M1; + } + else if (strstr(device_name, "M2")) { + return APPLE_M2; + } + return APPLE_UNKNOWN; +} + +MetalGPUVendor MetalInfo::get_device_vendor(id device) +{ + const char *device_name = [device.name UTF8String]; + if (strstr(device_name, "Intel")) { return METAL_GPU_INTEL; } - else if (device_name.find("AMD") != string::npos) { + else if (strstr(device_name, "AMD")) { return METAL_GPU_AMD; } - else if (device_name.find("Apple") != string::npos) { + else if (strstr(device_name, "Apple")) { return METAL_GPU_APPLE; } return METAL_GPU_UNKNOWN; @@ -41,9 +83,8 @@ vector> const &MetalInfo::get_usable_devices() metal_printf("Usable Metal devices:\n"); for (id device in MTLCopyAllDevices()) { - const char *device_name = [device.name UTF8String]; - - MetalGPUVendor vendor = get_vendor_from_device_name(device_name); + string device_name = get_device_name(device); + MetalGPUVendor vendor = get_device_vendor(device); bool usable = false; if (@available(macos 12.2, *)) { @@ -55,12 +96,12 @@ vector> const &MetalInfo::get_usable_devices() } if (usable) { - metal_printf("- %s\n", device_name); + metal_printf("- %s\n", device_name.c_str()); [device retain]; usable_devices.push_back(device); } else { - metal_printf(" (skipping \"%s\")\n", device_name); + metal_printf(" (skipping \"%s\")\n", device_name.c_str()); } } if (usable_devices.empty()) { diff --git a/release/scripts/addons b/release/scripts/addons index bdf75cb276d..c51e0bb1793 160000 --- a/release/scripts/addons +++ b/release/scripts/addons @@ -1 +1 @@ -Subproject commit bdf75cb276dfd3b5266c909de4c099c00c68a659 +Subproject commit c51e0bb1793c44c7a1b7435593dd5022cf7c8eec diff --git a/source/tools b/source/tools index 01b4c0e4a17..ccc8fceb6bd 160000 --- a/source/tools +++ b/source/tools @@ -1 +1 @@ -Subproject commit 01b4c0e4a172819414229445c314be34527bf412 +Subproject commit ccc8fceb6bd83ffbf6e5207247fb8f76fc47a5b6 -- cgit v1.2.3