Received: by 2002:a05:7412:8d10:b0:f3:1519:9f41 with SMTP id bj16csp4969417rdb; Tue, 12 Dec 2023 15:04:43 -0800 (PST) X-Google-Smtp-Source: AGHT+IGt6awkkrQfkTPnVM3Dr0j+KXZhUMKzXwkOH0ylZDcfb7yDSUXWXSif6pKF8ULRRD5tF++L X-Received: by 2002:a05:6a00:140c:b0:6ce:2732:577 with SMTP id l12-20020a056a00140c00b006ce27320577mr7983705pfu.40.1702422282798; Tue, 12 Dec 2023 15:04:42 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1702422282; cv=none; d=google.com; s=arc-20160816; b=U3KdlcORO6gzioYeoj92dZrfN2ekWt8q+jeb8edCboCB2d/guMHoWLPCWFWw7bwO7S UHI17vuqFEWE3TjY9gh7mEMKazFw18u8jlff3WEfpVF/73mJe28QREHLsAWLC21W8rW4 KtpFcGEQ4JwCPoSukmBfWVqOptAwTvNTtBNrzj1k9XcBBDTnOYY5KUShq+ObhgCJOsQl phthxWhD4bC001xTFQxLMVfP+JbFy3ocp9DKXSpFw2kOoLnZMV/ou87sZRFkBE0YYHc1 TPW/UgpWBu7d7a3NkPp0ZPcGU7ljjaCv6N6CAuTi5xwsF+gfrBCtNcKwJmsrYxDphJjy uYXw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=3QNn5hucGHimQD/byNx2E4b3usuVMXcNuvNSj8HRIbQ=; fh=fjecWn2tsXHKF5pPtw+gI2dQE/iSXdFsWSc8KUP/zmc=; b=PuEYA6KnuJdmNQD7aAGWyOndsq1v4mlrpB2kMErw6JLBZ4ZMCRkWzG8ih4Z7UC+PbP V6uYQ5J6oNK/Gg6AUvgb+tZL9eSffiQZD9KpXGY8MvwgQ071ihAXNoXOt/xxuSIl/1cK sDUh+lJYW/nCGvqT8NP42EVjp1T1rJRGTog5JfI+c6rNS3Zau+emLGCIFhfK48fVzWJf PVaLr1iQOKld9P1lTy+nEaoAwrCo4MZ3kHHzdA75oGjEdM+4+tyHC90o69GThMFTUZ3T gMfeyUksEjOg3FN7uCj7JEgZUXCY2tbJLXcoiOEKDSix6ZcbzgnjdrY1P8a1v1DzYPXo cd4Q== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@intel.com header.s=Intel header.b=daOXzcUQ; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.32 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=intel.com Return-Path: Received: from agentk.vger.email (agentk.vger.email. [23.128.96.32]) by mx.google.com with ESMTPS id v29-20020a63481d000000b005bde6fae09asi8218444pga.135.2023.12.12.15.04.42 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 12 Dec 2023 15:04:42 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.32 as permitted sender) client-ip=23.128.96.32; Authentication-Results: mx.google.com; dkim=pass header.i=@intel.com header.s=Intel header.b=daOXzcUQ; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.32 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=intel.com Received: from out1.vger.email (depot.vger.email [IPv6:2620:137:e000::3:0]) by agentk.vger.email (Postfix) with ESMTP id AE308804B11F; Tue, 12 Dec 2023 15:04:35 -0800 (PST) X-Virus-Status: Clean X-Virus-Scanned: clamav-milter 0.103.11 at agentk.vger.email Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1377956AbjLLXEM (ORCPT + 99 others); Tue, 12 Dec 2023 18:04:12 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40968 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1377945AbjLLXDn (ORCPT ); Tue, 12 Dec 2023 18:03:43 -0500 Received: from mgamail.intel.com (mgamail.intel.com [192.55.52.93]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8894B10D8; Tue, 12 Dec 2023 15:03:31 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1702422211; x=1733958211; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=LSts5xKMFQPZVuTT4Ye0kZVPVu/oNteFmUfX9bIUYIQ=; b=daOXzcUQ+4jYo2/Da6oMgnfu+Zdz8yF3s+CXayL7T94s6GKIn1FlMnou +oMtyt/RwOrGEgj27l5HUwuRSes7Lz4ixptMq3AFtTmsSuyhr/TZOkzUZ Zh9u6sL6Un5Kopqm4AEuNxp9ESEm4zg6vUJNHCzGhYsEoCvMHgL1i/QxH /hjusHDBoyOYHgo1NaiI00pXSy60Gh9aP4DxaYmSsJGGY8tDZU+/qIJNF dWEKWKmotSz62xZ/9U5iIL11t3xxFlyGMjUbkHdE6jvhdcB6VVVerW8ny 3N5ltqry5ZXARH8pDjnAG0++QwlOOd61Wu4s11/6wtysYBDMyJihluSr7 g==; X-IronPort-AV: E=McAfee;i="6600,9927,10922"; a="392055979" X-IronPort-AV: E=Sophos;i="6.04,271,1695711600"; d="scan'208";a="392055979" Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 12 Dec 2023 15:02:53 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10922"; a="864392012" X-IronPort-AV: E=Sophos;i="6.04,271,1695711600"; d="scan'208";a="864392012" Received: from node-10329.jf.intel.com ([10.54.34.22]) by FMSMGA003.fm.intel.com with ESMTP; 12 Dec 2023 15:02:52 -0800 From: weilin.wang@intel.com To: weilin.wang@intel.com, Ian Rogers , Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Alexander Shishkin , Jiri Olsa , Namhyung Kim , Adrian Hunter , Kan Liang Cc: linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org, Perry Taylor , Samantha Alt , Caleb Biggers , Mark Rutland , Yang Jihong Subject: [RFC PATCH v3 09/18] perf stat: Add functions to create new group and assign events into groups for hardware-grouping method Date: Tue, 12 Dec 2023 15:02:15 -0800 Message-Id: <20231212230224.1473300-11-weilin.wang@intel.com> X-Mailer: git-send-email 2.39.3 In-Reply-To: <20231212230224.1473300-1-weilin.wang@intel.com> References: <20231212230224.1473300-1-weilin.wang@intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-0.9 required=5.0 tests=DKIMWL_WL_HIGH,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on agentk.vger.email Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-Greylist: Sender passed SPF test, not delayed by milter-greylist-4.6.4 (agentk.vger.email [0.0.0.0]); Tue, 12 Dec 2023 15:04:35 -0800 (PST) From: Weilin Wang Add struct metricgroup__pmu_group_list to hold the lists of groups from different PMUs. Each PMU has one separate list. Add struct metricgroup__group as one node (one group in the grouping result) of the metricgroup__pmu_group_list. It uses two bitmaps to log counter availabilities(gp counters and fixed counters). Add functions to create group and assign event into the groups based on the event restrictions (struct metricgroup__event_info) and counter availability (pmu_info_list and bitmaps). New group is inserted into the list of groups. Add functions to handle counter bitmaps. Add functions do find and insert operations to handle inserting event into groups. Add function to fill all bits of one counter bitmap. Add functions to create new groups when no counter is available in all the existing groups. Signed-off-by: Weilin Wang --- tools/lib/bitmap.c | 20 +++ tools/perf/util/metricgroup.c | 254 ++++++++++++++++++++++++++++++++++ tools/perf/util/metricgroup.h | 37 +++++ 3 files changed, 311 insertions(+) diff --git a/tools/lib/bitmap.c b/tools/lib/bitmap.c index c3e4871967bc..a96dbf001244 100644 --- a/tools/lib/bitmap.c +++ b/tools/lib/bitmap.c @@ -100,3 +100,23 @@ bool __bitmap_intersects(const unsigned long *bitmap1, return true; return false; } + +void bitmap_clear(unsigned long *map, unsigned int start, int len) +{ + unsigned long *p = map + BIT_WORD(start); + const unsigned int size = start + len; + int bits_to_clear = BITS_PER_LONG - (start % BITS_PER_LONG); + unsigned long mask_to_clear = BITMAP_FIRST_WORD_MASK(start); + + while (len - bits_to_clear >= 0) { + *p &= ~mask_to_clear; + len -= bits_to_clear; + bits_to_clear = BITS_PER_LONG; + mask_to_clear = ~0UL; + p++; + } + if (len) { + mask_to_clear &= BITMAP_LAST_WORD_MASK(size); + *p &= ~mask_to_clear; + } +} diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c index a393584c7a73..9d06fe4488dc 100644 --- a/tools/perf/util/metricgroup.c +++ b/tools/perf/util/metricgroup.c @@ -1450,6 +1450,27 @@ static int set_counter_bitmap(int pos, unsigned long *bitmap) return 0; } +static int find_counter_bitmap(unsigned long *addr1, + unsigned long *addr2, + unsigned long *bit) +{ + unsigned long find_bit = find_next_and_bit(addr1, addr2, NR_COUNTERS, 0); + + if (find_bit == NR_COUNTERS) + return -ERANGE; + *bit = find_bit; + return 0; +} + +static int use_counter_bitmap(unsigned long *bitmap, + unsigned long find_bit) +{ + if (find_bit >= NR_COUNTERS) + return -EINVAL; + bitmap_clear(bitmap, find_bit, 1); + return 0; +} + static int parse_fixed_counter(const char *counter, unsigned long *bitmap, bool *fixed) @@ -1507,6 +1528,38 @@ static int parse_counter(const char *counter, return 0; } +static void group_event_list_free(struct metricgroup__group *groups) +{ + struct metricgroup__group_events *e, *tmp; + + list_for_each_entry_safe(e, tmp, &groups->event_head, nd) { + list_del_init(&e->nd); + free(e); + } +} + +static void group_list_free(struct metricgroup__pmu_group_list *groups) +{ + struct metricgroup__group *g, *tmp; + + list_for_each_entry_safe(g, tmp, &groups->group_head, nd) { + list_del_init(&g->nd); + group_event_list_free(g); + free(g); + } +} + +static void metricgroup__free_group_list(struct list_head *groups) +{ + struct metricgroup__pmu_group_list *g, *tmp; + + list_for_each_entry_safe(g, tmp, groups, nd) { + list_del_init(&g->nd); + group_list_free(g); + free(g); + } +} + static void metricgroup__free_event_info(struct list_head *event_info_list) { @@ -1682,6 +1735,203 @@ static int get_pmu_counter_layouts(struct list_head *pmu_info_list, return ret; } +static int fill_counter_bitmap(unsigned long *bitmap, int start, int size) +{ + int ret; + + bitmap_zero(bitmap, NR_COUNTERS); + + for (int pos = start; pos < start + size; pos++) { + ret = set_counter_bitmap(pos, bitmap); + if (ret) + return ret; + } + return 0; +} + +/** + * Find if there is a counter available for event e in current_group. If a + * counter is available, use this counter by fill the bit in the correct counter + * bitmap. Otherwise, return error (-ERANGE). + */ +static int find_and_set_counters(struct metricgroup__event_info *e, + struct metricgroup__group *current_group) +{ + int ret; + unsigned long find_bit = 0; + + if (e->free_counter) + return 0; + if (e->fixed_counter) { + ret = find_counter_bitmap(current_group->fixed_counters, e->counters, + &find_bit); + if (ret) + return ret; + pr_debug("found counter for [event]=%s [e->fixed_counters]=%lu\n", + e->name, *current_group->fixed_counters); + ret = use_counter_bitmap(current_group->fixed_counters, find_bit); + } else { + ret = find_counter_bitmap(current_group->gp_counters, e->counters, + &find_bit); + if (ret) + return ret; + pr_debug("found counter for [event]=%s [e->gp_counters]=%lu\n", + e->name, *current_group->gp_counters); + ret = use_counter_bitmap(current_group->gp_counters, find_bit); + } + return ret; +} + +static int _insert_event(struct metricgroup__event_info *e, + struct metricgroup__group *group) +{ + struct metricgroup__group_events *event = malloc(sizeof(struct metricgroup__group_events)); + + if (!event) + return -ENOMEM; + event->event_name = e->name; + if (e->fixed_counter) + list_add(&event->nd, &group->event_head); + else + list_add_tail(&event->nd, &group->event_head); + return 0; +} + +/** + * Insert the new_group node at the end of the group list. + */ +static int insert_new_group(struct list_head *head, + struct metricgroup__group *new_group, + size_t size, + size_t fixed_size) +{ + INIT_LIST_HEAD(&new_group->event_head); + fill_counter_bitmap(new_group->gp_counters, 0, size); + fill_counter_bitmap(new_group->fixed_counters, 0, fixed_size); + list_add_tail(&new_group->nd, head); + return 0; +} + +/** + * Insert event e into a group capable to include it + * + */ +static int insert_event_to_group(struct metricgroup__event_info *e, + struct metricgroup__pmu_group_list *pmu_group_head) +{ + struct metricgroup__group *g; + int ret; + struct list_head *head; + + list_for_each_entry(g, &pmu_group_head->group_head, nd) { + ret = find_and_set_counters(e, g); + if (!ret) { /* return if successfully find and set counter*/ + ret = _insert_event(e, g); + return ret; + } + } + /* + * We were not able to find an existing group to insert this event. + * Continue to create a new group and insert the event in it. + */ + { + struct metricgroup__group *current_group = + malloc(sizeof(struct metricgroup__group)); + + if (!current_group) + return -ENOMEM; + pr_debug("create_new_group for [event] %s\n", e->name); + + head = &pmu_group_head->group_head; + ret = insert_new_group(head, current_group, pmu_group_head->size, + pmu_group_head->fixed_size); + if (ret) + return ret; + ret = find_and_set_counters(e, current_group); + if (ret) + return ret; + ret = _insert_event(e, current_group); + } + + return ret; +} + +/** + * assign_event_grouping - Assign an event into a group. If existing group + * cannot include it, create a new group and insert the event to it. + */ +static int assign_event_grouping(struct metricgroup__event_info *e, + struct list_head *pmu_info_list, + struct list_head *groups) +{ + int ret = 0; + + struct metricgroup__pmu_group_list *g = NULL; + struct metricgroup__pmu_group_list *pmu_group_head = NULL; + + list_for_each_entry(g, groups, nd) { + if (!strcasecmp(g->pmu_name, e->pmu_name)) { + pr_debug("found group for event %s in pmu %s\n", e->name, g->pmu_name); + pmu_group_head = g; + break; + } + } + if (!pmu_group_head) { + struct metricgroup__pmu_counters *p; + + pmu_group_head = malloc(sizeof(struct metricgroup__pmu_group_list)); + if (!pmu_group_head) + return -ENOMEM; + INIT_LIST_HEAD(&pmu_group_head->group_head); + pr_debug("create new group for event %s in pmu %s\n", e->name, e->pmu_name); + pmu_group_head->pmu_name = e->pmu_name; + list_for_each_entry(p, pmu_info_list, nd) { + if (!strcasecmp(p->name, e->pmu_name)) { + pmu_group_head->size = p->size; + pmu_group_head->fixed_size = p->fixed_size; + break; + } + } + list_add_tail(&pmu_group_head->nd, groups); + } + + ret = insert_event_to_group(e, pmu_group_head); + return ret; +} + +/** + * create_grouping - Create a list of groups and place all the events of + * event_info_list into these groups. + * @pmu_info_list: the list of PMU units info based on pmu-events data, used for + * creating new groups. + * @event_info_list: the list of events to be grouped. + * @groupings: the list of groups with events placed in. + * @modifier: any modifiers added to the events. + */ +static int create_grouping(struct list_head *pmu_info_list, + struct list_head *event_info_list, + struct list_head *groupings __maybe_unused, + const char *modifier __maybe_unused) +{ + int ret = 0; + struct metricgroup__event_info *e; + LIST_HEAD(groups); + char *bit_buf = malloc(NR_COUNTERS); + + //TODO: for each new core group, we should consider to add events that uses fixed counters + list_for_each_entry(e, event_info_list, nd) { + bitmap_scnprintf(e->counters, NR_COUNTERS, bit_buf, NR_COUNTERS); + pr_debug("Event name %s, [pmu]=%s, [counters]=%s\n", e->name, + e->pmu_name, bit_buf); + ret = assign_event_grouping(e, pmu_info_list, &groups); + if (ret) + goto out; + } +out: + metricgroup__free_group_list(&groups); + return ret; +}; + /** * hw_aware_build_grouping - Build event groupings by reading counter * requirement of the events and counter available on the system from @@ -1713,6 +1963,10 @@ static int hw_aware_build_grouping(struct expr_parse_ctx *ctx __maybe_unused, goto err_out; } ret = get_pmu_counter_layouts(&pmu_info_list, ltable); + if (ret) + goto err_out; + ret = create_grouping(&pmu_info_list, &event_info_list, groupings, + modifier); err_out: metricgroup__free_event_info(&event_info_list); diff --git a/tools/perf/util/metricgroup.h b/tools/perf/util/metricgroup.h index 802ca15e7c6b..51596e4b4341 100644 --- a/tools/perf/util/metricgroup.h +++ b/tools/perf/util/metricgroup.h @@ -109,6 +109,43 @@ struct metricgroup__pmu_counters { size_t fixed_size; }; +/** + * A list of groups for this pmu. + * This is updated during the grouping. + */ +struct metricgroup__pmu_group_list { + struct list_head nd; + /** The name of the pmu(/core) the events collected on. */ + const char *pmu_name; + /** The number of gp counters in the pmu(/core). */ + size_t size; + /** The number of fixed counters in the pmu(/core) if applicable. */ + size_t fixed_size; + /** Head to the list of groups using this pmu(/core)*/ + struct list_head group_head; +}; + +/** + * This is one node in the metricgroup__pmu_group_list. + * It represents on group. + */ +struct metricgroup__group { + struct list_head nd; + /** The bitmaps represent availability of the counters. + * They are updated once the corresponding counter is used by + * an event (event inserted into the group). + */ + DECLARE_BITMAP(gp_counters, NR_COUNTERS); + DECLARE_BITMAP(fixed_counters, NR_COUNTERS); + /** Head to the list of event names in this group*/ + struct list_head event_head; +}; + +struct metricgroup__group_events { + struct list_head nd; + const char *event_name; +}; + /** * Each group is one node in the group string list. */ -- 2.39.3