Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F176480131
D59371.id189835.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
28 KB
Referenced Files
None
Subscribers
None
D59371.id189835.diff
View Options
diff --git a/tests/sys/pmc/Makefile b/tests/sys/pmc/Makefile
--- a/tests/sys/pmc/Makefile
+++ b/tests/sys/pmc/Makefile
@@ -4,6 +4,9 @@
ATF_TESTS_C+= pmc_credexec_test
ATF_TESTS_C+= pmc_detach_test
ATF_TESTS_C+= pmc_exec_test
+ATF_TESTS_C+= pmc_group_gate_test
+ATF_TESTS_C+= pmc_group_test
+ATF_TESTS_C+= pmc_groupread_test
.if ${MACHINE_ARCH} == "amd64"
ATF_TESTS_C+= pmc_exterr_test
.endif
diff --git a/tests/sys/pmc/pmc_group_gate_test.c b/tests/sys/pmc/pmc_group_gate_test.c
new file mode 100644
--- /dev/null
+++ b/tests/sys/pmc/pmc_group_gate_test.c
@@ -0,0 +1,204 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2026 Advanced Micro Devices, Inc.
+ */
+
+/*
+ * The v1.4 input gates.
+ * Allocation accepts the inputs the revision makes legal:
+ * PMC_F_DESCENDANTS, and system-wide sampling on a deferred PMC.
+ * Commit rejects the two ways of misusing PMC_F_DESCENDANTS.
+ *
+ * The split matters for feature probing.
+ * Allocation-time EOPNOTSUPP is the standard signal for "this module
+ * does not have the feature".
+ * So misuse of a feature that IS present must instead return EINVAL
+ * from commit. A tool that saw EOPNOTSUPP here would wrongly report
+ * a working module as one without grouping.
+ */
+
+#include <sys/types.h>
+#include <sys/sysctl.h>
+
+#include <errno.h>
+#include <pmc.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <atf-c.h>
+
+#define TEST_EVENT "instructions"
+#define TEST_CPU 0
+#define SAMPLE_COUNT 65536
+
+static bool
+is_amd(void)
+{
+ char vendor[64];
+ size_t len;
+
+ len = sizeof(vendor);
+ if (sysctlbyname("kern.hwpmc.cpuid", vendor, &len, NULL, 0) != 0)
+ return (false);
+ return (strstr(vendor, "AuthenticAMD") != NULL ||
+ strstr(vendor, "HygonGenuine") != NULL);
+}
+
+static void
+require_hwpmc(void)
+{
+
+ if (pmc_init() != 0)
+ atf_tc_skip("hwpmc(4) is not available: %s", strerror(errno));
+ if (!is_amd())
+ atf_tc_skip("PMC grouping is supported only on AMD CPUs");
+}
+
+static void
+require_root(void)
+{
+
+ if (geteuid() != 0)
+ atf_tc_skip("system-mode PMCs require root");
+}
+
+/*
+ * Commit a two-member group. The leader and non-leader carry the
+ * given flags. Return the commit result: 0, or -1 with errno set.
+ * Release everything before returning.
+ */
+static int
+commit_with_flags(enum pmc_mode mode, int cpu, uint32_t leader_flags,
+ uint32_t member_flags, uint64_t count)
+{
+ uint32_t gid;
+ pmc_id_t leader, member;
+ int error, rv;
+
+ leader = member = PMC_ID_INVALID;
+ ATF_REQUIRE_MSG(pmc_allocate_group(TEST_EVENT, mode, leader_flags, cpu,
+ &leader, count) == 0,
+ "leader pmc_allocate_group failed: errno %d (%s)", errno,
+ strerror(errno));
+ ATF_REQUIRE_MSG(pmc_allocate_group(TEST_EVENT, mode, member_flags, cpu,
+ &member, count) == 0,
+ "member pmc_allocate_group failed: errno %d (%s)", errno,
+ strerror(errno));
+ ATF_REQUIRE_MSG(pmc_group_create(&gid) == 0,
+ "pmc_group_create failed: errno %d (%s)", errno, strerror(errno));
+ ATF_REQUIRE_MSG(pmc_group_add(gid, leader, 1) == 0,
+ "leader pmc_group_add failed: errno %d (%s)", errno,
+ strerror(errno));
+ ATF_REQUIRE_MSG(pmc_group_add(gid, member, 0) == 0,
+ "member pmc_group_add failed: errno %d (%s)", errno,
+ strerror(errno));
+ rv = pmc_group_commit(gid);
+
+ error = errno;
+ if (leader != PMC_ID_INVALID)
+ (void)pmc_release(leader);
+ if (member != PMC_ID_INVALID)
+ (void)pmc_release(member);
+ errno = error;
+ return (rv);
+}
+
+/* Allocate accepts PMC_F_DESCENDANTS. The leader designation comes later. */
+ATF_TC_WITHOUT_HEAD(alloc_descendants_accepted);
+ATF_TC_BODY(alloc_descendants_accepted, tc)
+{
+ pmc_id_t id;
+
+ require_hwpmc();
+ ATF_REQUIRE_MSG(pmc_allocate_group(TEST_EVENT, PMC_MODE_TC,
+ PMC_F_DESCENDANTS, PMC_CPU_ANY, &id, 0) == 0,
+ "deferred alloc with PMC_F_DESCENDANTS failed: %s",
+ strerror(errno));
+ ATF_CHECK_EQ(pmc_release(id), 0);
+}
+
+/* Allocate accepts a deferred system-sampling allocation. */
+ATF_TC_WITHOUT_HEAD(alloc_system_sampling_accepted);
+ATF_TC_BODY(alloc_system_sampling_accepted, tc)
+{
+ pmc_id_t id;
+
+ require_hwpmc();
+ require_root();
+ ATF_REQUIRE_MSG(pmc_allocate_group(TEST_EVENT, PMC_MODE_SS, 0,
+ TEST_CPU, &id, SAMPLE_COUNT) == 0,
+ "deferred PMC_MODE_SS alloc failed: %s", strerror(errno));
+ ATF_CHECK_EQ(pmc_release(id), 0);
+}
+
+/* A grouped sampling allocation may carry a nonzero count. Counting may not. */
+ATF_TC_WITHOUT_HEAD(alloc_count_gate_is_counting_only);
+ATF_TC_BODY(alloc_count_gate_is_counting_only, tc)
+{
+ pmc_id_t id;
+
+ require_hwpmc();
+ ATF_REQUIRE_MSG(pmc_allocate_group(TEST_EVENT, PMC_MODE_TS, 0,
+ PMC_CPU_ANY, &id, SAMPLE_COUNT) == 0,
+ "grouped sampling alloc with nonzero count failed: %s",
+ strerror(errno));
+ ATF_CHECK_EQ(pmc_release(id), 0);
+
+ errno = 0;
+ ATF_CHECK_EQ(pmc_allocate_group(TEST_EVENT, PMC_MODE_TC, 0,
+ PMC_CPU_ANY, &id, SAMPLE_COUNT), -1);
+ ATF_CHECK_EQ(errno, EINVAL);
+}
+
+/* The flag is leader-only. On a non-leader, commit fails with EINVAL. */
+ATF_TC_WITHOUT_HEAD(commit_descendants_on_nonleader);
+ATF_TC_BODY(commit_descendants_on_nonleader, tc)
+{
+
+ require_hwpmc();
+ errno = 0;
+ ATF_CHECK_EQ(commit_with_flags(PMC_MODE_TC, PMC_CPU_ANY, 0,
+ PMC_F_DESCENDANTS, 0), -1);
+ ATF_CHECK_EQ(errno, EINVAL);
+}
+
+/* A CPU-bound group cannot follow a fork. Commit fails with EINVAL. */
+ATF_TC_WITHOUT_HEAD(commit_descendants_on_system_leader);
+ATF_TC_BODY(commit_descendants_on_system_leader, tc)
+{
+
+ require_hwpmc();
+ require_root();
+ errno = 0;
+ ATF_CHECK_EQ(commit_with_flags(PMC_MODE_SC, TEST_CPU,
+ PMC_F_DESCENDANTS, 0, 0), -1);
+ ATF_CHECK_EQ(errno, EINVAL);
+}
+
+/* The same group without the flag commits. So the flag causes the EINVAL above. */
+ATF_TC_WITHOUT_HEAD(commit_descendants_on_virtual_leader);
+ATF_TC_BODY(commit_descendants_on_virtual_leader, tc)
+{
+
+ require_hwpmc();
+ ATF_CHECK_MSG(commit_with_flags(PMC_MODE_TC, PMC_CPU_ANY,
+ PMC_F_DESCENDANTS, 0, 0) == 0,
+ "virtual group with PMC_F_DESCENDANTS on the leader failed to "
+ "commit: %s", strerror(errno));
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, alloc_descendants_accepted);
+ ATF_TP_ADD_TC(tp, alloc_system_sampling_accepted);
+ ATF_TP_ADD_TC(tp, alloc_count_gate_is_counting_only);
+ ATF_TP_ADD_TC(tp, commit_descendants_on_nonleader);
+ ATF_TP_ADD_TC(tp, commit_descendants_on_system_leader);
+ ATF_TP_ADD_TC(tp, commit_descendants_on_virtual_leader);
+
+ return (atf_no_error());
+}
diff --git a/tests/sys/pmc/pmc_group_test.c b/tests/sys/pmc/pmc_group_test.c
new file mode 100644
--- /dev/null
+++ b/tests/sys/pmc/pmc_group_test.c
@@ -0,0 +1,258 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2026 Advanced Micro Devices, Inc.
+ */
+
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <sys/wait.h>
+
+#include <errno.h>
+#include <pmc.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <atf-c.h>
+
+static bool
+is_amd(void)
+{
+ char vendor[64];
+ size_t len;
+
+ len = sizeof(vendor);
+ if (sysctlbyname("kern.hwpmc.cpuid", vendor, &len, NULL, 0) != 0)
+ return (false);
+ return (strstr(vendor, "AuthenticAMD") != NULL ||
+ strstr(vendor, "HygonGenuine") != NULL);
+}
+
+static void
+require_hwpmc(void)
+{
+
+ if (pmc_init() != 0)
+ atf_tc_skip("hwpmc(4) is not available: %s", strerror(errno));
+ if (!is_amd())
+ atf_tc_skip("PMC grouping is supported only on AMD CPUs");
+}
+
+static void __attribute__((noinline))
+spin(void)
+{
+ volatile uint64_t sink;
+ uint64_t i;
+
+ sink = 0;
+ for (i = 0; i < 10 * 1000 * 1000; i++)
+ sink += i;
+}
+
+static pmc_id_t
+allocate_grouped(void)
+{
+ pmc_id_t id;
+
+ ATF_REQUIRE_MSG(pmc_allocate_group("instructions", PMC_MODE_TC, 0,
+ PMC_CPU_ANY, &id, 0) == 0, "pmc_allocate_group failed: %s",
+ strerror(errno));
+ return (id);
+}
+
+ATF_TC_WITHOUT_HEAD(committed_release);
+ATF_TC_BODY(committed_release, tc)
+{
+ pmc_id_t fresh, leader, sibling;
+ pmc_value_t value;
+ uint32_t groupid;
+
+ require_hwpmc();
+ leader = allocate_grouped();
+ sibling = allocate_grouped();
+ ATF_REQUIRE_MSG(pmc_group_create(&groupid) == 0,
+ "pmc_group_create failed: %s", strerror(errno));
+ ATF_REQUIRE_MSG(pmc_group_add(groupid, leader, 1) == 0,
+ "leader add failed: %s", strerror(errno));
+ ATF_REQUIRE_MSG(pmc_group_add(groupid, sibling, 0) == 0,
+ "sibling add failed: %s", strerror(errno));
+ ATF_REQUIRE_MSG(pmc_group_commit(groupid) == 0,
+ "pmc_group_commit failed: %s", strerror(errno));
+
+ errno = 0;
+ ATF_CHECK_EQ(pmc_detach(leader, getpid()), -1);
+ ATF_CHECK_EQ(errno, EBUSY);
+ errno = 0;
+ ATF_CHECK_EQ(pmc_detach(sibling, getpid()), -1);
+ ATF_CHECK_EQ(errno, EBUSY);
+ ATF_REQUIRE_MSG(pmc_attach(leader, getpid()) == 0,
+ "leader attach failed: %s", strerror(errno));
+ ATF_REQUIRE_MSG(pmc_start(leader) == 0,
+ "leader start failed: %s", strerror(errno));
+ spin();
+
+ ATF_REQUIRE_MSG(pmc_release(leader) == 0,
+ "leader release failed: %s", strerror(errno));
+ errno = 0;
+ ATF_CHECK_EQ(pmc_release(sibling), -1);
+ ATF_CHECK_EQ(errno, EINVAL);
+ errno = 0;
+ ATF_CHECK_EQ(pmc_read(sibling, &value), -1);
+ ATF_CHECK_EQ(errno, EINVAL);
+
+ fresh = allocate_grouped();
+ ATF_CHECK(fresh != sibling);
+ errno = 0;
+ ATF_CHECK_EQ(pmc_group_add(groupid, fresh, 1), -1);
+ ATF_CHECK_EQ(errno, EINVAL);
+ ATF_REQUIRE(pmc_release(fresh) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(committed_nonleader_errno_contract);
+ATF_TC_BODY(committed_nonleader_errno_contract, tc)
+{
+ pmc_id_t leader, sibling;
+ uint32_t groupid;
+ int error;
+
+ require_hwpmc();
+ leader = allocate_grouped();
+ sibling = allocate_grouped();
+ ATF_REQUIRE_MSG(pmc_group_create(&groupid) == 0,
+ "pmc_group_create failed: %s", strerror(errno));
+ ATF_REQUIRE_MSG(pmc_group_add(groupid, leader, 1) == 0,
+ "leader add failed: %s", strerror(errno));
+ ATF_REQUIRE_MSG(pmc_group_add(groupid, sibling, 0) == 0,
+ "sibling add failed: %s", strerror(errno));
+ ATF_REQUIRE_MSG(pmc_group_commit(groupid) == 0,
+ "pmc_group_commit failed: %s", strerror(errno));
+
+ errno = 0;
+ error = pmc_attach(sibling, getpid());
+ ATF_CHECK_MSG(error == -1 && errno == ENOTTY,
+ "non-leader pmc_attach returned %d, errno %d (%s), expected "
+ "-1/ENOTTY", error, errno, strerror(errno));
+ errno = 0;
+ error = pmc_start(sibling);
+ ATF_CHECK_MSG(error == -1 && errno == ENOTTY,
+ "non-leader pmc_start returned %d, errno %d (%s), expected "
+ "-1/ENOTTY", error, errno, strerror(errno));
+ errno = 0;
+ error = pmc_stop(sibling);
+ ATF_CHECK_MSG(error == -1 && errno == ENOTTY,
+ "non-leader pmc_stop returned %d, errno %d (%s), expected "
+ "-1/ENOTTY", error, errno, strerror(errno));
+ errno = 0;
+ error = pmc_release(sibling);
+ ATF_CHECK_MSG(error == -1 && errno == ENOTTY,
+ "non-leader pmc_release returned %d, errno %d (%s), expected "
+ "-1/ENOTTY", error, errno, strerror(errno));
+
+ ATF_REQUIRE_MSG(pmc_release(leader) == 0,
+ "leader cleanup release failed: %s", strerror(errno));
+}
+
+ATF_TC_WITHOUT_HEAD(uncommitted_release);
+ATF_TC_BODY(uncommitted_release, tc)
+{
+ pmc_id_t leader, new_leader, probe, sibling;
+ uint32_t groupid, released_groupid;
+
+ require_hwpmc();
+ leader = allocate_grouped();
+ sibling = allocate_grouped();
+ ATF_REQUIRE(pmc_group_create(&groupid) == 0);
+ ATF_REQUIRE(pmc_group_add(groupid, leader, 1) == 0);
+ ATF_REQUIRE(pmc_group_add(groupid, sibling, 0) == 0);
+
+ ATF_REQUIRE_MSG(pmc_release(leader) == 0,
+ "uncommitted leader release failed: %s", strerror(errno));
+ errno = 0;
+ ATF_CHECK_EQ(pmc_group_commit(groupid), -1);
+ ATF_CHECK_EQ(errno, EINVAL);
+
+ new_leader = allocate_grouped();
+ ATF_REQUIRE_MSG(pmc_group_add(groupid, new_leader, 1) == 0,
+ "replacement leader add failed: %s", strerror(errno));
+ ATF_REQUIRE_MSG(pmc_group_commit(groupid) == 0,
+ "replacement leader commit failed: %s", strerror(errno));
+ ATF_REQUIRE_MSG(pmc_release(new_leader) == 0,
+ "replacement leader release failed: %s", strerror(errno));
+
+ probe = allocate_grouped();
+ ATF_REQUIRE(pmc_group_create(&released_groupid) == 0);
+ ATF_REQUIRE(pmc_group_add(released_groupid, probe, 0) == 0);
+ ATF_REQUIRE_MSG(pmc_release(probe) == 0,
+ "last uncommitted member release failed: %s", strerror(errno));
+ probe = allocate_grouped();
+ errno = 0;
+ ATF_CHECK_EQ(pmc_group_add(released_groupid, probe, 1), -1);
+ ATF_CHECK_EQ(errno, EINVAL);
+ ATF_REQUIRE(pmc_release(probe) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(owner_exit);
+ATF_TC_BODY(owner_exit, tc)
+{
+ pmc_id_t id;
+ uint32_t groupid;
+ pid_t pid;
+ int status;
+
+ require_hwpmc();
+ pid = fork();
+ ATF_REQUIRE(pid >= 0);
+ if (pid == 0) {
+ if (pmc_allocate_group("instructions", PMC_MODE_TC, 0,
+ PMC_CPU_ANY, &id, 0) != 0 ||
+ pmc_group_create(&groupid) != 0 ||
+ pmc_group_add(groupid, id, 1) != 0 ||
+ pmc_group_commit(groupid) != 0 || pmc_attach(id, 0) != 0 ||
+ pmc_start(id) != 0)
+ _exit(1);
+ spin();
+ _exit(0);
+ }
+ ATF_REQUIRE(waitpid(pid, &status, 0) == pid);
+ ATF_REQUIRE(WIFEXITED(status));
+ ATF_REQUIRE_EQ(WEXITSTATUS(status), 0);
+
+ id = allocate_grouped();
+ ATF_REQUIRE(pmc_group_create(&groupid) == 0);
+ ATF_REQUIRE(pmc_group_add(groupid, id, 1) == 0);
+ ATF_REQUIRE_MSG(pmc_group_commit(groupid) == 0,
+ "post-exit group commit failed: %s", strerror(errno));
+ ATF_REQUIRE(pmc_release(id) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(uncommitted_nonleader_release);
+ATF_TC_BODY(uncommitted_nonleader_release, tc)
+{
+ pmc_id_t leader, sibling;
+ uint32_t groupid;
+
+ require_hwpmc();
+ leader = allocate_grouped();
+ sibling = allocate_grouped();
+ ATF_REQUIRE(pmc_group_create(&groupid) == 0);
+ ATF_REQUIRE(pmc_group_add(groupid, leader, 1) == 0);
+ ATF_REQUIRE(pmc_group_add(groupid, sibling, 0) == 0);
+ ATF_REQUIRE_MSG(pmc_release(sibling) == 0,
+ "uncommitted sibling release failed: %s", strerror(errno));
+ ATF_REQUIRE_MSG(pmc_group_commit(groupid) == 0,
+ "one-member commit failed: %s", strerror(errno));
+ ATF_REQUIRE(pmc_release(leader) == 0);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, committed_release);
+ ATF_TP_ADD_TC(tp, committed_nonleader_errno_contract);
+ ATF_TP_ADD_TC(tp, owner_exit);
+ ATF_TP_ADD_TC(tp, uncommitted_release);
+ ATF_TP_ADD_TC(tp, uncommitted_nonleader_release);
+ return (atf_no_error());
+}
diff --git a/tests/sys/pmc/pmc_groupread_test.c b/tests/sys/pmc/pmc_groupread_test.c
new file mode 100644
--- /dev/null
+++ b/tests/sys/pmc/pmc_groupread_test.c
@@ -0,0 +1,460 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2026 Advanced Micro Devices, Inc.
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+
+#include <errno.h>
+#include <pmc.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <atf-c.h>
+
+#define SPIN_ITERS (50ULL * 1000 * 1000)
+
+struct test_group {
+ uint32_t tg_groupid;
+ pmc_id_t tg_ids[2];
+ u_int tg_nmembers;
+ u_int tg_leader;
+ bool tg_started;
+};
+
+static bool
+is_amd(void)
+{
+ char vendor[64];
+ size_t len;
+
+ len = sizeof(vendor);
+ if (sysctlbyname("kern.hwpmc.cpuid", vendor, &len, NULL, 0) != 0)
+ return (false);
+ return (strstr(vendor, "AuthenticAMD") != NULL ||
+ strstr(vendor, "HygonGenuine") != NULL);
+}
+
+static void
+cleanup_group(struct test_group *group)
+{
+
+ if (group->tg_started)
+ (void)pmc_stop(group->tg_ids[group->tg_leader]);
+ (void)pmc_release(group->tg_ids[group->tg_leader]);
+}
+
+static int
+setup_group(struct test_group *group, u_int nmembers, u_int leader)
+{
+ u_int i;
+ int error;
+
+ memset(group, 0, sizeof(*group));
+ group->tg_nmembers = nmembers;
+ group->tg_leader = leader;
+ for (i = 0; i < nitems(group->tg_ids); i++)
+ group->tg_ids[i] = PMC_ID_INVALID;
+ for (i = 0; i < nmembers; i++) {
+ if (pmc_allocate_group("instructions", PMC_MODE_TC, 0,
+ PMC_CPU_ANY, &group->tg_ids[i], 0) != 0)
+ goto fail;
+ }
+ if (pmc_group_create(&group->tg_groupid) != 0)
+ goto fail;
+ for (i = 0; i < nmembers; i++) {
+ if (pmc_group_add(group->tg_groupid, group->tg_ids[i],
+ i == leader) != 0)
+ goto fail;
+ }
+ errno = 0;
+ if (pmc_group_add(group->tg_groupid, group->tg_ids[leader], 1) == 0 ||
+ errno != EINVAL) {
+ errno = EPROTO;
+ goto fail;
+ }
+ if (pmc_group_commit(group->tg_groupid) != 0)
+ goto fail;
+ return (0);
+
+fail:
+ error = errno;
+ for (i = 0; i < nmembers; i++) {
+ if (group->tg_ids[i] != PMC_ID_INVALID)
+ (void)pmc_release(group->tg_ids[i]);
+ }
+ errno = error;
+ return (-1);
+}
+
+static void
+require_hwpmc(void)
+{
+
+ if (pmc_init() != 0)
+ atf_tc_skip("hwpmc(4) is not available: %s", strerror(errno));
+ if (!is_amd())
+ atf_tc_skip("PMC grouping is supported only on AMD CPUs");
+}
+
+static void __attribute__((noinline))
+spin(void)
+{
+ volatile uint64_t sink;
+ uint64_t i;
+
+ sink = 0;
+ for (i = 0; i < SPIN_ITERS; i++)
+ sink += i;
+}
+
+ATF_TC_WITHOUT_HEAD(capacity_and_order);
+ATF_TC_BODY(capacity_and_order, tc)
+{
+ struct pmc_group_member members[2], members_before[2];
+ struct pmc_group_times times, times_before;
+ struct test_group group;
+ pmc_value_t value;
+ uint64_t enabled, running;
+ uint32_t n;
+ int rv;
+
+ require_hwpmc();
+ ATF_REQUIRE_MSG(setup_group(&group, 2, 1) == 0,
+ "setup_group failed: %s", strerror(errno));
+
+ /* A size query returns the member count and, if asked, the times. */
+ memset(×, 0xa5, sizeof(times));
+ memcpy(×_before, ×, sizeof(times));
+ n = 0;
+ ATF_CHECK_EQ(pmc_group_read(group.tg_ids[group.tg_leader], &n, NULL,
+ ×), 0);
+ ATF_CHECK_EQ(n, 2);
+ ATF_CHECK(memcmp(×, ×_before, sizeof(times)) != 0);
+ ATF_CHECK(times.pgt_running <= times.pgt_enabled);
+
+ /* A size query without times must succeed. */
+ n = 0;
+ ATF_CHECK_EQ(pmc_group_read(group.tg_ids[group.tg_leader], &n, NULL,
+ NULL), 0);
+ ATF_CHECK_EQ(n, 2);
+
+ memset(members, 0xa5, sizeof(members));
+ memcpy(members_before, members, sizeof(members));
+ memset(×, 0xa5, sizeof(times));
+ memcpy(×_before, ×, sizeof(times));
+ n = 1;
+ errno = 0;
+ rv = pmc_group_read(group.tg_ids[group.tg_leader], &n, members,
+ ×);
+ ATF_CHECK_EQ(rv, -1);
+ ATF_CHECK_EQ(errno, E2BIG);
+ ATF_CHECK_EQ(n, 2);
+ ATF_CHECK(memcmp(members, members_before, sizeof(members)) == 0);
+ ATF_CHECK(memcmp(×, ×_before, sizeof(times)) == 0);
+
+ memset(members, 0, sizeof(members));
+ memset(×, 0, sizeof(times));
+ n = nitems(members);
+ ATF_CHECK_EQ(pmc_group_read(group.tg_ids[group.tg_leader], &n,
+ members, ×), 0);
+ ATF_CHECK_EQ(n, 2);
+ ATF_CHECK_EQ(members[0].pm_pmcid, group.tg_ids[group.tg_leader]);
+ ATF_CHECK_EQ(members[1].pm_pmcid, group.tg_ids[0]);
+ ATF_CHECK_EQ(members[0].pm_value, 0);
+ ATF_CHECK_EQ(members[1].pm_value, 0);
+ ATF_CHECK_EQ(times.pgt_enabled, 0);
+ ATF_CHECK_EQ(times.pgt_running, 0);
+ ATF_CHECK_EQ(times.pgt_enabled_wall, 0);
+ ATF_CHECK_EQ(times.pgt_wall, 0);
+ ATF_CHECK_EQ(times.pgt_flags, PMC_GROUP_F_TIME_THREAD_NS);
+
+ n = PMC_GROUP_MAX_MEMBERS + 1;
+ errno = 0;
+ ATF_CHECK_EQ(pmc_group_read(group.tg_ids[group.tg_leader], &n,
+ members, ×), -1);
+ ATF_CHECK_EQ(errno, EINVAL);
+ ATF_CHECK_EQ(n, PMC_GROUP_MAX_MEMBERS + 1);
+
+ memset(members, 0xa5, sizeof(members));
+ memcpy(members_before, members, sizeof(members));
+ memset(×, 0xa5, sizeof(times));
+ memcpy(×_before, ×, sizeof(times));
+ n = nitems(members);
+ errno = 0;
+ ATF_CHECK_EQ(pmc_group_read(group.tg_ids[0], &n, members, ×), -1);
+ ATF_CHECK_EQ(errno, ENOTTY);
+ ATF_CHECK_EQ(n, nitems(members));
+ ATF_CHECK(memcmp(members, members_before, sizeof(members)) == 0);
+ ATF_CHECK(memcmp(×, ×_before, sizeof(times)) == 0);
+
+ value = 11;
+ enabled = 22;
+ running = 33;
+ errno = 0;
+ ATF_CHECK_EQ(pmc_read_pair(group.tg_ids[0], &value, &enabled,
+ &running), -1);
+ ATF_CHECK_EQ(errno, EOPNOTSUPP);
+ ATF_CHECK_EQ(value, 11);
+ ATF_CHECK_EQ(enabled, 22);
+ ATF_CHECK_EQ(running, 33);
+
+ cleanup_group(&group);
+}
+
+ATF_TC_WITHOUT_HEAD(live_snapshot);
+ATF_TC_BODY(live_snapshot, tc)
+{
+ struct pmc_group_member first, second, third;
+ struct pmc_group_times first_times, second_times, third_times;
+ struct test_group group;
+ pmc_value_t pair_value;
+ uint64_t pair_enabled, pair_running;
+ uint32_t n;
+
+ require_hwpmc();
+ ATF_REQUIRE_MSG(setup_group(&group, 1, 0) == 0,
+ "setup_group failed: %s", strerror(errno));
+ if (pmc_attach(group.tg_ids[0], getpid()) != 0) {
+ ATF_CHECK_MSG(false, "pmc_attach failed: %s", strerror(errno));
+ cleanup_group(&group);
+ return;
+ }
+ if (pmc_start(group.tg_ids[0]) != 0) {
+ ATF_CHECK_MSG(false, "pmc_start failed: %s", strerror(errno));
+ cleanup_group(&group);
+ return;
+ }
+ group.tg_started = true;
+
+ spin();
+ n = 1;
+ if (pmc_group_read(group.tg_ids[0], &n, &first, &first_times) != 0) {
+ ATF_CHECK_MSG(false, "first group read failed: %s",
+ strerror(errno));
+ cleanup_group(&group);
+ return;
+ }
+ n = 1;
+ if (pmc_group_read(group.tg_ids[0], &n, &second,
+ &second_times) != 0) {
+ ATF_CHECK_MSG(false, "second group read failed: %s",
+ strerror(errno));
+ cleanup_group(&group);
+ return;
+ }
+ spin();
+ n = 1;
+ if (pmc_group_read(group.tg_ids[0], &n, &third, &third_times) != 0) {
+ ATF_CHECK_MSG(false, "third group read failed: %s",
+ strerror(errno));
+ cleanup_group(&group);
+ return;
+ }
+
+ ATF_CHECK_EQ(first.pm_pmcid, group.tg_ids[0]);
+ ATF_CHECK(first.pm_value > 0);
+ ATF_CHECK(second.pm_value >= first.pm_value);
+ ATF_CHECK(third.pm_value > second.pm_value);
+ ATF_CHECK(second.pm_value - first.pm_value < first.pm_value);
+ ATF_CHECK(first_times.pgt_running <= first_times.pgt_enabled);
+ ATF_CHECK(second_times.pgt_running <= second_times.pgt_enabled);
+ ATF_CHECK(third_times.pgt_running <= third_times.pgt_enabled);
+ ATF_CHECK(first_times.pgt_enabled_wall > 0);
+ ATF_CHECK(first_times.pgt_wall > 0);
+ ATF_CHECK(second_times.pgt_enabled >= first_times.pgt_enabled);
+ ATF_CHECK(second_times.pgt_running >= first_times.pgt_running);
+ ATF_CHECK(second_times.pgt_enabled_wall >=
+ first_times.pgt_enabled_wall);
+ ATF_CHECK(second_times.pgt_wall >= first_times.pgt_wall);
+ ATF_CHECK(third_times.pgt_enabled > second_times.pgt_enabled);
+ ATF_CHECK(third_times.pgt_running > second_times.pgt_running);
+ ATF_CHECK(third_times.pgt_enabled_wall >
+ second_times.pgt_enabled_wall);
+ ATF_CHECK(third_times.pgt_wall > second_times.pgt_wall);
+ ATF_CHECK_EQ(third_times.pgt_flags, PMC_GROUP_F_TIME_THREAD_NS);
+
+ pair_value = 0;
+ pair_enabled = 0;
+ pair_running = 0;
+ ATF_CHECK_EQ(pmc_read_pair(group.tg_ids[0], &pair_value,
+ &pair_enabled, &pair_running), 0);
+ ATF_CHECK(pair_value >= third.pm_value);
+ ATF_CHECK(pair_enabled >= third_times.pgt_enabled);
+ ATF_CHECK(pair_running >= third_times.pgt_running);
+ ATF_CHECK(pair_running <= pair_enabled);
+
+ cleanup_group(&group);
+}
+
+ATF_TC_WITHOUT_HEAD(sampling_member);
+ATF_TC_BODY(sampling_member, tc)
+{
+ struct pmc_group_member members[2];
+ struct pmc_group_times times;
+ struct test_group group;
+ uint32_t n;
+
+ require_hwpmc();
+ memset(&group, 0, sizeof(group));
+ group.tg_nmembers = 2;
+ group.tg_leader = 0;
+ group.tg_ids[0] = group.tg_ids[1] = PMC_ID_INVALID;
+ ATF_REQUIRE_MSG(pmc_allocate_group("instructions", PMC_MODE_TC, 0,
+ PMC_CPU_ANY, &group.tg_ids[0], 0) == 0,
+ "counting allocation failed: %s", strerror(errno));
+ ATF_REQUIRE_MSG(pmc_allocate_group("instructions", PMC_MODE_TS, 0,
+ PMC_CPU_ANY, &group.tg_ids[1], 1000) == 0,
+ "sampling allocation failed: %s", strerror(errno));
+ ATF_REQUIRE(pmc_group_create(&group.tg_groupid) == 0);
+ ATF_REQUIRE(pmc_group_add(group.tg_groupid, group.tg_ids[0], 1) == 0);
+ ATF_REQUIRE(pmc_group_add(group.tg_groupid, group.tg_ids[1], 0) == 0);
+ ATF_REQUIRE_MSG(pmc_group_commit(group.tg_groupid) == 0,
+ "mixed group commit failed: %s", strerror(errno));
+
+ memset(members, 0, sizeof(members));
+ memset(×, 0, sizeof(times));
+ n = nitems(members);
+ ATF_REQUIRE_MSG(pmc_group_read(group.tg_ids[0], &n, members,
+ ×) == 0, "mixed group read failed: %s", strerror(errno));
+ ATF_CHECK_EQ(n, 2);
+ ATF_CHECK_EQ(members[0].pm_pmcid, group.tg_ids[0]);
+ ATF_CHECK_EQ(members[0].pm_mflags, 0);
+ ATF_CHECK_EQ(members[1].pm_pmcid, group.tg_ids[1]);
+ ATF_CHECK_EQ(members[1].pm_mflags, PMC_GROUP_MEMBER_F_SAMPLES);
+ ATF_CHECK_EQ(members[1].pm_value, 0);
+ cleanup_group(&group);
+}
+
+ATF_TC_WITHOUT_HEAD(sampling_live);
+ATF_TC_BODY(sampling_live, tc)
+{
+ struct pmc_group_member first, second;
+ struct pmc_group_times first_times, second_times;
+ struct test_group group;
+ pmc_value_t pair_value;
+ FILE *logfile;
+ uint64_t pair_enabled, pair_running;
+ uint32_t n;
+
+ require_hwpmc();
+ logfile = tmpfile();
+ ATF_REQUIRE(logfile != NULL);
+ ATF_REQUIRE_MSG(pmc_configure_logfile(fileno(logfile)) == 0,
+ "logfile configuration failed: %s", strerror(errno));
+ memset(&group, 0, sizeof(group));
+ group.tg_nmembers = 1;
+ group.tg_leader = 0;
+ group.tg_ids[0] = group.tg_ids[1] = PMC_ID_INVALID;
+ ATF_REQUIRE_MSG(pmc_allocate_group("instructions", PMC_MODE_TS, 0,
+ PMC_CPU_ANY, &group.tg_ids[0], 1000) == 0,
+ "sampling allocation failed: %s", strerror(errno));
+ ATF_REQUIRE(pmc_group_create(&group.tg_groupid) == 0);
+ ATF_REQUIRE(pmc_group_add(group.tg_groupid, group.tg_ids[0], 1) == 0);
+ ATF_REQUIRE_MSG(pmc_group_commit(group.tg_groupid) == 0,
+ "sampling group commit failed: %s", strerror(errno));
+ ATF_REQUIRE_MSG(pmc_attach(group.tg_ids[0], getpid()) == 0,
+ "sampling attach failed: %s", strerror(errno));
+ ATF_REQUIRE_MSG(pmc_start(group.tg_ids[0]) == 0,
+ "sampling start failed: %s", strerror(errno));
+ group.tg_started = true;
+
+ spin();
+ n = 1;
+ ATF_REQUIRE_MSG(pmc_group_read(group.tg_ids[0], &n, &first,
+ &first_times) == 0, "live sampling read failed: %s",
+ strerror(errno));
+ ATF_CHECK_EQ(first.pm_mflags, PMC_GROUP_MEMBER_F_SAMPLES);
+ ATF_CHECK(first.pm_value > 0);
+ ATF_CHECK(first_times.pgt_running <= first_times.pgt_enabled);
+ ATF_REQUIRE(pmc_stop(group.tg_ids[0]) == 0);
+ group.tg_started = false;
+ n = 1;
+ ATF_REQUIRE(pmc_group_read(group.tg_ids[0], &n, &second,
+ &second_times) == 0);
+ ATF_CHECK(second.pm_value >= first.pm_value);
+ ATF_CHECK(second_times.pgt_enabled >= first_times.pgt_enabled);
+ ATF_CHECK(second_times.pgt_running >= first_times.pgt_running);
+
+ pair_value = pair_enabled = pair_running = 0;
+ ATF_REQUIRE(pmc_read_pair(group.tg_ids[0], &pair_value,
+ &pair_enabled, &pair_running) == 0);
+ ATF_CHECK(pair_value >= second.pm_value);
+ ATF_CHECK(pair_running <= pair_enabled);
+ cleanup_group(&group);
+ ATF_REQUIRE(pmc_configure_logfile(-1) == 0);
+ ATF_REQUIRE(fclose(logfile) == 0);
+}
+
+/* Check that a size query returns group times. */
+ATF_TC_WITHOUT_HEAD(times_without_members);
+ATF_TC_BODY(times_without_members, tc)
+{
+ struct pmc_group_member member;
+ struct pmc_group_times query_times, member_times;
+ struct test_group group;
+ uint32_t n;
+
+ require_hwpmc();
+ ATF_REQUIRE_MSG(setup_group(&group, 1, 0) == 0,
+ "setup_group failed: %s", strerror(errno));
+ if (pmc_attach(group.tg_ids[0], getpid()) != 0) {
+ ATF_CHECK_MSG(false, "pmc_attach failed: %s", strerror(errno));
+ cleanup_group(&group);
+ return;
+ }
+ if (pmc_start(group.tg_ids[0]) != 0) {
+ ATF_CHECK_MSG(false, "pmc_start failed: %s", strerror(errno));
+ cleanup_group(&group);
+ return;
+ }
+ group.tg_started = true;
+
+ spin();
+ memset(&query_times, 0, sizeof(query_times));
+ n = 0;
+ if (pmc_group_read(group.tg_ids[0], &n, NULL, &query_times) != 0) {
+ ATF_CHECK_MSG(false, "size query failed: %s", strerror(errno));
+ cleanup_group(&group);
+ return;
+ }
+ ATF_CHECK_EQ(n, group.tg_nmembers);
+ ATF_CHECK(query_times.pgt_enabled > 0);
+ ATF_CHECK(query_times.pgt_running > 0);
+ ATF_CHECK(query_times.pgt_enabled_wall > 0);
+ ATF_CHECK(query_times.pgt_wall > 0);
+ ATF_CHECK(query_times.pgt_running <= query_times.pgt_enabled);
+ ATF_CHECK_EQ(query_times.pgt_flags, PMC_GROUP_F_TIME_THREAD_NS);
+
+ /* Check the times with a member read. */
+ memset(&member_times, 0, sizeof(member_times));
+ n = 1;
+ if (pmc_group_read(group.tg_ids[0], &n, &member, &member_times) != 0) {
+ ATF_CHECK_MSG(false, "member read failed: %s",
+ strerror(errno));
+ cleanup_group(&group);
+ return;
+ }
+ ATF_CHECK(member_times.pgt_enabled >= query_times.pgt_enabled);
+ ATF_CHECK(member_times.pgt_running >= query_times.pgt_running);
+ ATF_CHECK_EQ(member_times.pgt_flags, query_times.pgt_flags);
+
+ cleanup_group(&group);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, capacity_and_order);
+ ATF_TP_ADD_TC(tp, live_snapshot);
+ ATF_TP_ADD_TC(tp, sampling_member);
+ ATF_TP_ADD_TC(tp, sampling_live);
+ ATF_TP_ADD_TC(tp, times_without_members);
+ return (atf_no_error());
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Tue, Oct 20, 5:05 AM (7 h, 29 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
41092305
Default Alt Text
D59371.id189835.diff (28 KB)
Attached To
Mode
D59371: tests: cover PMC group lifecycle and snapshots
Attached
Detach File
Event Timeline
Log In to Comment