summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmds/gpu_counter_producer/Android.bp26
-rw-r--r--cmds/gpu_counter_producer/OWNERS1
-rw-r--r--cmds/gpu_counter_producer/main.cpp160
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;
+}