Skip to content

Commit

Permalink
Revert "Unload drivers which report 0 physical devices"
Browse files Browse the repository at this point in the history
This reverts commit ba275bd.
  • Loading branch information
charles-lunarg committed Dec 18, 2023
1 parent 984164a commit a79e2d6
Show file tree
Hide file tree
Showing 6 changed files with 39 additions and 267 deletions.
107 changes: 16 additions & 91 deletions loader/loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ loader_platform_thread_mutex loader_global_instance_list_lock;
// functionality, but the fact that the libraries already been loaded causes any call that needs to load ICD libraries to speed up
// significantly. This can have a huge impact when making repeated calls to vkEnumerateInstanceExtensionProperties and
// vkCreateInstance.
struct loader_icd_tramp_list preloaded_icds;
struct loader_icd_tramp_list scanned_icds;

// controls whether loader_platform_close_library() closes the libraries or not - controlled by an environment
// variables - this is just the definition of the variable, usage is in vk_loader_platform.h
Expand Down Expand Up @@ -1342,24 +1342,6 @@ struct loader_icd_term *loader_icd_add(struct loader_instance *ptr_inst, const s

return icd_term;
}
// Closes the library handle in the scanned ICD, free the lib_name string, and zeros out all data
void loader_unload_scanned_icd(struct loader_instance *inst, struct loader_scanned_icd *scanned_icd) {
if (NULL == scanned_icd) {
return;
}
if (scanned_icd->handle) {
loader_platform_close_library(scanned_icd->handle);
scanned_icd->handle = NULL;
}
loader_instance_heap_free(inst, scanned_icd->lib_name);
scanned_icd->lib_name = NULL;
scanned_icd->CreateInstance = NULL;
scanned_icd->EnumerateInstanceExtensionProperties = NULL;
scanned_icd->GetInstanceProcAddr = NULL;
scanned_icd->GetPhysicalDeviceProcAddr = NULL;
scanned_icd->api_version = 0;
scanned_icd->interface_version = 0;
}

// Determine the ICD interface version to use.
// @param icd
Expand Down Expand Up @@ -1395,7 +1377,7 @@ bool loader_get_icd_interface_version(PFN_vkNegotiateLoaderICDInterfaceVersion f
return true;
}

