diff --git a/tools/lib/perf/cpumap.c b/tools/lib/perf/cpumap.c
index 2a5a29217374..23e907078b28 100644
--- a/tools/lib/perf/cpumap.c
+++ b/tools/lib/perf/cpumap.c
@@ -1,4 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0-only
+#define _GNU_SOURCE
 #include <perf/cpumap.h>
 #include <stdlib.h>
 #include <linux/refcount.h>
@@ -7,6 +8,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
+#include <sched.h>
 #include <ctype.h>
 #include <limits.h>
 
@@ -201,7 +203,7 @@ static struct perf_cpu_map *cpu_map__read_all_cpu_map(void)
 	return cpus;
 }
 
-struct perf_cpu_map *perf_cpu_map__new(const char *cpu_list)
+struct perf_cpu_map *__perf_cpu_map__new(const char *cpu_list, char sep)
 {
 	struct perf_cpu_map *cpus = NULL;
 	unsigned long start_cpu, end_cpu = 0;
@@ -225,7 +227,7 @@ struct perf_cpu_map *perf_cpu_map__new(const char *cpu_list)
 		p = NULL;
 		start_cpu = strtoul(cpu_list, &p, 0);
 		if (start_cpu >= INT_MAX
-		    || (*p != '\0' && *p != ',' && *p != '-'))
+		    || (*p != '\0' && *p != sep && *p != '-'))
 			goto invalid;
 
 		if (*p == '-') {
@@ -233,7 +235,7 @@ struct perf_cpu_map *perf_cpu_map__new(const char *cpu_list)
 			p = NULL;
 			end_cpu = strtoul(cpu_list, &p, 0);
 
-			if (end_cpu >= INT_MAX || (*p != '\0' && *p != ','))
+			if (end_cpu >= INT_MAX || (*p != '\0' && *p != sep))
 				goto invalid;
 
 			if (end_cpu < start_cpu)
@@ -278,6 +280,11 @@ struct perf_cpu_map *perf_cpu_map__new(const char *cpu_list)
 	return cpus;
 }
 
