forked from LeddaZ/frameworks_base
167 lines
4.5 KiB
C++
167 lines
4.5 KiB
C++
/*
|
|
* 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 (getenv("LD_LIBRARY_PATH") == nullptr) {
|
|
setenv("LD_LIBRARY_PATH", "/vendor/lib64:/vendor/lib", 0 /*override*/);
|
|
LOG_INFO("execv with: LD_LIBRARY_PATH=%s", getenv("LD_LIBRARY_PATH"));
|
|
execvpe(pname, argv, environ);
|
|
}
|
|
|
|
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;
|
|
}
|