bpfprogs: Add a time_in_state program am: c5c05168c8
am: d9f987b07e

Change-Id: I3ad0c0cbc15c4243a2d416e0fb8ca7a2e13f2575
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..a74b62a
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,16 @@
+# https://clang.llvm.org/docs/ClangFormatStyleOptions.html
+# Please keep this file in sync with system/core/.clang-format-4
+#
+BasedOnStyle: Google
+AccessModifierOffset: -2
+AllowShortFunctionsOnASingleLine: Inline
+BreakBeforeTernaryOperators: true
+ColumnLimit: 100
+CommentPragmas: NOLINT:.*
+DerivePointerAlignment: false
+IndentWidth: 4
+ContinuationIndentWidth: 8
+PointerAlignment: Left
+SpaceAfterCStyleCast: true
+TabWidth: 4
+UseTab: Never
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..3286594
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,24 @@
+//
+// Copyright (C) 2018 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.
+//
+
+bpf {
+    name: "time_in_state.o",
+    srcs: ["time_in_state.c"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+}
diff --git a/helpers.h b/helpers.h
new file mode 100644
index 0000000..e68408a
--- /dev/null
+++ b/helpers.h
@@ -0,0 +1,29 @@
+#include <linux/bpf.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+/* place things in different elf sections */
+#define SEC(NAME) __attribute__((section(NAME), used))
+
+/* helper functions */
+static void* (*bpf_map_lookup_elem)(void* map, void* key) = (void*) BPF_FUNC_map_lookup_elem;
+static int (*bpf_map_update_elem)(void* map, void* key, void* value,
+                                  unsigned long long flags) = (void*) BPF_FUNC_map_update_elem;
+static int (*bpf_map_delete_elem)(void* map, void* key) = (void*) BPF_FUNC_map_delete_elem;
+static int (*bpf_probe_read)(void* dst, int size, void* unsafe_ptr) = (void*) BPF_FUNC_probe_read;
+static unsigned long long (*bpf_ktime_get_ns)(void) = (void*) BPF_FUNC_ktime_get_ns;
+static int (*bpf_trace_printk)(const char* fmt, int fmt_size, ...) = (void*) BPF_FUNC_trace_printk;
+static unsigned long long (*bpf_get_current_pid_tgid)(void) = (void*) BPF_FUNC_get_current_pid_tgid;
+static unsigned long long (*bpf_get_current_uid_gid)(void) = (void*) BPF_FUNC_get_current_uid_gid;
+static unsigned long long (*bpf_get_smp_processor_id)(void) = (void*) BPF_FUNC_get_smp_processor_id;
+
+/* loader usage */
+struct bpf_map_def {
+    unsigned int type;
+    unsigned int key_size;
+    unsigned int value_size;
+    unsigned int max_entries;
+    unsigned int map_flags;
+    unsigned int pad1;
+    unsigned int pad2;
+};
diff --git a/time_in_state.c b/time_in_state.c
new file mode 100644
index 0000000..d61d279
--- /dev/null
+++ b/time_in_state.c
@@ -0,0 +1,94 @@
+/*
+ * time_in_state eBPF program
+ *
+ * Copyright (C) 2018 Google
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "helpers.h"
+
+struct time_key {
+    uint32_t uid;
+    uint32_t freq;
+};
+
+struct bpf_map_def SEC("maps") uid_times = {
+        .type = BPF_MAP_TYPE_PERCPU_HASH,
+        .key_size = sizeof(struct time_key),
+        .value_size = sizeof(uint64_t),
+        .max_entries = 10240,
+};
+
+struct bpf_map_def SEC("maps") cpu_last_update = {
+        .type = BPF_MAP_TYPE_PERCPU_ARRAY,
+        .key_size = sizeof(int),
+        .value_size = sizeof(uint64_t),
+        .max_entries = 1,
+};
+
+struct bpf_map_def SEC("maps") cpu_freq = {
+        .type = BPF_MAP_TYPE_ARRAY,
+        .key_size = sizeof(int),
+        .value_size = sizeof(uint32_t),
+        /* Assume max of 1024 CPUs */
+        .max_entries = 1024,
+};
+
+struct switch_args {
+    unsigned long long ignore;
+    char prev_comm[16];
+    int prev_pid;
+    int prev_prio;
+    long long prev_state;
+    char next_comm[16];
+    int next_pid;
+    int next_prio;
+};
+
+SEC("tracepoint/sched/sched_switch")
+int tp_sched_switch(struct switch_args* args) {
+    uint32_t zero = 0;
+    uint64_t* last = bpf_map_lookup_elem(&cpu_last_update, &zero);
+    if (!last) return 0;
+    uint64_t old_last = *last;
+    uint64_t time = bpf_ktime_get_ns();
+    *last = time;
+    uint32_t cpu = bpf_get_smp_processor_id();
+    uint32_t* freq = bpf_map_lookup_elem(&cpu_freq, &cpu);
+    if (args->prev_pid && old_last && freq && *freq) {
+        uint32_t uid = bpf_get_current_uid_gid();
+        struct time_key key = {.uid = uid, .freq = *freq};
+        uint64_t* tot_time = bpf_map_lookup_elem(&uid_times, &key);
+        uint64_t delta = time - old_last;
+        if (!tot_time)
+            bpf_map_update_elem(&uid_times, &key, &delta, BPF_ANY);
+        else
+            *tot_time += delta;
+    }
+    return 0;
+}
+
+struct cpufreq_args {
+    unsigned long long ignore;
+    unsigned int state;
+    unsigned int cpu_id;
+};
+
+SEC("tracepoint/power/cpu_frequency")
+int tp_cpufreq(struct cpufreq_args* args) {
+    unsigned int cpu = args->cpu_id;
+    unsigned int new = args->state;
+    bpf_map_update_elem(&cpu_freq, &cpu, &new, BPF_ANY);
+    return 0;
+}
+
+char _license[] SEC("license") = "GPL";