get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/809043/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 809043,
    "url": "http://patchwork.ozlabs.org/api/patches/809043/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/netdev/patch/20170902054824.371962-2-yhs@fb.com/",
    "project": {
        "id": 7,
        "url": "http://patchwork.ozlabs.org/api/projects/7/?format=api",
        "name": "Linux network development",
        "link_name": "netdev",
        "list_id": "netdev.vger.kernel.org",
        "list_email": "netdev@vger.kernel.org",
        "web_url": null,
        "scm_url": null,
        "webscm_url": null,
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<20170902054824.371962-2-yhs@fb.com>",
    "list_archive_url": null,
    "date": "2017-09-02T05:48:21",
    "name": "[v2,net-next,1/4] bpf: add helper bpf_perf_read_counter_time for perf event array map",
    "commit_ref": null,
    "pull_url": null,
    "state": "changes-requested",
    "archived": true,
    "hash": "5dee1c6b34ed08fe707a6f7ef7418d1d8185a0cc",
    "submitter": {
        "id": 71628,
        "url": "http://patchwork.ozlabs.org/api/people/71628/?format=api",
        "name": "Yonghong Song",
        "email": "yhs@fb.com"
    },
    "delegate": {
        "id": 34,
        "url": "http://patchwork.ozlabs.org/api/users/34/?format=api",
        "username": "davem",
        "first_name": "David",
        "last_name": "Miller",
        "email": "davem@davemloft.net"
    },
    "mbox": "http://patchwork.ozlabs.org/project/netdev/patch/20170902054824.371962-2-yhs@fb.com/mbox/",
    "series": [
        {
            "id": 1139,
            "url": "http://patchwork.ozlabs.org/api/series/1139/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/netdev/list/?series=1139",
            "date": "2017-09-02T05:48:21",
            "name": "bpf: add two helpers to read perf event enabled/running time",
            "version": 2,
            "mbox": "http://patchwork.ozlabs.org/series/1139/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/809043/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/809043/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<netdev-owner@vger.kernel.org>",
        "X-Original-To": "patchwork-incoming@ozlabs.org",
        "Delivered-To": "patchwork-incoming@ozlabs.org",
        "Authentication-Results": [
            "ozlabs.org;\n\tspf=none (mailfrom) smtp.mailfrom=vger.kernel.org\n\t(client-ip=209.132.180.67; helo=vger.kernel.org;\n\tenvelope-from=netdev-owner@vger.kernel.org;\n\treceiver=<UNKNOWN>)",
            "ozlabs.org; dkim=pass (1024-bit key;\n\tunprotected) header.d=fb.com header.i=@fb.com header.b=\"Yfj3zGcH\";\n\tdkim-atps=neutral"
        ],
        "Received": [
            "from vger.kernel.org (vger.kernel.org [209.132.180.67])\n\tby ozlabs.org (Postfix) with ESMTP id 3xklXX6R9kz9s76\n\tfor <patchwork-incoming@ozlabs.org>;\n\tSat,  2 Sep 2017 15:48:44 +1000 (AEST)",
            "(majordomo@vger.kernel.org) by vger.kernel.org via listexpand\n\tid S1751460AbdIBFs1 (ORCPT <rfc822;patchwork-incoming@ozlabs.org>);\n\tSat, 2 Sep 2017 01:48:27 -0400",
            "from mx0a-00082601.pphosted.com ([67.231.145.42]:53448 \"EHLO\n\tmx0a-00082601.pphosted.com\" rhost-flags-OK-OK-OK-OK)\n\tby vger.kernel.org with ESMTP id S1750946AbdIBFsZ (ORCPT\n\t<rfc822;netdev@vger.kernel.org>); Sat, 2 Sep 2017 01:48:25 -0400",
            "from pps.filterd (m0109333.ppops.net [127.0.0.1])\n\tby mx0a-00082601.pphosted.com (8.16.0.21/8.16.0.21) with SMTP id\n\tv82557Lc018906\n\tfor <netdev@vger.kernel.org>; Fri, 1 Sep 2017 22:48:25 -0700",
            "from mail.thefacebook.com ([199.201.64.23])\n\tby mx0a-00082601.pphosted.com with ESMTP id 2cqkgd0bug-1\n\t(version=TLSv1 cipher=ECDHE-RSA-AES256-SHA bits=256 verify=NOT)\n\tfor <netdev@vger.kernel.org>; Fri, 01 Sep 2017 22:48:25 -0700",
            "from mx-out.facebook.com (192.168.52.123) by\n\tPRN-CHUB14.TheFacebook.com (192.168.16.24) with Microsoft SMTP Server\n\tid 14.3.319.2; Fri, 1 Sep 2017 22:48:24 -0700",
            "by devbig474.prn1.facebook.com (Postfix, from userid 128203)  id\n\t743CE46E0470; Fri,  1 Sep 2017 22:48:24 -0700 (PDT)"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=fb.com;\n\th=from : to : cc : subject\n\t: date : message-id : in-reply-to : references : mime-version :\n\tcontent-type; s=facebook;\n\tbh=Pd/3A8zKZXOl9qQxJF1KHAC4A5pHsO9I8yCs6fR3lBM=; \n\tb=Yfj3zGcHfHa1a4YHgZZW/535qa5m+0HxhOF0g7M2CLAk+qyKt24ngmYERVz8UtDepjio\n\tVKcvwxav7WNK33T4EsdWACBHyRTQ5Nl/ihah2+k0Fzbvu3qIrvcWqfv0Tcmh63ju8hZa\n\tf6IfGbwyyvrrfRxVfkxIJjRA0dc0euSMNxo= ",
        "X-ThriftRelayHost": "devbig474.prn1.facebook.com",
        "Smtp-Origin-Hostprefix": "devbig",
        "From": "Yonghong Song <yhs@fb.com>",
        "Smtp-Origin-Hostname": "devbig474.prn1.facebook.com",
        "To": "<peterz@infradead.org>, <rostedt@goodmis.org>, <ast@fb.com>,\n\t<daniel@iogearbox.net>, <netdev@vger.kernel.org>",
        "CC": "<kernel-team@fb.com>",
        "Smtp-Origin-Cluster": "prn1c29",
        "Subject": "[PATCH v2 net-next 1/4] bpf: add helper bpf_perf_read_counter_time\n\tfor perf event array map",
        "Date": "Fri, 1 Sep 2017 22:48:21 -0700",
        "Message-ID": "<20170902054824.371962-2-yhs@fb.com>",
        "X-Mailer": "git-send-email 2.9.5",
        "In-Reply-To": "<20170902054824.371962-1-yhs@fb.com>",
        "References": "<20170902054824.371962-1-yhs@fb.com>",
        "X-FB-Internal": [
            "Safe",
            "Safe"
        ],
        "MIME-Version": "1.0",
        "Content-Type": "text/plain",
        "X-Proofpoint-Spam-Reason": "safe",
        "X-Proofpoint-Virus-Version": "vendor=fsecure engine=2.50.10432:, ,\n\tdefinitions=2017-09-02_01:, , signatures=0",
        "Sender": "netdev-owner@vger.kernel.org",
        "Precedence": "bulk",
        "List-ID": "<netdev.vger.kernel.org>",
        "X-Mailing-List": "netdev@vger.kernel.org"
    },
    "content": "Hardware pmu counters are limited resources. When there are more\npmu based perf events opened than available counters, kernel will\nmultiplex these events so each event gets certain percentage\n(but not 100%) of the pmu time. In case that multiplexing happens,\nthe number of samples or counter value will not reflect the\ncase compared to no multiplexing. This makes comparison between\ndifferent runs difficult.\n\nTypically, the number of samples or counter value should be\nnormalized before comparing to other experiments. The typical\nnormalization is done like:\n  normalized_num_samples = num_samples * time_enabled / time_running\n  normalized_counter_value = counter_value * time_enabled / time_running\nwhere time_enabled is the time enabled for event and time_running is\nthe time running for event since last normalization.\n\nThis patch adds helper bpf_perf_read_counter_time for kprobed based perf\nevent array map, to read perf counter and enabled/running time.\nThe enabled/running time is accumulated since the perf event open.\nTo achieve scaling factor between two bpf invocations, users\ncan can use cpu_id as the key (which is typical for perf array usage model)\nto remember the previous value and do the calculation inside the\nbpf program.\n\nSigned-off-by: Yonghong Song <yhs@fb.com>\n---\n include/linux/perf_event.h |  3 ++-\n include/uapi/linux/bpf.h   | 21 ++++++++++++++++++++-\n kernel/bpf/arraymap.c      |  2 +-\n kernel/bpf/verifier.c      |  4 +++-\n kernel/events/core.c       | 19 +++++++++++++------\n kernel/trace/bpf_trace.c   | 44 ++++++++++++++++++++++++++++++++++++++++----\n 6 files changed, 79 insertions(+), 14 deletions(-)",
    "diff": "diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h\nindex b14095b..5a50808 100644\n--- a/include/linux/perf_event.h\n+++ b/include/linux/perf_event.h\n@@ -898,7 +898,8 @@ perf_event_create_kernel_counter(struct perf_event_attr *attr,\n \t\t\t\tvoid *context);\n extern void perf_pmu_migrate_context(struct pmu *pmu,\n \t\t\t\tint src_cpu, int dst_cpu);\n-int perf_event_read_local(struct perf_event *event, u64 *value);\n+int perf_event_read_local(struct perf_event *event, u64 *value,\n+\t\t\t  u64 *enabled, u64 *running);\n extern u64 perf_event_read_value(struct perf_event *event,\n \t\t\t\t u64 *enabled, u64 *running);\n \ndiff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h\nindex ba848b7..9c23bef 100644\n--- a/include/uapi/linux/bpf.h\n+++ b/include/uapi/linux/bpf.h\n@@ -582,6 +582,14 @@ union bpf_attr {\n  *\t@map: pointer to sockmap to update\n  *\t@key: key to insert/update sock in map\n  *\t@flags: same flags as map update elem\n+ *\n+ * int bpf_perf_read_counter_time(map, flags, counter_time_buf, buf_size)\n+ *     read perf event counter value and perf event enabled/running time\n+ *     @map: pointer to perf_event_array map\n+ *     @flags: index of event in the map or bitmask flags\n+ *     @counter_time_buf: buf to fill\n+ *     @buf_size: size of the counter_time_buf\n+ *     Return: 0 on success or negative error code\n  */\n #define __BPF_FUNC_MAPPER(FN)\t\t\\\n \tFN(unspec),\t\t\t\\\n@@ -638,6 +646,7 @@ union bpf_attr {\n \tFN(redirect_map),\t\t\\\n \tFN(sk_redirect_map),\t\t\\\n \tFN(sock_map_update),\t\t\\\n+\tFN(perf_read_counter_time),\t\t\\\n \n /* integer value in 'imm' field of BPF_CALL instruction selects which helper\n  * function eBPF program intends to call\n@@ -681,7 +690,8 @@ enum bpf_func_id {\n #define BPF_F_ZERO_CSUM_TX\t\t(1ULL << 1)\n #define BPF_F_DONT_FRAGMENT\t\t(1ULL << 2)\n \n-/* BPF_FUNC_perf_event_output and BPF_FUNC_perf_event_read flags. */\n+/* BPF_FUNC_perf_event_output, BPF_FUNC_perf_event_read and\n+ * BPF_FUNC_perf_read_counter_time flags. */\n #define BPF_F_INDEX_MASK\t\t0xffffffffULL\n #define BPF_F_CURRENT_CPU\t\tBPF_F_INDEX_MASK\n /* BPF_FUNC_perf_event_output for sk_buff input context. */\n@@ -864,4 +874,13 @@ enum {\n #define TCP_BPF_IW\t\t1001\t/* Set TCP initial congestion window */\n #define TCP_BPF_SNDCWND_CLAMP\t1002\t/* Set sndcwnd_clamp */\n \n+struct bpf_perf_time {\n+\t__u64 enabled;\n+\t__u64 running;\n+};\n+struct bpf_perf_counter_time {\n+\t__u64 counter;\n+\tstruct bpf_perf_time time;\n+};\n+\n #endif /* _UAPI__LINUX_BPF_H__ */\ndiff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c\nindex 98c0f00..68d8666 100644\n--- a/kernel/bpf/arraymap.c\n+++ b/kernel/bpf/arraymap.c\n@@ -492,7 +492,7 @@ static void *perf_event_fd_array_get_ptr(struct bpf_map *map,\n \n \tee = ERR_PTR(-EOPNOTSUPP);\n \tevent = perf_file->private_data;\n-\tif (perf_event_read_local(event, &value) == -EOPNOTSUPP)\n+\tif (perf_event_read_local(event, &value, NULL, NULL) == -EOPNOTSUPP)\n \t\tgoto err_out;\n \n \tee = bpf_event_entry_gen(perf_file, map_file);\ndiff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c\nindex d690c7d..c4d29e3 100644\n--- a/kernel/bpf/verifier.c\n+++ b/kernel/bpf/verifier.c\n@@ -1494,7 +1494,8 @@ static int check_map_func_compatibility(struct bpf_map *map, int func_id)\n \t\tbreak;\n \tcase BPF_MAP_TYPE_PERF_EVENT_ARRAY:\n \t\tif (func_id != BPF_FUNC_perf_event_read &&\n-\t\t    func_id != BPF_FUNC_perf_event_output)\n+\t\t    func_id != BPF_FUNC_perf_event_output &&\n+\t\t    func_id != BPF_FUNC_perf_read_counter_time)\n \t\t\tgoto error;\n \t\tbreak;\n \tcase BPF_MAP_TYPE_STACK_TRACE:\n@@ -1537,6 +1538,7 @@ static int check_map_func_compatibility(struct bpf_map *map, int func_id)\n \t\tbreak;\n \tcase BPF_FUNC_perf_event_read:\n \tcase BPF_FUNC_perf_event_output:\n+\tcase BPF_FUNC_perf_read_counter_time:\n \t\tif (map->map_type != BPF_MAP_TYPE_PERF_EVENT_ARRAY)\n \t\t\tgoto error;\n \t\tbreak;\ndiff --git a/kernel/events/core.c b/kernel/events/core.c\nindex 8c01572..20c4039 100644\n--- a/kernel/events/core.c\n+++ b/kernel/events/core.c\n@@ -3670,7 +3670,8 @@ static inline u64 perf_event_count(struct perf_event *event)\n  *     will not be local and we cannot read them atomically\n  *   - must not have a pmu::count method\n  */\n-int perf_event_read_local(struct perf_event *event, u64 *value)\n+int perf_event_read_local(struct perf_event *event, u64 *value,\n+\t\t\t  u64 *enabled, u64 *running)\n {\n \tunsigned long flags;\n \tint ret = 0;\n@@ -3694,7 +3695,7 @@ int perf_event_read_local(struct perf_event *event, u64 *value)\n \t * It must not have a pmu::count method, those are not\n \t * NMI safe.\n \t */\n-\tif (event->pmu->count) {\n+\tif (value && event->pmu->count) {\n \t\tret = -EOPNOTSUPP;\n \t\tgoto out;\n \t}\n@@ -3718,10 +3719,16 @@ int perf_event_read_local(struct perf_event *event, u64 *value)\n \t * or local to this CPU. Furthermore it means its ACTIVE (otherwise\n \t * oncpu == -1).\n \t */\n-\tif (event->oncpu == smp_processor_id())\n-\t\tevent->pmu->read(event);\n-\n-\t*value = local64_read(&event->count);\n+\tif (value) {\n+\t\tif (event->oncpu == smp_processor_id())\n+\t\t\tevent->pmu->read(event);\n+\t\t*value = local64_read(&event->count);\n+\t}\n+\tif (enabled && running) {\n+\t\tu64 ctx_time = event->shadow_ctx_time + perf_clock();\n+\t\t*enabled = ctx_time - event->tstamp_enabled;\n+\t\t*running = ctx_time - event->tstamp_running;\n+\t}\n out:\n \tlocal_irq_restore(flags);\n \ndiff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c\nindex dc498b6..7ef953f 100644\n--- a/kernel/trace/bpf_trace.c\n+++ b/kernel/trace/bpf_trace.c\n@@ -255,13 +255,13 @@ const struct bpf_func_proto *bpf_get_trace_printk_proto(void)\n \treturn &bpf_trace_printk_proto;\n }\n \n-BPF_CALL_2(bpf_perf_event_read, struct bpf_map *, map, u64, flags)\n-{\n+static __always_inline int\n+get_map_perf_counter(struct bpf_map *map, u64 flags,\n+\t\tu64 *value, u64 *enabled, u64 *running) {\n \tstruct bpf_array *array = container_of(map, struct bpf_array, map);\n \tunsigned int cpu = smp_processor_id();\n \tu64 index = flags & BPF_F_INDEX_MASK;\n \tstruct bpf_event_entry *ee;\n-\tu64 value = 0;\n \tint err;\n \n \tif (unlikely(flags & ~(BPF_F_INDEX_MASK)))\n@@ -275,7 +275,17 @@ BPF_CALL_2(bpf_perf_event_read, struct bpf_map *, map, u64, flags)\n \tif (!ee)\n \t\treturn -ENOENT;\n \n-\terr = perf_event_read_local(ee->event, &value);\n+\terr = perf_event_read_local(ee->event, value, enabled, running);\n+\treturn err;\n+}\n+\n+\n+BPF_CALL_2(bpf_perf_event_read, struct bpf_map *, map, u64, flags)\n+{\n+\tu64 value = 0;\n+\tint err;\n+\n+\terr = get_map_perf_counter(map, flags, &value, NULL, NULL);\n \t/*\n \t * this api is ugly since we miss [-22..-2] range of valid\n \t * counter values, but that's uapi\n@@ -285,6 +295,20 @@ BPF_CALL_2(bpf_perf_event_read, struct bpf_map *, map, u64, flags)\n \treturn value;\n }\n \n+BPF_CALL_4(bpf_perf_read_counter_time, struct bpf_map *, map, u64, flags,\n+\tstruct bpf_perf_counter_time *, buf, u32, size)\n+{\n+\tint err;\n+\n+\tif (unlikely(size != sizeof(struct bpf_perf_counter_time)))\n+\t\treturn -EINVAL;\n+\terr = get_map_perf_counter(map, flags, &buf->counter, &buf->time.enabled,\n+                            &buf->time.running);\n+\tif (err)\n+\t\treturn err;\n+\treturn 0;\n+}\n+\n static const struct bpf_func_proto bpf_perf_event_read_proto = {\n \t.func\t\t= bpf_perf_event_read,\n \t.gpl_only\t= true,\n@@ -293,6 +317,16 @@ static const struct bpf_func_proto bpf_perf_event_read_proto = {\n \t.arg2_type\t= ARG_ANYTHING,\n };\n \n+static const struct bpf_func_proto bpf_perf_read_counter_time_proto = {\n+\t.func\t\t= bpf_perf_read_counter_time,\n+\t.gpl_only\t= true,\n+\t.ret_type\t= RET_INTEGER,\n+\t.arg1_type\t= ARG_CONST_MAP_PTR,\n+\t.arg2_type\t= ARG_ANYTHING,\n+\t.arg3_type\t= ARG_PTR_TO_UNINIT_MEM,\n+\t.arg4_type\t= ARG_CONST_SIZE,\n+};\n+\n static DEFINE_PER_CPU(struct perf_sample_data, bpf_sd);\n \n static __always_inline u64\n@@ -499,6 +533,8 @@ static const struct bpf_func_proto *kprobe_prog_func_proto(enum bpf_func_id func\n \t\treturn &bpf_perf_event_output_proto;\n \tcase BPF_FUNC_get_stackid:\n \t\treturn &bpf_get_stackid_proto;\n+\tcase BPF_FUNC_perf_read_counter_time:\n+\t\treturn &bpf_perf_read_counter_time_proto;\n \tdefault:\n \t\treturn tracing_func_proto(func_id);\n \t}\n",
    "prefixes": [
        "v2",
        "net-next",
        "1/4"
    ]
}