Skip to content

Commit

Permalink
Verify supporting 16 KB page sizes on A15
Browse files Browse the repository at this point in the history
  • Loading branch information
zongdu-arm committed Sep 3, 2024
1 parent 387b50c commit 0dcb4d2
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";

This comment has been minimized.

Copy link
@per-mathisen-arm

per-mathisen-arm Sep 3, 2024

Collaborator

Why this change? It adds an undocumented extra step to the data collection process. Also same comment for change below.

This comment has been minimized.

Copy link
@zongdu-arm

zongdu-arm Sep 4, 2024

Author Contributor

The new unrooted devices do not have permission to write to /sdcard root directory.
For its, keep it consistent with result_file_basename, both are in /sdcard/Download/

#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 0dcb4d2

Please sign in to comment.