Skip to content

Commit

Permalink
Merge pull request #20 from zongdu-arm/main
Browse files Browse the repository at this point in the history
Verify supporting 16 KB page sizes on A15
  • Loading branch information
per-mathisen-arm authored Sep 6, 2024
2 parents 387b50c + 0dcb4d2 commit 5a9ea40
Show file tree
Hide file tree
Showing 7 changed files with 171 additions and 150 deletions.
24 changes: 23 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ ferret.py.

Build
=====
```
git submodule update --init --recursive
```

Linux
-----
Expand Down Expand Up @@ -69,6 +72,9 @@ Example:
Using as a layer (Vulkan only)
==============================

Linux
-----

Once built, the layer and json manifest will be in <build_dir>/implicit_layer.d

Set the following env. vars to enable the layer on linux:
Expand All @@ -86,8 +92,24 @@ Then set the following env var to point to your libcollector JSON configuration
export VK_LIBCOLLECTOR_CONFIG_PATH=<path_to_json>
```

Android
-------

Local file to push to the location on Android specified:

```bash
adb push arm64/libVkLayer_libcollector.so /data/app/{app_path}/lib/arm64/
adb push layer/libcollector_config.json /sdcard/Download/
```

Set the following env. vars to enable the layer on Android:

```bash
adb shell setprop debug.vulkan.layer.1 VK_LAYER_ARM_libcollector
```

Then run your app as normal. One result file will be created per device in your application, and by default the results are written to the run directory.
To override this, set the "result_file_basename" field in the config json.
To override this, set the "result_file_basename" field in the config json. Get the result file in the specified location, for example: /sdcard/Download/results_device_0.json

JSON interface (layer specific)
---------------------------
Expand Down
1 change: 1 addition & 0 deletions android/gradle/collector_android/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,4 @@ find_library(android-lib android)

add_executable(burrow ${BURROW_SOURCES})
target_link_libraries(burrow app-glue ${log-lib} ${android-lib} ${app-glue} collector_android)
target_link_options(burrow PRIVATE -Wl,-z,max-page-size=16384)
1 change: 1 addition & 0 deletions android/gradle/layer_android/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,4 @@ find_library(android-lib android)

add_library(VkLayer_libcollector SHARED ${LAYER_SOURCES})
target_link_libraries(VkLayer_libcollector ${log-lib} ${android-lib})
target_link_options(VkLayer_libcollector PRIVATE -Wl,-z,max-page-size=16384)
1 change: 1 addition & 0 deletions android/jni/Android.mk
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ LOCAL_C_INCLUDES := \

LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -llog -latomic

LOCAL_LDFLAGS += -Wl,-z,max-page-size=16384
LOCAL_STATIC_LIBRARIES := collector_android
LOCAL_CPP_FEATURES += exceptions

Expand Down
38 changes: 38 additions & 0 deletions layer/libcollector_config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"result_file_basename" : "/sdcard/Download/results.json",
"num_subframes_per_frame" : 1,
"frame_trigger_function" : "vkQueuePresentKHR",
"start_frame" : 0,
"end_frame" : 99999,
"collectors": {
"perf": {
"set": 4,
"event": [
{
"name": "CPUCyclesUser",
"type": 4,
"config": 17,
"excludeKernel": true
},
{
"name": "CPUCyclesKernel",
"type": 4,
"config": 17,
"excludeUser": true
},
{
"name": "CPUInstructionUser",
"type": 4,
"config": 8,
"excludeKernel": true
},
{
"name": "CPUInstructionKernel",
"type": 4,
"config": 8,
"excludeUser": true
}
]
}
}
}
188 changes: 106 additions & 82 deletions layer/vulkan_layer.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include "layer/vulkan_layer.hpp"

static std::mutex context_mutex;
static std::unordered_map<VkInstance, InstanceDispatchTable*> instance_dispatch_map;
static std::unordered_map<void*, InstanceDispatchTable*> instance_dispatch_map;
static std::unordered_map<VkDevice, vkCollectorContext*> device_to_context_map;
static std::unordered_map<VkQueue, vkCollectorContext*> queue_to_context_map;

Expand All @@ -11,12 +11,21 @@ static Json::Value glibcollector_config;
std::mutex vkCollectorContext::id_mutex;
uint32_t vkCollectorContext::next_id = 0;

template <typename dispatchable_type>
void *get_key(dispatchable_type inst) {
return *reinterpret_cast<void **>(inst);
}

#define GET_PROC_ADDR(func) \
if (!strcmp(funcName, #func)) \
return (PFN_vkVoidFunction)&lc_##func;

std::string get_config_path() {
std::string config_path = "libcollector_config.json";

#ifdef ANDROID
// TODO(tomped01): Find a better way on android
config_path = "/sdcard/libcollector_config.json";
config_path = "/sdcard/Download/libcollector_config.json";
#else
const char* env_path = std::getenv("VK_LIBCOLLECTOR_CONFIG_PATH");
if (env_path) {
Expand Down Expand Up @@ -68,7 +77,7 @@ bool read_config() {

if (glibcollector_config.get("result_file_basename", "").asString() == "") {
#ifdef ANDROID
glibcollector_config["result_file_basename"] = "/sdcard/results.json";
glibcollector_config["result_file_basename"] = "/sdcard/Download/results.json";
#else
glibcollector_config["result_file_basename"] = "results.json";
#endif
Expand All @@ -86,54 +95,6 @@ bool read_config() {
return true;
}


VK_LAYER_EXPORT PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char *pName) {
if (!gconfig_initialized) {
// Do this as early as possible
read_config();

gconfig_initialized = true;
}

if(!strcmp(pName, "vkGetInstanceProcAddr")) return (PFN_vkVoidFunction)&vkGetInstanceProcAddr;
if(!strcmp(pName, "vkCreateInstance")) return (PFN_vkVoidFunction)&lc_vkCreateInstance;
if(!strcmp(pName, "vkCreateDevice")) return (PFN_vkVoidFunction)&lc_vkCreateDevice;
if(!strcmp(pName, "vkDestroyInstance")) return (PFN_vkVoidFunction)&lc_vkDestroyInstance;
if(!strcmp(pName, "vkEnumerateInstanceLayerProperties")) return (PFN_vkVoidFunction)&lc_vkEnumerateInstanceLayerProperties;
if(!strcmp(pName, "vkEnumerateInstanceExtensionProperties")) return (PFN_vkVoidFunction)&lc_vkEnumerateInstanceExtensionProperties;

context_mutex.lock();
InstanceDispatchTable* instance_dtable = instance_dispatch_map[instance];
PFN_vkGetInstanceProcAddr gipa = instance_dtable->gipa;
context_mutex.unlock();

return gipa(instance, pName);
}


VK_LAYER_EXPORT PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice device, const char* pName) {
if(!strcmp(pName, "vkGetDeviceProcAddr")) return (PFN_vkVoidFunction)&vkGetDeviceProcAddr;
if(!strcmp(pName, "vkDestroyDevice")) return (PFN_vkVoidFunction)&lc_vkDestroyDevice;
if(!strcmp(pName, "vkGetDeviceQueue")) return (PFN_vkVoidFunction)&lc_vkGetDeviceQueue;

if (glibcollector_config.get("frame_trigger_function", "").asString() == std::string("vkQueueSubmit")) {
DBG_LOG("LIBCOLLECTOR LAYER: Sampling function set to vkQueueSubmit\n");
if(!strcmp(pName, "vkQueueSubmit")) return (PFN_vkVoidFunction)&lc_vkQueueSubmit;
} else {
DBG_LOG("LIBCOLLECTOR LAYER: Sampling function set to vkQueuePresentKHR\n");
if(!strcmp(pName, "vkQueuePresentKHR")) return (PFN_vkVoidFunction)&lc_vkQueuePresentKHR;
}

context_mutex.lock();
vkCollectorContext* context = device_to_context_map[device];
PFN_vkGetDeviceProcAddr gdpa;
gdpa = context->gdpa;
context_mutex.unlock();

return gdpa(device, pName);
}


VK_LAYER_EXPORT VkResult VKAPI_CALL lc_vkCreateInstance(
const VkInstanceCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
Expand All @@ -158,9 +119,10 @@ VK_LAYER_EXPORT VkResult VKAPI_CALL lc_vkCreateInstance(
InstanceDispatchTable* new_table = new InstanceDispatchTable();
new_table->gipa = (PFN_vkGetInstanceProcAddr)gipa(*pInstance, "vkGetInstanceProcAddr");
new_table->nextDestroyInstance = (PFN_vkDestroyInstance)gipa(*pInstance, "vkDestroyInstance");
new_table->nextEnumerateDeviceExtensionProperties = (PFN_vkEnumerateDeviceExtensionProperties)gipa(*pInstance, "vkEnumerateDeviceExtensionProperties");

context_mutex.lock();
instance_dispatch_map[*pInstance] = new_table;
instance_dispatch_map[get_key(*pInstance)] = new_table;

context_mutex.unlock();

Expand All @@ -173,9 +135,9 @@ VK_LAYER_EXPORT void VKAPI_CALL lc_vkDestroyInstance(
const VkAllocationCallbacks* pAllocator
) {
context_mutex.lock();
InstanceDispatchTable* table = instance_dispatch_map[instance];
InstanceDispatchTable* table = instance_dispatch_map[get_key(instance)];
PFN_vkDestroyInstance nextDestroyInstance = table->nextDestroyInstance;
instance_dispatch_map.erase(instance);
instance_dispatch_map.erase(get_key(instance));
context_mutex.unlock();

delete table;
Expand Down Expand Up @@ -302,9 +264,9 @@ VK_LAYER_EXPORT VkResult VKAPI_CALL lc_vkQueuePresentKHR(
}


// Pre-instance functions
// Enum-instance functions

VK_LAYER_EXPORT VkResult VKAPI_CALL lc_vkEnumerateInstanceLayerProperties(
VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceLayerProperties(
uint32_t* pPropertyCount,
VkLayerProperties* pProperties
) {
Expand All @@ -322,7 +284,17 @@ VK_LAYER_EXPORT VkResult VKAPI_CALL lc_vkEnumerateInstanceLayerProperties(
return VK_SUCCESS;
}

VK_LAYER_EXPORT VkResult VKAPI_CALL lc_vkEnumerateInstanceExtensionProperties(

VK_LAYER_EXPORT VkResult VKAPI_CALL vkEnumerateDeviceLayerProperties(
VkPhysicalDevice physicalDevice,
uint32_t *pPropertyCount,
VkLayerProperties *pProperties
) {
return vkEnumerateInstanceLayerProperties(pPropertyCount, pProperties);
}


VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceExtensionProperties(
const char* pLayerName,
uint32_t* pPropertyCount,
VkExtensionProperties* pProperties
Expand All @@ -337,39 +309,91 @@ VK_LAYER_EXPORT VkResult VKAPI_CALL lc_vkEnumerateInstanceExtensionProperties(
return VK_ERROR_LAYER_NOT_PRESENT;
}

// Pre-instance interface functions, not currently in use, but can be enabled if/when we update to manifest format 1.2.1
VK_LAYER_EXPORT VkResult VKAPI_CALL vkEnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice,
const char *pLayerName,
uint32_t *pPropertyCount,
VkExtensionProperties *pProperties)
{
if (pLayerName == NULL || strcmp(pLayerName, "VK_LAYER_ARM_libcollector")) {
if (physicalDevice == VK_NULL_HANDLE)
{
return VK_SUCCESS;
}

VkResult lc_pre_vkEnumerateInstanceExtensionProperties(
const VkEnumerateInstanceExtensionPropertiesChain* pChain,
const char* pLayerName,
uint32_t* pPropertyCount,
VkExtensionProperties* pProperties
) {
if (pLayerName == NULL) {
return VK_ERROR_LAYER_NOT_PRESENT;
} else if (!strcmp(pLayerName, "VK_LAYER_ARM_libcollector")) {
return pChain->pfnNextLayer(pChain->pNextLink, pLayerName, pPropertyCount, pProperties);
return instance_dispatch_map[get_key(physicalDevice)]->nextEnumerateDeviceExtensionProperties(
physicalDevice, pLayerName, pPropertyCount, pProperties);
}

return VK_ERROR_LAYER_NOT_PRESENT;
if (pPropertyCount != nullptr) {
*pPropertyCount = 0;
}

return VK_SUCCESS;
}

VkResult lc_pre_vkEnumerateInstanceLayerProperties(
const VkEnumerateInstanceLayerPropertiesChain* pChain,
uint32_t* pPropertyCount,
VkLayerProperties* pProperties
) {
if (pProperties == nullptr) {
*pPropertyCount = 1;

VK_LAYER_EXPORT PFN_vkVoidFunction VKAPI_CALL lc_vkGetDeviceProcAddr(VkDevice device, const char *funcName) {
GET_PROC_ADDR(vkGetDeviceProcAddr);
GET_PROC_ADDR(vkDestroyDevice);
GET_PROC_ADDR(vkGetDeviceQueue);

if (glibcollector_config.get("frame_trigger_function", "").asString() == std::string("vkQueueSubmit")) {
DBG_LOG("LIBCOLLECTOR LAYER: Sampling function set to vkQueueSubmit\n");
GET_PROC_ADDR(vkQueueSubmit);
} else {
const char* layer_name = "VK_LAYER_ARM_libcollector";
strncpy(pProperties[0].layerName, layer_name, strlen(layer_name) + 1);
pProperties[0].specVersion = VK_MAKE_API_VERSION(0, 1, 1, 2);
pProperties[0].implementationVersion = 2;
const char* layer_description = "ARM libcollector layer implementation.";
strncpy(pProperties[0].description, layer_description, strlen(layer_description) + 1);
DBG_LOG("LIBCOLLECTOR LAYER: Sampling function set to vkQueuePresentKHR\n");
GET_PROC_ADDR(vkQueuePresentKHR);
}

context_mutex.lock();
vkCollectorContext* context = device_to_context_map[device];
PFN_vkGetDeviceProcAddr gdpa;
gdpa = context->gdpa;
context_mutex.unlock();

return gdpa(device, funcName);
}


VK_LAYER_EXPORT PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice device, const char *funcName) {
return lc_vkGetDeviceProcAddr(device, funcName);
}


VK_LAYER_EXPORT PFN_vkVoidFunction VKAPI_CALL lc_vkGetInstanceProcAddr(VkInstance instance,
const char *funcName) {
if (!gconfig_initialized) {
// Do this as early as possible
read_config();

gconfig_initialized = true;
}

GET_PROC_ADDR(vkGetInstanceProcAddr);
GET_PROC_ADDR(vkCreateInstance);
GET_PROC_ADDR(vkCreateDevice);
GET_PROC_ADDR(vkDestroyInstance);

context_mutex.lock();
InstanceDispatchTable* instance_dtable = instance_dispatch_map[get_key(instance)];
PFN_vkGetInstanceProcAddr gipa = instance_dtable->gipa;
context_mutex.unlock();

return gipa(instance, funcName);
}


VK_LAYER_EXPORT PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char *funcName) {
return lc_vkGetInstanceProcAddr(instance, funcName);
}


VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
vkNegotiateLoaderLayerInterfaceVersion(VkNegotiateLayerInterface *pVersionStruct) {
pVersionStruct->pfnGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)&lc_vkGetInstanceProcAddr;
pVersionStruct->pfnGetDeviceProcAddr = (PFN_vkGetDeviceProcAddr)&lc_vkGetDeviceProcAddr;
pVersionStruct->pfnGetPhysicalDeviceProcAddr = nullptr;

return VK_SUCCESS;
}

Expand Down
Loading

0 comments on commit 5a9ea40

Please sign in to comment.