void loader_clear_scanned_icd_list(const struct loader_instance *inst, struct loader_icd_tramp_list *icd_tramp_list) {
void loader_scanned_icd_clear(const struct loader_instance *inst, struct loader_icd_tramp_list *icd_tramp_list) {
if (0 != icd_tramp_list->capacity && icd_tramp_list->scanned_list) {
for (uint32_t i = 0; i < icd_tramp_list->count; i++) {
if (icd_tramp_list->scanned_list[i].handle) {
Expand All @@ -1411,14 +1393,14 @@ void loader_clear_scanned_icd_list(const struct loader_instance *inst, struct lo
icd_tramp_list->scanned_list = NULL;
}

VkResult loader_init_scanned_icd_list(const struct loader_instance *inst, struct loader_icd_tramp_list *icd_tramp_list) {
VkResult loader_scanned_icd_init(const struct loader_instance *inst, struct loader_icd_tramp_list *icd_tramp_list) {
VkResult res = VK_SUCCESS;
loader_clear_scanned_icd_list(inst, icd_tramp_list);
loader_scanned_icd_clear(inst, icd_tramp_list);
icd_tramp_list->capacity = 8 * sizeof(struct loader_scanned_icd);
icd_tramp_list->scanned_list = loader_instance_heap_alloc(inst, icd_tramp_list->capacity, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
if (NULL == icd_tramp_list->scanned_list) {
loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
"loader_init_scanned_icd_list: Realloc failed for layer list when attempting to add new layer");
"loader_scanned_icd_init: Realloc failed for layer list when attempting to add new layer");
res = VK_ERROR_OUT_OF_HOST_MEMORY;
}
return res;
Expand Down Expand Up @@ -1894,22 +1876,22 @@ void loader_preload_icds(void) {
loader_platform_thread_lock_mutex(&loader_preload_icd_lock);

// Already preloaded, skip loading again.
if (preloaded_icds.scanned_list != NULL) {
if (scanned_icds.scanned_list != NULL) {
loader_platform_thread_unlock_mutex(&loader_preload_icd_lock);
return;
}

VkResult result = loader_icd_scan(NULL, &preloaded_icds, NULL, NULL);
VkResult result = loader_icd_scan(NULL, &scanned_icds, NULL, NULL);
if (result != VK_SUCCESS) {
loader_clear_scanned_icd_list(NULL, &preloaded_icds);
loader_scanned_icd_clear(NULL, &scanned_icds);
}
loader_platform_thread_unlock_mutex(&loader_preload_icd_lock);
}

// Release the ICD libraries that were preloaded
void loader_unload_preloaded_icds(void) {
loader_platform_thread_lock_mutex(&loader_preload_icd_lock);
loader_clear_scanned_icd_list(NULL, &preloaded_icds);
loader_scanned_icd_clear(NULL, &scanned_icds);
loader_platform_thread_unlock_mutex(&loader_preload_icd_lock);
}

Expand Down Expand Up @@ -3579,7 +3561,7 @@ VkResult loader_icd_scan(const struct loader_instance *inst, struct loader_icd_t
struct ICDManifestInfo *icd_details = NULL;

// Set up the ICD Trampoline list so elements can be written into it.
res = loader_init_scanned_icd_list(inst, icd_tramp_list);
res = loader_scanned_icd_init(inst, icd_tramp_list);
if (res == VK_ERROR_OUT_OF_HOST_MEMORY) {
return res;
}
Expand Down Expand Up @@ -5536,6 +5518,8 @@ VKAPI_ATTR void VKAPI_CALL terminator_DestroyInstance(VkInstance instance, const
if (NULL == ptr_instance) {
return;
}
struct loader_icd_term *icd_terms = ptr_instance->icd_terms;
struct loader_icd_term *next_icd_term;

// Remove this instance from the list of instances:
struct loader_instance *prev = NULL;
Expand All @@ -5555,19 +5539,18 @@ VKAPI_ATTR void VKAPI_CALL terminator_DestroyInstance(VkInstance instance, const
}
loader_platform_thread_unlock_mutex(&loader_global_instance_list_lock);

struct loader_icd_term *icd_terms = ptr_instance->icd_terms;
while (NULL != icd_terms) {
if (icd_terms->instance) {
icd_terms->dispatch.DestroyInstance(icd_terms->instance, pAllocator);
}
struct loader_icd_term *next_icd_term = icd_terms->next;
next_icd_term = icd_terms->next;
icd_terms->instance = VK_NULL_HANDLE;
loader_icd_destroy(ptr_instance, icd_terms, pAllocator);

icd_terms = next_icd_term;
}

loader_clear_scanned_icd_list(ptr_instance, &ptr_instance->icd_tramp_list);
loader_scanned_icd_clear(ptr_instance, &ptr_instance->icd_tramp_list);
loader_destroy_generic_list(ptr_instance, (struct loader_generic_list *)&ptr_instance->ext_list);
if (NULL != ptr_instance->phys_devs_term) {
for (uint32_t i = 0; i < ptr_instance->phys_dev_count_term; i++) {
Expand Down Expand Up @@ -6201,7 +6184,6 @@ VkResult setup_loader_term_phys_devs(struct loader_instance *inst) {
}
icd_phys_dev_array[icd_idx].icd_term = icd_term;
icd_phys_dev_array[icd_idx].icd_index = icd_idx;
icd_term->physical_device_count = icd_phys_dev_array[icd_idx].device_count;
icd_term = icd_term->next;
++icd_idx;
}
Expand Down Expand Up @@ -6366,63 +6348,6 @@ VkResult setup_loader_term_phys_devs(struct loader_instance *inst) {

return res;
}
/**
* Iterates through all drivers and unloads any which do not contain physical devices.
* This saves address space, which for 32 bit applications is scarse.
* This must only be called after a call to vkEnumeratePhysicalDevices that isn't just querying the count
*/
void unload_drivers_without_physical_devices(struct loader_instance *inst) {
struct loader_icd_term *cur_icd_term = inst->icd_terms;
struct loader_icd_term *prev_icd_term = NULL;

while (NULL != cur_icd_term) {
struct loader_icd_term *next_icd_term = cur_icd_term->next;
if (cur_icd_term->physical_device_count == 0) {
uint32_t cur_scanned_icd_index = UINT32_MAX;
if (inst->icd_tramp_list.scanned_list) {
for (uint32_t i = 0; i < inst->icd_tramp_list.count; i++) {
if (&(inst->icd_tramp_list.scanned_list[i]) == cur_icd_term->scanned_icd) {
cur_scanned_icd_index = i;
break;
}
}
}
if (cur_scanned_icd_index != UINT32_MAX) {
loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
"Removing driver %s due to not having any physical devices", cur_icd_term->scanned_icd->lib_name);
if (cur_icd_term->instance) {
cur_icd_term->dispatch.DestroyInstance(cur_icd_term->instance, &(inst->alloc_callbacks));
}
cur_icd_term->instance = VK_NULL_HANDLE;
loader_icd_destroy(inst, cur_icd_term, &(inst->alloc_callbacks));
cur_icd_term = NULL;
struct loader_scanned_icd *scanned_icd_to_remove = &inst->icd_tramp_list.scanned_list[cur_scanned_icd_index];
// Iterate through preloaded ICDs and remove the corresponding driver from that list
loader_platform_thread_lock_mutex(&loader_preload_icd_lock);
if (NULL != preloaded_icds.scanned_list) {
for (uint32_t i = 0; i < preloaded_icds.count; i++) {
if (strcmp(preloaded_icds.scanned_list[i].lib_name, scanned_icd_to_remove->lib_name) == 0) {
loader_unload_scanned_icd(inst, &preloaded_icds.scanned_list[i]);
break;
}
}
}
loader_platform_thread_unlock_mutex(&loader_preload_icd_lock);

loader_unload_scanned_icd(inst, scanned_icd_to_remove);
}

if (NULL == prev_icd_term) {
inst->icd_terms = next_icd_term;
} else {
prev_icd_term->next = next_icd_term;
}
} else {
prev_icd_term = cur_icd_term;
}
cur_icd_term = next_icd_term;
}
}

VkResult setup_loader_tramp_phys_dev_groups(struct loader_instance *inst, uint32_t group_count,
VkPhysicalDeviceGroupProperties *groups) {
Expand Down Expand Up @@ -6738,7 +6663,7 @@ terminator_EnumerateInstanceExtensionProperties(const VkEnumerateInstanceExtensi
}
} else {
// Preload ICD libraries so subsequent calls to EnumerateInstanceExtensionProperties don't have to load them
// loader_preload_icds();
loader_preload_icds();

// Scan/discover all ICD libraries
res = loader_icd_scan(NULL, &icd_tramp_list, NULL, NULL);
Expand All @@ -6751,7 +6676,7 @@ terminator_EnumerateInstanceExtensionProperties(const VkEnumerateInstanceExtensi
if (VK_SUCCESS != res) {
goto out;
}
loader_clear_scanned_icd_list(NULL, &icd_tramp_list);
loader_scanned_icd_clear(NULL, &icd_tramp_list);

// Append enabled implicit layers.
res = loader_scan_for_implicit_layers(NULL, &instance_layers, &layer_filters);
Expand Down
5 changes: 2 additions & 3 deletions loader/loader.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,8 @@ void loader_destroy_pointer_layer_list(const struct loader_instance *inst, struc
void loader_delete_layer_list_and_properties(const struct loader_instance *inst, struct loader_layer_list *layer_list);
void loader_remove_layer_in_list(const struct loader_instance *inst, struct loader_layer_list *layer_list,
uint32_t layer_to_remove);
VkResult loader_init_scanned_icd_list(const struct loader_instance *inst, struct loader_icd_tramp_list *icd_tramp_list);
void loader_clear_scanned_icd_list(const struct loader_instance *inst, struct loader_icd_tramp_list *icd_tramp_list);
VkResult loader_scanned_icd_init(const struct loader_instance *inst, struct loader_icd_tramp_list *icd_tramp_list);
void loader_scanned_icd_clear(const struct loader_instance *inst, struct loader_icd_tramp_list *icd_tramp_list);
VkResult loader_icd_scan(const struct loader_instance *inst, struct loader_icd_tramp_list *icd_tramp_list,
const VkInstanceCreateInfo *pCreateInfo, bool *skipped_portability_drivers);
void loader_icd_destroy(struct loader_instance *ptr_inst, struct loader_icd_term *icd_term,
Expand Down Expand Up @@ -199,7 +199,6 @@ VkResult loader_validate_device_extensions(struct loader_instance *this_instance
VkResult setup_loader_tramp_phys_devs(struct loader_instance *inst, uint32_t phys_dev_count, VkPhysicalDevice *phys_devs);
VkResult setup_loader_tramp_phys_dev_groups(struct loader_instance *inst, uint32_t group_count,
VkPhysicalDeviceGroupProperties *groups);
void unload_drivers_without_physical_devices(struct loader_instance *inst);

VkStringErrorFlags vk_string_validate(const int max_length, const char *char_array);
char *loader_get_next_path(char *path);
Expand Down
2 changes: 0 additions & 2 deletions loader/loader_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -229,8 +229,6 @@ struct loader_icd_term {

PFN_PhysDevExt phys_dev_ext[MAX_NUM_UNKNOWN_EXTS];
bool supports_get_dev_prop_2;

uint32_t physical_device_count;
};

// Per ICD library structure
Expand Down
6 changes: 1 addition & 5 deletions loader/trampoline.c
Original file line number Diff line number Diff line change
Expand Up @@ -773,7 +773,7 @@ LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateInstance(const VkInstanceCr
loader_destroy_pointer_layer_list(ptr_instance, &ptr_instance->app_activated_layer_list);

loader_delete_layer_list_and_properties(ptr_instance, &ptr_instance->instance_layer_list);
loader_clear_scanned_icd_list(ptr_instance, &ptr_instance->icd_tramp_list);
loader_scanned_icd_clear(ptr_instance, &ptr_instance->icd_tramp_list);
loader_destroy_generic_list(ptr_instance, (struct loader_generic_list *)&ptr_instance->ext_list);

// Free any icd_terms that were created.
Expand Down Expand Up @@ -895,15 +895,11 @@ LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDevices(VkInstan
if (VK_SUCCESS != update_res) {
res = update_res;
}

// Unloads any drivers that do not expose any physical devices - should save some address space
unload_drivers_without_physical_devices(inst);
}

out:

loader_platform_thread_unlock_mutex(&loader_lock);

return res;
}

Expand Down
59 changes: 20 additions & 39 deletions tests/live_verification/time_dynamic_loading.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,45 +30,26 @@
#include <chrono>
#include <iostream>
#include <vector>
#include <string>
#include <iomanip>
#include <thread>

int main() {
// uint32_t iterations = 20;
// std::vector<std::chrono::microseconds> samples;
// samples.resize(iterations);
// for (uint32_t i = 0; i < iterations; i++) {
// auto t1 = std::chrono::system_clock::now();
// uint32_t count = 0;
// vkEnumerateInstanceExtensionProperties(nullptr, &count, nullptr);
// // vkEnumerateInstanceLayerProperties(&count, nullptr);
// // vkEnumerateInstanceVersion(&count);
// auto t2 = std::chrono::system_clock::now();
// samples[i] = std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1);
// }
// std::chrono::microseconds total_time{};
// for (uint32_t i = 0; i < iterations; i++) {
// total_time += samples[i];
// }
// std::cout << "average time " << total_time.count() / iterations << " (μs)\n";
// std::cout << std::setw(10) << "Iteration" << std::setw(12) << " Time (μs)\n";
// for (uint32_t i = 0; i < iterations; i++) {
// std::cout << std::setw(10) << std::to_string(i) << std::setw(12) << samples[i].count() << "\n";
// }

uint32_t count = 0;
VkInstanceCreateInfo ci{};
VkInstance i{};
auto res = vkCreateInstance(&ci, nullptr, &i);
if (res != VK_SUCCESS) return -1;
std::cout << "After called vkCreateInstance\n";
do {
std::cout << '\n' << "Press a key to continue...";
} while (std::cin.get() != '\n');
vkDestroyInstance(i, nullptr);
std::cout << "After called vkDestroyInstance\n";
do {
std::cout << '\n' << "Press a key to continue...";
} while (std::cin.get() != '\n');
uint32_t iterations = 20;
std::vector<std::chrono::milliseconds> samples;
samples.resize(iterations);
for (uint32_t i = 0; i < iterations; i++) {
auto t1 = std::chrono::system_clock::now();
uint32_t count = 0;
vkEnumerateInstanceExtensionProperties(nullptr, &count, nullptr);
// vkEnumerateInstanceLayerProperties(&count, nullptr);
// vkEnumerateInstanceVersion(&count);
auto t2 = std::chrono::system_clock::now();
samples[i] = std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1);
}
std::chrono::milliseconds total_time{};
for (uint32_t i = 0; i < iterations; i++) {
total_time += samples[i];
}
std::cout << "average time " << total_time.count() / iterations << "ms\n";
std::cout << "first call time " << samples[0].count() << "ms\n";
std::cout << "second call time " << samples[1].count() << "ms\n";
std::cout << "last call time " << samples[iterations - 1].count() << "ms\n";
}
Loading

0 comments on commit a79e2d6

Please sign in to comment.