+struct perf_cpu_map *perf_cpu_map__new(const char *cpu_list)
+{
+	return __perf_cpu_map__new(cpu_list, ',');
+}
+
 static int __perf_cpu_map__nr(const struct perf_cpu_map *cpus)
 {
 	return RC_CHK_ACCESS(cpus)->nr;
@@ -479,3 +486,35 @@ struct perf_cpu_map *perf_cpu_map__intersect(struct perf_cpu_map *orig,
 	free(tmp_cpus);
 	return merged;
 }
+
+/* The caller is responsible for freeing returned cpu_set_t with CPU_FREE(). */
+cpu_set_t *perf_cpu_map__2_cpuset(struct perf_cpu_map *cpus, size_t *cpuset_size)
+{
+	cpu_set_t *cpusetp;
+	int max_cpu;
+	struct perf_cpu cpu;
+	int idx;
+
+	if (perf_cpu_map__has_any_cpu(cpus))
+		return NULL;
+
+	max_cpu = perf_cpu_map__max(cpus).cpu;
+	if (max_cpu < 0)
+		return NULL;
+
+	cpusetp = CPU_ALLOC(max_cpu + 1);
+	if (cpusetp == NULL)
+		return NULL;
+
+	*cpuset_size = CPU_ALLOC_SIZE(max_cpu + 1);
+	CPU_ZERO_S(*cpuset_size, cpusetp);
+
+	perf_cpu_map__for_each_cpu(cpu, idx, cpus) {
+		if (cpu.cpu == -1)
+			continue;
+
+		CPU_SET_S(cpu.cpu, *cpuset_size, cpusetp);
+	}
+
+	return cpusetp;
+}
diff --git a/tools/lib/perf/include/perf/cpumap.h b/tools/lib/perf/include/perf/cpumap.h
index e38d859a384d..1a0498f92dbe 100644
--- a/tools/lib/perf/include/perf/cpumap.h
+++ b/tools/lib/perf/include/perf/cpumap.h
@@ -3,6 +3,7 @@
 #define __LIBPERF_CPUMAP_H
 
 #include <perf/core.h>
+#include <sched.h>
 #include <stdio.h>
 #include <stdbool.h>
 
@@ -23,6 +24,7 @@ struct perf_cpu_map;
  */
 LIBPERF_API struct perf_cpu_map *perf_cpu_map__dummy_new(void);
 LIBPERF_API struct perf_cpu_map *perf_cpu_map__default_new(void);
+LIBPERF_API struct perf_cpu_map *__perf_cpu_map__new(const char *cpu_list, char sep);
 LIBPERF_API struct perf_cpu_map *perf_cpu_map__new(const char *cpu_list);
 LIBPERF_API struct perf_cpu_map *perf_cpu_map__read(FILE *file);
 LIBPERF_API struct perf_cpu_map *perf_cpu_map__get(struct perf_cpu_map *map);
@@ -46,6 +48,8 @@ LIBPERF_API bool perf_cpu_map__equal(const struct perf_cpu_map *lhs,
  */
 LIBPERF_API bool perf_cpu_map__has_any_cpu(const struct perf_cpu_map *map);
 
+LIBPERF_API cpu_set_t *perf_cpu_map__2_cpuset(struct perf_cpu_map *cpus, size_t *cpuset_size);
+
 #define perf_cpu_map__for_each_cpu(cpu, idx, cpus)		\
 	for ((idx) = 0, (cpu) = perf_cpu_map__cpu(cpus, idx);	\
 	     (idx) < perf_cpu_map__nr(cpus);			\
diff --git a/tools/lib/perf/libperf.map b/tools/lib/perf/libperf.map
index 190b56ae923a..fe0946e34471 100644
--- a/tools/lib/perf/libperf.map
+++ b/tools/lib/perf/libperf.map
@@ -5,6 +5,7 @@ LIBPERF_0.0.1 {
 		perf_cpu_map__default_new;
 		perf_cpu_map__get;
 		perf_cpu_map__put;
+		__perf_cpu_map__new;
 		perf_cpu_map__new;
 		perf_cpu_map__read;
 		perf_cpu_map__nr;
@@ -12,6 +13,7 @@ LIBPERF_0.0.1 {
 		perf_cpu_map__empty;
 		perf_cpu_map__max;
 		perf_cpu_map__has;
+		perf_cpu_map__2_cpuset;
 		perf_thread_map__new_array;
 		perf_thread_map__new_dummy;
 		perf_thread_map__set_pid;
diff --git a/tools/perf/tests/cpumap.c b/tools/perf/tests/cpumap.c
index 7730fc2ab40b..0661bdfbb252 100644
--- a/tools/perf/tests/cpumap.c
+++ b/tools/perf/tests/cpumap.c
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 #include "tests.h"
+#include <sched.h>
 #include <stdio.h>
 #include "cpumap.h"
 #include "event.h"
@@ -247,12 +248,33 @@ static int test__cpu_map_equal(struct test_suite *test __maybe_unused, int subte
 	return TEST_OK;
 }
 
+static int test__cpu_map_convert(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
+{
+	struct perf_cpu_map *any = perf_cpu_map__dummy_new();
+	struct perf_cpu_map *cpus = perf_cpu_map__new("1-2");
+	cpu_set_t *cpu_set;
+	size_t setsize;
+
+	cpu_set = perf_cpu_map__2_cpuset(any, &setsize);
+	TEST_ASSERT_VAL("not equal", cpu_set == NULL);
+	CPU_FREE(cpu_set);
+
+	cpu_set = perf_cpu_map__2_cpuset(cpus, &setsize);
+	TEST_ASSERT_VAL("cpus", cpu_set != NULL);
+	TEST_ASSERT_VAL("bad cpuset", !CPU_ISSET_S(0, setsize, cpu_set));
+	TEST_ASSERT_VAL("bad cpuset", CPU_ISSET_S(1, setsize, cpu_set));
+	TEST_ASSERT_VAL("bad cpuset", CPU_ISSET_S(2, setsize, cpu_set));
+
+	return TEST_OK;
+}
+
 static struct test_case tests__cpu_map[] = {
 	TEST_CASE("Synthesize cpu map", cpu_map_synthesize),
 	TEST_CASE("Print cpu map", cpu_map_print),
 	TEST_CASE("Merge cpu map", cpu_map_merge),
 	TEST_CASE("Intersect cpu map", cpu_map_intersect),
 	TEST_CASE("Equal cpu map", cpu_map_equal),
+	TEST_CASE("Convert cpu map", cpu_map_convert),
 	{	.name = NULL, }
 };
 
