Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c0e66bcd authored by Suren Baghdasaryan's avatar Suren Baghdasaryan Committed by android-build-merger
Browse files

Merge "lmkd: Isolate statslog related code from lmkd code" am: 7718c75b

am: 4510a688

Change-Id: Ie331e0d81ca0e06886e6c88725c83ee266913ae9
parents 5917fa18 4510a688
Loading
Loading
Loading
Loading
+14 −7
Original line number Diff line number Diff line
cc_defaults {
    name: "stats_defaults",

    product_variables: {
        use_lmkd_stats_log: {
            cflags: [
                "-DLMKD_LOG_STATS"
            ],
        },
    },
}

cc_binary {
    name: "lmkd",

@@ -15,13 +27,7 @@ cc_binary {
    local_include_dirs: ["include"],
    cflags: ["-Werror", "-DLMKD_TRACE_KILLS"],
    init_rc: ["lmkd.rc"],
    product_variables: {
        use_lmkd_stats_log: {
            cflags: [
                "-DLMKD_LOG_STATS"
            ],
        },
    },
    defaults: ["stats_defaults"],
    logtags: ["event.logtags"],
}

@@ -32,6 +38,7 @@ cc_library_static {
        "-Wall",
        "-Werror",
    ],
    defaults: ["stats_defaults"],
    shared_libs: [
        "liblog",
    ],
+82 −277
Original line number Diff line number Diff line
@@ -47,9 +47,7 @@
#include <psi/psi.h>
#include <system/thread_defs.h>

#ifdef LMKD_LOG_STATS
#include "statslog.h"
#endif

/*
 * Define LMKD_TRACE_KILLS to record lmkd kills in kernel traces
@@ -186,6 +184,7 @@ static int psi_complete_stall_ms;
static int thrashing_limit_pct;
static int thrashing_limit_decay_pct;
static bool use_psi_monitors = false;
static struct kernel_poll_info kpoll_info;
static struct psi_threshold psi_thresholds[VMPRESS_LEVEL_COUNT] = {
    { PSI_SOME, 70 },    /* 70ms out of 1sec for partial stall */
    { PSI_SOME, 100 },   /* 100ms out of 1sec for partial stall */
@@ -477,11 +476,6 @@ struct reread_data {
    int fd;
};

#ifdef LMKD_LOG_STATS
static bool enable_stats_log;
static android_log_context log_ctx;
#endif

#define PIDHASH_SZ 1024
static struct proc *pidhash[PIDHASH_SZ];
#define pid_hashfn(x) ((((x) >> 8) ^ (x)) & (PIDHASH_SZ - 1))
@@ -505,9 +499,6 @@ static uint32_t killcnt_total = 0;
/* PAGE_SIZE / 1024 */
static long page_k;

static char* proc_get_name(int pid);
static void poll_kernel();

static int clamp(int low, int high, int value) {
    return max(min(value, high), low);
}
@@ -772,6 +763,60 @@ out:
    return (int)tgid;
}

static int proc_get_size(int pid) {
    char path[PATH_MAX];
    char line[LINE_MAX];
    int fd;
    int rss = 0;
    int total;
    ssize_t ret;

    /* gid containing AID_READPROC required */
    snprintf(path, PATH_MAX, "/proc/%d/statm", pid);
    fd = open(path, O_RDONLY | O_CLOEXEC);
    if (fd == -1)
        return -1;

    ret = read_all(fd, line, sizeof(line) - 1);
    if (ret < 0) {
        close(fd);
        return -1;
    }

    sscanf(line, "%d %d ", &total, &rss);
    close(fd);
    return rss;
}

static char *proc_get_name(int pid) {
    char path[PATH_MAX];
    static char line[LINE_MAX];
    int fd;
    char *cp;
    ssize_t ret;

    /* gid containing AID_READPROC required */
    snprintf(path, PATH_MAX, "/proc/%d/cmdline", pid);
    fd = open(path, O_RDONLY | O_CLOEXEC);
    if (fd == -1) {
        return NULL;
    }
    ret = read_all(fd, line, sizeof(line) - 1);
    close(fd);
    if (ret < 0) {
        return NULL;
    }

    cp = strchr(line, ' ');
    if (cp) {
        *cp = '\0';
    } else {
        line[ret] = '\0';
    }

    return line;
}

