You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
227 lines
6.3 KiB
227 lines
6.3 KiB
#include <arpa/inet.h> |
|
#include <iostream> |
|
#include <chrono> |
|
#include <cutils/sockets.h> |
|
#include <hardware/gralloc.h> |
|
#include <vector> |
|
#include <tuple> |
|
#include <algorithm> |
|
#include <tuple> |
|
#include <numeric> |
|
#include <fcntl.h> |
|
#include <string> |
|
#include <fstream> |
|
#include <sys/stat.h> |
|
#include <sys/wait.h> |
|
|
|
using namespace std; |
|
|
|
#define ASSERT_TRUE(cond) \ |
|
do { \ |
|
if (!(cond)) {\ |
|
cerr << __func__ << "( " << getpid() << "):" << __LINE__ << " condition:" << #cond << " failed\n" << endl; \ |
|
exit(EXIT_FAILURE); \ |
|
} \ |
|
} while (0) |
|
|
|
class Pipe { |
|
int m_readFd; |
|
int m_writeFd; |
|
Pipe(const Pipe &) = delete; |
|
Pipe& operator=(const Pipe &) = delete; |
|
Pipe& operator=(const Pipe &&) = delete; |
|
public: |
|
Pipe(int readFd, int writeFd) : m_readFd{readFd}, m_writeFd{writeFd} { |
|
fcntl(m_readFd, F_SETFD, FD_CLOEXEC); |
|
fcntl(m_writeFd, F_SETFD, FD_CLOEXEC); |
|
} |
|
Pipe(Pipe&& rval) noexcept { |
|
m_readFd = rval.m_readFd; |
|
m_writeFd = rval.m_writeFd; |
|
rval.m_readFd = 0; |
|
rval.m_writeFd = 0; |
|
} |
|
~Pipe() { |
|
if (m_readFd) |
|
close(m_readFd); |
|
if (m_writeFd) |
|
close(m_writeFd); |
|
} |
|
void preserveOverFork(bool preserve) { |
|
if (preserve) { |
|
fcntl(m_readFd, F_SETFD, 0); |
|
fcntl(m_writeFd, F_SETFD,0); |
|
} else { |
|
fcntl(m_readFd, F_SETFD, FD_CLOEXEC); |
|
fcntl(m_writeFd, F_SETFD, FD_CLOEXEC); |
|
} |
|
} |
|
int getReadFd() { |
|
return m_readFd; |
|
} |
|
int getWriteFd() { |
|
return m_writeFd; |
|
} |
|
void signal() { |
|
bool val = true; |
|
int error = write(m_writeFd, &val, sizeof(val)); |
|
ASSERT_TRUE(error == sizeof(val)); |
|
}; |
|
void wait() { |
|
bool val = false; |
|
int error = read(m_readFd, &val, sizeof(val)); |
|
ASSERT_TRUE(error == sizeof(val)); |
|
} |
|
bool wait_ret_error() { |
|
bool val = false; |
|
int error = read(m_readFd, &val, sizeof(val)); |
|
return (error != 1); |
|
} |
|
template <typename T> void send(const T& v) { |
|
int error = write(m_writeFd, &v, sizeof(T)); |
|
ASSERT_TRUE(error >= 0); |
|
} |
|
template <typename T> void recv(T& v) { |
|
int error = read(m_readFd, &v, sizeof(T)); |
|
ASSERT_TRUE(error >= 0); |
|
} |
|
static Pipe makePipeFromFds(int readFd, int writeFd) { |
|
return Pipe(readFd, writeFd); |
|
} |
|
static tuple<Pipe, Pipe> createPipePair() { |
|
int a[2]; |
|
int b[2]; |
|
|
|
int error1 = pipe(a); |
|
int error2 = pipe(b); |
|
ASSERT_TRUE(error1 >= 0); |
|
ASSERT_TRUE(error2 >= 0); |
|
|
|
return make_tuple(Pipe(a[0], b[1]), Pipe(b[0], a[1])); |
|
} |
|
}; |
|
|
|
void createProcess(Pipe pipe, const char *exName, const char *arg) |
|
{ |
|
pipe.preserveOverFork(true); |
|
pid_t pid = fork(); |
|
// child proc |
|
if (pid == 0) { |
|
char readFdStr[16]; |
|
char writeFdStr[16]; |
|
snprintf(readFdStr, sizeof(readFdStr), "%d", pipe.getReadFd()); |
|
snprintf(writeFdStr, sizeof(writeFdStr), "%d", pipe.getWriteFd()); |
|
execl(exName, exName, "--worker", arg, readFdStr, writeFdStr, nullptr); |
|
ASSERT_TRUE(0); |
|
} |
|
// parent process |
|
else if (pid > 0) { |
|
pipe.preserveOverFork(false); |
|
return; |
|
} |
|
else { |
|
ASSERT_TRUE(0); |
|
} |
|
} |
|
|
|
|
|
static void write_oomadj_to_lmkd(int oomadj) { |
|
// Connect to lmkd and store our oom_adj |
|
int lmk_procprio_cmd[4]; |
|
int sock; |
|
int tries = 10; |
|
while ((sock = socket_local_client("lmkd", |
|
ANDROID_SOCKET_NAMESPACE_RESERVED, |
|
SOCK_SEQPACKET)) < 0) { |
|
usleep(100000); |
|
if (tries-- < 0) break; |
|
} |
|
if (sock < 0) { |
|
cout << "Failed to connect to lmkd, errno " << errno << endl; |
|
exit(1); |
|
} |
|
lmk_procprio_cmd[0] = htonl(1); |
|
lmk_procprio_cmd[1] = htonl(getpid()); |
|
lmk_procprio_cmd[2] = htonl(getuid()); |
|
lmk_procprio_cmd[3] = htonl(oomadj); |
|
|
|
int written = write(sock, lmk_procprio_cmd, sizeof(lmk_procprio_cmd)); |
|
cout << "Wrote " << written << " bytes to lmkd control socket." << endl; |
|
} |
|
|
|
#ifdef ENABLE_MEM_CGROUPS |
|
static void create_memcg() { |
|
char buf[256]; |
|
pid_t pid = getpid(); |
|
snprintf(buf, sizeof(buf), "/dev/memctl/apps/%u", pid); |
|
|
|
int tasks = mkdir(buf, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); |
|
if (tasks < 0) { |
|
cout << "Failed to create memory cgroup" << endl; |
|
return; |
|
} |
|
snprintf(buf, sizeof(buf), "/dev/memctl/apps/%u/tasks", pid); |
|
tasks = open(buf, O_WRONLY); |
|
if (tasks < 0) { |
|
cout << "Unable to add process to memory cgroup" << endl; |
|
return; |
|
} |
|
snprintf(buf, sizeof(buf), "%u", pid); |
|
write(tasks, buf, strlen(buf)); |
|
close(tasks); |
|
} |
|
#endif |
|
|
|
size_t s = 4 * (1 << 20); |
|
void *gptr; |
|
int main(int argc, char *argv[]) |
|
{ |
|
if ((argc > 1) && (std::string(argv[1]) == "--worker")) { |
|
#ifdef ENABLE_MEM_CGROUPS |
|
create_memcg(); |
|
#endif |
|
write_oomadj_to_lmkd(atoi(argv[2])); |
|
Pipe p{atoi(argv[3]), atoi(argv[4])}; |
|
|
|
long long allocCount = 0; |
|
while (1) { |
|
p.wait(); |
|
char *ptr = (char*)malloc(s); |
|
memset(ptr, (int)allocCount >> 10, s); |
|
for (int i = 0; i < s; i+= 4096) { |
|
*((long long*)&ptr[i]) = allocCount + i; |
|
} |
|
usleep(10 * 1000); |
|
gptr = ptr; |
|
//cout << "total alloc: " << allocCount / (1<<20)<< " adj: " << argv[2]<< endl;; |
|
//cout << "ptr: " << (long long)(void*)ptr << endl;; |
|
p.signal(); |
|
allocCount += s; |
|
} |
|
} else { |
|
cout << "parent:" << argc << endl; |
|
|
|
write_oomadj_to_lmkd(-1000); |
|
for (int i = 1000; i >= 0; i -= 100) { |
|
auto pipes = Pipe::createPipePair(); |
|
char arg[16]; |
|
snprintf(arg, sizeof(arg), "%d", i); |
|
createProcess(std::move(std::get<1>(pipes)), argv[0], arg); |
|
Pipe &p = std::get<0>(pipes); |
|
|
|
size_t t = 0; |
|
while (1) { |
|
//;cout << getpid() << ":" << "parent signal" << endl; |
|
p.signal(); |
|
if (p.wait_ret_error()) { |
|
int status; |
|
waitpid(0, &status, 0); |
|
break; |
|
} |
|
t += s; |
|
} |
|
cout << "adj: " << i << " sz: " << t / (1 << 20) << endl; |
|
} |
|
} |
|
return 0; |
|
}
|
|
|