diff options
| -rw-r--r-- | cmds/gpu_counter_producer/Android.bp | 26 | ||||
| -rw-r--r-- | cmds/gpu_counter_producer/OWNERS | 1 | ||||
| -rw-r--r-- | cmds/gpu_counter_producer/main.cpp | 160 |
3 files changed, 187 insertions, 0 deletions
diff --git a/cmds/gpu_counter_producer/Android.bp b/cmds/gpu_counter_producer/Android.bp new file mode 100644 index 000000000000..5b118ce62679 --- /dev/null +++ b/cmds/gpu_counter_producer/Android.bp @@ -0,0 +1,26 @@ +package { + // See: http://go/android-license-faq + default_applicable_licenses: ["frameworks_base_license"], +} + +cc_binary { + name: "gpu_counter_producer", + + srcs: ["main.cpp"], + + shared_libs: [ + "libdl", + "liblog", + ], + + cflags: [ + "-Wall", + "-Werror", + "-Wunused", + "-Wunreachable-code", + "-fPIE", + "-pie", + ], + + soc_specific: true, +} diff --git a/cmds/gpu_counter_producer/OWNERS b/cmds/gpu_counter_producer/OWNERS new file mode 100644 index 000000000000..892c2fb81cde --- /dev/null +++ b/cmds/gpu_counter_producer/OWNERS @@ -0,0 +1 @@ +pmuetschard@google.com diff --git a/cmds/gpu_counter_producer/main.cpp b/cmds/gpu_counter_producer/main.cpp new file mode 100644 index 000000000000..1054cba74a6b --- /dev/null +++ b/cmds/gpu_counter_producer/main.cpp @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "gpu_counters" + +#include <dlfcn.h> +#include <fcntl.h> +#include <log/log.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#define _LOG(level, msg, ...) \ + do { \ + fprintf(stderr, #level ": " msg "\n", ##__VA_ARGS__); \ + ALOG##level(msg, ##__VA_ARGS__); \ + } while (false) + +#define LOG_ERR(msg, ...) _LOG(E, msg, ##__VA_ARGS__) +#define LOG_WARN(msg, ...) _LOG(W, msg, ##__VA_ARGS__) +#define LOG_INFO(msg, ...) _LOG(I, msg, ##__VA_ARGS__) + +#define NELEM(x) (sizeof(x) / sizeof(x[0])) + +typedef void (*FN_PTR)(void); + +const char* kProducerPaths[] = { + "libgpudataproducer.so", +}; +const char* kPidFileName = "/data/local/tmp/gpu_counter_producer.pid"; + +static FN_PTR loadLibrary(const char* lib) { + char* error; + + LOG_INFO("Trying %s", lib); + void* handle = dlopen(lib, RTLD_GLOBAL); + if ((error = dlerror()) != nullptr || handle == nullptr) { + LOG_WARN("Error loading lib: %s", error); + return nullptr; + } + + FN_PTR startFunc = (FN_PTR)dlsym(handle, "start"); + if ((error = dlerror()) != nullptr) { + LOG_ERR("Error looking for start symbol: %s", error); + dlclose(handle); + return nullptr; + } + return startFunc; +} + +static void killExistingProcess() { + int fd = open(kPidFileName, O_RDONLY); + if (fd == -1) { + return; + } + char pidString[10]; + if (read(fd, pidString, 10) > 0) { + int pid = -1; + sscanf(pidString, "%d", &pid); + if (pid > 0) { + kill(pid, SIGINT); + } + } + close(fd); +} + +static bool writeToPidFile() { + killExistingProcess(); + int fd = open(kPidFileName, O_CREAT | O_WRONLY | O_TRUNC, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); + if (fd == -1) { + return false; + } + pid_t pid = getpid(); + char pidString[10]; + sprintf(pidString, "%d", pid); + write(fd, pidString, strlen(pidString)); + close(fd); + return true; +} + +static void clearPidFile() { + unlink(kPidFileName); +} + +static void usage(const char* pname) { + fprintf(stderr, + "Starts the GPU hardware counter profiling Perfetto data producer.\n\n" + "usage: %s [-hf]\n" + " -f: run in the foreground.\n" + " -h: this message.\n", + pname); +} + +// Program to load the GPU Perfetto producer .so and call start(). +int main(int argc, char** argv) { + const char* pname = argv[0]; + bool foreground = false; + int c; + while ((c = getopt(argc, argv, "fh")) != -1) { + switch (c) { + case 'f': + foreground = true; + break; + case '?': + case ':': + case 'h': + usage(pname); + return 1; + } + } + + if (optind < argc) { + usage(pname); + return 1; + } + + if (!foreground) { + daemon(0, 0); + } + + if (!writeToPidFile()) { + LOG_ERR("Could not open %s", kPidFileName); + return 1; + } + + dlerror(); // Clear any possibly ignored previous error. + FN_PTR startFunc = nullptr; + for (int i = 0; startFunc == nullptr && i < NELEM(kProducerPaths); i++) { + startFunc = loadLibrary(kProducerPaths[i]); + } + + if (startFunc == nullptr) { + LOG_ERR("Did not find the producer library"); + LOG_ERR("LD_LIBRARY_PATH=%s", getenv("LD_LIBRARY_PATH")); + clearPidFile(); + return 1; + } + + LOG_INFO("Calling start at %p", startFunc); + (*startFunc)(); + LOG_WARN("Producer has exited."); + + clearPidFile(); + return 0; +} |