static void cmd_procprio(LMKD_CTRL_PACKET packet) {
    struct proc *procp;
    char path[80];
@@ -811,9 +856,7 @@ static void cmd_procprio(LMKD_CTRL_PACKET packet) {
    }

    if (use_inkernel_interface) {
#ifdef LMKD_LOG_STATS
        stats_store_taskname(params.pid, proc_get_name(params.pid));
#endif
        stats_store_taskname(params.pid, proc_get_name(params.pid), kpoll_info.poll_fd);
        return;
    }

@@ -884,16 +927,7 @@ static void cmd_procremove(LMKD_CTRL_PACKET packet) {
    struct lmk_procremove params;

    if (use_inkernel_interface) {
#ifdef LMKD_LOG_STATS
        /* Perform an extra check before the pid is removed, after which it
         * will be impossible for poll_kernel to get the taskname. poll_kernel()
         * is potentially a long-running blocking function; however this method
         * handles AMS requests but does not block AMS.*/
        if (enable_stats_log) {
            poll_kernel();
        }
        stats_remove_taskname(params.pid);
#endif
        stats_remove_taskname(params.pid, kpoll_info.poll_fd);
        return;
    }

@@ -911,9 +945,7 @@ static void cmd_procpurge() {
    struct proc *next;

    if (use_inkernel_interface) {
#ifdef LMKD_LOG_STATS
        stats_purge_tasknames();
#endif
        return;
    }

@@ -1231,89 +1263,6 @@ static void ctrl_connect_handler(int data __unused, uint32_t events __unused,
    maxevents++;
}

#ifdef LMKD_LOG_STATS
static void memory_stat_parse_line(char* line, struct memory_stat* mem_st) {
    char key[LINE_MAX + 1];
    int64_t value;

    sscanf(line, "%" STRINGIFY(LINE_MAX) "s  %" SCNd64 "", key, &value);

    if (strcmp(key, "total_") < 0) {
        return;
    }

    if (!strcmp(key, "total_pgfault"))
        mem_st->pgfault = value;
    else if (!strcmp(key, "total_pgmajfault"))
        mem_st->pgmajfault = value;
    else if (!strcmp(key, "total_rss"))
        mem_st->rss_in_bytes = value;
    else if (!strcmp(key, "total_cache"))
        mem_st->cache_in_bytes = value;
    else if (!strcmp(key, "total_swap"))
        mem_st->swap_in_bytes = value;
}

static int memory_stat_from_cgroup(struct memory_stat* mem_st, int pid, uid_t uid) {
    FILE *fp;
    char buf[PATH_MAX];

    snprintf(buf, sizeof(buf), MEMCG_PROCESS_MEMORY_STAT_PATH, uid, pid);

    fp = fopen(buf, "r");

    if (fp == NULL) {
        ALOGE("%s open failed: %s", buf, strerror(errno));
        return -1;
    }

    while (fgets(buf, PAGE_SIZE, fp) != NULL) {
        memory_stat_parse_line(buf, mem_st);
    }
    fclose(fp);

    return 0;
}

static int memory_stat_from_procfs(struct memory_stat* mem_st, int pid) {
    char path[PATH_MAX];
    char buffer[PROC_STAT_BUFFER_SIZE];
    int fd, ret;

    snprintf(path, sizeof(path), PROC_STAT_FILE_PATH, pid);
    if ((fd = open(path, O_RDONLY | O_CLOEXEC)) < 0) {
        ALOGE("%s open failed: %s", path, strerror(errno));
        return -1;
    }

    ret = read(fd, buffer, sizeof(buffer));
    if (ret < 0) {
        ALOGE("%s read failed: %s", path, strerror(errno));
        close(fd);
        return -1;
    }
    close(fd);

    // field 10 is pgfault
    // field 12 is pgmajfault
    // field 22 is starttime
    // field 24 is rss_in_pages
    int64_t pgfault = 0, pgmajfault = 0, starttime = 0, rss_in_pages = 0;
    if (sscanf(buffer,
               "%*u %*s %*s %*d %*d %*d %*d %*d %*d %" SCNd64 " %*d "
               "%" SCNd64 " %*d %*u %*u %*d %*d %*d %*d %*d %*d "
               "%" SCNd64 " %*d %" SCNd64 "",
               &pgfault, &pgmajfault, &starttime, &rss_in_pages) != 4) {
        return -1;
    }
    mem_st->pgfault = pgfault;
    mem_st->pgmajfault = pgmajfault;
    mem_st->rss_in_bytes = (rss_in_pages * PAGE_SIZE);
    mem_st->process_start_time_ns = starttime * (NS_PER_SEC / sysconf(_SC_CLK_TCK));
    return 0;
}
#endif

/*
 * /proc/zoneinfo parsing routines
 * Expected file format is:
@@ -1626,60 +1575,6 @@ static void meminfo_log(union meminfo *mi) {
    android_log_reset(ctx);
}

static int proc_get_size(int pid) {
    char path[PATH_MAX];
    char line[LINE_MAX];
    int fd;
    int rss = 0;
    int total;
    ssize_t ret;

    /* gid containing AID_READPROC required */
    snprintf(path, PATH_MAX, "/proc/%d/statm", pid);
    fd = open(path, O_RDONLY | O_CLOEXEC);
    if (fd == -1)
        return -1;

    ret = read_all(fd, line, sizeof(line) - 1);
    if (ret < 0) {
        close(fd);
        return -1;
    }

    sscanf(line, "%d %d ", &total, &rss);
    close(fd);
    return rss;
}

static char *proc_get_name(int pid) {
    char path[PATH_MAX];
    static char line[LINE_MAX];
    int fd;
    char *cp;
    ssize_t ret;

    /* gid containing AID_READPROC required */
    snprintf(path, PATH_MAX, "/proc/%d/cmdline", pid);
    fd = open(path, O_RDONLY | O_CLOEXEC);
    if (fd == -1) {
        return NULL;
    }
    ret = read_all(fd, line, sizeof(line) - 1);
    close(fd);
    if (ret < 0) {
        return NULL;
    }

    cp = strchr(line, ' ');
    if (cp) {
        *cp = '\0';
    } else {
        line[ret] = '\0';
    }

    return line;
}

static struct proc *proc_adj_lru(int oomadj) {
    return (struct proc *)adjslot_tail(&procadjslot_list[ADJTOSLOT(oomadj)]);
}
@@ -1753,14 +1648,7 @@ static int kill_one_process(struct proc* procp, int min_oom_score, const char *r
    int tasksize;
    int r;
    int result = -1;

#ifdef LMKD_LOG_STATS
    struct memory_stat mem_st = {};
    int memory_stat_parse_result = -1;
#else
    /* To prevent unused parameter warning */
    (void)(min_oom_score);
#endif
    struct memory_stat *mem_st;

    tgid = proc_get_tgid(pid);
    if (tgid >= 0 && tgid != pid) {
@@ -1778,15 +1666,7 @@ static int kill_one_process(struct proc* procp, int min_oom_score, const char *r
        goto out;
    }

#ifdef LMKD_LOG_STATS
    if (enable_stats_log) {
        if (per_app_memcg) {
            memory_stat_parse_result = memory_stat_from_cgroup(&mem_st, pid, uid);
        } else {
            memory_stat_parse_result = memory_stat_from_procfs(&mem_st, pid);
        }
    }
#endif
    mem_st = stats_read_memory_stat(per_app_memcg, pid, uid);

    TRACE_KILL_START(pid);

@@ -1814,18 +1694,9 @@ static int kill_one_process(struct proc* procp, int min_oom_score, const char *r

    last_killed_pid = pid;

#ifdef LMKD_LOG_STATS
    if (memory_stat_parse_result == 0) {
        stats_write_lmk_kill_occurred(log_ctx, LMK_KILL_OCCURRED, uid, taskname,
                procp->oomadj, mem_st.pgfault, mem_st.pgmajfault, mem_st.rss_in_bytes,
                mem_st.cache_in_bytes, mem_st.swap_in_bytes, mem_st.process_start_time_ns,
                min_oom_score);
    } else if (enable_stats_log) {
        stats_write_lmk_kill_occurred(log_ctx, LMK_KILL_OCCURRED, uid, taskname, procp->oomadj,
                                      -1, -1, tasksize * BYTES_IN_KILOBYTE, -1, -1, -1,
                                      min_oom_score);
    }
#endif
    stats_write_lmk_kill_occurred(LMK_KILL_OCCURRED, uid, taskname,
            procp->oomadj, min_oom_score, tasksize, mem_st);

    result = tasksize;

out:
@@ -1844,10 +1715,7 @@ out:
static int find_and_kill_process(int min_score_adj, const char *reason) {
    int i;
    int killed_size = 0;

#ifdef LMKD_LOG_STATS
    bool lmk_state_change_start = false;
#endif

    for (i = OOM_SCORE_ADJ_MAX; i >= min_score_adj; i--) {
        struct proc *procp;
@@ -1861,13 +1729,11 @@ static int find_and_kill_process(int min_score_adj, const char *reason) {

            killed_size = kill_one_process(procp, min_score_adj, reason);
            if (killed_size >= 0) {
#ifdef LMKD_LOG_STATS
                if (enable_stats_log && !lmk_state_change_start) {
                if (!lmk_state_change_start) {
                    lmk_state_change_start = true;
                    stats_write_lmk_state_changed(log_ctx, LMK_STATE_CHANGED,
                    stats_write_lmk_state_changed(LMK_STATE_CHANGED,
                                                  LMK_STATE_CHANGE_START);
                }
#endif
                break;
            }
        }
@@ -1876,11 +1742,9 @@ static int find_and_kill_process(int min_score_adj, const char *reason) {
        }
    }

#ifdef LMKD_LOG_STATS
    if (enable_stats_log && lmk_state_change_start) {
        stats_write_lmk_state_changed(log_ctx, LMK_STATE_CHANGED, LMK_STATE_CHANGE_STOP);
    if (lmk_state_change_start) {
        stats_write_lmk_state_changed(LMK_STATE_CHANGED, LMK_STATE_CHANGE_STOP);
    }
#endif

    return killed_size;
}
@@ -2586,74 +2450,13 @@ err_open_mpfd:
    return false;
}

#ifdef LMKD_LOG_STATS
static int kernel_poll_fd = -1;
static void poll_kernel() {
    if (kernel_poll_fd == -1) {
        // not waiting
        return;
    }

    while (1) {
        char rd_buf[256];
        int bytes_read =
                TEMP_FAILURE_RETRY(pread(kernel_poll_fd, (void*)rd_buf, sizeof(rd_buf), 0));
        if (bytes_read <= 0) break;
        rd_buf[bytes_read] = '\0';

        int64_t pid;
        int64_t uid;
        int64_t group_leader_pid;
        int64_t min_flt;
        int64_t maj_flt;
        int64_t rss_in_pages;
        int16_t oom_score_adj;
        int16_t min_score_adj;
        int64_t starttime;
        char* taskname = 0;
        int fields_read = sscanf(rd_buf,
                                 "%" SCNd64 " %" SCNd64 " %" SCNd64 " %" SCNd64 " %" SCNd64
                                 " %" SCNd64 " %" SCNd16 " %" SCNd16 " %" SCNd64 "\n%m[^\n]",
                                 &pid, &uid, &group_leader_pid, &min_flt, &maj_flt, &rss_in_pages,
                                 &oom_score_adj, &min_score_adj, &starttime, &taskname);

        /* only the death of the group leader process is logged */
        if (fields_read == 10 && group_leader_pid == pid) {
            int64_t process_start_time_ns = starttime * (NS_PER_SEC / sysconf(_SC_CLK_TCK));
            stats_write_lmk_kill_occurred_pid(log_ctx, LMK_KILL_OCCURRED, uid, pid, oom_score_adj,
                                              min_flt, maj_flt, rss_in_pages * PAGE_SIZE, 0, 0,
                                              process_start_time_ns, min_score_adj);
        }

        free(taskname);
    }
}

static struct event_handler_info kernel_poll_hinfo = {0, poll_kernel};

static void init_poll_kernel() {
    struct epoll_event epev;
    kernel_poll_fd =
            TEMP_FAILURE_RETRY(open("/proc/lowmemorykiller", O_RDONLY | O_NONBLOCK | O_CLOEXEC));

    if (kernel_poll_fd < 0) {
        ALOGE("kernel lmk event file could not be opened; errno=%d", kernel_poll_fd);
        return;
    }

    epev.events = EPOLLIN;
    epev.data.ptr = (void*)&kernel_poll_hinfo;
    if (epoll_ctl(epollfd, EPOLL_CTL_ADD, kernel_poll_fd, &epev) != 0) {
        ALOGE("epoll_ctl for lmk events failed; errno=%d", errno);
        close(kernel_poll_fd);
        kernel_poll_fd = -1;
    } else {
        maxevents++;
    }
static void kernel_event_handler(int data __unused, uint32_t events __unused,
                                 struct polling_params *poll_params __unused) {
    kpoll_info.handler(kpoll_info.poll_fd);
}
#endif

static int init(void) {
    static struct event_handler_info kernel_poll_hinfo = { 0, kernel_event_handler };
    struct reread_data file_data = {
        .filename = ZONEINFO_PATH,
        .fd = -1,
@@ -2704,11 +2507,17 @@ static int init(void) {

    if (use_inkernel_interface) {
        ALOGI("Using in-kernel low memory killer interface");
#ifdef LMKD_LOG_STATS
        if (enable_stats_log) {
            init_poll_kernel();
        if (init_poll_kernel(&kpoll_info)) {
            epev.events = EPOLLIN;
            epev.data.ptr = (void*)&kernel_poll_hinfo;
            if (epoll_ctl(epollfd, EPOLL_CTL_ADD, kpoll_info.poll_fd, &epev) != 0) {
                ALOGE("epoll_ctl for lmk events failed (errno=%d)", errno);
                close(kpoll_info.poll_fd);
                kpoll_info.poll_fd = -1;
            } else {
                maxevents++;
            }
        }
#endif
    } else {
        /* Try to use psi monitor first if kernel has it */
        use_psi_monitors = property_get_bool("ro.lmk.use_psi", true) &&
@@ -2907,9 +2716,7 @@ int main(int argc __unused, char **argv __unused) {

    ctx = create_android_logger(MEMINFO_LOG_TAG);

#ifdef LMKD_LOG_STATS
    statslog_init(&log_ctx, &enable_stats_log);
#endif
    statslog_init();

    if (!init()) {
        if (!use_inkernel_interface) {
@@ -2938,9 +2745,7 @@ int main(int argc __unused, char **argv __unused) {
        mainloop();
    }

#ifdef LMKD_LOG_STATS
    statslog_destroy(&log_ctx);
#endif
    statslog_destroy();

    android_log_destroy(&ctx);

+255 −45

File changed.

Preview size limit exceeded, changes collapsed.

+57 −46
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
#define _STATSLOG_H_

#include <assert.h>
#include <inttypes.h>
#include <stats_event_list.h>
#include <stdbool.h>
#include <sys/cdefs.h>
@@ -26,6 +27,20 @@

__BEGIN_DECLS

struct memory_stat {
    int64_t pgfault;
    int64_t pgmajfault;
    int64_t rss_in_bytes;
    int64_t cache_in_bytes;
    int64_t swap_in_bytes;
    int64_t process_start_time_ns;
};

struct kernel_poll_info {
    int poll_fd;
    void (*handler)(int poll_fd);
};

/*
 * These are defined in
 * http://cs/android/frameworks/base/cmds/statsd/src/atoms.proto
@@ -35,37 +50,17 @@ __BEGIN_DECLS
#define LMK_STATE_CHANGE_START 1
#define LMK_STATE_CHANGE_STOP 2

#ifdef LMKD_LOG_STATS

/*
 * The single event tag id for all stats logs.
 * Keep this in sync with system/core/logcat/event.logtags
 */
const static int kStatsEventTag = 1937006964;

static inline void statslog_init(android_log_context* log_ctx, bool* enable_stats_log) {
    assert(log_ctx != NULL);
    assert(enable_stats_log != NULL);
    *enable_stats_log = property_get_bool("ro.lmk.log_stats", false);

    if (*enable_stats_log) {
        *log_ctx = create_android_logger(kStatsEventTag);
    }
}
void statslog_init();

static inline void statslog_destroy(android_log_context* log_ctx) {
    assert(log_ctx != NULL);
    if (*log_ctx) {
        android_log_destroy(log_ctx);
    }
}

struct memory_stat {
    int64_t pgfault;
    int64_t pgmajfault;
    int64_t rss_in_bytes;
    int64_t cache_in_bytes;
    int64_t swap_in_bytes;
    int64_t process_start_time_ns;
};
void statslog_destroy();

#define MEMCG_PROCESS_MEMORY_STAT_PATH "/dev/memcg/apps/uid_%u/pid_%u/memory.stat"
#define PROC_STAT_FILE_PATH "/proc/%d/stat"
@@ -78,47 +73,63 @@ struct memory_stat {
 * Code: LMK_STATE_CHANGED = 54
 */
int
stats_write_lmk_state_changed(android_log_context ctx, int32_t code, int32_t state);
stats_write_lmk_state_changed(int32_t code, int32_t state);

/**
 * Logs the event when LMKD kills a process to reduce memory pressure.
 * Code: LMK_KILL_OCCURRED = 51
 */
int
stats_write_lmk_kill_occurred_pid(android_log_context ctx, int32_t code, int32_t uid, int pid,
                                  int32_t oom_score, int64_t pgfault, int64_t pgmajfault,
                                  int64_t rss_in_bytes, int64_t cache_in_bytes,
                                  int64_t swap_in_bytes, int64_t process_start_time_ns,
                                  int32_t min_oom_score);
stats_write_lmk_kill_occurred(int32_t code, int32_t uid,
                              char const* process_name, int32_t oom_score, int32_t min_oom_score,
                              int tasksize, struct memory_stat *mem_st);

/**
 * Logs the event when LMKD kills a process to reduce memory pressure.
 * Code: LMK_KILL_OCCURRED = 51
 */
int
stats_write_lmk_kill_occurred(android_log_context ctx, int32_t code, int32_t uid,
                              char const* process_name, int32_t oom_score, int64_t pgfault,
                              int64_t pgmajfault, int64_t rss_in_bytes, int64_t cache_in_bytes,
                              int64_t swap_in_bytes, int64_t process_start_time_ns,
                              int32_t min_oom_score);
struct memory_stat *stats_read_memory_stat(bool per_app_memcg, int pid, uid_t uid);

/**
 * Registers a process taskname by pid, while it is still alive.
 */
void
stats_store_taskname(int pid, const char* taskname);
void stats_store_taskname(int pid, const char* taskname, int poll_fd);

/**
 * Unregister all process tasknames.
 */
void
stats_purge_tasknames();
void stats_purge_tasknames();

/**
 * Unregister a process taskname, e.g. after it has been killed.
 */
void
stats_remove_taskname(int pid);
void stats_remove_taskname(int pid, int poll_fd);

bool init_poll_kernel(struct kernel_poll_info *poll_info);

#else /* LMKD_LOG_STATS */

static inline void statslog_init() {}
static inline void statslog_destroy() {}

static inline int
stats_write_lmk_state_changed(int32_t code __unused, int32_t state __unused) { return -EINVAL; }

static inline int
stats_write_lmk_kill_occurred(int32_t code __unused, int32_t uid __unused,
                              char const* process_name __unused, int32_t oom_score __unused,
                              int32_t min_oom_score __unused, int tasksize __unused,
                              struct memory_stat *mem_st __unused) { return -EINVAL; }

static inline struct memory_stat *stats_read_memory_stat(bool per_app_memcg __unused,
                                    int pid __unused, uid_t uid __unused) { return NULL; }

static inline void stats_store_taskname(int pid __unused, const char* taskname __unused,
                                        int poll_fd __unused) {}

static inline void stats_purge_tasknames() {}

static inline void stats_remove_taskname(int pid __unused, int poll_fd __unused) {}

static inline bool init_poll_kernel(struct kernel_poll_info *poll_info __unused) { return false; }

#endif /* LMKD_LOG_STATS */

__END_DECLS