Skip to contentSkip to conversation

perf/x86 queue

PATCH In review Peter Zijlstra 14 participants 121 messages Jan 22, 2010 – Apr 7, 2010

Subsystems (12)
x86 VFS Kbuild Library code +8 more subsystems
lore
Share & tools
lore
#0 lore raw

cover perf/x86 queue

This is my current perf/x86 queue, after I test this lot a bit, I'll look at stacking that AMD stuff on top.

After that I'll have a look at Roberts bits, most of that looked quite nice.

#1 lore raw

PATCH 1/10 perf_events: improve x86 event scheduling (v5)

This patch improves event scheduling by maximizing the use of PMU registers regardless of the order in which events are created in a group.

The algorithm takes into account the list of counter constraints for each event. It assigns events to counters from the most constrained, i.e., works on only one counter, to the least constrained, i.e., works on any counter.

Intel Fixed counter events and the BTS special event are also handled via this algorithm which is designed to be fairly generic.

The patch also updates the validation of an event to use the scheduling algorithm. This will cause early failure in perf_event_open().

The 2nd version of this patch follows the model used by PPC, by running the scheduling algorithm and the actual assignment separately. Actual assignment takes place in hw_perf_enable() whereas scheduling is implemented in hw_perf_group_sched_in() and x86_pmu_enable().

[[email protected]: fixup whitespace and style nits as well as

                         adding is_x86_event() ]

LKML-Reference: <[email protected]>

---
 arch/x86/include/asm/perf_event.h |   16 
 arch/x86/kernel/cpu/perf_event.c  |  771 +++++++++++++++++++++++++++-----------
 2 files changed, 572 insertions(+), 215 deletions(-)
arch/x86/include/asm/perf_event.h +14 -2
Index: linux-2.6/arch/x86/include/asm/perf_event.h
===================================================================
@@ -27,7 +27,14 @@
 /*
  * Includes eventsel and unit mask as well:
  */
-#define ARCH_PERFMON_EVENT_MASK				    0xffff
+
+
+#define INTEL_ARCH_EVTSEL_MASK		0x000000FFULL
+#define INTEL_ARCH_UNIT_MASK		0x0000FF00ULL
+#define INTEL_ARCH_EDGE_MASK		0x00040000ULL
+#define INTEL_ARCH_INV_MASK		0x00800000ULL
+#define INTEL_ARCH_CNT_MASK		0xFF000000ULL
+#define INTEL_ARCH_EVENT_MASK	(INTEL_ARCH_UNIT_MASK|INTEL_ARCH_EVTSEL_MASK)
 
 /*
  * filter mask to validate fixed counter events.
@@ -38,7 +45,12 @@
  *  The other filters are supported by fixed counters.
  *  The any-thread option is supported starting with v3.
  */
-#define ARCH_PERFMON_EVENT_FILTER_MASK			0xff840000
+#define INTEL_ARCH_FIXED_MASK \
+	(INTEL_ARCH_CNT_MASK| \
+	 INTEL_ARCH_INV_MASK| \
+	 INTEL_ARCH_EDGE_MASK|\
+	 INTEL_ARCH_UNIT_MASK|\
+	 INTEL_ARCH_EVENT_MASK)
 
 #define ARCH_PERFMON_UNHALTED_CORE_CYCLES_SEL		      0x3c
 #define ARCH_PERFMON_UNHALTED_CORE_CYCLES_UMASK		(0x00 << 8)
arch/x86/kernel/cpu/perf_event.c +558 -213

949 lines not on this page · raw message

#2 lore raw

PATCH 2/10 perf_events: Add fast-path to the rescheduling code

In reply to Peter Zijlstra

The 6th version does:
- implement correct fastpath scheduling, i.e., reuse previous assignment
- skip reprogramming counters in hw_perf_enable() with a generation number

LKML-Reference: <[email protected]>

---
 arch/x86/kernel/cpu/perf_event.c |  148 +++++++++++++++++++++++----------------
 include/linux/perf_event.h       |    2 
 2 files changed, 93 insertions(+), 57 deletions(-)
arch/x86/kernel/cpu/perf_event.c +91 -57
Index: linux-2.6/arch/x86/kernel/cpu/perf_event.c
===================================================================
@@ -87,6 +87,7 @@ struct cpu_hw_events {
 	int			n_events;
 	int			n_added;
 	int			assign[X86_PMC_IDX_MAX]; /* event to counter assignment */
+	u64			tags[X86_PMC_IDX_MAX];
 	struct perf_event	*event_list[X86_PMC_IDX_MAX]; /* in enabled order */
 };
 
@@ -1013,6 +1014,8 @@ static int __hw_perf_event_init(struct p
 	hwc->config = ARCH_PERFMON_EVENTSEL_INT;
 
 	hwc->idx = -1;
+	hwc->last_cpu = -1;
+	hwc->last_tag = ~0ULL;
 
 	/*
 	 * Count user and OS events unless requested not to.
@@ -1245,6 +1248,46 @@ static int x86_schedule_events(struct cp
 	}
 
 	/*
+	 * fastpath, try to reuse previous register
+	 */
+	for (i = 0, num = n; i < n; i++, num--) {
+		hwc = &cpuc->event_list[i]->hw;
+		c = (unsigned long *)constraints[i];
+
+		/* never assigned */
+		if (hwc->idx == -1)
+			break;
+
+		/* constraint still honored */
+		if (!test_bit(hwc->idx, c))
+			break;
+
+		/* not already used */
+		if (test_bit(hwc->idx, used_mask))
+			break;
+
+#if 0
+		pr_debug("CPU%d fast config=0x%llx idx=%d assign=%c\n",
+			 smp_processor_id(),
+			 hwc->config,
+			 hwc->idx,
+			 assign ? 'y' : 'n');
+#endif
+
+		set_bit(hwc->idx, used_mask);
+		if (assign)
+			assign[i] = hwc->idx;
+	}
+	if (!num)
+		goto done;
+
+	/*
+	 * begin slow path
+	 */
+
+	bitmap_zero(used_mask, X86_PMC_IDX_MAX);
+
+	/*
 	 * weight = number of possible counters
 	 *
 	 * 1    = most constrained, only works on one counter
@@ -1263,10 +1306,9 @@ static int x86_schedule_events(struct cp
 	if (x86_pmu.num_events_fixed)
 		wmax++;
 
-	num = n;
-	for (w = 1; num && w <= wmax; w++) {
+	for (w = 1, num = n; num && w <= wmax; w++) {
 		/* for each event */
-		for (i = 0; i < n; i++) {
+		for (i = 0; num && i < n; i++) {
 			c = (unsigned long *)constraints[i];
 			hwc = &cpuc->event_list[i]->hw;
 
@@ -1274,28 +1316,6 @@ static int x86_schedule_events(struct cp
 			if (weight != w)
 				continue;
 
-			/*
-			 * try to reuse previous assignment
-			 *
-			 * This is possible despite the fact that
-			 * events or events order may have changed.
-			 *
-			 * What matters is the level of constraints
-			 * of an event and this is constant for now.
-			 *
-			 * This is possible also because we always
-			 * scan from most to least constrained. Thus,
-			 * if a counter can be reused, it means no,
-			 * more constrained events, needed it. And
-			 * next events will either compete for it
-			 * (which cannot be solved anyway) or they
-			 * have fewer constraints, and they can use
-			 * another counter.
-			 */
-			j = hwc->idx;
-			if (j != -1 && !test_bit(j, used_mask))
-				goto skip;
-
 			for_each_bit(j, c, X86_PMC_IDX_MAX) {
 				if (!test_bit(j, used_mask))
 					break;
@@ -1303,22 +1323,23 @@ static int x86_schedule_events(struct cp
 
 			if (j == X86_PMC_IDX_MAX)
 				break;
-skip:
-			set_bit(j, used_mask);
 
 #if 0
-			pr_debug("CPU%d config=0x%llx idx=%d assign=%c\n",
+			pr_debug("CPU%d slow config=0x%llx idx=%d assign=%c\n",
 				smp_processor_id(),
 				hwc->config,
 				j,
 				assign ? 'y' : 'n');
 #endif
 
+			set_bit(j, used_mask);
+
 			if (assign)
 				assign[i] = j;
 			num--;
 		}
 	}
+done:
 	/*
 	 * scheduling failed or is just a simulation,
 	 * free resources if necessary
@@ -1357,7 +1378,7 @@ static int collect_events(struct cpu_hw_
 
 	list_for_each_entry(event, &leader->sibling_list, group_entry) {
 		if (!is_x86_event(event) ||
-		    event->state == PERF_EVENT_STATE_OFF)
+		    event->state <= PERF_EVENT_STATE_OFF)
 			continue;
 
 		if (n >= max_count)
@@ -1369,11 +1390,15 @@ static int collect_events(struct cpu_hw_
 	return n;
 }
 
-
 static inline void x86_assign_hw_event(struct perf_event *event,
-				struct hw_perf_event *hwc, int idx)
+				struct cpu_hw_events *cpuc,
+				int idx)
 {
+	struct hw_perf_event *hwc = &event->hw;
+
 	hwc->idx = idx;
+	hwc->last_cpu = smp_processor_id();
+	hwc->last_tag = ++cpuc->tags[idx];
 
 	if (hwc->idx == X86_PMC_IDX_FIXED_BTS) {
 		hwc->config_base = 0;
@@ -1392,6 +1417,14 @@ static inline void x86_assign_hw_event(s
 	}
 }
 
+static bool match_prev_assignment(struct hw_perf_event *hwc,
+				  struct cpu_hw_events *cpuc, int idx)
+{
+	return hwc->idx == cpuc->assign[idx] &&
+	       hwc->last_cpu == smp_processor_id() &&
+	       hwc->last_tag == cpuc->tags[idx];
+}
+
 void hw_perf_enable(void)
 {
 	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
@@ -1401,45 +1434,33 @@ void hw_perf_enable(void)
 
 	if (!x86_pmu_initialized())
 		return;
+
 	if (cpuc->n_added) {
 		/*
 		 * apply assignment obtained either from
 		 * hw_perf_group_sched_in() or x86_pmu_enable()
 		 *
-		 * step1: save events moving to new counters
-		 * step2: reprogram moved events into new counters
+		 * We either re-enable or re-program and re-enable.
+		 * All events are disabled by the time we come here.
+		 * That means their state has been saved already.
 		 */
 		for (i = 0; i < cpuc->n_events; i++) {
-
 			event = cpuc->event_list[i];
 			hwc = &event->hw;
 
-			if (hwc->idx == -1 || hwc->idx == cpuc->assign[i])
-				continue;
-
-			x86_pmu.disable(hwc, hwc->idx);
-
-			clear_bit(hwc->idx, cpuc->active_mask);
-			barrier();
-			cpuc->events[hwc->idx] = NULL;
-
-			x86_perf_event_update(event, hwc, hwc->idx);
-
-			hwc->idx = -1;
-		}
-
-		for (i = 0; i < cpuc->n_events; i++) {
-
-			event = cpuc->event_list[i];
-			hwc = &event->hw;
-
-			if (hwc->idx == -1) {
-				x86_assign_hw_event(event, hwc, cpuc->assign[i]);
+			/*
+			 * we can avoid reprogramming counter if:
+			 * - assigned same counter as last time
+			 * - running on same CPU as last time
+			 * - no other event has used the counter since
+			 */
+			if (!match_prev_assignment(hwc, cpuc, i)) {
+				x86_assign_hw_event(event, cpuc, cpuc->assign[i]);
 				x86_perf_event_set_period(event, hwc, hwc->idx);
 			}
 			/*
 			 * need to mark as active because x86_pmu_disable()
-			 * clear active_mask and eventsp[] yet it preserves
+			 * clear active_mask and events[] yet it preserves
 			 * idx
 			 */
 			set_bit(hwc->idx, cpuc->active_mask);
@@ -2191,6 +2212,8 @@ static void amd_get_event_constraints(st
 				      struct perf_event *event,
 				      u64 *idxmsk)
 {
+	/* no constraints, means supports all generic counters */
+	bitmap_fill((unsigned long *)idxmsk, x86_pmu.num_events);
 }
 
 static int x86_event_sched_in(struct perf_event *event,
@@ -2265,7 +2288,7 @@ int hw_perf_group_sched_in(struct perf_e
 
 	n1 = 1;
 	list_for_each_entry(sub, &leader->sibling_list, group_entry) {
-		if (sub->state != PERF_EVENT_STATE_OFF) {
+		if (sub->state > PERF_EVENT_STATE_OFF) {
 			ret = x86_event_sched_in(sub, cpuctx, cpu);
 			if (ret)
 				goto undo;
@@ -2620,12 +2643,23 @@ static int validate_group(struct perf_ev
 
 const struct pmu *hw_perf_event_init(struct perf_event *event)
 {
+	const struct pmu *tmp;
 	int err;
 
 	err = __hw_perf_event_init(event);
 	if (!err) {
+		/*
+		 * we temporarily connect event to its pmu
+		 * such that validate_group() can classify
+		 * it as an x86 event using is_x86_event()
+		 */
+		tmp = event->pmu;
+		event->pmu = &pmu;
+
 		if (event->group_leader != event)
 			err = validate_group(event);
+
+		event->pmu = tmp;
 	}
 	if (err) {
 		if (event->destroy)
include/linux/perf_event.h +2 -0
Index: linux-2.6/include/linux/perf_event.h
===================================================================
@@ -478,9 +478,11 @@ struct hw_perf_event {
 	union {
 		struct { /* hardware */
 			u64		config;
+			u64		last_tag;
 			unsigned long	config_base;
 			unsigned long	event_base;
 			int		idx;
+			int		last_cpu;
 		};
 		struct { /* software */
 			s64		remaining;
#3 lore raw

PATCH 3/10 perf_event: x86: Allocate the fake_cpuc

In reply to Peter Zijlstra

GCC was complaining the stack usage was too large, so allocate the structure.

LKML-Reference: <new-submission>

---
 arch/x86/kernel/cpu/perf_event.c |   29 +++++++++++++++++++----------
 1 file changed, 19 insertions(+), 10 deletions(-)
arch/x86/kernel/cpu/perf_event.c +19 -10
Index: linux-2.6/arch/x86/kernel/cpu/perf_event.c
===================================================================
@@ -2614,10 +2614,13 @@ static const struct pmu pmu = {
 static int validate_group(struct perf_event *event)
 {
 	struct perf_event *leader = event->group_leader;
-	struct cpu_hw_events fake_cpuc;
-	int n;
+	struct cpu_hw_events *fake_cpuc;
+	int ret, n;
 
-	memset(&fake_cpuc, 0, sizeof(fake_cpuc));
+	ret = -ENOMEM;
+	fake_cpuc = kmalloc(sizeof(*fake_cpuc), GFP_KERNEL | __GFP_ZERO);
+	if (!fake_cpuc)
+		goto out;
 
 	/*
 	 * the event is not yet connected with its
@@ -2625,18 +2628,24 @@ static int validate_group(struct perf_ev
 	 * existing siblings, then add the new event
 	 * before we can simulate the scheduling
 	 */
-	n = collect_events(&fake_cpuc, leader, true);
+	ret = -ENOSPC;
+	n = collect_events(fake_cpuc, leader, true);
 	if (n < 0)
-		return -ENOSPC;
+		goto out_free;
 
-	fake_cpuc.n_events = n;
-	n = collect_events(&fake_cpuc, event, false);
+	fake_cpuc->n_events = n;
+	n = collect_events(fake_cpuc, event, false);
 	if (n < 0)
-		return -ENOSPC;
+		goto out_free;
 
-	fake_cpuc.n_events = n;
+	fake_cpuc->n_events = n;
 
-	return x86_schedule_events(&fake_cpuc, n, NULL);
+	ret = x86_schedule_events(fake_cpuc, n, NULL);
+
+out_free:
+	kfree(fake_cpuc);
+out:
+	return ret;
 }
 
 const struct pmu *hw_perf_event_init(struct perf_event *event)
#4 lore raw

[tip:perf/core] perf_event: x86: Allocate the fake_cpuc

Commit-ID:  502568d563bcc37ac505a83341c0c95b88c015a8
Gitweb:     http://git.kernel.org/tip/502568d563bcc37ac505a83341c0c95b88c015a8
Author:     Peter Zijlstra <[email protected]>
AuthorDate: Fri, 22 Jan 2010 14:35:46 +0100
Committer:  Ingo Molnar <[email protected]>
CommitDate: Fri, 29 Jan 2010 09:01:35 +0100

perf_event: x86: Allocate the fake_cpuc

GCC was complaining the stack usage was too large, so allocate the structure.

Cc Stephane Eranian <[email protected]>

LKML-Reference: <[email protected]>

---
 arch/x86/kernel/cpu/perf_event.c |   29 +++++++++++++++++++----------
 1 files changed, 19 insertions(+), 10 deletions(-)
arch/x86/kernel/cpu/perf_event.c +19 -10
index 0bd23d0..7bd359a 100644
@@ -2606,10 +2606,13 @@ static const struct pmu pmu = {
 static int validate_group(struct perf_event *event)
 {
 	struct perf_event *leader = event->group_leader;
-	struct cpu_hw_events fake_cpuc;
-	int n;
+	struct cpu_hw_events *fake_cpuc;
+	int ret, n;
 
-	memset(&fake_cpuc, 0, sizeof(fake_cpuc));
+	ret = -ENOMEM;
+	fake_cpuc = kmalloc(sizeof(*fake_cpuc), GFP_KERNEL | __GFP_ZERO);
+	if (!fake_cpuc)
+		goto out;
 
 	/*
 	 * the event is not yet connected with its
@@ -2617,18 +2620,24 @@ static int validate_group(struct perf_event *event)
 	 * existing siblings, then add the new event
 	 * before we can simulate the scheduling
 	 */
-	n = collect_events(&fake_cpuc, leader, true);
+	ret = -ENOSPC;
+	n = collect_events(fake_cpuc, leader, true);
 	if (n < 0)
-		return -ENOSPC;
+		goto out_free;
 
-	fake_cpuc.n_events = n;
-	n = collect_events(&fake_cpuc, event, false);
+	fake_cpuc->n_events = n;
+	n = collect_events(fake_cpuc, event, false);
 	if (n < 0)
-		return -ENOSPC;
+		goto out_free;
 
-	fake_cpuc.n_events = n;
+	fake_cpuc->n_events = n;
 
-	return x86_schedule_events(&fake_cpuc, n, NULL);
+	ret = x86_schedule_events(fake_cpuc, n, NULL);
+
+out_free:
+	kfree(fake_cpuc);
+out:
+	return ret;
 }
 
 const struct pmu *hw_perf_event_init(struct perf_event *event)
#5 lore raw

PATCH 4/10 perf_event: x86: Fixup weight tying issue

In reply to Peter Zijlstra

constraints gets defined an u64 but in long quantities and then cast to long.

LKML-Reference: <new-submission>

---
 arch/x86/kernel/cpu/perf_event.c |    6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
arch/x86/kernel/cpu/perf_event.c +3 -3
Index: linux-2.6/arch/x86/kernel/cpu/perf_event.c
===================================================================
@@ -1235,7 +1235,7 @@ static int x86_schedule_events(struct cp
 	int i, j , w, num;
 	int weight, wmax;
 	unsigned long *c;
-	u64 constraints[X86_PMC_IDX_MAX][BITS_TO_LONGS(X86_PMC_IDX_MAX)];
+	unsigned long constraints[X86_PMC_IDX_MAX][BITS_TO_LONGS(X86_PMC_IDX_MAX)];
 	unsigned long used_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
 	struct hw_perf_event *hwc;
 
@@ -1252,7 +1252,7 @@ static int x86_schedule_events(struct cp
 	 */
 	for (i = 0, num = n; i < n; i++, num--) {
 		hwc = &cpuc->event_list[i]->hw;
-		c = (unsigned long *)constraints[i];
+		c = constraints[i];
 
 		/* never assigned */
 		if (hwc->idx == -1)
@@ -1309,7 +1309,7 @@ static int x86_schedule_events(struct cp
 	for (w = 1, num = n; num && w <= wmax; w++) {
 		/* for each event */
 		for (i = 0; num && i < n; i++) {
-			c = (unsigned long *)constraints[i];
+			c = constraints[i];
 			hwc = &cpuc->event_list[i]->hw;
 
 			weight = bitmap_weight(c, X86_PMC_IDX_MAX);
#6 lore raw

[tip:perf/core] perf_event: x86: Fixup constraints typing issue

Commit-ID:  81269a085669b5130058a0275aa7ba9f94abd1fa
Gitweb:     http://git.kernel.org/tip/81269a085669b5130058a0275aa7ba9f94abd1fa
Author:     Peter Zijlstra <[email protected]>
AuthorDate: Fri, 22 Jan 2010 14:55:22 +0100
Committer:  Ingo Molnar <[email protected]>
CommitDate: Fri, 29 Jan 2010 09:01:36 +0100

perf_event: x86: Fixup constraints typing issue

Constraints gets defined an u64 but in long quantities and then cast to long.

Cc Stephane Eranian <[email protected]>

LKML-Reference: <[email protected]>

---
 arch/x86/kernel/cpu/perf_event.c |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)
arch/x86/kernel/cpu/perf_event.c +3 -3
index 7bd359a..7e181a5 100644
@@ -1232,7 +1232,7 @@ static int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)
 	int i, j , w, num;
 	int weight, wmax;
 	unsigned long *c;
-	u64 constraints[X86_PMC_IDX_MAX][BITS_TO_LONGS(X86_PMC_IDX_MAX)];
+	unsigned long constraints[X86_PMC_IDX_MAX][BITS_TO_LONGS(X86_PMC_IDX_MAX)];
 	unsigned long used_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
 	struct hw_perf_event *hwc;
 
@@ -1249,7 +1249,7 @@ static int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)
 	 */
 	for (i = 0, num = n; i < n; i++, num--) {
 		hwc = &cpuc->event_list[i]->hw;
-		c = (unsigned long *)constraints[i];
+		c = constraints[i];
 
 		/* never assigned */
 		if (hwc->idx == -1)
@@ -1306,7 +1306,7 @@ static int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)
 	for (w = 1, num = n; num && w <= wmax; w++) {
 		/* for each event */
 		for (i = 0; num && i < n; i++) {
-			c = (unsigned long *)constraints[i];
+			c = constraints[i];
 			hwc = &cpuc->event_list[i]->hw;
 
 			weight = bitmap_weight(c, X86_PMC_IDX_MAX);
#7 lore raw

PATCH 5/10 perf_event: x86: Clean up some of the u64/long bitmask casting

In reply to Peter Zijlstra

We need this to be u64 for direct assigment, but the bitmask functions all work on unsigned long, leading to cast heaven, solve this by using a union.

LKML-Reference: <new-submission>

---
 arch/x86/kernel/cpu/perf_event.c |   47 +++++++++++++++++++--------------------
 1 file changed, 23 insertions(+), 24 deletions(-)
arch/x86/kernel/cpu/perf_event.c +23 -24
Index: linux-2.6/arch/x86/kernel/cpu/perf_event.c
===================================================================
@@ -69,10 +69,11 @@ struct debug_store {
 	u64	pebs_event_reset[MAX_PEBS_EVENTS];
 };
 
-#define BITS_TO_U64(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u64))
-
 struct event_constraint {
-	u64	idxmsk[BITS_TO_U64(X86_PMC_IDX_MAX)];
+	union {
+		unsigned long	idxmsk[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
+		u64		idxmsk64[1];
+	};
 	int	code;
 	int	cmask;
 };
@@ -91,13 +92,14 @@ struct cpu_hw_events {
 	struct perf_event	*event_list[X86_PMC_IDX_MAX]; /* in enabled order */
 };
 
-#define EVENT_CONSTRAINT(c, n, m) { \
-	.code = (c),	\
-	.cmask = (m),	\
-	.idxmsk[0] = (n) }
+#define EVENT_CONSTRAINT(c, n, m) { 	\
+	{ .idxmsk64[0] = (n) },		\
+	.code = (c),			\
+	.cmask = (m),			\
+}
 
 #define EVENT_CONSTRAINT_END \
-	{ .code = 0, .cmask = 0, .idxmsk[0] = 0 }
+	EVENT_CONSTRAINT(0, 0, 0)
 
 #define for_each_event_constraint(e, c) \
 	for ((e) = (c); (e)->cmask; (e)++)
@@ -127,8 +129,11 @@ struct x86_pmu {
 	u64		intel_ctrl;
 	void		(*enable_bts)(u64 config);
 	void		(*disable_bts)(void);
-	void		(*get_event_constraints)(struct cpu_hw_events *cpuc, struct perf_event *event, u64 *idxmsk);
-	void		(*put_event_constraints)(struct cpu_hw_events *cpuc, struct perf_event *event);
+	void		(*get_event_constraints)(struct cpu_hw_events *cpuc,
+						 struct perf_event *event,
+						 unsigned long *idxmsk);
+	void		(*put_event_constraints)(struct cpu_hw_events *cpuc,
+						 struct perf_event *event);
 	const struct event_constraint *event_constraints;
 };
 
@@ -2154,14 +2159,11 @@ perf_event_nmi_handler(struct notifier_b
 	return NOTIFY_STOP;
 }
 
-static struct event_constraint bts_constraint = {
-	.code = 0,
-	.cmask = 0,
-	.idxmsk[0] = 1ULL << X86_PMC_IDX_FIXED_BTS
-};
+static struct event_constraint bts_constraint =
+	EVENT_CONSTRAINT(0, 1ULL << X86_PMC_IDX_FIXED_BTS, 0);
 
 static int intel_special_constraints(struct perf_event *event,
-				     u64 *idxmsk)
+				     unsigned long *idxmsk)
 {
 	unsigned int hw_event;
 
@@ -2181,14 +2183,14 @@ static int intel_special_constraints(str
 
 static void intel_get_event_constraints(struct cpu_hw_events *cpuc,
 					struct perf_event *event,
-					u64 *idxmsk)
+					unsigned long *idxmsk)
 {
 	const struct event_constraint *c;
 
 	/*
 	 * cleanup bitmask
 	 */
-	bitmap_zero((unsigned long *)idxmsk, X86_PMC_IDX_MAX);
+	bitmap_zero(idxmsk, X86_PMC_IDX_MAX);
 
 	if (intel_special_constraints(event, idxmsk))
 		return;
@@ -2196,10 +2198,7 @@ static void intel_get_event_constraints(
 	if (x86_pmu.event_constraints) {
 		for_each_event_constraint(c, x86_pmu.event_constraints) {
 			if ((event->hw.config & c->cmask) == c->code) {
-
-				bitmap_copy((unsigned long *)idxmsk,
-					    (unsigned long *)c->idxmsk,
-					    X86_PMC_IDX_MAX);
+				bitmap_copy(idxmsk, c->idxmsk, X86_PMC_IDX_MAX);
 				return;
 			}
 		}
@@ -2210,10 +2209,10 @@ static void intel_get_event_constraints(
 
 static void amd_get_event_constraints(struct cpu_hw_events *cpuc,
 				      struct perf_event *event,
-				      u64 *idxmsk)
+				      unsigned long *idxmsk)
 {
 	/* no constraints, means supports all generic counters */
-	bitmap_fill((unsigned long *)idxmsk, x86_pmu.num_events);
+	bitmap_fill(idxmsk, x86_pmu.num_events);
 }
 
 static int x86_event_sched_in(struct perf_event *event,
#8 lore raw

[tip:perf/core] perf_event: x86: Clean up some of the u64/long bitmask casting

Commit-ID:  c91e0f5da81c6f3a611a1bd6d0cca6717c90fdab
Gitweb:     http://git.kernel.org/tip/c91e0f5da81c6f3a611a1bd6d0cca6717c90fdab
Author:     Peter Zijlstra <[email protected]>
AuthorDate: Fri, 22 Jan 2010 15:25:59 +0100
Committer:  Ingo Molnar <[email protected]>
CommitDate: Fri, 29 Jan 2010 09:01:37 +0100

perf_event: x86: Clean up some of the u64/long bitmask casting

We need this to be u64 for direct assigment, but the bitmask functions all work on unsigned long, leading to cast heaven, solve this by using a union.

Cc Stephane Eranian <[email protected]>

LKML-Reference: <[email protected]>

---
 arch/x86/kernel/cpu/perf_event.c |   47 ++++++++++++++++++-------------------
 1 files changed, 23 insertions(+), 24 deletions(-)
arch/x86/kernel/cpu/perf_event.c +23 -24
index 7e181a5..921bbf7 100644
@@ -69,10 +69,11 @@ struct debug_store {
 	u64	pebs_event_reset[MAX_PEBS_EVENTS];
 };
 
-#define BITS_TO_U64(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u64))
-
 struct event_constraint {
-	u64	idxmsk[BITS_TO_U64(X86_PMC_IDX_MAX)];
+	union {
+		unsigned long	idxmsk[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
+		u64		idxmsk64[1];
+	};
 	int	code;
 	int	cmask;
 };
@@ -90,13 +91,14 @@ struct cpu_hw_events {
 	struct perf_event	*event_list[X86_PMC_IDX_MAX]; /* in enabled order */
 };
 
-#define EVENT_CONSTRAINT(c, n, m) { \
-	.code = (c),	\
-	.cmask = (m),	\
-	.idxmsk[0] = (n) }
+#define EVENT_CONSTRAINT(c, n, m) { 	\
+	{ .idxmsk64[0] = (n) },		\
+	.code = (c),			\
+	.cmask = (m),			\
+}
 
 #define EVENT_CONSTRAINT_END \
-	{ .code = 0, .cmask = 0, .idxmsk[0] = 0 }
+	EVENT_CONSTRAINT(0, 0, 0)
 
 #define for_each_event_constraint(e, c) \
 	for ((e) = (c); (e)->cmask; (e)++)
@@ -126,8 +128,11 @@ struct x86_pmu {
 	u64		intel_ctrl;
 	void		(*enable_bts)(u64 config);
 	void		(*disable_bts)(void);
-	void		(*get_event_constraints)(struct cpu_hw_events *cpuc, struct perf_event *event, u64 *idxmsk);
-	void		(*put_event_constraints)(struct cpu_hw_events *cpuc, struct perf_event *event);
+	void		(*get_event_constraints)(struct cpu_hw_events *cpuc,
+						 struct perf_event *event,
+						 unsigned long *idxmsk);
+	void		(*put_event_constraints)(struct cpu_hw_events *cpuc,
+						 struct perf_event *event);
 	const struct event_constraint *event_constraints;
 };
 
@@ -2144,14 +2149,11 @@ perf_event_nmi_handler(struct notifier_block *self,
 	return NOTIFY_STOP;
 }
 
-static struct event_constraint bts_constraint = {
-	.code = 0,
-	.cmask = 0,
-	.idxmsk[0] = 1ULL << X86_PMC_IDX_FIXED_BTS
-};
+static struct event_constraint bts_constraint =
+	EVENT_CONSTRAINT(0, 1ULL << X86_PMC_IDX_FIXED_BTS, 0);
 
 static int intel_special_constraints(struct perf_event *event,
-				     u64 *idxmsk)
+				     unsigned long *idxmsk)
 {
 	unsigned int hw_event;
 
@@ -2171,14 +2173,14 @@ static int intel_special_constraints(struct perf_event *event,
 
 static void intel_get_event_constraints(struct cpu_hw_events *cpuc,
 					struct perf_event *event,
-					u64 *idxmsk)
+					unsigned long *idxmsk)
 {
 	const struct event_constraint *c;
 
 	/*
 	 * cleanup bitmask
 	 */
-	bitmap_zero((unsigned long *)idxmsk, X86_PMC_IDX_MAX);
+	bitmap_zero(idxmsk, X86_PMC_IDX_MAX);
 
 	if (intel_special_constraints(event, idxmsk))
 		return;
@@ -2186,10 +2188,7 @@ static void intel_get_event_constraints(struct cpu_hw_events *cpuc,
 	if (x86_pmu.event_constraints) {
 		for_each_event_constraint(c, x86_pmu.event_constraints) {
 			if ((event->hw.config & c->cmask) == c->code) {
-
-				bitmap_copy((unsigned long *)idxmsk,
-					    (unsigned long *)c->idxmsk,
-					    X86_PMC_IDX_MAX);
+				bitmap_copy(idxmsk, c->idxmsk, X86_PMC_IDX_MAX);
 				return;
 			}
 		}
@@ -2200,10 +2199,10 @@ static void intel_get_event_constraints(struct cpu_hw_events *cpuc,
 
 static void amd_get_event_constraints(struct cpu_hw_events *cpuc,
 				      struct perf_event *event,
-				      u64 *idxmsk)
+				      unsigned long *idxmsk)
 {
 	/* no constraints, means supports all generic counters */
-	bitmap_fill((unsigned long *)idxmsk, x86_pmu.num_events);
+	bitmap_fill(idxmsk, x86_pmu.num_events);
 }
 
 static int x86_event_sched_in(struct perf_event *event,
#9 lore raw

PATCH 6/10 perf_event: x86: Reduce some overly long lines with some MACROs

In reply to Peter Zijlstra

Introduce INTEL_EVENT_CONSTRAINT and FIXED_EVENT_CONSTRAINT to reduce some line length and typing work.

LKML-Reference: <new-submission>

---
 arch/x86/kernel/cpu/perf_event.c |   68 +++++++++++++++++++++------------------
 1 file changed, 37 insertions(+), 31 deletions(-)
arch/x86/kernel/cpu/perf_event.c +37 -31
Index: linux-2.6/arch/x86/kernel/cpu/perf_event.c
===================================================================
@@ -98,6 +98,12 @@ struct cpu_hw_events {
 	.cmask = (m),			\
 }
 
+#define INTEL_EVENT_CONSTRAINT(c, n)	\
+	EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK)
+
+#define FIXED_EVENT_CONSTRAINT(c, n)	\
+	EVENT_CONSTRAINT(c, n, INTEL_ARCH_FIXED_MASK)
+
 #define EVENT_CONSTRAINT_END \
 	EVENT_CONSTRAINT(0, 0, 0)
 
@@ -193,12 +199,12 @@ static u64 p6_pmu_raw_event(u64 hw_event
 
 static struct event_constraint intel_p6_event_constraints[] =
 {
-	EVENT_CONSTRAINT(0xc1, 0x1, INTEL_ARCH_EVENT_MASK),	/* FLOPS */
-	EVENT_CONSTRAINT(0x10, 0x1, INTEL_ARCH_EVENT_MASK),	/* FP_COMP_OPS_EXE */
-	EVENT_CONSTRAINT(0x11, 0x1, INTEL_ARCH_EVENT_MASK),	/* FP_ASSIST */
-	EVENT_CONSTRAINT(0x12, 0x2, INTEL_ARCH_EVENT_MASK),	/* MUL */
-	EVENT_CONSTRAINT(0x13, 0x2, INTEL_ARCH_EVENT_MASK),	/* DIV */
-	EVENT_CONSTRAINT(0x14, 0x1, INTEL_ARCH_EVENT_MASK),	/* CYCLES_DIV_BUSY */
+	INTEL_EVENT_CONSTRAINT(0xc1, 0x1),	/* FLOPS */
+	INTEL_EVENT_CONSTRAINT(0x10, 0x1),	/* FP_COMP_OPS_EXE */
+	INTEL_EVENT_CONSTRAINT(0x11, 0x1),	/* FP_ASSIST */
+	INTEL_EVENT_CONSTRAINT(0x12, 0x2),	/* MUL */
+	INTEL_EVENT_CONSTRAINT(0x13, 0x2),	/* DIV */
+	INTEL_EVENT_CONSTRAINT(0x14, 0x1),	/* CYCLES_DIV_BUSY */
 	EVENT_CONSTRAINT_END
 };
 
@@ -218,41 +224,41 @@ static const u64 intel_perfmon_event_map
 
 static struct event_constraint intel_core_event_constraints[] =
 {
-	EVENT_CONSTRAINT(0xc0, (0x3|(1ULL<<32)), INTEL_ARCH_FIXED_MASK), /* INSTRUCTIONS_RETIRED */
-	EVENT_CONSTRAINT(0x3c, (0x3|(1ULL<<33)), INTEL_ARCH_FIXED_MASK), /* UNHALTED_CORE_CYCLES */
-	EVENT_CONSTRAINT(0x10, 0x1, INTEL_ARCH_EVENT_MASK), /* FP_COMP_OPS_EXE */
-	EVENT_CONSTRAINT(0x11, 0x2, INTEL_ARCH_EVENT_MASK), /* FP_ASSIST */
-	EVENT_CONSTRAINT(0x12, 0x2, INTEL_ARCH_EVENT_MASK), /* MUL */
-	EVENT_CONSTRAINT(0x13, 0x2, INTEL_ARCH_EVENT_MASK), /* DIV */
-	EVENT_CONSTRAINT(0x14, 0x1, INTEL_ARCH_EVENT_MASK), /* CYCLES_DIV_BUSY */
-	EVENT_CONSTRAINT(0x18, 0x1, INTEL_ARCH_EVENT_MASK), /* IDLE_DURING_DIV */
-	EVENT_CONSTRAINT(0x19, 0x2, INTEL_ARCH_EVENT_MASK), /* DELAYED_BYPASS */
-	EVENT_CONSTRAINT(0xa1, 0x1, INTEL_ARCH_EVENT_MASK), /* RS_UOPS_DISPATCH_CYCLES */
-	EVENT_CONSTRAINT(0xcb, 0x1, INTEL_ARCH_EVENT_MASK), /* MEM_LOAD_RETIRED */
+	FIXED_EVENT_CONSTRAINT(0xc0, (0x3|(1ULL<<32))), /* INSTRUCTIONS_RETIRED */
+	FIXED_EVENT_CONSTRAINT(0x3c, (0x3|(1ULL<<33))), /* UNHALTED_CORE_CYCLES */
+	INTEL_EVENT_CONSTRAINT(0x10, 0x1), /* FP_COMP_OPS_EXE */
+	INTEL_EVENT_CONSTRAINT(0x11, 0x2), /* FP_ASSIST */
+	INTEL_EVENT_CONSTRAINT(0x12, 0x2), /* MUL */
+	INTEL_EVENT_CONSTRAINT(0x13, 0x2), /* DIV */
+	INTEL_EVENT_CONSTRAINT(0x14, 0x1), /* CYCLES_DIV_BUSY */
+	INTEL_EVENT_CONSTRAINT(0x18, 0x1), /* IDLE_DURING_DIV */
+	INTEL_EVENT_CONSTRAINT(0x19, 0x2), /* DELAYED_BYPASS */
+	INTEL_EVENT_CONSTRAINT(0xa1, 0x1), /* RS_UOPS_DISPATCH_CYCLES */
+	INTEL_EVENT_CONSTRAINT(0xcb, 0x1), /* MEM_LOAD_RETIRED */
 	EVENT_CONSTRAINT_END
 };
 
 static struct event_constraint intel_nehalem_event_constraints[] =
 {
-	EVENT_CONSTRAINT(0xc0, (0x3|(1ULL<<32)), INTEL_ARCH_FIXED_MASK), /* INSTRUCTIONS_RETIRED */
-	EVENT_CONSTRAINT(0x3c, (0x3|(1ULL<<33)), INTEL_ARCH_FIXED_MASK), /* UNHALTED_CORE_CYCLES */
-	EVENT_CONSTRAINT(0x40, 0x3, INTEL_ARCH_EVENT_MASK), /* L1D_CACHE_LD */
-	EVENT_CONSTRAINT(0x41, 0x3, INTEL_ARCH_EVENT_MASK), /* L1D_CACHE_ST */
-	EVENT_CONSTRAINT(0x42, 0x3, INTEL_ARCH_EVENT_MASK), /* L1D_CACHE_LOCK */
-	EVENT_CONSTRAINT(0x43, 0x3, INTEL_ARCH_EVENT_MASK), /* L1D_ALL_REF */
-	EVENT_CONSTRAINT(0x4e, 0x3, INTEL_ARCH_EVENT_MASK), /* L1D_PREFETCH */
-	EVENT_CONSTRAINT(0x4c, 0x3, INTEL_ARCH_EVENT_MASK), /* LOAD_HIT_PRE */
-	EVENT_CONSTRAINT(0x51, 0x3, INTEL_ARCH_EVENT_MASK), /* L1D */
-	EVENT_CONSTRAINT(0x52, 0x3, INTEL_ARCH_EVENT_MASK), /* L1D_CACHE_PREFETCH_LOCK_FB_HIT */
-	EVENT_CONSTRAINT(0x53, 0x3, INTEL_ARCH_EVENT_MASK), /* L1D_CACHE_LOCK_FB_HIT */
-	EVENT_CONSTRAINT(0xc5, 0x3, INTEL_ARCH_EVENT_MASK), /* CACHE_LOCK_CYCLES */
+	FIXED_EVENT_CONSTRAINT(0xc0, (0x3|(1ULL<<32))), /* INSTRUCTIONS_RETIRED */
+	FIXED_EVENT_CONSTRAINT(0x3c, (0x3|(1ULL<<33))), /* UNHALTED_CORE_CYCLES */
+	INTEL_EVENT_CONSTRAINT(0x40, 0x3), /* L1D_CACHE_LD */
+	INTEL_EVENT_CONSTRAINT(0x41, 0x3), /* L1D_CACHE_ST */
+	INTEL_EVENT_CONSTRAINT(0x42, 0x3), /* L1D_CACHE_LOCK */
+	INTEL_EVENT_CONSTRAINT(0x43, 0x3), /* L1D_ALL_REF */
+	INTEL_EVENT_CONSTRAINT(0x4e, 0x3), /* L1D_PREFETCH */
+	INTEL_EVENT_CONSTRAINT(0x4c, 0x3), /* LOAD_HIT_PRE */
+	INTEL_EVENT_CONSTRAINT(0x51, 0x3), /* L1D */
+	INTEL_EVENT_CONSTRAINT(0x52, 0x3), /* L1D_CACHE_PREFETCH_LOCK_FB_HIT */
+	INTEL_EVENT_CONSTRAINT(0x53, 0x3), /* L1D_CACHE_LOCK_FB_HIT */
+	INTEL_EVENT_CONSTRAINT(0xc5, 0x3), /* CACHE_LOCK_CYCLES */
 	EVENT_CONSTRAINT_END
 };
 
 static struct event_constraint intel_gen_event_constraints[] =
 {
-	EVENT_CONSTRAINT(0xc0, (0x3|(1ULL<<32)), INTEL_ARCH_FIXED_MASK), /* INSTRUCTIONS_RETIRED */
-	EVENT_CONSTRAINT(0x3c, (0x3|(1ULL<<33)), INTEL_ARCH_FIXED_MASK), /* UNHALTED_CORE_CYCLES */
+	FIXED_EVENT_CONSTRAINT(0xc0, (0x3|(1ULL<<32))), /* INSTRUCTIONS_RETIRED */
+	FIXED_EVENT_CONSTRAINT(0x3c, (0x3|(1ULL<<33))), /* UNHALTED_CORE_CYCLES */
 	EVENT_CONSTRAINT_END
 };
 
#10 lore raw

[tip:perf/core] perf_event: x86: Reduce some overly long lines with some MACROs

Commit-ID:  8433be1184e4f22c37d4b8ed36cde529a47882f4
Gitweb:     http://git.kernel.org/tip/8433be1184e4f22c37d4b8ed36cde529a47882f4
Author:     Peter Zijlstra <[email protected]>
AuthorDate: Fri, 22 Jan 2010 15:38:26 +0100
Committer:  Ingo Molnar <[email protected]>
CommitDate: Fri, 29 Jan 2010 09:01:38 +0100

perf_event: x86: Reduce some overly long lines with some MACROs

Introduce INTEL_EVENT_CONSTRAINT and FIXED_EVENT_CONSTRAINT to reduce some line length and typing work.

Cc Stephane Eranian <[email protected]>

LKML-Reference: <[email protected]>

---
 arch/x86/kernel/cpu/perf_event.c |   68 ++++++++++++++++++++-----------------
 1 files changed, 37 insertions(+), 31 deletions(-)
arch/x86/kernel/cpu/perf_event.c +37 -31
index 921bbf7..4d1ed10 100644
@@ -97,6 +97,12 @@ struct cpu_hw_events {
 	.cmask = (m),			\
 }
 
+#define INTEL_EVENT_CONSTRAINT(c, n)	\
+	EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK)
+
+#define FIXED_EVENT_CONSTRAINT(c, n)	\
+	EVENT_CONSTRAINT(c, n, INTEL_ARCH_FIXED_MASK)
+
 #define EVENT_CONSTRAINT_END \
 	EVENT_CONSTRAINT(0, 0, 0)
 
@@ -192,12 +198,12 @@ static u64 p6_pmu_raw_event(u64 hw_event)
 
 static struct event_constraint intel_p6_event_constraints[] =
 {
-	EVENT_CONSTRAINT(0xc1, 0x1, INTEL_ARCH_EVENT_MASK),	/* FLOPS */
-	EVENT_CONSTRAINT(0x10, 0x1, INTEL_ARCH_EVENT_MASK),	/* FP_COMP_OPS_EXE */
-	EVENT_CONSTRAINT(0x11, 0x1, INTEL_ARCH_EVENT_MASK),	/* FP_ASSIST */
-	EVENT_CONSTRAINT(0x12, 0x2, INTEL_ARCH_EVENT_MASK),	/* MUL */
-	EVENT_CONSTRAINT(0x13, 0x2, INTEL_ARCH_EVENT_MASK),	/* DIV */
-	EVENT_CONSTRAINT(0x14, 0x1, INTEL_ARCH_EVENT_MASK),	/* CYCLES_DIV_BUSY */
+	INTEL_EVENT_CONSTRAINT(0xc1, 0x1),	/* FLOPS */
+	INTEL_EVENT_CONSTRAINT(0x10, 0x1),	/* FP_COMP_OPS_EXE */
+	INTEL_EVENT_CONSTRAINT(0x11, 0x1),	/* FP_ASSIST */
+	INTEL_EVENT_CONSTRAINT(0x12, 0x2),	/* MUL */
+	INTEL_EVENT_CONSTRAINT(0x13, 0x2),	/* DIV */
+	INTEL_EVENT_CONSTRAINT(0x14, 0x1),	/* CYCLES_DIV_BUSY */
 	EVENT_CONSTRAINT_END
 };
 
@@ -217,41 +223,41 @@ static const u64 intel_perfmon_event_map[] =
 
 static struct event_constraint intel_core_event_constraints[] =
 {
-	EVENT_CONSTRAINT(0xc0, (0x3|(1ULL<<32)), INTEL_ARCH_FIXED_MASK), /* INSTRUCTIONS_RETIRED */
-	EVENT_CONSTRAINT(0x3c, (0x3|(1ULL<<33)), INTEL_ARCH_FIXED_MASK), /* UNHALTED_CORE_CYCLES */
-	EVENT_CONSTRAINT(0x10, 0x1, INTEL_ARCH_EVENT_MASK), /* FP_COMP_OPS_EXE */
-	EVENT_CONSTRAINT(0x11, 0x2, INTEL_ARCH_EVENT_MASK), /* FP_ASSIST */
-	EVENT_CONSTRAINT(0x12, 0x2, INTEL_ARCH_EVENT_MASK), /* MUL */
-	EVENT_CONSTRAINT(0x13, 0x2, INTEL_ARCH_EVENT_MASK), /* DIV */
-	EVENT_CONSTRAINT(0x14, 0x1, INTEL_ARCH_EVENT_MASK), /* CYCLES_DIV_BUSY */
-	EVENT_CONSTRAINT(0x18, 0x1, INTEL_ARCH_EVENT_MASK), /* IDLE_DURING_DIV */
-	EVENT_CONSTRAINT(0x19, 0x2, INTEL_ARCH_EVENT_MASK), /* DELAYED_BYPASS */
-	EVENT_CONSTRAINT(0xa1, 0x1, INTEL_ARCH_EVENT_MASK), /* RS_UOPS_DISPATCH_CYCLES */
-	EVENT_CONSTRAINT(0xcb, 0x1, INTEL_ARCH_EVENT_MASK), /* MEM_LOAD_RETIRED */
+	FIXED_EVENT_CONSTRAINT(0xc0, (0x3|(1ULL<<32))), /* INSTRUCTIONS_RETIRED */
+	FIXED_EVENT_CONSTRAINT(0x3c, (0x3|(1ULL<<33))), /* UNHALTED_CORE_CYCLES */
+	INTEL_EVENT_CONSTRAINT(0x10, 0x1), /* FP_COMP_OPS_EXE */
+	INTEL_EVENT_CONSTRAINT(0x11, 0x2), /* FP_ASSIST */
+	INTEL_EVENT_CONSTRAINT(0x12, 0x2), /* MUL */
+	INTEL_EVENT_CONSTRAINT(0x13, 0x2), /* DIV */
+	INTEL_EVENT_CONSTRAINT(0x14, 0x1), /* CYCLES_DIV_BUSY */
+	INTEL_EVENT_CONSTRAINT(0x18, 0x1), /* IDLE_DURING_DIV */
+	INTEL_EVENT_CONSTRAINT(0x19, 0x2), /* DELAYED_BYPASS */
+	INTEL_EVENT_CONSTRAINT(0xa1, 0x1), /* RS_UOPS_DISPATCH_CYCLES */
+	INTEL_EVENT_CONSTRAINT(0xcb, 0x1), /* MEM_LOAD_RETIRED */
 	EVENT_CONSTRAINT_END
 };
 
 static struct event_constraint intel_nehalem_event_constraints[] =
 {
-	EVENT_CONSTRAINT(0xc0, (0x3|(1ULL<<32)), INTEL_ARCH_FIXED_MASK), /* INSTRUCTIONS_RETIRED */
-	EVENT_CONSTRAINT(0x3c, (0x3|(1ULL<<33)), INTEL_ARCH_FIXED_MASK), /* UNHALTED_CORE_CYCLES */
-	EVENT_CONSTRAINT(0x40, 0x3, INTEL_ARCH_EVENT_MASK), /* L1D_CACHE_LD */
-	EVENT_CONSTRAINT(0x41, 0x3, INTEL_ARCH_EVENT_MASK), /* L1D_CACHE_ST */
-	EVENT_CONSTRAINT(0x42, 0x3, INTEL_ARCH_EVENT_MASK), /* L1D_CACHE_LOCK */
-	EVENT_CONSTRAINT(0x43, 0x3, INTEL_ARCH_EVENT_MASK), /* L1D_ALL_REF */
-	EVENT_CONSTRAINT(0x4e, 0x3, INTEL_ARCH_EVENT_MASK), /* L1D_PREFETCH */
-	EVENT_CONSTRAINT(0x4c, 0x3, INTEL_ARCH_EVENT_MASK), /* LOAD_HIT_PRE */
-	EVENT_CONSTRAINT(0x51, 0x3, INTEL_ARCH_EVENT_MASK), /* L1D */
-	EVENT_CONSTRAINT(0x52, 0x3, INTEL_ARCH_EVENT_MASK), /* L1D_CACHE_PREFETCH_LOCK_FB_HIT */
-	EVENT_CONSTRAINT(0x53, 0x3, INTEL_ARCH_EVENT_MASK), /* L1D_CACHE_LOCK_FB_HIT */
-	EVENT_CONSTRAINT(0xc5, 0x3, INTEL_ARCH_EVENT_MASK), /* CACHE_LOCK_CYCLES */
+	FIXED_EVENT_CONSTRAINT(0xc0, (0x3|(1ULL<<32))), /* INSTRUCTIONS_RETIRED */
+	FIXED_EVENT_CONSTRAINT(0x3c, (0x3|(1ULL<<33))), /* UNHALTED_CORE_CYCLES */
+	INTEL_EVENT_CONSTRAINT(0x40, 0x3), /* L1D_CACHE_LD */
+	INTEL_EVENT_CONSTRAINT(0x41, 0x3), /* L1D_CACHE_ST */
+	INTEL_EVENT_CONSTRAINT(0x42, 0x3), /* L1D_CACHE_LOCK */
+	INTEL_EVENT_CONSTRAINT(0x43, 0x3), /* L1D_ALL_REF */
+	INTEL_EVENT_CONSTRAINT(0x4e, 0x3), /* L1D_PREFETCH */
+	INTEL_EVENT_CONSTRAINT(0x4c, 0x3), /* LOAD_HIT_PRE */
+	INTEL_EVENT_CONSTRAINT(0x51, 0x3), /* L1D */
+	INTEL_EVENT_CONSTRAINT(0x52, 0x3), /* L1D_CACHE_PREFETCH_LOCK_FB_HIT */
+	INTEL_EVENT_CONSTRAINT(0x53, 0x3), /* L1D_CACHE_LOCK_FB_HIT */
+	INTEL_EVENT_CONSTRAINT(0xc5, 0x3), /* CACHE_LOCK_CYCLES */
 	EVENT_CONSTRAINT_END
 };
 
 static struct event_constraint intel_gen_event_constraints[] =
 {
-	EVENT_CONSTRAINT(0xc0, (0x3|(1ULL<<32)), INTEL_ARCH_FIXED_MASK), /* INSTRUCTIONS_RETIRED */
-	EVENT_CONSTRAINT(0x3c, (0x3|(1ULL<<33)), INTEL_ARCH_FIXED_MASK), /* UNHALTED_CORE_CYCLES */
+	FIXED_EVENT_CONSTRAINT(0xc0, (0x3|(1ULL<<32))), /* INSTRUCTIONS_RETIRED */
+	FIXED_EVENT_CONSTRAINT(0x3c, (0x3|(1ULL<<33))), /* UNHALTED_CORE_CYCLES */
 	EVENT_CONSTRAINT_END
 };
 
#11 lore raw

PATCH 7/10 bitops: Provide compile time HWEIGHT{8,16,32,64}

In reply to Peter Zijlstra

Provide compile time versions of hweight.

LKML-Reference: <new-submission>

---
 include/linux/bitops.h |   14 ++++++++++++++
 1 file changed, 14 insertions(+)
include/linux/bitops.h +14 -0
Index: linux-2.6/include/linux/bitops.h
===================================================================
@@ -45,6 +45,20 @@ static inline unsigned long hweight_long
 	return sizeof(w) == 4 ? hweight32(w) : hweight64(w);
 }
 
+#define HWEIGHT8(w) 			\
+      (	(!!((w) & (1ULL << 0))) +	\
+	(!!((w) & (1ULL << 1))) +	\
+	(!!((w) & (1ULL << 2))) +	\
+	(!!((w) & (1ULL << 3))) +	\
+	(!!((w) & (1ULL << 4))) +	\
+	(!!((w) & (1ULL << 5))) +	\
+	(!!((w) & (1ULL << 6))) +	\
+	(!!((w) & (1ULL << 7)))	)
+
+#define HWEIGHT16(w) (HWEIGHT8(w)  + HWEIGHT8(w >> 8))
+#define HWEIGHT32(w) (HWEIGHT16(w) + HWEIGHT16(w >> 16))
+#define HWEIGHT64(w) (HWEIGHT32(w) + HWEIGHT32(w >> 32))
+
 /**
  * rol32 - rotate a 32-bit value left
  * @word: value to rotate
#12 lore raw

[tip:perf/core] bitops: Provide compile time HWEIGHT{8,16,32,64}

Commit-ID:  9f41699ed067fa695faff8e2e9981b2550abec62
Gitweb:     http://git.kernel.org/tip/9f41699ed067fa695faff8e2e9981b2550abec62
Author:     Peter Zijlstra <[email protected]>
AuthorDate: Fri, 22 Jan 2010 15:59:29 +0100
Committer:  Ingo Molnar <[email protected]>
CommitDate: Fri, 29 Jan 2010 09:01:39 +0100

bitops: Provide compile time HWEIGHT{8,16,32,64}

Provide compile time versions of hweight.

Cc Stephane Eranian <[email protected]>
Cc Linus Torvalds <[email protected]>
Cc Andrew Morton <[email protected]>
Cc Thomas Gleixner <[email protected]>

LKML-Reference: <[email protected]>

[ Remove some whitespace damage while we are at it ]
---
 include/linux/bitops.h |   18 ++++++++++++++++--
 1 files changed, 16 insertions(+), 2 deletions(-)
include/linux/bitops.h +16 -2
index c05a29c..ba0fd1e 100644
@@ -25,7 +25,7 @@
 static __inline__ int get_bitmask_order(unsigned int count)
 {
 	int order;
-	
+
 	order = fls(count);
 	return order;	/* We could be slightly more clever with -1 here... */
 }
@@ -33,7 +33,7 @@ static __inline__ int get_bitmask_order(unsigned int count)
 static __inline__ int get_count_order(unsigned int count)
 {
 	int order;
-	
+
 	order = fls(count) - 1;
 	if (count & (count - 1))
 		order++;
@@ -45,6 +45,20 @@ static inline unsigned long hweight_long(unsigned long w)
 	return sizeof(w) == 4 ? hweight32(w) : hweight64(w);
 }
 
+#define HWEIGHT8(w)			\
+      (	(!!((w) & (1ULL << 0))) +	\
+	(!!((w) & (1ULL << 1))) +	\
+	(!!((w) & (1ULL << 2))) +	\
+	(!!((w) & (1ULL << 3))) +	\
+	(!!((w) & (1ULL << 4))) +	\
+	(!!((w) & (1ULL << 5))) +	\
+	(!!((w) & (1ULL << 6))) +	\
+	(!!((w) & (1ULL << 7)))	)
+
+#define HWEIGHT16(w) (HWEIGHT8(w)  + HWEIGHT8(w >> 8))
+#define HWEIGHT32(w) (HWEIGHT16(w) + HWEIGHT16(w >> 16))
+#define HWEIGHT64(w) (HWEIGHT32(w) + HWEIGHT32(w >> 32))
+
 /**
  * rol32 - rotate a 32-bit value left
  * @word: value to rotate
maintainer
#13 lore raw

Re: [tip:perf/core] bitops: Provide compile time HWEIGHT{8,16,32,64}

include/linux/bitops.h static inline unsigned long hweight_long(unsigned long w) · line 60

Quoted 13 lines · On Fri, 29 Jan 2010 09:28:04 GMT tip-bot for Peter Zijlstra…
include/linux/bitops.h +13 -0
+#define HWEIGHT8(w)			\
+      (	(!!((w) & (1ULL << 0))) +	\
+	(!!((w) & (1ULL << 1))) +	\
+	(!!((w) & (1ULL << 2))) +	\
+	(!!((w) & (1ULL << 3))) +	\
+	(!!((w) & (1ULL << 4))) +	\
+	(!!((w) & (1ULL << 5))) +	\
+	(!!((w) & (1ULL << 6))) +	\
+	(!!((w) & (1ULL << 7)))	)
+
+#define HWEIGHT16(w) (HWEIGHT8(w)  + HWEIGHT8(w >> 8))
+#define HWEIGHT32(w) (HWEIGHT16(w) + HWEIGHT16(w >> 16))
+#define HWEIGHT64(w) (HWEIGHT32(w) + HWEIGHT32(w >> 32))

Would be nice if it had a comment explaining why it exists. If people accidentally use this with non-constant arguments, the generated code will be pretty ghastly.

Or add some barf-if-not-__constant_p() thing, perhaps.

#14 lore raw

Re: [tip:perf/core] bitops: Provide compile time HWEIGHT{8,16,32,64}

Quoted 20 lines · Andrew Morton

include/linux/bitops.h static inline unsigned long hweight_long(unsigned long w) · line 60

Quoted 13 lines · On Fri, 29 Jan 2010 09:28:04 GMT tip-bot for Peter Zijlstra…
include/linux/bitops.h +13 -0
+#define HWEIGHT8(w)			\
+      (	(!!((w) & (1ULL << 0))) +	\
+	(!!((w) & (1ULL << 1))) +	\
+	(!!((w) & (1ULL << 2))) +	\
+	(!!((w) & (1ULL << 3))) +	\
+	(!!((w) & (1ULL << 4))) +	\
+	(!!((w) & (1ULL << 5))) +	\
+	(!!((w) & (1ULL << 6))) +	\
+	(!!((w) & (1ULL << 7)))	)
+
+#define HWEIGHT16(w) (HWEIGHT8(w)  + HWEIGHT8(w >> 8))
+#define HWEIGHT32(w) (HWEIGHT16(w) + HWEIGHT16(w >> 16))
+#define HWEIGHT64(w) (HWEIGHT32(w) + HWEIGHT32(w >> 32))

Would be nice if it had a comment explaining why it exists. If people accidentally use this with non-constant arguments, the generated code will be pretty ghastly.

Quoted 1 line

Or add some barf-if-not-__constant_p() thing, perhaps.

Yeah, agreed.

Ingo

maintainer
#15 lore raw

Re: [tip:perf/core] bitops: Provide compile time HWEIGHT{8,16,32,64}

Quoted 23 lines · On Fri, 29 Jan 2010 11:04:31 +0100 Ingo Molnar <[email protected]> wrote:
Quoted 20 lines · Andrew Morton

include/linux/bitops.h static inline unsigned long hweight_long(unsigned long w) · line 60

Quoted 13 lines · On Fri, 29 Jan 2010 09:28:04 GMT tip-bot for Peter Zijlstra…
include/linux/bitops.h +13 -0
+#define HWEIGHT8(w)			\
+      (	(!!((w) & (1ULL << 0))) +	\
+	(!!((w) & (1ULL << 1))) +	\
+	(!!((w) & (1ULL << 2))) +	\
+	(!!((w) & (1ULL << 3))) +	\
+	(!!((w) & (1ULL << 4))) +	\
+	(!!((w) & (1ULL << 5))) +	\
+	(!!((w) & (1ULL << 6))) +	\
+	(!!((w) & (1ULL << 7)))	)
+
+#define HWEIGHT16(w) (HWEIGHT8(w)  + HWEIGHT8(w >> 8))
+#define HWEIGHT32(w) (HWEIGHT16(w) + HWEIGHT16(w >> 16))
+#define HWEIGHT64(w) (HWEIGHT32(w) + HWEIGHT32(w >> 32))

Would be nice if it had a comment explaining why it exists. If people accidentally use this with non-constant arguments, the generated code will be pretty ghastly.

Quoted 4 lines
Quoted 1 line

Or add some barf-if-not-__constant_p() thing, perhaps.

Yeah, agreed.

Also...

Should we just do

#define HWEIGHT(x) HWEIGHT64(x)

and make HWEIGHT() the sole officially-exported interface? I mean, all it does is emit an obfuscated constant - perhaps we can save users from having to pick which one of the above to use by giving them a "this one always works" interface.

That might require some casting to suppress "shift out of range" warnings though.

<wonders if we'd otherwise end up needing an HWEIGHT_LONG()>

maintainer
#16 lore raw

Re: [tip:perf/core] bitops: Provide compile time HWEIGHT{8,16,32,64}

In reply to Andrew Morton
Quoted 11 lines · Andrew Morton
Quoted 9 lines · On Fri, 29 Jan 2010 09:28:04 GMT tip-bot for Peter Zijlstra…
(quoted diff) +9 -0
+#define HWEIGHT8(w)			\
+      (	(!!((w) & (1ULL << 0))) +	\
+	(!!((w) & (1ULL << 1))) +	\
+	(!!((w) & (1ULL << 2))) +	\
+	(!!((w) & (1ULL << 3))) +	\
+	(!!((w) & (1ULL << 4))) +	\
+	(!!((w) & (1ULL << 5))) +	\
+	(!!((w) & (1ULL << 6))) +	\
+	(!!((w) & (1ULL << 7)))	)
Quoted 8 lines

Review

Quoted 4 lines
(quoted diff) +4 -0
+
+#define HWEIGHT16(w) (HWEIGHT8(w)  + HWEIGHT8(w >> 8))
+#define HWEIGHT32(w) (HWEIGHT16(w) + HWEIGHT16(w >> 16))
+#define HWEIGHT64(w) (HWEIGHT32(w) + HWEIGHT32(w >> 32))

Would be nice if it had a comment explaining why it exists. If people accidentally use this with non-constant arguments, the generated code will be pretty ghastly.

*sigh* and here I though it being placed right next to hweight_long() which uses the arch hweightN() would be clue enough.

If people are so clueless, who says they'll read a comment.. but sure I guess I can add one.

Quoted 1 line

Or add some barf-if-not-__constant_p() thing, perhaps.

I've actually sneaked one non-constant usage in, but since its in an init path I didn't care to fix that, but I guess here goes:

---
Subject: bitops: Dummyify the compile-time hweight versions

Because it seems allowed to not think and write kernel code.

---

arch/x86/kernel/cpu/perf_event.c +7 -3
Index: linux-2.6/arch/x86/kernel/cpu/perf_event.c
===================================================================
@@ -93,13 +93,16 @@ struct cpu_hw_events {
 	struct perf_event	*event_list[X86_PMC_IDX_MAX]; /* in enabled order */
 };
 
-#define EVENT_CONSTRAINT(c, n, m) {	\
+#define __EVENT_CONSTRAINT(c, n, m, w) {\
 	{ .idxmsk64[0] = (n) },		\
 	.code = (c),			\
 	.cmask = (m),			\
-	.weight = HWEIGHT64((u64)(n)),	\
+	.weight = (w),			\
 }
 
+#define EVENT_CONSTRAINT(c, n, m)	\
+	__EVENT_CONSTRAINT(c, n, m, HWEIGHT(n))
+
 #define INTEL_EVENT_CONSTRAINT(c, n)	\
 	EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVTSEL_MASK)
 
@@ -2646,7 +2649,8 @@ void __init init_hw_perf_events(void)
 	register_die_notifier(&perf_event_nmi_notifier);
 
 	unconstrained = (struct event_constraint)
-		EVENT_CONSTRAINT(0, (1ULL << x86_pmu.num_events) - 1, 0);
+		__EVENT_CONSTRAINT(0, (1ULL << x86_pmu.num_events) - 1, 
+				   0, x86_pmu.num_events);
 
 	pr_info("... version:                %d\n",     x86_pmu.version);
 	pr_info("... bit width:              %d\n",     x86_pmu.event_bits);
include/linux/bitops.h +21 -11
Index: linux-2.6/include/linux/bitops.h
===================================================================
@@ -45,19 +45,29 @@ static inline unsigned long hweight_long
 	return sizeof(w) == 4 ? hweight32(w) : hweight64(w);
 }
 
-#define HWEIGHT8(w)			\
-      (	(!!((w) & (1ULL << 0))) +	\
-	(!!((w) & (1ULL << 1))) +	\
-	(!!((w) & (1ULL << 2))) +	\
-	(!!((w) & (1ULL << 3))) +	\
-	(!!((w) & (1ULL << 4))) +	\
-	(!!((w) & (1ULL << 5))) +	\
-	(!!((w) & (1ULL << 6))) +	\
+/*
+ * Clearly slow versions of the hweightN() functions, their benefit is
+ * of course compile time evaluation of constant arguments.
+ */
+#define HWEIGHT8(w)					\
+      (	BUILD_BUG_ON_ZERO(!__builtin_constant_p(w)) +	\
+	(!!((w) & (1ULL << 0))) +			\
+	(!!((w) & (1ULL << 1))) +			\
+	(!!((w) & (1ULL << 2))) +			\
+	(!!((w) & (1ULL << 3))) +			\
+	(!!((w) & (1ULL << 4))) +			\
+	(!!((w) & (1ULL << 5))) +			\
+	(!!((w) & (1ULL << 6))) +			\
 	(!!((w) & (1ULL << 7)))	)
 
-#define HWEIGHT16(w) (HWEIGHT8(w)  + HWEIGHT8(w >> 8))
-#define HWEIGHT32(w) (HWEIGHT16(w) + HWEIGHT16(w >> 16))
-#define HWEIGHT64(w) (HWEIGHT32(w) + HWEIGHT32(w >> 32))
+#define HWEIGHT16(w) (HWEIGHT8(w)  + HWEIGHT8((w) >> 8))
+#define HWEIGHT32(w) (HWEIGHT16(w) + HWEIGHT16((w) >> 16))
+#define HWEIGHT64(w) (HWEIGHT32(w) + HWEIGHT32((w) >> 32))
+
+/*
+ * For us lazy bastards
+ */
+#define HWEIGHT(w)   HWEIGHT64((u64)(w))
 
 /**
  * rol32 - rotate a 32-bit value left
#17 lore raw

Re: [tip:perf/core] bitops: Provide compile time HWEIGHT{8,16,32,64}

Quoted 3 lines · Peter Zijlstra

*sigh* and here I though it being placed right next to hweight_long() which uses the arch hweightN() would be clue enough.

No. People who add new uses may be copying old uses, without looking at the definition.

Also, people who _change_ uses may be changing a value that used to be a constant into a variable when something is made more dynamic. At which point it really makes sense to have a function that requires a constant to _check_ that it gets a constant.

Quoted 2 lines

If people are so clueless, who says they'll read a comment.. but sure I guess I can add one.

The comment nobody cares about. But surprisingly crap code generation? That's bad.

Quoted 3 lines

Subject: bitops: Dummyify the compile-time hweight versions

Because it seems allowed to not think and write kernel code.

I would suggest you look in the mirror at some point.

Linus

#18 lore raw

Re: [tip:perf/core] bitops: Provide compile time HWEIGHT{8,16,32,64}

In reply to Peter Zijlstra
Quoted 7 lines · Peter Zijlstra

*sigh* and here I though it being placed right next to hweight_long() which uses the arch hweightN() would be clue enough.

If people are so clueless, who says they'll read a comment.. but sure I guess I can add one.

I would personally say that the Right Way[TM] to do this is to call these __constant_hweightX() -- so the name reflects the function -- and then have

#define hweight(x) (__builtin_constant_p(x) ? __constant_hweight(x) :
__arch_hweight(x))

[example does not reflect actual naming]

-hpa

maintainer
#19 lore raw

Re: [tip:perf/core] bitops: Provide compile time HWEIGHT{8,16,32,64}

Quoted 6 lines · H. Peter Anvin

I would personally say that the Right Way[TM] to do this is to call these __constant_hweightX() -- so the name reflects the function -- and then have

#define hweight(x) (__builtin_constant_p(x) ? __constant_hweight(x) :
__arch_hweight(x))

I actually considered that, but since I didn't have a full cross compile set around I wasn't sure.

The trouble is that asm/bitops.h used to be sufficient for hweightN(), but with such a scheme we'd need linux/bitops.h.

Anyway, something like the below, I'll try and run it through the cross compilers I have on monday or something.

---
 arch/alpha/include/asm/bitops.h      |   14 +++++++-------
 arch/sparc/include/asm/bitops_64.h   |    8 ++++----
 include/asm-generic/bitops/hweight.h |    8 ++++----
 include/linux/bitops.h               |   33 +++++++++++++++++++--------------
 lib/hweight.c                        |   19 ++++++++++---------
 5 files changed, 44 insertions(+), 38 deletions(-)
arch/alpha/include/asm/bitops.h +7 -7
Index: linux-2.6/arch/alpha/include/asm/bitops.h
===================================================================
@@ -405,24 +405,24 @@ static inline int fls(int x)
 
 #if defined(CONFIG_ALPHA_EV6) && defined(CONFIG_ALPHA_EV67)
 /* Whee.  EV67 can calculate it directly.  */
-static inline unsigned long hweight64(unsigned long w)
+static inline unsigned long __arch_hweight64(unsigned long w)
 {
 	return __kernel_ctpop(w);
 }
 
-static inline unsigned int hweight32(unsigned int w)
+static inline unsigned int __arch_hweight32(unsigned int w)
 {
-	return hweight64(w);
+	return __arch_hweight64(w);
 }
 
-static inline unsigned int hweight16(unsigned int w)
+static inline unsigned int __arch_hweight16(unsigned int w)
 {
-	return hweight64(w & 0xffff);
+	return __arch_hweight64(w & 0xffff);
 }
 
-static inline unsigned int hweight8(unsigned int w)
+static inline unsigned int __arch_hweight8(unsigned int w)
 {
-	return hweight64(w & 0xff);
+	return __arch_hweight64(w & 0xff);
 }
 #else
 #include <asm-generic/bitops/hweight.h>
arch/sparc/include/asm/bitops_64.h +4 -4
Index: linux-2.6/arch/sparc/include/asm/bitops_64.h
===================================================================
@@ -44,7 +44,7 @@ extern void change_bit(unsigned long nr,
 
 #ifdef ULTRA_HAS_POPULATION_COUNT
 
-static inline unsigned int hweight64(unsigned long w)
+static inline unsigned int __arch_hweight64(unsigned long w)
 {
 	unsigned int res;
 
@@ -52,7 +52,7 @@ static inline unsigned int hweight64(uns
 	return res;
 }
 
-static inline unsigned int hweight32(unsigned int w)
+static inline unsigned int __arch_hweight32(unsigned int w)
 {
 	unsigned int res;
 
@@ -60,7 +60,7 @@ static inline unsigned int hweight32(uns
 	return res;
 }
 
-static inline unsigned int hweight16(unsigned int w)
+static inline unsigned int __arch_hweight16(unsigned int w)
 {
 	unsigned int res;
 
@@ -68,7 +68,7 @@ static inline unsigned int hweight16(uns
 	return res;
 }
 
-static inline unsigned int hweight8(unsigned int w)
+static inline unsigned int __arch_hweight8(unsigned int w)
 {
 	unsigned int res;
 
include/asm-generic/bitops/hweight.h +4 -4
Index: linux-2.6/include/asm-generic/bitops/hweight.h
===================================================================
@@ -3,9 +3,9 @@
 
 #include <asm/types.h>
 
-extern unsigned int hweight32(unsigned int w);
-extern unsigned int hweight16(unsigned int w);
-extern unsigned int hweight8(unsigned int w);
-extern unsigned long hweight64(__u64 w);
+extern unsigned int __arch_hweight32(unsigned int w);
+extern unsigned int __arch_hweight16(unsigned int w);
+extern unsigned int __arch_hweight8(unsigned int w);
+extern unsigned long __arch_hweight64(__u64 w);
 
 #endif /* _ASM_GENERIC_BITOPS_HWEIGHT_H_ */
include/linux/bitops.h +19 -14
Index: linux-2.6/include/linux/bitops.h
===================================================================
@@ -40,16 +40,7 @@ static __inline__ int get_count_order(un
 	return order;
 }
 
-static inline unsigned long hweight_long(unsigned long w)
-{
-	return sizeof(w) == 4 ? hweight32(w) : hweight64(w);
-}
-
-/*
- * Clearly slow versions of the hweightN() functions, their benefit is
- * of course compile time evaluation of constant arguments.
- */
-#define HWEIGHT8(w)					\
+#define __const_hweight8(w)				\
       (	BUILD_BUG_ON_ZERO(!__builtin_constant_p(w)) +	\
 	(!!((w) & (1ULL << 0))) +			\
 	(!!((w) & (1ULL << 1))) +			\
@@ -60,15 +51,29 @@ static inline unsigned long hweight_long
 	(!!((w) & (1ULL << 6))) +			\
 	(!!((w) & (1ULL << 7)))	)
 
-#define HWEIGHT16(w) (HWEIGHT8(w)  + HWEIGHT8((w) >> 8))
-#define HWEIGHT32(w) (HWEIGHT16(w) + HWEIGHT16((w) >> 16))
-#define HWEIGHT64(w) (HWEIGHT32(w) + HWEIGHT32((w) >> 32))
+#define __const_hweight16(w) (__const_hweight8(w)  + __const_hweight8((w) >> 8))
+#define __const_hweight32(w) (__const_hweight16(w) + __const_hweight16((w) >> 16))
+#define __const_hweight64(w) (__const_hweight32(w) + __const_hweight32((w) >> 32))
+
+#define hweight8(w)	\
+	(__builtin_constant_p(w) ? __const_hweight8(w) : __arch_hweight8(w))
+#define hweight16(w)	\
+	(__builtin_constant_p(w) ? __const_hweight16(w) : __arch_hweight16(w))
+#define hweight32(w)	\
+	(__builtin_constant_p(w) ? __const_hweight32(w) : __arch_hweight32(w))
+#define hweight64(w)	\
+	(__builtin_constant_p(w) ? __const_hweight64(w) : __arch_hweight64(w))
 
 /*
  * Type invariant version that simply casts things to the
  * largest type.
  */
-#define HWEIGHT(w)   HWEIGHT64((u64)(w))
+#define HWEIGHT(w)   __const_hweight64((u64)(w))
+
+static inline unsigned long hweight_long(unsigned long w)
+{
+	return sizeof(w) == 4 ? hweight32(w) : hweight64(w);
+}
 
 /**
  * rol32 - rotate a 32-bit value left
lib/hweight.c +10 -9
Index: linux-2.6/lib/hweight.c
===================================================================
@@ -9,7 +9,7 @@
  * The Hamming Weight of a number is the total number of bits set in it.
  */
 
-unsigned int hweight32(unsigned int w)
+unsigned int __arhc_hweight32(unsigned int w)
 {
 #ifdef ARCH_HAS_FAST_MULTIPLIER
 	w -= (w >> 1) & 0x55555555;
@@ -24,29 +24,30 @@ unsigned int hweight32(unsigned int w)
 	return (res + (res >> 16)) & 0x000000FF;
 #endif
 }
-EXPORT_SYMBOL(hweight32);
+EXPORT_SYMBOL(__arch_hweight32);
 
-unsigned int hweight16(unsigned int w)
+unsigned int __arch_hweight16(unsigned int w)
 {
 	unsigned int res = w - ((w >> 1) & 0x5555);
 	res = (res & 0x3333) + ((res >> 2) & 0x3333);
 	res = (res + (res >> 4)) & 0x0F0F;
 	return (res + (res >> 8)) & 0x00FF;
 }
-EXPORT_SYMBOL(hweight16);
+EXPORT_SYMBOL(__arch_hweight16);
 
-unsigned int hweight8(unsigned int w)
+unsigned int __arch_hweight8(unsigned int w)
 {
 	unsigned int res = w - ((w >> 1) & 0x55);
 	res = (res & 0x33) + ((res >> 2) & 0x33);
 	return (res + (res >> 4)) & 0x0F;
 }
-EXPORT_SYMBOL(hweight8);
+EXPORT_SYMBOL(__arch_hweight8);
 
-unsigned long hweight64(__u64 w)
+unsigned long __arch_hweight64(__u64 w)
 {
 #if BITS_PER_LONG == 32
-	return hweight32((unsigned int)(w >> 32)) + hweight32((unsigned int)w);
+	return __arch_hweight32((unsigned int)(w >> 32)) +
+	       __arch_hweight32((unsigned int)w);
 #elif BITS_PER_LONG == 64
 #ifdef ARCH_HAS_FAST_MULTIPLIER
 	w -= (w >> 1) & 0x5555555555555555ul;
@@ -63,4 +64,4 @@ unsigned long hweight64(__u64 w)
 #endif
 #endif
 }
-EXPORT_SYMBOL(hweight64);
+EXPORT_SYMBOL(__arch_hweight64);
maintainer
#20 lore raw

Re: [tip:perf/core] bitops: Provide compile time HWEIGHT{8,16,32,64}

Quoted 9 lines · Peter Zijlstra
Quoted 6 lines · H. Peter Anvin

I would personally say that the Right Way[TM] to do this is to call these __constant_hweightX() -- so the name reflects the function -- and then have

#define hweight(x) (__builtin_constant_p(x) ? __constant_hweight(x) :
__arch_hweight(x))

Quoted 8 lines

I actually considered that, but since I didn't have a full cross compile set around I wasn't sure.

The trouble is that asm/bitops.h used to be sufficient for hweightN(), but with such a scheme we'd need linux/bitops.h.

Anyway, something like the below, I'll try and run it through the cross compilers I have on monday or something.

Ok, that didn't compile, utter include dependency hell.

The below does work, but is still a tad ugly in that if you want to use any of the HWEIGHT functions that use BUILD_BUG_ON_ZERO() you have to have included linux/kernel.h yourself.

But at least it builds on x86_64, alpha and sparc64 (didn't have a ia64 compiler around).

FWIW I was tempted to change the return type of hweight64() from unsigned long to unsigned int, its not as if it'll ever return a value larger than 64.

---
 arch/alpha/include/asm/bitops.h            |   18 ++++++------
 arch/ia64/include/asm/bitops.h             |   11 ++++---
 arch/sparc/include/asm/bitops_64.h         |   11 ++++---
 include/asm-generic/bitops/arch_hweight.h  |   11 +++++++
 include/asm-generic/bitops/const_hweight.h |   42 +++++++++++++++++++++++++++++
 include/asm-generic/bitops/hweight.h       |    8 +----
 include/linux/bitops.h                     |   25 -----------------
 lib/hweight.c                              |   19 ++++++-------
 8 files changed, 87 insertions(+), 58 deletions(-)
arch/alpha/include/asm/bitops.h +10 -8
Index: linux-2.6/arch/alpha/include/asm/bitops.h
===================================================================
@@ -405,29 +405,31 @@ static inline int fls(int x)
 
 #if defined(CONFIG_ALPHA_EV6) && defined(CONFIG_ALPHA_EV67)
 /* Whee.  EV67 can calculate it directly.  */
-static inline unsigned long hweight64(unsigned long w)
+static inline unsigned long __arch_hweight64(unsigned long w)
 {
 	return __kernel_ctpop(w);
 }
 
-static inline unsigned int hweight32(unsigned int w)
+static inline unsigned int __arch_weight32(unsigned int w)
 {
-	return hweight64(w);
+	return __arch_hweight64(w);
 }
 
-static inline unsigned int hweight16(unsigned int w)
+static inline unsigned int __arch_hweight16(unsigned int w)
 {
-	return hweight64(w & 0xffff);
+	return __arch_hweight64(w & 0xffff);
 }
 
-static inline unsigned int hweight8(unsigned int w)
+static inline unsigned int __arch_hweight8(unsigned int w)
 {
-	return hweight64(w & 0xff);
+	return __arch_hweight64(w & 0xff);
 }
 #else
-#include <asm-generic/bitops/hweight.h>
+#include <asm-generic/bitops/arch_hweight.h>
 #endif
 
+#include <asm-generic/bitops/const_hweight.h>
+
 #endif /* __KERNEL__ */
 
 #include <asm-generic/bitops/find.h>
arch/ia64/include/asm/bitops.h +6 -5
Index: linux-2.6/arch/ia64/include/asm/bitops.h
===================================================================
@@ -437,17 +437,18 @@ __fls (unsigned long x)
  * hweightN: returns the hamming weight (i.e. the number
  * of bits set) of a N-bit word
  */
-static __inline__ unsigned long
-hweight64 (unsigned long x)
+static __inline__ unsigned long __arch_hweight64(unsigned long x)
 {
 	unsigned long result;
 	result = ia64_popcnt(x);
 	return result;
 }
 
-#define hweight32(x)	(unsigned int) hweight64((x) & 0xfffffffful)
-#define hweight16(x)	(unsigned int) hweight64((x) & 0xfffful)
-#define hweight8(x)	(unsigned int) hweight64((x) & 0xfful)
+#define __arch_hweight32(x) ((unsigned int) __arch_hweight64((x) & 0xfffffffful))
+#define __arch_hweight16(x) ((unsigned int) __arch_hweight64((x) & 0xfffful))
+#define __arch_hweight8(x)  ((unsigned int) __arch_hweight64((x) & 0xfful))
+
+#include <asm-generic/bitops/const_hweight.h>
 
 #endif /* __KERNEL__ */
 
arch/sparc/include/asm/bitops_64.h +6 -5
Index: linux-2.6/arch/sparc/include/asm/bitops_64.h
===================================================================
@@ -44,7 +44,7 @@ extern void change_bit(unsigned long nr,
 
 #ifdef ULTRA_HAS_POPULATION_COUNT
 
-static inline unsigned int hweight64(unsigned long w)
+static inline unsigned int __arch_hweight64(unsigned long w)
 {
 	unsigned int res;
 
@@ -52,7 +52,7 @@ static inline unsigned int hweight64(uns
 	return res;
 }
 
-static inline unsigned int hweight32(unsigned int w)
+static inline unsigned int __arch_hweight32(unsigned int w)
 {
 	unsigned int res;
 
@@ -60,7 +60,7 @@ static inline unsigned int hweight32(uns
 	return res;
 }
 
-static inline unsigned int hweight16(unsigned int w)
+static inline unsigned int __arch_hweight16(unsigned int w)
 {
 	unsigned int res;
 
@@ -68,7 +68,7 @@ static inline unsigned int hweight16(uns
 	return res;
 }
 
-static inline unsigned int hweight8(unsigned int w)
+static inline unsigned int __arch_hweight8(unsigned int w)
 {
 	unsigned int res;
 
@@ -78,9 +78,10 @@ static inline unsigned int hweight8(unsi
 
 #else
 
-#include <asm-generic/bitops/hweight.h>
+#include <asm-generic/bitops/arch_hweight.h>
 
 #endif
+#include <asm-generic/bitops/const_hweight.h>
 #include <asm-generic/bitops/lock.h>
 #endif /* __KERNEL__ */
 
include/asm-generic/bitops/arch_hweight.h new file +11 -0
Index: linux-2.6/include/asm-generic/bitops/arch_hweight.h
===================================================================
@@ -0,0 +1,11 @@
+#ifndef _ASM_GENERIC_BITOPS_ARCH_HWEIGHT_H_
+#define _ASM_GENERIC_BITOPS_ARCH_HWEIGHT_H_
+
+#include <asm/types.h>
+
+extern unsigned int __arch_hweight32(unsigned int w);
+extern unsigned int __arch_hweight16(unsigned int w);
+extern unsigned int __arch_hweight8(unsigned int w);
+extern unsigned long __arch_hweight64(__u64 w);
+
+#endif /* _ASM_GENERIC_BITOPS_HWEIGHT_H_ */
include/asm-generic/bitops/const_hweight.h new file +42 -0

42 lines not on this page · raw message

include/asm-generic/bitops/hweight.h +2 -6
Index: linux-2.6/include/asm-generic/bitops/hweight.h
===================================================================
@@ -1,11 +1,7 @@
 #ifndef _ASM_GENERIC_BITOPS_HWEIGHT_H_
 #define _ASM_GENERIC_BITOPS_HWEIGHT_H_
 
-#include <asm/types.h>
-
-extern unsigned int hweight32(unsigned int w);
-extern unsigned int hweight16(unsigned int w);
-extern unsigned int hweight8(unsigned int w);
-extern unsigned long hweight64(__u64 w);
+#include <asm-generic/bitops/arch_hweight.h>
+#include <asm-generic/bitops/const_hweight.h>
 
 #endif /* _ASM_GENERIC_BITOPS_HWEIGHT_H_ */
include/linux/bitops.h +0 -25
Index: linux-2.6/include/linux/bitops.h
===================================================================
@@ -45,31 +45,6 @@ static inline unsigned long hweight_long
 	return sizeof(w) == 4 ? hweight32(w) : hweight64(w);
 }
 
-/*
- * Clearly slow versions of the hweightN() functions, their benefit is
- * of course compile time evaluation of constant arguments.
- */
-#define HWEIGHT8(w)					\
-      (	BUILD_BUG_ON_ZERO(!__builtin_constant_p(w)) +	\
-	(!!((w) & (1ULL << 0))) +			\
-	(!!((w) & (1ULL << 1))) +			\
-	(!!((w) & (1ULL << 2))) +			\
-	(!!((w) & (1ULL << 3))) +			\
-	(!!((w) & (1ULL << 4))) +			\
-	(!!((w) & (1ULL << 5))) +			\
-	(!!((w) & (1ULL << 6))) +			\
-	(!!((w) & (1ULL << 7)))	)
-
-#define HWEIGHT16(w) (HWEIGHT8(w)  + HWEIGHT8((w) >> 8))
-#define HWEIGHT32(w) (HWEIGHT16(w) + HWEIGHT16((w) >> 16))
-#define HWEIGHT64(w) (HWEIGHT32(w) + HWEIGHT32((w) >> 32))
-
-/*
- * Type invariant version that simply casts things to the
- * largest type.
- */
-#define HWEIGHT(w)   HWEIGHT64((u64)(w))
-
 /**
  * rol32 - rotate a 32-bit value left
  * @word: value to rotate
lib/hweight.c +10 -9
Index: linux-2.6/lib/hweight.c
===================================================================
@@ -9,7 +9,7 @@
  * The Hamming Weight of a number is the total number of bits set in it.
  */
 
-unsigned int hweight32(unsigned int w)
+unsigned int __arch_hweight32(unsigned int w)
 {
 #ifdef ARCH_HAS_FAST_MULTIPLIER
 	w -= (w >> 1) & 0x55555555;
@@ -24,29 +24,30 @@ unsigned int hweight32(unsigned int w)
 	return (res + (res >> 16)) & 0x000000FF;
 #endif
 }
-EXPORT_SYMBOL(hweight32);
+EXPORT_SYMBOL(__arch_hweight32);
 
-unsigned int hweight16(unsigned int w)
+unsigned int __arch_hweight16(unsigned int w)
 {
 	unsigned int res = w - ((w >> 1) & 0x5555);
 	res = (res & 0x3333) + ((res >> 2) & 0x3333);
 	res = (res + (res >> 4)) & 0x0F0F;
 	return (res + (res >> 8)) & 0x00FF;
 }
-EXPORT_SYMBOL(hweight16);
+EXPORT_SYMBOL(__arch_hweight16);
 
-unsigned int hweight8(unsigned int w)
+unsigned int __arch_hweight8(unsigned int w)
 {
 	unsigned int res = w - ((w >> 1) & 0x55);
 	res = (res & 0x33) + ((res >> 2) & 0x33);
 	return (res + (res >> 4)) & 0x0F;
 }
-EXPORT_SYMBOL(hweight8);
+EXPORT_SYMBOL(__arch_hweight8);
 
-unsigned long hweight64(__u64 w)
+unsigned long __arch_hweight64(__u64 w)
 {
 #if BITS_PER_LONG == 32
-	return hweight32((unsigned int)(w >> 32)) + hweight32((unsigned int)w);
+	return __arch_hweight32((unsigned int)(w >> 32)) +
+	       __arch_hweight32((unsigned int)w);
 #elif BITS_PER_LONG == 64
 #ifdef ARCH_HAS_FAST_MULTIPLIER
 	w -= (w >> 1) & 0x5555555555555555ul;
@@ -63,4 +64,4 @@ unsigned long hweight64(__u64 w)
 #endif
 #endif
 }
-EXPORT_SYMBOL(hweight64);
+EXPORT_SYMBOL(__arch_hweight64);
reviewer Acked-by
#21 lore raw

Re: [tip:perf/core] bitops: Provide compile time HWEIGHT{8,16,32,64}

Quoted 5 lines · Peter Zijlstra

The below does work, but is still a tad ugly in that if you want to use any of the HWEIGHT functions that use BUILD_BUG_ON_ZERO() you have to have included linux/kernel.h yourself.

Quoted 7 lines

But at least it builds on x86_64, alpha and sparc64 (didn't have a ia64 compiler around).

FWIW I was tempted to change the return type of hweight64() from unsigned long to unsigned int, its not as if it'll ever return a value larger than 64.

That might generate worse code in some cases, though (something that needs it as a 64-bit value would have to extend it unnecessarily), but probably the easiest is to just compile and see what happens.

x86 also has a POPCNT instruction now, which we should be able to use via alternatives. That's something to do after your cleanup is in.

Anyway, I like the cleanup.

-hpa

#22 lore raw

[tip:core/hweight] bitops: Optimize hweight() by making use of compile-time evaluation

In reply to Peter Zijlstra
Commit-ID:  1527bc8b928dd1399c3d3467dd47d9ede210978a
Gitweb:     http://git.kernel.org/tip/1527bc8b928dd1399c3d3467dd47d9ede210978a
Author:     Peter Zijlstra <[email protected]>
AuthorDate: Mon, 1 Feb 2010 15:03:07 +0100
Committer:  H. Peter Anvin <[email protected]>
CommitDate: Tue, 6 Apr 2010 15:52:11 -0700

bitops: Optimize hweight() by making use of compile-time evaluation

Rename the extisting runtime hweight() implementations to __arch_hweight(), rename the compile-time versions to __const_hweight() and then have hweight() pick between them.

LKML-Reference: <20100318111929.GB11152@aftab>

LKML-Reference: <1265028224.24455.154.camel@laptop>

---
 arch/alpha/include/asm/bitops.h            |   18 ++++++-----
 arch/ia64/include/asm/bitops.h             |   11 ++++---
 arch/sparc/include/asm/bitops_64.h         |   11 ++++---
 include/asm-generic/bitops/arch_hweight.h  |   11 +++++++
 include/asm-generic/bitops/const_hweight.h |   42 ++++++++++++++++++++++++++++
 include/asm-generic/bitops/hweight.h       |    8 +----
 include/linux/bitops.h                     |   25 ----------------
 lib/hweight.c                              |   19 ++++++------
 8 files changed, 87 insertions(+), 58 deletions(-)
arch/alpha/include/asm/bitops.h +10 -8
index 15f3ae2..296da1d 100644
@@ -405,29 +405,31 @@ static inline int fls(int x)
 
 #if defined(CONFIG_ALPHA_EV6) && defined(CONFIG_ALPHA_EV67)
 /* Whee.  EV67 can calculate it directly.  */
-static inline unsigned long hweight64(unsigned long w)
+static inline unsigned long __arch_hweight64(unsigned long w)
 {
 	return __kernel_ctpop(w);
 }
 
-static inline unsigned int hweight32(unsigned int w)
+static inline unsigned int __arch_weight32(unsigned int w)
 {
-	return hweight64(w);
+	return __arch_hweight64(w);
 }
 
-static inline unsigned int hweight16(unsigned int w)
+static inline unsigned int __arch_hweight16(unsigned int w)
 {
-	return hweight64(w & 0xffff);
+	return __arch_hweight64(w & 0xffff);
 }
 
-static inline unsigned int hweight8(unsigned int w)
+static inline unsigned int __arch_hweight8(unsigned int w)
 {
-	return hweight64(w & 0xff);
+	return __arch_hweight64(w & 0xff);
 }
 #else
-#include <asm-generic/bitops/hweight.h>
+#include <asm-generic/bitops/arch_hweight.h>
 #endif
 
+#include <asm-generic/bitops/const_hweight.h>
+
 #endif /* __KERNEL__ */
 
 #include <asm-generic/bitops/find.h>
arch/ia64/include/asm/bitops.h +6 -5
index 6ebc229..9da3df6 100644
@@ -437,17 +437,18 @@ __fls (unsigned long x)
  * hweightN: returns the hamming weight (i.e. the number
  * of bits set) of a N-bit word
  */
-static __inline__ unsigned long
-hweight64 (unsigned long x)
+static __inline__ unsigned long __arch_hweight64(unsigned long x)
 {
 	unsigned long result;
 	result = ia64_popcnt(x);
 	return result;
 }
 
-#define hweight32(x)	(unsigned int) hweight64((x) & 0xfffffffful)
-#define hweight16(x)	(unsigned int) hweight64((x) & 0xfffful)
-#define hweight8(x)	(unsigned int) hweight64((x) & 0xfful)
+#define __arch_hweight32(x) ((unsigned int) __arch_hweight64((x) & 0xfffffffful))
+#define __arch_hweight16(x) ((unsigned int) __arch_hweight64((x) & 0xfffful))
+#define __arch_hweight8(x)  ((unsigned int) __arch_hweight64((x) & 0xfful))
+
+#include <asm-generic/bitops/const_hweight.h>
 
 #endif /* __KERNEL__ */
 
arch/sparc/include/asm/bitops_64.h +6 -5
index e72ac9c..766121a 100644
@@ -44,7 +44,7 @@ extern void change_bit(unsigned long nr, volatile unsigned long *addr);
 
 #ifdef ULTRA_HAS_POPULATION_COUNT
 
-static inline unsigned int hweight64(unsigned long w)
+static inline unsigned int __arch_hweight64(unsigned long w)
 {
 	unsigned int res;
 
@@ -52,7 +52,7 @@ static inline unsigned int hweight64(unsigned long w)
 	return res;
 }
 
-static inline unsigned int hweight32(unsigned int w)
+static inline unsigned int __arch_hweight32(unsigned int w)
 {
 	unsigned int res;
 
@@ -60,7 +60,7 @@ static inline unsigned int hweight32(unsigned int w)
 	return res;
 }
 
-static inline unsigned int hweight16(unsigned int w)
+static inline unsigned int __arch_hweight16(unsigned int w)
 {
 	unsigned int res;
 
@@ -68,7 +68,7 @@ static inline unsigned int hweight16(unsigned int w)
 	return res;
 }
 
-static inline unsigned int hweight8(unsigned int w)
+static inline unsigned int __arch_hweight8(unsigned int w)
 {
 	unsigned int res;
 
@@ -78,9 +78,10 @@ static inline unsigned int hweight8(unsigned int w)
 
 #else
 
-#include <asm-generic/bitops/hweight.h>
+#include <asm-generic/bitops/arch_hweight.h>
 
 #endif
+#include <asm-generic/bitops/const_hweight.h>
 #include <asm-generic/bitops/lock.h>
 #endif /* __KERNEL__ */
 
include/asm-generic/bitops/arch_hweight.h new file +11 -0
new file mode 100644
index 0000000..3a7be84
@@ -0,0 +1,11 @@
+#ifndef _ASM_GENERIC_BITOPS_ARCH_HWEIGHT_H_
+#define _ASM_GENERIC_BITOPS_ARCH_HWEIGHT_H_
+
+#include <asm/types.h>
+
+extern unsigned int __arch_hweight32(unsigned int w);
+extern unsigned int __arch_hweight16(unsigned int w);
+extern unsigned int __arch_hweight8(unsigned int w);
+extern unsigned long __arch_hweight64(__u64 w);
+
+#endif /* _ASM_GENERIC_BITOPS_HWEIGHT_H_ */
include/asm-generic/bitops/const_hweight.h new file +42 -0

42 lines not on this page · raw message

include/asm-generic/bitops/hweight.h +2 -6
index fbbc383..a94d651 100644
@@ -1,11 +1,7 @@
 #ifndef _ASM_GENERIC_BITOPS_HWEIGHT_H_
 #define _ASM_GENERIC_BITOPS_HWEIGHT_H_
 
-#include <asm/types.h>
-
-extern unsigned int hweight32(unsigned int w);
-extern unsigned int hweight16(unsigned int w);
-extern unsigned int hweight8(unsigned int w);
-extern unsigned long hweight64(__u64 w);
+#include <asm-generic/bitops/arch_hweight.h>
+#include <asm-generic/bitops/const_hweight.h>
 
 #endif /* _ASM_GENERIC_BITOPS_HWEIGHT_H_ */
include/linux/bitops.h +0 -25
index b793898..c55d5bc 100644
@@ -47,31 +47,6 @@ static inline unsigned long hweight_long(unsigned long w)
 	return sizeof(w) == 4 ? hweight32(w) : hweight64(w);
 }
 
-/*
- * Clearly slow versions of the hweightN() functions, their benefit is
- * of course compile time evaluation of constant arguments.
- */
-#define HWEIGHT8(w)					\
-      (	BUILD_BUG_ON_ZERO(!__builtin_constant_p(w)) +	\
-	(!!((w) & (1ULL << 0))) +			\
-	(!!((w) & (1ULL << 1))) +			\
-	(!!((w) & (1ULL << 2))) +			\
-	(!!((w) & (1ULL << 3))) +			\
-	(!!((w) & (1ULL << 4))) +			\
-	(!!((w) & (1ULL << 5))) +			\
-	(!!((w) & (1ULL << 6))) +			\
-	(!!((w) & (1ULL << 7)))	)
-
-#define HWEIGHT16(w) (HWEIGHT8(w)  + HWEIGHT8((w) >> 8))
-#define HWEIGHT32(w) (HWEIGHT16(w) + HWEIGHT16((w) >> 16))
-#define HWEIGHT64(w) (HWEIGHT32(w) + HWEIGHT32((w) >> 32))
-
-/*
- * Type invariant version that simply casts things to the
- * largest type.
- */
-#define HWEIGHT(w)   HWEIGHT64((u64)(w))
-
 /**
  * rol32 - rotate a 32-bit value left
  * @word: value to rotate
lib/hweight.c +10 -9
index 63ee4eb..a6927e7 100644
@@ -9,7 +9,7 @@
  * The Hamming Weight of a number is the total number of bits set in it.
  */
 
-unsigned int hweight32(unsigned int w)
+unsigned int __arch_hweight32(unsigned int w)
 {
 #ifdef ARCH_HAS_FAST_MULTIPLIER
 	w -= (w >> 1) & 0x55555555;
@@ -24,29 +24,30 @@ unsigned int hweight32(unsigned int w)
 	return (res + (res >> 16)) & 0x000000FF;
 #endif
 }
-EXPORT_SYMBOL(hweight32);
+EXPORT_SYMBOL(__arch_hweight32);
 
-unsigned int hweight16(unsigned int w)
+unsigned int __arch_hweight16(unsigned int w)
 {
 	unsigned int res = w - ((w >> 1) & 0x5555);
 	res = (res & 0x3333) + ((res >> 2) & 0x3333);
 	res = (res + (res >> 4)) & 0x0F0F;
 	return (res + (res >> 8)) & 0x00FF;
 }
-EXPORT_SYMBOL(hweight16);
+EXPORT_SYMBOL(__arch_hweight16);
 
-unsigned int hweight8(unsigned int w)
+unsigned int __arch_hweight8(unsigned int w)
 {
 	unsigned int res = w - ((w >> 1) & 0x55);
 	res = (res & 0x33) + ((res >> 2) & 0x33);
 	return (res + (res >> 4)) & 0x0F;
 }
-EXPORT_SYMBOL(hweight8);
+EXPORT_SYMBOL(__arch_hweight8);
 
-unsigned long hweight64(__u64 w)
+unsigned long __arch_hweight64(__u64 w)
 {
 #if BITS_PER_LONG == 32
-	return hweight32((unsigned int)(w >> 32)) + hweight32((unsigned int)w);
+	return __arch_hweight32((unsigned int)(w >> 32)) +
+	       __arch_hweight32((unsigned int)w);
 #elif BITS_PER_LONG == 64
 #ifdef ARCH_HAS_FAST_MULTIPLIER
 	w -= (w >> 1) & 0x5555555555555555ul;
@@ -63,4 +64,4 @@ unsigned long hweight64(__u64 w)
 #endif
 #endif
 }
-EXPORT_SYMBOL(hweight64);
+EXPORT_SYMBOL(__arch_hweight64);
#23 lore raw

Re: [PATCH 07/10] bitops: Provide compile time HWEIGHT{8,16,32,64}

In reply to Peter Zijlstra
Quoted 13 lines · Peter Zijlstra

Provide compile time versions of hweight.

LKML-Reference: <new-submission>
---
 include/linux/bitops.h |   14 ++++++++++++++

 1 file changed, 14 insertions(+)

Index: linux-2.6/include/linux/bitops.h
===================================================================

include/linux/bitops.h static inline unsigned long hweight_long · line 46

Quoted 2 lines
include/linux/bitops.h +0 -0
@@ -45,6 +45,20 @@ static inline unsigned long hweight_long
        return sizeof(w) == 4 ? hweight32(w) : hweight64(w);
  }

I like it. Maybe provide a comment that this provides the Hamming weight, it took me a second to realize what this was.

Quoted 27 lines
include/linux/bitops.h +14 -2
+#define HWEIGHT8(w)                    \
+      (        (!!((w) & (1ULL << 0))) +       \
+       (!!((w) & (1ULL << 1))) +       \
+       (!!((w) & (1ULL << 2))) +       \
+       (!!((w) & (1ULL << 3))) +       \
+       (!!((w) & (1ULL << 4))) +       \
+       (!!((w) & (1ULL << 5))) +       \
+       (!!((w) & (1ULL << 6))) +       \
+       (!!((w) & (1ULL << 7))) )
+
+#define HWEIGHT16(w) (HWEIGHT8(w)  + HWEIGHT8(w >> 8))
+#define HWEIGHT32(w) (HWEIGHT16(w) + HWEIGHT16(w >> 16))
+#define HWEIGHT64(w) (HWEIGHT32(w) + HWEIGHT32(w >> 32))
+
  /**
  * rol32 - rotate a 32-bit value left
  * @word: value to rotate
 
--
 
--

To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

maintainer
#24 lore raw

Re: [PATCH 07/10] bitops: Provide compile time HWEIGHT{8,16,32,64}

Quoted 3 lines · John Kacur

I like it. Maybe provide a comment that this provides the Hamming weight, it took me a second to realize what this was.

its called _H_weight for crying out loud.

#25 lore raw

Re: [PATCH 07/10] bitops: Provide compile time HWEIGHT{8,16,32,64}

Quoted 7 lines · Peter Zijlstra
Quoted 3 lines · John Kacur

I like it. Maybe provide a comment that this provides the Hamming weight, it took me a second to realize what this was.

its called _H_weight for crying out loud.

Ha. :) You're right, but it's always obvious when your hands are dirty with algorithms that can use it. Easy to forget when you're working on other stuff. Put the term in there so we can google it more easily.

#26 lore raw

Re: [PATCH 07/10] bitops: Provide compile time HWEIGHT{8,16,32,64}

In reply to Peter Zijlstra
Quoted 7 lines · Peter Zijlstra
Quoted 3 lines · John Kacur

I like it. Maybe provide a comment that this provides the Hamming weight, it took me a second to realize what this was.

its called _H_weight for crying out loud.

True... although in computer architecture, when talking about bits, I think you find that the term population count (popcount) is more readily recognized.

-hpa

#27 lore raw

Re: [PATCH 07/10] bitops: Provide compile time HWEIGHT{8,16,32,64}

In reply to Peter Zijlstra
Quoted 6 lines · Peter Zijlstra
Quoted 3 lines · John Kacur

I like it. Maybe provide a comment that this provides the Hamming weight, it took me a second to realize what this was.

its called _H_weight for crying out loud.

I always forget such abbreviations :-/

I think when a single kernel hacker requests a clarifying comment that's reason enough to add it. After all he broke through a barrier of laziness to write that email ;-)

Ingo

#28 lore raw

PATCH 8/10 perf_event: Optimize the constraint searching bits

In reply to Peter Zijlstra

Instead of copying bitmasks around, pass pointers to the constraint structure.

LKML-Reference: <new-submission>

---
 arch/x86/kernel/cpu/perf_event.c |   81 ++++++++++++++++++---------------------
 1 file changed, 38 insertions(+), 43 deletions(-)
arch/x86/kernel/cpu/perf_event.c +35 -42
Index: linux-2.6/arch/x86/kernel/cpu/perf_event.c
===================================================================
@@ -135,12 +138,14 @@ struct x86_pmu {
 	u64		intel_ctrl;
 	void		(*enable_bts)(u64 config);
 	void		(*disable_bts)(void);
-	void		(*get_event_constraints)(struct cpu_hw_events *cpuc,
-						 struct perf_event *event,
-						 unsigned long *idxmsk);
+
+	struct event_constraint *
+			(*get_event_constraints)(struct cpu_hw_events *cpuc,
+						 struct perf_event *event);
+
 	void		(*put_event_constraints)(struct cpu_hw_events *cpuc,
 						 struct perf_event *event);
-	const struct event_constraint *event_constraints;
+	struct event_constraint *event_constraints;
 };
 
 static struct x86_pmu x86_pmu __read_mostly;
@@ -1244,18 +1249,16 @@ static inline int is_x86_event(struct pe
 static int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)
 {
 	int i, j , w, num;
-	int weight, wmax;
-	unsigned long *c;
-	unsigned long constraints[X86_PMC_IDX_MAX][BITS_TO_LONGS(X86_PMC_IDX_MAX)];
+	int weight, wmax;
+	struct event_constraint *c, *constraints[X86_PMC_IDX_MAX];
 	unsigned long used_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
 	struct hw_perf_event *hwc;
 
 	bitmap_zero(used_mask, X86_PMC_IDX_MAX);
 
 	for (i = 0; i < n; i++) {
-		x86_pmu.get_event_constraints(cpuc,
-					      cpuc->event_list[i],
-					      constraints[i]);
+		constraints[i] =
+		  x86_pmu.get_event_constraints(cpuc, cpuc->event_list[i]);
 	}
 
 	/*
@@ -1270,7 +1273,7 @@ static int x86_schedule_events(struct cp
 			break;
 
 		/* constraint still honored */
-		if (!test_bit(hwc->idx, c))
+		if (!test_bit(hwc->idx, c->idxmsk))
 			break;
 
 		/* not already used */
@@ -1323,11 +1326,11 @@ static int x86_schedule_events(struct cp
 			c = constraints[i];
 			hwc = &cpuc->event_list[i]->hw;
 
-			weight = bitmap_weight(c, X86_PMC_IDX_MAX);
+			weight = bitmap_weight(c->idxmsk, X86_PMC_IDX_MAX);
 			if (weight != w)
 				continue;
 
-			for_each_bit(j, c, X86_PMC_IDX_MAX) {
+			for_each_bit(j, c->idxmsk, X86_PMC_IDX_MAX) {
 				if (!test_bit(j, used_mask))
 					break;
 			}
@@ -2165,11 +2167,13 @@ perf_event_nmi_handler(struct notifier_b
 	return NOTIFY_STOP;
 }
 
+static struct event_constraint unconstrained;
+
 static struct event_constraint bts_constraint =
 	EVENT_CONSTRAINT(0, 1ULL << X86_PMC_IDX_FIXED_BTS, 0);
 
-static int intel_special_constraints(struct perf_event *event,
-				     unsigned long *idxmsk)
+static struct event_constraint *
+intel_special_constraints(struct perf_event *event)
 {
 	unsigned int hw_event;
 
@@ -2179,46 +2183,34 @@ static int intel_special_constraints(str
 		      x86_pmu.event_map(PERF_COUNT_HW_BRANCH_INSTRUCTIONS)) &&
 		     (event->hw.sample_period == 1))) {
 
-		bitmap_copy((unsigned long *)idxmsk,
-			    (unsigned long *)bts_constraint.idxmsk,
-			    X86_PMC_IDX_MAX);
-		return 1;
+		return &bts_constraint;
 	}
-	return 0;
+	return NULL;
 }
 
-static void intel_get_event_constraints(struct cpu_hw_events *cpuc,
-					struct perf_event *event,
-					unsigned long *idxmsk)
+static struct event_constraint *
+intel_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event)
 {
-	const struct event_constraint *c;
+	struct event_constraint *c;
 
-	/*
-	 * cleanup bitmask
-	 */
-	bitmap_zero(idxmsk, X86_PMC_IDX_MAX);
-
-	if (intel_special_constraints(event, idxmsk))
-		return;
+	c = intel_special_constraints(event);
+	if (c)
+		return c;
 
 	if (x86_pmu.event_constraints) {
 		for_each_event_constraint(c, x86_pmu.event_constraints) {
-			if ((event->hw.config & c->cmask) == c->code) {
-				bitmap_copy(idxmsk, c->idxmsk, X86_PMC_IDX_MAX);
-				return;
-			}
+			if ((event->hw.config & c->cmask) == c->code)
+				return c;
 		}
 	}
-	/* no constraints, means supports all generic counters */
-	bitmap_fill((unsigned long *)idxmsk, x86_pmu.num_events);
+
+	return &unconstrained;
 }
 
-static void amd_get_event_constraints(struct cpu_hw_events *cpuc,
-				      struct perf_event *event,
-				      unsigned long *idxmsk)
+static struct event_constraint *
+amd_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event)
 {
-	/* no constraints, means supports all generic counters */
-	bitmap_fill(idxmsk, x86_pmu.num_events);
+	return &unconstrained;
 }
 
 static int x86_event_sched_in(struct perf_event *event,
@@ -2586,6 +2578,9 @@ void __init init_hw_perf_events(void)
 	perf_events_lapic_init();
 	register_die_notifier(&perf_event_nmi_notifier);
 
+	unconstrained = (struct event_constraint)
+		EVENT_CONSTRAINT(0, (1ULL << x86_pmu.num_events) - 1, 0);
+
 	pr_info("... version:                %d\n",     x86_pmu.version);
 	pr_info("... bit width:              %d\n",     x86_pmu.event_bits);
 	pr_info("... generic registers:      %d\n",     x86_pmu.num_events);
#29 lore raw

Re: [PATCH 08/10] perf_event: Optimize the constraint searching bits

On Fri, Jan 22, 2010 at 4:50 PM, Peter Zijlstra <[email protected]> wrote:> Instead of copying bitmasks around, pass pointers to the constraint structure.>The reason I changed that is because of the AMD situation where constraintsare dynamically generated. So we need to get some storage from somwhere.See my AMD NB patch,

Quoted 1 line
Signed-off-by Peter Zijlstra <[email protected]>> LKML-Reference: <new-submission>> --->  arch/x86/kernel/cpu/perf_event.c |   81 ++++++++++++++++++--------------------->  1 file changed, 38 insertions(+), 43 deletions(-)>> Index: linux-2.6/arch/x86/kernel/cpu/perf_event.c> ===================================================================> --- linux-2.6.orig/arch/x86/kernel/cpu/perf_event.c> +++ linux-2.6/arch/x86/kernel/cpu/perf_event.c> @@ -135,12 +138,14 @@ struct x86_pmu {>        u64             intel_ctrl;>        void            (*enable_bts)(u64 config);>        void            (*disable_bts)(void);> -       void            (*get_event_constraints)(struct cpu_hw_events *cpuc,> -                                                struct perf_event *event,> -                                                unsigned long *idxmsk);> +> +       struct event_constraint *> +                       (*get_event_constraints)(struct cpu_hw_events *cpuc,> +                                                struct perf_event *event);> +>        void            (*put_event_constraints)(struct cpu_hw_events *cpuc,>                                                 struct perf_event *event);> -       const struct event_constraint *event_constraints;> +       struct event_constraint *event_constraints;>  };>>  static struct x86_pmu x86_pmu __read_mostly;> @@ -1244,18 +1249,16 @@ static inline int is_x86_event(struct pe>  static int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)>  {>        int i, j , w, num;> -       int weight, wmax;> -       unsigned long *c;> -       unsigned long constraints[X86_PMC_IDX_MAX][BITS_TO_LONGS(X86_PMC_IDX_MAX)];> +       int weight, wmax;> +       struct event_constraint *c, *constraints[X86_PMC_IDX_MAX];>        unsigned long used_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)];>        struct hw_perf_event *hwc;>>        bitmap_zero(used_mask, X86_PMC_IDX_MAX);>>        for (i = 0; i < n; i++) {> -               x86_pmu.get_event_constraints(cpuc,> -                                             cpuc->event_list[i],> -                                             constraints[i]);> +               constraints[i] => +                 x86_pmu.get_event_constraints(cpuc, cpuc->event_list[i]);>        }>>        /*> @@ -1270,7 +1273,7 @@ static int x86_schedule_events(struct cp>                        break;>>                /* constraint still honored */> -               if (!test_bit(hwc->idx, c))> +               if (!test_bit(hwc->idx, c->idxmsk))>                        break;>>                /* not already used */> @@ -1323,11 +1326,11 @@ static int x86_schedule_events(struct cp>                        c = constraints[i];>                        hwc = &cpuc->event_list[i]->hw;>> -                       weight = bitmap_weight(c, X86_PMC_IDX_MAX);> +                       weight = bitmap_weight(c->idxmsk, X86_PMC_IDX_MAX);>                        if (weight != w)>                                continue;>> -                       for_each_bit(j, c, X86_PMC_IDX_MAX) {> +                       for_each_bit(j, c->idxmsk, X86_PMC_IDX_MAX) {>                                if (!test_bit(j, used_mask))>                                        break;>                        }> @@ -2165,11 +2167,13 @@ perf_event_nmi_handler(struct notifier_b>        return NOTIFY_STOP;>  }>> +static struct event_constraint unconstrained;> +>  static struct event_constraint bts_constraint =>        EVENT_CONSTRAINT(0, 1ULL << X86_PMC_IDX_FIXED_BTS, 0);>> -static int intel_special_constraints(struct perf_event *event,> -                                    unsigned long *idxmsk)> +static struct event_constraint *> +intel_special_constraints(struct perf_event *event)>  {>        unsigned int hw_event;>> @@ -2179,46 +2183,34 @@ static int intel_special_constraints(str>                      x86_pmu.event_map(PERF_COUNT_HW_BRANCH_INSTRUCTIONS)) &&>                     (event->hw.sample_period == 1))) {>> -               bitmap_copy((unsigned long *)idxmsk,> -                           (unsigned long *)bts_constraint.idxmsk,> -                           X86_PMC_IDX_MAX);> -               return 1;> +               return &bts_constraint;>        }> -       return 0;> +       return NULL;>  }>> -static void intel_get_event_constraints(struct cpu_hw_events *cpuc,> -                                       struct perf_event *event,> -                                       unsigned long *idxmsk)> +static struct event_constraint *> +intel_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event)>  {> -       const struct event_constraint *c;> +       struct event_constraint *c;>> -       /*> -        * cleanup bitmask> -        */> -       bitmap_zero(idxmsk, X86_PMC_IDX_MAX);> -> -       if (intel_special_constraints(event, idxmsk))> -               return;> +       c = intel_special_constraints(event);> +       if (c)> +               return c;>>        if (x86_pmu.event_constraints) {>                for_each_event_constraint(c, x86_pmu.event_constraints) {> -                       if ((event->hw.config & c->cmask) == c->code) {> -                               bitmap_copy(idxmsk, c->idxmsk, X86_PMC_IDX_MAX);> -                               return;> -                       }> +                       if ((event->hw.config & c->cmask) == c->code)> +                               return c;>                }>        }> -       /* no constraints, means supports all generic counters */> -       bitmap_fill((unsigned long *)idxmsk, x86_pmu.num_events);> +> +       return &unconstrained;>  }>> -static void amd_get_event_constraints(struct cpu_hw_events *cpuc,> -                                     struct perf_event *event,> -                                     unsigned long *idxmsk)> +static struct event_constraint *> +amd_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event)>  {> -       /* no constraints, means supports all generic counters */> -       bitmap_fill(idxmsk, x86_pmu.num_events);> +       return &unconstrained;>  }>>  static int x86_event_sched_in(struct perf_event *event,> @@ -2586,6 +2578,9 @@ void __init init_hw_perf_events(void)>        perf_events_lapic_init();>        register_die_notifier(&perf_event_nmi_notifier);>> +       unconstrained = (struct event_constraint)> +               EVENT_CONSTRAINT(0, (1ULL << x86_pmu.num_events) - 1, 0);> +>        pr_info("... version:                %d\n",     x86_pmu.version);>        pr_info("... bit width:              %d\n",     x86_pmu.event_bits);>        pr_info("... generic registers:      %d\n",     x86_pmu.num_events);>> -->>

-- Stephane Eranian | EMEA Software EngineeringGoogle France | 38 avenue de l'Opéra | 75002 ParisTel : +33 (0) 1 42 68 53 00This email may be confidential or privileged. If you received thiscommunication by mistake, pleasedon't forward it to anyone else, please erase all copies andattachments, and please let me know thatit went to the wrong person. Thanks���{.n�+�������+%�����ݶ��w��{.n�+����{��G�����{ay�ʇڙ�,j��f���h��������z_�(�階�ݢj"���m������G������?����&���~��iO��z��v�^�m���� ������?�I�

maintainer
#30 lore raw

Re: [PATCH 08/10] perf_event: Optimize the constraint searching bits

Quoted 6 lines · Stephane Eranian
Quoted 2 lines · Peter Zijlstra

Instead of copying bitmasks around, pass pointers to the constraint structure.

The reason I changed that is because of the AMD situation where constraints are dynamically generated. So we need to get some storage from somwhere. See my AMD NB patch,

Can't we still do that by embedding 4 event_constraint structures in struct amd_nb and rewriting those as we need?

#31 lore raw

Re: [PATCH 08/10] perf_event: Optimize the constraint searching bits

Quoted 11 lines · Peter Zijlstra
Quoted 6 lines · Stephane Eranian
Quoted 2 lines · Peter Zijlstra

Instead of copying bitmasks around, pass pointers to the constraint structure.

The reason I changed that is because of the AMD situation where constraints are dynamically generated. So we need to get some storage from somwhere. See my AMD NB patch,

Can't we still do that by embedding 4 event_constraint structures in struct amd_nb and rewriting those as we need?

We sure could do that too.

#32 lore raw

[tip:perf/core] perf_event: x86: Optimize the constraint searching bits

In reply to Peter Zijlstra
Commit-ID:  63b146490befc027a7e0923e333269e68b20d380
Gitweb:     http://git.kernel.org/tip/63b146490befc027a7e0923e333269e68b20d380
Author:     Peter Zijlstra <[email protected]>
AuthorDate: Fri, 22 Jan 2010 16:32:17 +0100
Committer:  Ingo Molnar <[email protected]>
CommitDate: Fri, 29 Jan 2010 09:01:40 +0100

perf_event: x86: Optimize the constraint searching bits

Instead of copying bitmasks around, pass pointers to the constraint structure.

Cc Stephane Eranian <[email protected]>

LKML-Reference: <[email protected]>

---
 arch/x86/kernel/cpu/perf_event.c |   75 +++++++++++++++++---------------------
 1 files changed, 34 insertions(+), 41 deletions(-)
arch/x86/kernel/cpu/perf_event.c +34 -41
index 4d1ed10..092ad56 100644
@@ -134,12 +134,14 @@ struct x86_pmu {
 	u64		intel_ctrl;
 	void		(*enable_bts)(u64 config);
 	void		(*disable_bts)(void);
-	void		(*get_event_constraints)(struct cpu_hw_events *cpuc,
-						 struct perf_event *event,
-						 unsigned long *idxmsk);
+
+	struct event_constraint *
+			(*get_event_constraints)(struct cpu_hw_events *cpuc,
+						 struct perf_event *event);
+
 	void		(*put_event_constraints)(struct cpu_hw_events *cpuc,
 						 struct perf_event *event);
-	const struct event_constraint *event_constraints;
+	struct event_constraint *event_constraints;
 };
 
 static struct x86_pmu x86_pmu __read_mostly;
@@ -1242,17 +1244,15 @@ static int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)
 {
 	int i, j , w, num;
 	int weight, wmax;
-	unsigned long *c;
-	unsigned long constraints[X86_PMC_IDX_MAX][BITS_TO_LONGS(X86_PMC_IDX_MAX)];
+	struct event_constraint *c, *constraints[X86_PMC_IDX_MAX];
 	unsigned long used_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
 	struct hw_perf_event *hwc;
 
 	bitmap_zero(used_mask, X86_PMC_IDX_MAX);
 
 	for (i = 0; i < n; i++) {
-		x86_pmu.get_event_constraints(cpuc,
-					      cpuc->event_list[i],
-					      constraints[i]);
+		constraints[i] =
+		  x86_pmu.get_event_constraints(cpuc, cpuc->event_list[i]);
 	}
 
 	/*
@@ -1267,7 +1267,7 @@ static int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)
 			break;
 
 		/* constraint still honored */
-		if (!test_bit(hwc->idx, c))
+		if (!test_bit(hwc->idx, c->idxmsk))
 			break;
 
 		/* not already used */
@@ -1320,11 +1320,11 @@ static int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)
 			c = constraints[i];
 			hwc = &cpuc->event_list[i]->hw;
 
-			weight = bitmap_weight(c, X86_PMC_IDX_MAX);
+			weight = bitmap_weight(c->idxmsk, X86_PMC_IDX_MAX);
 			if (weight != w)
 				continue;
 
-			for_each_bit(j, c, X86_PMC_IDX_MAX) {
+			for_each_bit(j, c->idxmsk, X86_PMC_IDX_MAX) {
 				if (!test_bit(j, used_mask))
 					break;
 			}
@@ -2155,11 +2155,13 @@ perf_event_nmi_handler(struct notifier_block *self,
 	return NOTIFY_STOP;
 }
 
+static struct event_constraint unconstrained;
+
 static struct event_constraint bts_constraint =
 	EVENT_CONSTRAINT(0, 1ULL << X86_PMC_IDX_FIXED_BTS, 0);
 
-static int intel_special_constraints(struct perf_event *event,
-				     unsigned long *idxmsk)
+static struct event_constraint *
+intel_special_constraints(struct perf_event *event)
 {
 	unsigned int hw_event;
 
@@ -2169,46 +2171,34 @@ static int intel_special_constraints(struct perf_event *event,
 		      x86_pmu.event_map(PERF_COUNT_HW_BRANCH_INSTRUCTIONS)) &&
 		     (event->hw.sample_period == 1))) {
 
-		bitmap_copy((unsigned long *)idxmsk,
-			    (unsigned long *)bts_constraint.idxmsk,
-			    X86_PMC_IDX_MAX);
-		return 1;
+		return &bts_constraint;
 	}
-	return 0;
+	return NULL;
 }
 
-static void intel_get_event_constraints(struct cpu_hw_events *cpuc,
-					struct perf_event *event,
-					unsigned long *idxmsk)
+static struct event_constraint *
+intel_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event)
 {
-	const struct event_constraint *c;
+	struct event_constraint *c;
 
-	/*
-	 * cleanup bitmask
-	 */
-	bitmap_zero(idxmsk, X86_PMC_IDX_MAX);
-
-	if (intel_special_constraints(event, idxmsk))
-		return;
+	c = intel_special_constraints(event);
+	if (c)
+		return c;
 
 	if (x86_pmu.event_constraints) {
 		for_each_event_constraint(c, x86_pmu.event_constraints) {
-			if ((event->hw.config & c->cmask) == c->code) {
-				bitmap_copy(idxmsk, c->idxmsk, X86_PMC_IDX_MAX);
-				return;
-			}
+			if ((event->hw.config & c->cmask) == c->code)
+				return c;
 		}
 	}
-	/* no constraints, means supports all generic counters */
-	bitmap_fill((unsigned long *)idxmsk, x86_pmu.num_events);
+
+	return &unconstrained;
 }
 
-static void amd_get_event_constraints(struct cpu_hw_events *cpuc,
-				      struct perf_event *event,
-				      unsigned long *idxmsk)
+static struct event_constraint *
+amd_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event)
 {
-	/* no constraints, means supports all generic counters */
-	bitmap_fill(idxmsk, x86_pmu.num_events);
+	return &unconstrained;
 }
 
 static int x86_event_sched_in(struct perf_event *event,
@@ -2576,6 +2566,9 @@ void __init init_hw_perf_events(void)
 	perf_events_lapic_init();
 	register_die_notifier(&perf_event_nmi_notifier);
 
+	unconstrained = (struct event_constraint)
+		EVENT_CONSTRAINT(0, (1ULL << x86_pmu.num_events) - 1, 0);
+
 	pr_info("... version:                %d\n",     x86_pmu.version);
 	pr_info("... bit width:              %d\n",     x86_pmu.event_bits);
 	pr_info("... generic registers:      %d\n",     x86_pmu.num_events);
#33 lore raw

PATCH 9/10 perf_event: x86: Optimize constraint weight computation

In reply to Peter Zijlstra

Add a weight member to the constraint structure and avoid recomputing the weight at runtime.

LKML-Reference: <new-submission>

---
 arch/x86/kernel/cpu/perf_event.c |    9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)
arch/x86/kernel/cpu/perf_event.c +5 -4
Index: linux-2.6/arch/x86/kernel/cpu/perf_event.c
===================================================================
@@ -23,6 +23,7 @@
 #include <linux/uaccess.h>
 #include <linux/highmem.h>
 #include <linux/cpu.h>
+#include <linux/bitops.h>
 
 #include <asm/apic.h>
 #include <asm/stacktrace.h>
@@ -76,6 +77,7 @@ struct event_constraint {
 	};
 	int	code;
 	int	cmask;
+	int	weight;
 };
 
 struct cpu_hw_events {
@@ -96,6 +98,7 @@ struct cpu_hw_events {
 	{ .idxmsk64[0] = (n) },		\
 	.code = (c),			\
 	.cmask = (m),			\
+	.weight = HWEIGHT64((u64)(n)),	\
 }
 
 #define INTEL_EVENT_CONSTRAINT(c, n)	\
@@ -1245,8 +1248,7 @@ static inline int is_x86_event(struct pe
 
 static int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)
 {
-	int i, j , w, num;
-	int weight, wmax;
+	int i, j, w, num, wmax;
 	struct event_constraint *c, *constraints[X86_PMC_IDX_MAX];
 	unsigned long used_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
 	struct hw_perf_event *hwc;
@@ -1323,8 +1325,7 @@ static int x86_schedule_events(struct cp
 			c = constraints[i];
 			hwc = &cpuc->event_list[i]->hw;
 
-			weight = bitmap_weight(c->idxmsk, X86_PMC_IDX_MAX);
-			if (weight != w)
+			if (c->weight != w)
 				continue;
 
 			for_each_bit(j, c->idxmsk, X86_PMC_IDX_MAX) {
#34 lore raw

[tip:perf/core] perf_event: x86: Optimize constraint weight computation

Commit-ID:  272d30be622c9c6cbd514b1211ff359292001baa
Gitweb:     http://git.kernel.org/tip/272d30be622c9c6cbd514b1211ff359292001baa
Author:     Peter Zijlstra <[email protected]>
AuthorDate: Fri, 22 Jan 2010 16:32:17 +0100
Committer:  Ingo Molnar <[email protected]>
CommitDate: Fri, 29 Jan 2010 09:01:41 +0100

perf_event: x86: Optimize constraint weight computation

Add a weight member to the constraint structure and avoid recomputing the weight at runtime.

Cc Stephane Eranian <[email protected]>

LKML-Reference: <[email protected]>

---
 arch/x86/kernel/cpu/perf_event.c |    9 +++++----
 1 files changed, 5 insertions(+), 4 deletions(-)
arch/x86/kernel/cpu/perf_event.c +5 -4
index 092ad56..2c22ce4 100644
@@ -23,6 +23,7 @@
 #include <linux/uaccess.h>
 #include <linux/highmem.h>
 #include <linux/cpu.h>
+#include <linux/bitops.h>
 
 #include <asm/apic.h>
 #include <asm/stacktrace.h>
@@ -76,6 +77,7 @@ struct event_constraint {
 	};
 	int	code;
 	int	cmask;
+	int	weight;
 };
 
 struct cpu_hw_events {
@@ -95,6 +97,7 @@ struct cpu_hw_events {
 	{ .idxmsk64[0] = (n) },		\
 	.code = (c),			\
 	.cmask = (m),			\
+	.weight = HWEIGHT64((u64)(n)),	\
 }
 
 #define INTEL_EVENT_CONSTRAINT(c, n)	\
@@ -1242,8 +1245,7 @@ static inline int is_x86_event(struct perf_event *event)
 
 static int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)
 {
-	int i, j , w, num;
-	int weight, wmax;
+	int i, j, w, num, wmax;
 	struct event_constraint *c, *constraints[X86_PMC_IDX_MAX];
 	unsigned long used_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
 	struct hw_perf_event *hwc;
@@ -1320,8 +1322,7 @@ static int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)
 			c = constraints[i];
 			hwc = &cpuc->event_list[i]->hw;
 
-			weight = bitmap_weight(c->idxmsk, X86_PMC_IDX_MAX);
-			if (weight != w)
+			if (c->weight != w)
 				continue;
 
 			for_each_bit(j, c->idxmsk, X86_PMC_IDX_MAX) {
#35 lore raw

PATCH 10/10 perf_event: Optimize the fast path a little more

In reply to Peter Zijlstra

Remove num from the fast path and save a few ops.

LKML-Reference: <new-submission>

---
 arch/x86/kernel/cpu/perf_event.c |    6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
arch/x86/kernel/cpu/perf_event.c +3 -3
Index: linux-2.6/arch/x86/kernel/cpu/perf_event.c
===================================================================
@@ -1248,9 +1248,9 @@ static inline int is_x86_event(struct pe
 
 static int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)
 {
-	int i, j, w, num, wmax;
 	struct event_constraint *c, *constraints[X86_PMC_IDX_MAX];
 	unsigned long used_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
+	int i, j, w, wmax, num = 0;
 	struct hw_perf_event *hwc;
 
 	bitmap_zero(used_mask, X86_PMC_IDX_MAX);
@@ -1263,7 +1263,7 @@ static int x86_schedule_events(struct cp
 	/*
 	 * fastpath, try to reuse previous register
 	 */
-	for (i = 0, num = n; i < n; i++, num--) {
+	for (i = 0; i < n; i++) {
 		hwc = &cpuc->event_list[i]->hw;
 		c = constraints[i];
 
@@ -1291,7 +1291,7 @@ static int x86_schedule_events(struct cp
 		if (assign)
 			assign[i] = hwc->idx;
 	}
-	if (!num)
+	if (i == n)
 		goto done;
 
 	/*
#36 lore raw

[tip:perf/core] perf_event: x86: Optimize the fast path a little more

Commit-ID:  c933c1a603d5bf700ddce79216c1be0ec3bc0e6c
Gitweb:     http://git.kernel.org/tip/c933c1a603d5bf700ddce79216c1be0ec3bc0e6c
Author:     Peter Zijlstra <[email protected]>
AuthorDate: Fri, 22 Jan 2010 16:40:12 +0100
Committer:  Ingo Molnar <[email protected]>
CommitDate: Fri, 29 Jan 2010 09:01:42 +0100

perf_event: x86: Optimize the fast path a little more

Remove num from the fast path and save a few ops.

Cc Stephane Eranian <[email protected]>

LKML-Reference: <[email protected]>

---
 arch/x86/kernel/cpu/perf_event.c |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)
arch/x86/kernel/cpu/perf_event.c +3 -3
index 2c22ce4..33c889f 100644
@@ -1245,9 +1245,9 @@ static inline int is_x86_event(struct perf_event *event)
 
 static int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)
 {
-	int i, j, w, num, wmax;
 	struct event_constraint *c, *constraints[X86_PMC_IDX_MAX];
 	unsigned long used_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
+	int i, j, w, wmax, num = 0;
 	struct hw_perf_event *hwc;
 
 	bitmap_zero(used_mask, X86_PMC_IDX_MAX);
@@ -1260,7 +1260,7 @@ static int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)
 	/*
 	 * fastpath, try to reuse previous register
 	 */
-	for (i = 0, num = n; i < n; i++, num--) {
+	for (i = 0; i < n; i++) {
 		hwc = &cpuc->event_list[i]->hw;
 		c = constraints[i];
 
@@ -1288,7 +1288,7 @@ static int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)
 		if (assign)
 			assign[i] = hwc->idx;
 	}
-	if (!num)
+	if (i == n)
 		goto done;
 
 	/*
#37 lore raw

cover FMODE_NONOTIFY and FMODE_NEG_OFFSET bits

Andrew,

Resend the patches related to FMODE_* and O_*, rebased to the -mm tree.

O_* and FMODE_NONOTIFY collision fix/check
[PATCH 1/5] fanotify: fix FMODE_NONOTIFY bit number
[PATCH 2/5] bitops: compile time optimization for hweight_long(CONSTANT) [PATCH 3/5] vfs: O_* bit numbers uniqueness check

allow negative f_pos for /dev/kmem
[PATCH 4/5] vfs: introduce FMODE_NEG_OFFSET for allowing negative f_pos [PATCH 5/5] devmem: dont allow seek to last page

Thanks,
Fengguang

#38 lore raw

PATCH 1/5 fanotify: fix FMODE_NONOTIFY bit number

FMODE_NONOTIFY=0x800000 collides with __O_SYNC in sparc, so change it to 0x1000000.

---
 include/asm-generic/fcntl.h |    2 +-
 include/linux/fs.h          |    2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)
include/asm-generic/fcntl.h +1 -1
@@ -5,7 +5,7 @@
 
 /*
  * FMODE_EXEC is 0x20
- * FMODE_NONOTIFY is 0x800000
+ * FMODE_NONOTIFY is 0x1000000
  * These cannot be used by userspace O_* until internal and external open
  * flags are split.
  * -Eric Paris
include/linux/fs.h +1 -1
@@ -91,7 +91,7 @@ struct inodes_stat_t {
 #define FMODE_RANDOM		((__force fmode_t)0x1000)
 
 /* File was opened by fanotify and shouldn't generate fanotify events */
-#define FMODE_NONOTIFY		((__force fmode_t)0x800000)
+#define FMODE_NONOTIFY		((__force fmode_t)0x1000000)
 
 /*
  * The below are the various read and write types that we support. Some of
maintainer
#39 lore raw

Re: [PATCH 1/5] fanotify: fix FMODE_NONOTIFY bit number

Quoted 25 lines · On Sat, 30 Jan 2010 17:45:16 +0800 Wu Fengguang <[email protected]> wrote:

FMODE_NONOTIFY=0x800000 collides with __O_SYNC in sparc, so change it to 0x1000000.

---
 include/asm-generic/fcntl.h |    2 +-
 include/linux/fs.h          |    2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)
include/asm-generic/fcntl.h +1 -1
@@ -5,7 +5,7 @@
 
 /*
  * FMODE_EXEC is 0x20
- * FMODE_NONOTIFY is 0x800000
+ * FMODE_NONOTIFY is 0x1000000
  * These cannot be used by userspace O_* until internal and external open
  * flags are split.
  * -Eric Paris

include/linux/fs.h struct inodes_stat_t { · line 97

Quoted 8 lines
include/linux/fs.h +1 -1
@@ -91,7 +91,7 @@ struct inodes_stat_t {
 #define FMODE_RANDOM		((__force fmode_t)0x1000)
 
 /* File was opened by fanotify and shouldn't generate fanotify events */
-#define FMODE_NONOTIFY		((__force fmode_t)0x800000)
+#define FMODE_NONOTIFY		((__force fmode_t)0x1000000)
 
 /*
  * The below are the various read and write types that we support. Some of

Eric, please fix up "vfs: introduce FMODE_NONOTIFY" in your tree?

#40 lore raw

PATCH 2/5 bitops: compile time optimization for hweight_long(CONSTANT)

In reply to Wu Fengguang

This allows use of hweight_long() in BUILD_BUG_ON(). Suggested by Jamie.

CC Jamie Lokier <[email protected]>
CC Roland Dreier <[email protected]>
---
 include/linux/bitops.h |   12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)
include/linux/bitops.h +8 -4
@@ -40,10 +40,14 @@ static __inline__ int get_count_order(un
 	return order;
 }
 
-static inline unsigned long hweight_long(unsigned long w)
-{
-	return sizeof(w) == 4 ? hweight32(w) : hweight64(w);
-}
+#define hweight_long(x)				\
+(						\
+	__builtin_constant_p(x) ?		\
+		__builtin_popcountl(x) :	\
+		(sizeof(x) <= 4 ?		\
+			 hweight32(x) :		\
+			 hweight64(x))		\
+)
 
 /**
  * rol32 - rotate a 32-bit value left
maintainer
#41 lore raw

Re: [PATCH 2/5] bitops: compile time optimization for hweight_long(CONSTANT)

Quoted 21 lines · On Sat, 30 Jan 2010 17:45:17 +0800 Wu Fengguang <[email protected]> wrote:

This allows use of hweight_long() in BUILD_BUG_ON(). Suggested by Jamie.

CC Jamie Lokier <[email protected]>
CC Roland Dreier <[email protected]>
---
 include/linux/bitops.h |   12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)
include/linux/bitops.h +1 -4
@@ -40,10 +40,14 @@ static __inline__ int get_count_order(un
 	return order;
 }
 
-static inline unsigned long hweight_long(unsigned long w)
-{
-	return sizeof(w) == 4 ? hweight32(w) : hweight64(w);
-}
+#define hweight_long(x)				\

include/linux/bitops.h static __inline__ int get_count_order(un · line 53

Quoted 10 lines
include/linux/bitops.h +7 -0
+(						\
+	__builtin_constant_p(x) ?		\
+		__builtin_popcountl(x) :	\
+		(sizeof(x) <= 4 ?		\
+			 hweight32(x) :		\
+			 hweight64(x))		\
+)
 
 /**
  * rol32 - rotate a 32-bit value left

Peter's been mucking with a compile-time HWEIGHT(). An outdated version of that is presently in linux-next.

(I wonder if it could have used __builtin_popcount)

(I wonder which gcc versions support __builtin_popcount)

Anyway, I suspect you should be using that rather than tweaking hweight_long().

#42 lore raw

Re: [PATCH 2/5] bitops: compile time optimization for hweight_long(CONSTANT)

Quoted 13 lines · Andrew Morton
Quoted 13 lines
include/linux/bitops.h +8 -4
-static inline unsigned long hweight_long(unsigned long w)
-{
-	return sizeof(w) == 4 ? hweight32(w) : hweight64(w);
-}
+#define hweight_long(x)				\
+(						\
+	__builtin_constant_p(x) ?		\
+		__builtin_popcountl(x) :	\
+		(sizeof(x) <= 4 ?		\
+			 hweight32(x) :		\
+			 hweight64(x))		\
+)
Quoted 5 lines
Quoted 2 lines

/**
* rol32 - rotate a 32-bit value left

Peter's been mucking with a compile-time HWEIGHT(). An outdated version of that is presently in linux-next.

Ah I find it. Thanks.

Quoted 3 lines

(I wonder if it could have used __builtin_popcount)

(I wonder which gcc versions support __builtin_popcount)

This is how Jamie Lokier first recommended it to me:

Checked GCC 3.4.3 / 4.1 / 4.4: It expands as a compile-time constant if the argument is a compile-time constant, so can be used in BUILD_BUG_ON() and even for array sizes etc.

Is there an official lowest GCC version that Linux supports?

Quoted 2 lines

Anyway, I suspect you should be using that rather than tweaking hweight_long().

OK.

But.. if ever the GCC builtins can be used:

__builtin_popcount(unsigned int)
__builtin_popcountl(unsigned long)
__builtin_popcountll(unsigned long long)

it would be more natural to use hweight_long() or even introduce hweight_longlong() for (transparent) compile time computation.

Thanks,
Fengguang

maintainer
#43 lore raw

Re: [PATCH 2/5] bitops: compile time optimization for hweight_long(CONSTANT)

Quoted 1 line · On Wed, 3 Feb 2010 21:39:51 +0800 Wu Fengguang <[email protected]> wrote:

Is there an official lowest GCC version that Linux supports?

Documentation/Changes says gcc-3.2.

maintainer
#44 lore raw

Re: [PATCH 2/5] bitops: compile time optimization for hweight_long(CONSTANT)

Quoted 5 lines · Andrew Morton
Quoted 1 line · On Wed, 3 Feb 2010 21:39:51 +0800 Wu Fengguang <[email protected]> wrote:

Is there an official lowest GCC version that Linux supports?

Documentation/Changes says gcc-3.2.

Anyway, its not like that macro I used isn't straight forward. Not much a builtin can do better.

The only benefit the builtin has is possibly use machine popcnt instructions but we already deal with that in the kernel.

maintainer
#45 lore raw

Re: [PATCH 2/5] bitops: compile time optimization for hweight_long(CONSTANT)

Quoted 5 lines · On Wed, 03 Feb 2010 16:15:57 +0100 Peter Zijlstra <[email protected]> wrote:
Quoted 4 lines · Andrew Morton
Quoted 1 line · On Wed, 3 Feb 2010 21:39:51 +0800 Wu Fengguang <[email protected]> wrote:

Is there an official lowest GCC version that Linux supports?

Quoted 7 lines
Quoted 1 line

Documentation/Changes says gcc-3.2.

Anyway, its not like that macro I used isn't straight forward. Not much a builtin can do better.

The only benefit the builtin has is possibly use machine popcnt instructions but we already deal with that in the kernel.

We didn't deal with it on every architecture, which is something which the compiler extension takes care of.

In fact I can't find anywhere where we dealt with it on x86.

maintainer
#46 lore raw

Re: [PATCH 2/5] bitops: compile time optimization for hweight_long(CONSTANT)

Quoted 15 lines · Andrew Morton
Quoted 5 lines · On Wed, 03 Feb 2010 16:15:57 +0100 Peter Zijlstra <[email protected]> wrote:
Quoted 4 lines · Andrew Morton
Quoted 1 line · On Wed, 3 Feb 2010 21:39:51 +0800 Wu Fengguang <[email protected]> wrote:

Is there an official lowest GCC version that Linux supports?

Quoted 7 lines
Quoted 1 line

Documentation/Changes says gcc-3.2.

Anyway, its not like that macro I used isn't straight forward. Not much a builtin can do better.

The only benefit the builtin has is possibly use machine popcnt instructions but we already deal with that in the kernel.

Quoted 6 lines

We didn't deal with it on every architecture, which is something which the compiler extension takes care of.

In fact I can't find anywhere where we dealt with it on x86.

From what I know the popcnt ins on x86 is relatively new, hpa was going

to look at supporting it using alternatives.

#47 lore raw

Re: [PATCH 2/5] bitops: compile time optimization for hweight_long(CONSTANT)

Quoted 4 lines · Peter Zijlstra

From what I know the popcnt ins on x86 is relatively new, hpa was going to look at supporting it using alternatives.

And kernel-specific stuff like alternatives is pretty much the one thing that gcc *can't* do for us.

-hpa

Signature · 2 lines
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel.  I don't speak on their behalf.
#48 lore raw

Re: [PATCH 2/5] bitops: compile time optimization for hweight_long(CONSTANT)

In reply to Andrew Morton
Quoted 4 lines · Andrew Morton

We didn't deal with it on every architecture, which is something which the compiler extension takes care of.

In fact I can't find anywhere where we dealt with it on x86.

Yeah, we talked briefly about using hardware popcnt, see thread beginning at

http://linux.derkeiler.com/Mailing-Lists/Kernel/2009-06/msg00245.html

for example. I did an ftrace of the cpumask_weight() calls in sched.c to see whether there would be a measurable performance gain but it didn't seem so at the time. My numbers said something like ca. 170 hweight calls per second and since the <lib/hweight.c> implementations roughly translate to something like ~20 isns (hweight64 to about ~30), the whole thing wasn't worth the trouble considering checking binutils versions and slapping opcodes or using gcc intrinsics which involves gcc version checking.

An alternatives solution which is based on CPUID flag could add the popcnt opcode without checking any toolchain versions but how is the replaced instruction going to look like? Something like

alternative("call hweightXX", "popcnt", X86_FEATURE_POPCNT)

by making sure the arg is in some register first?

Hmm..

Signature · 6 lines
Regards/Gruss,
Boris.

--
Advanced Micro Devices, Inc.
Operating Systems Research Center
maintainer
#49 lore raw

Re: [PATCH 2/5] bitops: compile time optimization for hweight_long(CONSTANT)

Quoted 1 line · Borislav Petkov

alternative("call hweightXX", "popcnt", X86_FEATURE_POPCNT)

Make sure to apply a 0xff bitmask to the popcnt r16 call for hweight8(), and hweight64() needs a bit of magic for 32bit, but yes, something like that ought to work nicely.

#50 lore raw

Re: [PATCH 2/5] bitops: compile time optimization for hweight_long(CONSTANT)

Quoted 8 lines · Peter Zijlstra
Quoted 1 line · Borislav Petkov

alternative("call hweightXX", "popcnt", X86_FEATURE_POPCNT)

Make sure to apply a 0xff bitmask to the popcnt r16 call for hweight8(), and hweight64() needs a bit of magic for 32bit, but yes, something like that ought to work nicely.

Arguably the "best" option is to have the alternative being a jump to an out-of-line stub which does the necessary parameter marshalling before calling a stub. This technique is already used in a few other places.

-hpa

#51 lore raw

Re: [PATCH 2/5] bitops: compile time optimization for hweight_long(CONSTANT)

Quoted 5 lines · H. Peter Anvin
Quoted 4 lines · Peter Zijlstra
Quoted 1 line · Borislav Petkov

alternative("call hweightXX", "popcnt", X86_FEATURE_POPCNT)

Quoted 8 lines
Quoted 4 lines

Make sure to apply a 0xff bitmask to the popcnt r16 call for hweight8(), and hweight64() needs a bit of magic for 32bit, but yes, something like that ought to work nicely.

Arguably the "best" option is to have the alternative being a jump to an out-of-line stub which does the necessary parameter marshalling before calling a stub. This technique is already used in a few other places.

Ok, here's a first alpha prototype and completely untested. The asm output looks ok though. I've added separate 32-bit and 64-bit helpers in order to dispense with the if-else tests. The hw-popcnt versions are the opcodes for "popcnt %eax, %eax" and "popcnt %rax, %rax", respectively, so %rAX has to be preloaded with the bitmask and the computed value has to be retrieved from there afterwards. And yes, it looks not that elegant so I'm open for suggestions.

The good thing is, this should work on any toolchain since we don't rely on the compiler to know about popcnt and we're protected by CPUID flag so that the hw-popcnt version is used only on processors which support it.

Please take a good look and let me know what do you guys think.

Thanks.

--

 arch/x86/include/asm/bitops.h |    4 ++
 arch/x86/lib/Makefile         |    2 +-
 arch/x86/lib/popcnt.c         |   62 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 67 insertions(+), 1 deletions(-)
 create mode 100644 arch/x86/lib/popcnt.c
arch/x86/include/asm/bitops.h +4 -0
index 02b47a6..deb5013 100644
@@ -434,6 +434,10 @@ static inline int fls(int x)
 #endif
 	return r + 1;
 }
+
+
+extern int arch_hweight_long(unsigned long);
+
 #endif /* __KERNEL__ */
 
 #undef ADDR
arch/x86/lib/Makefile +1 -1
index cffd754..c03fe2d 100644
@@ -22,7 +22,7 @@ lib-y += usercopy_$(BITS).o getuser.o putuser.o
 lib-y += memcpy_$(BITS).o
 lib-$(CONFIG_KPROBES) += insn.o inat.o
 
-obj-y += msr.o msr-reg.o msr-reg-export.o
+obj-y += msr.o msr-reg.o msr-reg-export.o popcnt.o
 
 ifeq ($(CONFIG_X86_32),y)
         obj-y += atomic64_32.o
arch/x86/lib/popcnt.c new file +62 -0

62 lines not on this page · raw message

Signature · 9 lines
1.6.6

-- 
Regards/Gruss,
Boris.

--
Advanced Micro Devices, Inc.
Operating Systems Research Center
maintainer
#52 lore raw

Re: [PATCH 2/5] bitops: compile time optimization for hweight_long(CONSTANT)

Quoted 38 lines · Borislav Petkov
Quoted 5 lines · H. Peter Anvin
Quoted 4 lines · Peter Zijlstra
Quoted 1 line · Borislav Petkov

alternative("call hweightXX", "popcnt", X86_FEATURE_POPCNT)

Quoted 8 lines
Quoted 4 lines

Make sure to apply a 0xff bitmask to the popcnt r16 call for hweight8(), and hweight64() needs a bit of magic for 32bit, but yes, something like that ought to work nicely.

Arguably the "best" option is to have the alternative being a jump to an out-of-line stub which does the necessary parameter marshalling before calling a stub. This technique is already used in a few other places.

Ok, here's a first alpha prototype and completely untested. The asm output looks ok though. I've added separate 32-bit and 64-bit helpers in order to dispense with the if-else tests. The hw-popcnt versions are the opcodes for "popcnt %eax, %eax" and "popcnt %rax, %rax", respectively, so %rAX has to be preloaded with the bitmask and the computed value has to be retrieved from there afterwards. And yes, it looks not that elegant so I'm open for suggestions.

The good thing is, this should work on any toolchain since we don't rely on the compiler to know about popcnt and we're protected by CPUID flag so that the hw-popcnt version is used only on processors which support it.

Please take a good look and let me know what do you guys think.

arch/x86/lib/popcnt.c new file +8 -0
+int arch_hweight_long(unsigned long w)
+{
+	if (sizeof(w) == 4) {
+		asm volatile("movl %[w], %%eax" :: [w] "r" (w));
+		alternative("call _hweight32",
+			    "call _popcnt32",
+			    X86_FEATURE_POPCNT);
+		asm volatile("" : "=a" (w));

arch/x86/lib/popcnt.c line 62

Quoted 10 lines
arch/x86/lib/popcnt.c new file +10 -0
+
+	} else {
+		asm volatile("movq %[w], %%rax" :: [w] "r" (w));
+		alternative("call _hweight64",
+			    "call _popcnt64",
+			    X86_FEATURE_POPCNT);
+		asm volatile("" : "=a" (w));
+	}
+	return w;
+}

hweight_long() isn't an arch primitive, only __arch_hweight{8,16,32,64} are.

#53 lore raw

Re: [PATCH 2/5] bitops: compile time optimization for hweight_long(CONSTANT)

Quoted 2 lines · Peter Zijlstra

hweight_long() isn't an arch primitive, only __arch_hweight{8,16,32,64} are.

Yeah, I'm still looking for the proper location. hweight_long() is the generic version so do we want to do the

#ifndef __HAVE_ARCH_POPCNT
static inline unsigned long hweight_long(unsigned long w)
...

#endif

thing and define a x86-specific version?

Signature · 6 lines
Regards/Gruss,
Boris.

--
Advanced Micro Devices, Inc.
Operating Systems Research Center
maintainer
#54 lore raw

Re: [PATCH 2/5] bitops: compile time optimization for hweight_long(CONSTANT)

Quoted 7 lines · Borislav Petkov
Quoted 2 lines · Peter Zijlstra

hweight_long() isn't an arch primitive, only __arch_hweight{8,16,32,64} are.

Yeah, I'm still looking for the proper location. hweight_long() is the generic version so do we want to do the

Quoted 7 lines

#ifndef __HAVE_ARCH_POPCNT
static inline unsigned long hweight_long(unsigned long w)
....

#endif

thing and define a x86-specific version?

No, just don't touch hweight_long(), simply provide __arch_hweight{8,16,32,64} and all will be well.

hweight_long() is provided by <include/linux.h> and is constructed from height32() and hweight64() depending on the actual word size.

#55 lore raw

Re: [PATCH 2/5] bitops: compile time optimization for hweight_long(CONSTANT)

Quoted 2 lines · Peter Zijlstra

No, just don't touch hweight_long(), simply provide __arch_hweight{8,16,32,64} and all will be well.

Ok, another day, another version :)

It is, of course, completely untested but it builds and the asm looks ok. I think I've addressed all concerns so far.

--

 arch/x86/include/asm/hweight.h       |   14 ++++++++
 arch/x86/lib/Makefile                |    2 +-
 arch/x86/lib/hweight.c               |   57 ++++++++++++++++++++++++++++++++++
 include/asm-generic/bitops/hweight.h |   45 ++++++++++++++++++++++++--
 lib/hweight.c                        |   16 +++++-----
 5 files changed, 121 insertions(+), 13 deletions(-)
 create mode 100644 arch/x86/include/asm/hweight.h
 create mode 100644 arch/x86/lib/hweight.c
arch/x86/include/asm/hweight.h new file +14 -0
new file mode 100644
index 0000000..762125f
@@ -0,0 +1,14 @@
+#ifndef _ASM_X86_HWEIGHT_H
+#define _ASM_X86_HWEIGHT_H
+
+#define __arch_hweight8 __arch_hweight8
+#define __arch_hweight16 __arch_hweight16
+#define __arch_hweight32 __arch_hweight32
+#define __arch_hweight64 __arch_hweight64
+
+extern unsigned int __arch_hweight8(unsigned int);
+extern unsigned int __arch_hweight16(unsigned int);
+extern unsigned int __arch_hweight32(unsigned int);
+extern unsigned long __arch_hweight64(__u64);
+
+#endif /*_ASM_X86_HWEIGHT_H */
arch/x86/lib/Makefile +1 -1
index cffd754..e811bbd 100644
@@ -22,7 +22,7 @@ lib-y += usercopy_$(BITS).o getuser.o putuser.o
 lib-y += memcpy_$(BITS).o
 lib-$(CONFIG_KPROBES) += insn.o inat.o
 
-obj-y += msr.o msr-reg.o msr-reg-export.o
+obj-y += msr.o msr-reg.o msr-reg-export.o hweight.o
 
 ifeq ($(CONFIG_X86_32),y)
         obj-y += atomic64_32.o
arch/x86/lib/hweight.c new file +57 -0

57 lines not on this page · raw message

include/asm-generic/bitops/hweight.h +41 -4

51 lines not on this page · raw message

lib/hweight.c +8 -8
index 389424e..f7b81a1 100644
@@ -9,7 +9,7 @@
  * The Hamming Weight of a number is the total number of bits set in it.
  */
 
-unsigned int hweight32(unsigned int w)
+unsigned int _hweight32(unsigned int w)
 {
 	unsigned int res = w - ((w >> 1) & 0x55555555);
 	res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
@@ -17,26 +17,26 @@ unsigned int hweight32(unsigned int w)
 	res = res + (res >> 8);
 	return (res + (res >> 16)) & 0x000000FF;
 }
-EXPORT_SYMBOL(hweight32);
+EXPORT_SYMBOL(_hweight32);
 
-unsigned int hweight16(unsigned int w)
+unsigned int _hweight16(unsigned int w)
 {
 	unsigned int res = w - ((w >> 1) & 0x5555);
 	res = (res & 0x3333) + ((res >> 2) & 0x3333);
 	res = (res + (res >> 4)) & 0x0F0F;
 	return (res + (res >> 8)) & 0x00FF;
 }
-EXPORT_SYMBOL(hweight16);
+EXPORT_SYMBOL(_hweight16);
 
-unsigned int hweight8(unsigned int w)
+unsigned int _hweight8(unsigned int w)
 {
 	unsigned int res = w - ((w >> 1) & 0x55);
 	res = (res & 0x33) + ((res >> 2) & 0x33);
 	return (res + (res >> 4)) & 0x0F;
 }
-EXPORT_SYMBOL(hweight8);
+EXPORT_SYMBOL(_hweight8);
 
-unsigned long hweight64(__u64 w)
+unsigned long _hweight64(__u64 w)
 {
 #if BITS_PER_LONG == 32
 	return hweight32((unsigned int)(w >> 32)) + hweight32((unsigned int)w);
@@ -56,4 +56,4 @@ unsigned long hweight64(__u64 w)
 #endif
 #endif
 }
-EXPORT_SYMBOL(hweight64);
+EXPORT_SYMBOL(_hweight64);
Signature · 10 lines
1.6.4.2


-- 
Regards/Gruss,
Boris.

-
Advanced Micro Devices, Inc.
Operating Systems Research Center
maintainer
#56 lore raw

Re: [PATCH 2/5] bitops: compile time optimization for hweight_long(CONSTANT)

Quoted 8 lines · Borislav Petkov
Quoted 2 lines · Peter Zijlstra

No, just don't touch hweight_long(), simply provide __arch_hweight{8,16,32,64} and all will be well.

Ok, another day, another version :)

It is, of course, completely untested but it builds and the asm looks ok. I think I've addressed all concerns so far.

please work against a tree that has:

http://lkml.org/lkml/2010/2/4/119

in.

#57 lore raw

Re: [PATCH 2/5] bitops: compile time optimization for hweight_long(CONSTANT)

In reply to Borislav Petkov

arch/x86/lib/hweight.c line 20

Quoted 11 lines · Borislav Petkov
arch/x86/lib/hweight.c new file +11 -0
+
+unsigned int __arch_hweight16(unsigned int w)
+{
+	unsigned int res = 0;
+
+	asm volatile("xor %%dh, %%dh\n\t"
+		     __arch_hweight_alt(32)
+			: "=di" (res)
+			: "di" (w)
+			: "ecx", "memory");
+

This is wrong in more ways than I can shake a stick at.

a) "di" doesn't mean the DI register - it means the DX register (d) or an immediate (i). Since you don't have any reference to either %0 or %1 in your code, you have no way of knowing which one it is. The constraint for the di register is "D".

b) On 32 bits, the first argument register is in %eax (with %edx used for the upper half of a 32-bit argument), but on 64 bits, the first argument is in %rdi, with the return still in %rax.

c) You call a C function, but you don't clobber the set of registers that a C function would clobber. You either need to put the function in an assembly wrapper (which is better in the long run), or clobber the full set of registers that is clobbered by a C function (which is better in the short term) -- which is eax, edx, ecx on 32 bits, but rax, rdi, esi, rdx, rcx, r8, r9, r10, r11 on 64 bits.

d) On the other hand, you do *not* need a "memory" clobber.

-hpa

#58 lore raw

Re: [PATCH 2/5] bitops: compile time optimization for hweight_long(CONSTANT)

Quoted 14 lines · H. Peter Anvin

arch/x86/lib/hweight.c line 20

Quoted 11 lines · Borislav Petkov
arch/x86/lib/hweight.c new file +11 -0
+
+unsigned int __arch_hweight16(unsigned int w)
+{
+	unsigned int res = 0;
+
+	asm volatile("xor %%dh, %%dh\n\t"
+		     __arch_hweight_alt(32)
+			: "=di" (res)
+			: "di" (w)
+			: "ecx", "memory");
+

This is wrong in more ways than I can shake a stick at.

Thanks for reviewing it though - how else would I learn :).

Quoted 4 lines

a) "di" doesn't mean the DI register - it means the DX register (d) or an immediate (i). Since you don't have any reference to either %0 or %1 in your code, you have no way of knowing which one it is. The constraint for the di register is "D".

right.

Quoted 3 lines

b) On 32 bits, the first argument register is in %eax (with %edx used for the upper half of a 32-bit argument), but on 64 bits, the first argument is in %rdi, with the return still in %rax.

Sure, it is right there in arch/x86/include/asm/calling.h. Shame on me.

Quoted 6 lines

c) You call a C function, but you don't clobber the set of registers that a C function would clobber. You either need to put the function in an assembly wrapper (which is better in the long run), or clobber the full set of registers that is clobbered by a C function (which is better in the short term) -- which is eax, edx, ecx on 32 bits, but rax, rdi, esi, rdx, rcx, r8, r9, r10, r11 on 64 bits.

I think you mean rsi instead of esi here.

Well, the example Brian pointed me to - __mutex_fastpath_lock - lists the full set of clobbered registers. Please elaborate on the assembly wrapper for the function, wouldn't I need to list all the clobbered registers there too or am I missing something?

Quoted 1 line

d) On the other hand, you do *not* need a "memory" clobber.

Right, in this case we have all non-barrier like inlines so no memory clobber, according to the comment above alternative() macro.

Thanks.

Signature · 6 lines
Regards/Gruss,
Boris.

-
Advanced Micro Devices, Inc.
Operating Systems Research Center
#59 lore raw

Re: [PATCH 2/5] bitops: compile time optimization for hweight_long(CONSTANT)

Quoted 8 lines · Borislav Petkov
Quoted 7 lines

c) You call a C function, but you don't clobber the set of registers that a C function would clobber. You either need to put the function in an assembly wrapper (which is better in the long run), or clobber the full set of registers that is clobbered by a C function (which is better in the short term) -- which is eax, edx, ecx on 32 bits, but rax, rdi, esi, rdx, rcx, r8, r9, r10, r11 on 64 bits.

Quoted 7 lines

I think you mean rsi instead of esi here.

Well, the example Brian pointed me to - __mutex_fastpath_lock - lists the full set of clobbered registers. Please elaborate on the assembly wrapper for the function, wouldn't I need to list all the clobbered registers there too or am I missing something?

The notion there would be that you do push/pop in the assembly wrapper.

Quoted 4 lines
Quoted 1 line

d) On the other hand, you do *not* need a "memory" clobber.

Right, in this case we have all non-barrier like inlines so no memory clobber, according to the comment above alternative() macro.

OK, I'm missing something here.

A few more notions:

a. This is exactly the kind of code where you don't want to put "volatile" on your asm statement, because it's a pure compute.

b. It is really rather pointless to go through the whole alternatives work if you are then going to put it inside a function which isn't an inline ...

-hpa

Signature · 2 lines
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel.  I don't speak on their behalf.
#60 lore raw

Re: [PATCH 2/5] bitops: compile time optimization for hweight_long(CONSTANT)

Quoted 7 lines · H. Peter Anvin
Quoted 5 lines

Well, the example Brian pointed me to - __mutex_fastpath_lock - lists the full set of clobbered registers. Please elaborate on the assembly wrapper for the function, wouldn't I need to list all the clobbered registers there too or am I missing something?

The notion there would be that you do push/pop in the assembly wrapper.

Oh yes, something similar to SAVE/RESTORE_ALL in <arch/x86/kernel/entry_32.S> could work. Good idea!

Quoted 7 lines
Quoted 4 lines
Quoted 1 line

d) On the other hand, you do *not* need a "memory" clobber.

Right, in this case we have all non-barrier like inlines so no memory clobber, according to the comment above alternative() macro.

OK, I'm missing something here.

Quoted 8 lines

A few more notions:

a. This is exactly the kind of code where you don't want to put "volatile" on your asm statement, because it's a pure compute.

b. It is really rather pointless to go through the whole alternatives work if you are then going to put it inside a function which isn't an inline ...

Well, in the second version I did replace a 'call _hweightXX' with the actual popcnt opcode so the alternatives is only needed to do the replacement during boot. We might just as well do

if (X86_FEATURE_POPCNT)

	__hw_popcnt()

else
__software_hweight()

The only advantage of the alternatives is that it would save us the if-else test above each time we do cpumask_weight. However, the if-else approach is much more readable and obviates the need for all that macro magic and taking special care of calling c function from within asm. And since we do not call cpumask_weight all that often I'll honestly opt for alternative-less solution...

Hmm...

Thanks,
Boris.

#61 lore raw

Re: [PATCH 2/5] bitops: compile time optimization for hweight_long(CONSTANT)

Quoted 10 lines · Borislav Petkov

Well, in the second version I did replace a 'call _hweightXX' with the actual popcnt opcode so the alternatives is only needed to do the replacement during boot. We might just as well do

if (X86_FEATURE_POPCNT)

	__hw_popcnt()

else
__software_hweight()

Quoted 7 lines

The only advantage of the alternatives is that it would save us the if-else test above each time we do cpumask_weight. However, the if-else approach is much more readable and obviates the need for all that macro magic and taking special care of calling c function from within asm. And since we do not call cpumask_weight all that often I'll honestly opt for alternative-less solution...

The highest performance will be gotten by alternatives, but it only make sense if they are inlined at the point of use... otherwise it's basically pointless.

-hpa

#62 lore raw

Re: [PATCH 2/5] bitops: compile time optimization for hweight_long(CONSTANT)

Quoted 19 lines · H. Peter Anvin
Quoted 10 lines · Borislav Petkov

Well, in the second version I did replace a 'call _hweightXX' with the actual popcnt opcode so the alternatives is only needed to do the replacement during boot. We might just as well do

if (X86_FEATURE_POPCNT)

	__hw_popcnt()

else
__software_hweight()

Quoted 7 lines

The only advantage of the alternatives is that it would save us the if-else test above each time we do cpumask_weight. However, the if-else approach is much more readable and obviates the need for all that macro magic and taking special care of calling c function from within asm. And since we do not call cpumask_weight all that often I'll honestly opt for alternative-less solution...

Quoted 3 lines

The highest performance will be gotten by alternatives, but it only make sense if they are inlined at the point of use... otherwise it's basically pointless.

The popcnt-replacement part of the alternative would be as fast as possible since we're adding the opcode there but the slow version would add the additional overhead of saving/restoring the registers before calling the software hweight implementation. I'll do some tracing to see what a change like that would cost on machines which don't have popcnt.

Let me prep another version when I get back on Wed. (currently travelling) with all the stuff we discussed to see how it would turn.

Thanks,
Boris.

#63 lore raw

Re: [PATCH 2/5] bitops: compile time optimization for hweight_long(CONSTANT)

Quoted 2 lines · Borislav Petkov

Let me prep another version when I get back on Wed. (currently travelling) with all the stuff we discussed to see how it would turn.

Ok, here's another version ontop of PeterZ's patch at
http://lkml.org/lkml/2010/2/4/119. I need to handle 32- and 64-bit differently wrt to popcnt opcode so on 32-bit I do "popcnt %eax, %eax" while on 64-bit I do "popcnt %rdi, %rdi".

I also did some rudimentary tracing with the function graph tracer of all the cpumask_weight-calls in <kernel/sched.c> while doing a kernel compile and the preliminary results show that hweight in software takes about 9.768 usecs the longest while the hardware popcnt about 8.515 usecs. The machine is a Fam10 revB2 quadcore.

What remains to be done is see whether the saving/restoring of callee-clobbered regs with this patch has any noticeable negative effects on the software hweight case on machines which don't support popcnt. Also, I'm open for better tracing ideas :).

Thanks.

---
 arch/alpha/include/asm/bitops.h            |    4 +
 arch/ia64/include/asm/bitops.h             |    1 +
 arch/sparc/include/asm/bitops_64.h         |    4 +
 arch/x86/include/asm/bitops.h              |   10 +++
 arch/x86/lib/Makefile                      |    2 +-
 arch/x86/lib/hweight.c                     |   96 ++++++++++++++++++++++++++++
 include/asm-generic/bitops/arch_hweight.h  |    8 +-
 include/asm-generic/bitops/const_hweight.h |   43 +++++++++++-
 lib/hweight.c                              |   20 +++---
 9 files changed, 169 insertions(+), 19 deletions(-)
 create mode 100644 arch/x86/lib/hweight.c
arch/alpha/include/asm/bitops.h +4 -0
index 296da1d..7fe6943 100644
@@ -409,21 +409,25 @@ static inline unsigned long __arch_hweight64(unsigned long w)
 {
 	return __kernel_ctpop(w);
 }
+#define __arch_hweight64 __arch_hweight64
 
 static inline unsigned int __arch_weight32(unsigned int w)
 {
 	return __arch_hweight64(w);
 }
+#define __arch_hweight32 __arch_hweight32
 
 static inline unsigned int __arch_hweight16(unsigned int w)
 {
 	return __arch_hweight64(w & 0xffff);
 }
+#define __arch_hweight16 __arch_hweight16
 
 static inline unsigned int __arch_hweight8(unsigned int w)
 {
 	return __arch_hweight64(w & 0xff);
 }
+#define __arch_hweight8 __arch_hweight8
 #else
 #include <asm-generic/bitops/arch_hweight.h>
 #endif
arch/ia64/include/asm/bitops.h +1 -0
index 9da3df6..9b64f59 100644
@@ -443,6 +443,7 @@ static __inline__ unsigned long __arch_hweight64(unsigned long x)
 	result = ia64_popcnt(x);
 	return result;
 }
+#define __arch_hweight64 __arch_hweight64
 
 #define __arch_hweight32(x) ((unsigned int) __arch_hweight64((x) & 0xfffffffful))
 #define __arch_hweight16(x) ((unsigned int) __arch_hweight64((x) & 0xfffful))
arch/sparc/include/asm/bitops_64.h +4 -0
index 766121a..4982bc4 100644
@@ -51,6 +51,7 @@ static inline unsigned int __arch_hweight64(unsigned long w)
 	__asm__ ("popc %1,%0" : "=r" (res) : "r" (w));
 	return res;
 }
+#define __arch_hweight64 __arch_hweight64
 
 static inline unsigned int __arch_hweight32(unsigned int w)
 {
@@ -59,6 +60,7 @@ static inline unsigned int __arch_hweight32(unsigned int w)
 	__asm__ ("popc %1,%0" : "=r" (res) : "r" (w & 0xffffffff));
 	return res;
 }
+#define __arch_hweight32 __arch_hweight32
 
 static inline unsigned int __arch_hweight16(unsigned int w)
 {
@@ -67,6 +69,7 @@ static inline unsigned int __arch_hweight16(unsigned int w)
 	__asm__ ("popc %1,%0" : "=r" (res) : "r" (w & 0xffff));
 	return res;
 }
+#define __arch_hweight16 __arch_hweight16
 
 static inline unsigned int __arch_hweight8(unsigned int w)
 {
@@ -75,6 +78,7 @@ static inline unsigned int __arch_hweight8(unsigned int w)
 	__asm__ ("popc %1,%0" : "=r" (res) : "r" (w & 0xff));
 	return res;
 }
+#define __arch_hweight8 __arch_hweight8
 
 #else
 
arch/x86/include/asm/bitops.h +10 -0
index 02b47a6..187defe 100644
@@ -444,6 +444,16 @@ static inline int fls(int x)
 
 #define ARCH_HAS_FAST_MULTIPLIER 1
 
+extern unsigned int __arch_hweight32(unsigned int w);
+extern unsigned int __arch_hweight16(unsigned int w);
+extern unsigned int __arch_hweight8(unsigned int w);
+extern unsigned long __arch_hweight64(__u64 w);
+
+#define __arch_hweight32 __arch_hweight32
+#define __arch_hweight16 __arch_hweight16
+#define __arch_hweight8 __arch_hweight8
+#define __arch_hweight64 __arch_hweight64
+
 #include <asm-generic/bitops/hweight.h>
 
 #endif /* __KERNEL__ */
arch/x86/lib/Makefile +1 -1
index cffd754..e811bbd 100644
@@ -22,7 +22,7 @@ lib-y += usercopy_$(BITS).o getuser.o putuser.o
 lib-y += memcpy_$(BITS).o
 lib-$(CONFIG_KPROBES) += insn.o inat.o
 
-obj-y += msr.o msr-reg.o msr-reg-export.o
+obj-y += msr.o msr-reg.o msr-reg-export.o hweight.o
 
 ifeq ($(CONFIG_X86_32),y)
         obj-y += atomic64_32.o
arch/x86/lib/hweight.c new file +96 -0

96 lines not on this page · raw message

include/asm-generic/bitops/arch_hweight.h +4 -4
index 3a7be84..c72de8b 100644
@@ -3,9 +3,9 @@
 
 #include <asm/types.h>
 
-extern unsigned int __arch_hweight32(unsigned int w);
-extern unsigned int __arch_hweight16(unsigned int w);
-extern unsigned int __arch_hweight8(unsigned int w);
-extern unsigned long __arch_hweight64(__u64 w);
+extern unsigned int __sw_hweight32(unsigned int w);
+extern unsigned int __sw_hweight16(unsigned int w);
+extern unsigned int __sw_hweight8(unsigned int w);
+extern unsigned long __sw_hweight64(__u64 w);
 
 #endif /* _ASM_GENERIC_BITOPS_HWEIGHT_H_ */
include/asm-generic/bitops/const_hweight.h +39 -4

52 lines not on this page · raw message

lib/hweight.c +10 -10
index 9ff86df..f9ce440 100644
@@ -9,7 +9,7 @@
  * The Hamming Weight of a number is the total number of bits set in it.
  */
 
-unsigned int __arch_hweight32(unsigned int w)
+unsigned int __sw_hweight32(unsigned int w)
 {
 	unsigned int res = w - ((w >> 1) & 0x55555555);
 	res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
@@ -17,30 +17,30 @@ unsigned int __arch_hweight32(unsigned int w)
 	res = res + (res >> 8);
 	return (res + (res >> 16)) & 0x000000FF;
 }
-EXPORT_SYMBOL(__arch_hweight32);
+EXPORT_SYMBOL(__sw_hweight32);
 
-unsigned int __arch_hweight16(unsigned int w)
+unsigned int __sw_hweight16(unsigned int w)
 {
 	unsigned int res = w - ((w >> 1) & 0x5555);
 	res = (res & 0x3333) + ((res >> 2) & 0x3333);
 	res = (res + (res >> 4)) & 0x0F0F;
 	return (res + (res >> 8)) & 0x00FF;
 }
-EXPORT_SYMBOL(__arch_hweight16);
+EXPORT_SYMBOL(__sw_hweight16);
 
-unsigned int __arch_hweight8(unsigned int w)
+unsigned int __sw_hweight8(unsigned int w)
 {
 	unsigned int res = w - ((w >> 1) & 0x55);
 	res = (res & 0x33) + ((res >> 2) & 0x33);
 	return (res + (res >> 4)) & 0x0F;
 }
-EXPORT_SYMBOL(__arch_hweight8);
+EXPORT_SYMBOL(__sw_hweight8);
 
-unsigned long __arch_hweight64(__u64 w)
+unsigned long __sw_hweight64(__u64 w)
 {
 #if BITS_PER_LONG == 32
-	return __arch_hweight32((unsigned int)(w >> 32)) +
-	       __arch_hweight32((unsigned int)w);
+	return __sw_hweight32((unsigned int)(w >> 32)) +
+	       __sw_hweight32((unsigned int)w);
 #elif BITS_PER_LONG == 64
 #ifdef ARCH_HAS_FAST_MULTIPLIER
 	w -= (w >> 1) & 0x5555555555555555ul;
@@ -57,4 +57,4 @@ unsigned long __arch_hweight64(__u64 w)
 #endif
 #endif
 }
-EXPORT_SYMBOL(__arch_hweight64);
+EXPORT_SYMBOL(__sw_hweight64);
Signature · 10 lines
1.6.6.1


-- 
Regards/Gruss,
Boris.

--
Advanced Micro Devices, Inc.
Operating Systems Research Center
#64 lore raw

Re: [PATCH 2/5] bitops: compile time optimization for hweight_long(CONSTANT)

Quoted 8 lines · Borislav Petkov
Quoted 2 lines · Borislav Petkov

Let me prep another version when I get back on Wed. (currently travelling) with all the stuff we discussed to see how it would turn.

Ok, here's another version ontop of PeterZ's patch at
http://lkml.org/lkml/2010/2/4/119. I need to handle 32- and 64-bit differently wrt to popcnt opcode so on 32-bit I do "popcnt %eax, %eax" while on 64-bit I do "popcnt %rdi, %rdi".

On 64 bits it should be "popcnt %rdi, %rax".

Quoted 11 lines

I also did some rudimentary tracing with the function graph tracer of all the cpumask_weight-calls in <kernel/sched.c> while doing a kernel compile and the preliminary results show that hweight in software takes about 9.768 usecs the longest while the hardware popcnt about 8.515 usecs. The machine is a Fam10 revB2 quadcore.

What remains to be done is see whether the saving/restoring of callee-clobbered regs with this patch has any noticeable negative effects on the software hweight case on machines which don't support popcnt. Also, I'm open for better tracing ideas :).

arch/x86/lib/hweight.c line 91

Quoted 5 lines
arch/x86/lib/hweight.c new file +5 -0
+	asm volatile(PUSH_CLOBBERED
+		     ALTERNATIVE("call __sw_hweight64", POPCNT, X86_FEATURE_POPCNT)
+		      POP_CLOBBERED
+		     : "="ARG0 (res)
+		     : ARG0 (w));

Sorry, no.

You don't do the push/pop inline -- if you're going to take the hit of pushing this into the caller, it's better to list them as explicit clobbers and let the compiler figure out how to do it. The point of doing an explicit push/pop is that it can be pushed into the out-of-line subroutine.

Furthermore, you're still putting "volatile" on there... this is a pure computation -- no side effects -- so it is exactly when you *shouldn't* declare your asm statement volatile.

Note: given how simple and regular a popcnt actually is, it might be preferrable to have the out-of-line implementation either in assembly, or using gcc's -fcall-saved-* options to reduce the number of registers that is clobbered by the routine.

-hpa

Signature · 2 lines
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel.  I don't speak on their behalf.
#65 lore raw

Re: [PATCH 2/5] bitops: compile time optimization for hweight_long(CONSTANT)

Quoted 5 lines · H. Peter Anvin

You don't do the push/pop inline -- if you're going to take the hit of pushing this into the caller, it's better to list them as explicit clobbers and let the compiler figure out how to do it. The point of doing an explicit push/pop is that it can be pushed into the out-of-line subroutine.

Doh! Of course, this was wrong. See below.

Quoted 3 lines

Furthermore, you're still putting "volatile" on there... this is a pure computation -- no side effects -- so it is exactly when you *shouldn't* declare your asm statement volatile.

Also gone.

Quoted 4 lines

Note: given how simple and regular a popcnt actually is, it might be preferrable to have the out-of-line implementation either in assembly, or using gcc's -fcall-saved-* options to reduce the number of registers that is clobbered by the routine.

Yep, this is actually a very good idea. And it seems to work, I've tested it on an F10, K8 and even on an Atom and no blow ups so far...

---
 arch/alpha/include/asm/bitops.h            |    4 ++
 arch/ia64/include/asm/bitops.h             |    1 +
 arch/sparc/include/asm/bitops_64.h         |    4 ++
 arch/x86/include/asm/bitops.h              |   10 ++++
 arch/x86/lib/Makefile                      |    8 +++-
 arch/x86/lib/hweight.c                     |   72 ++++++++++++++++++++++++++++
 include/asm-generic/bitops/arch_hweight.h  |    8 ++--
 include/asm-generic/bitops/const_hweight.h |   43 +++++++++++++++--
 lib/hweight.c                              |   20 ++++----
 9 files changed, 151 insertions(+), 19 deletions(-)
 create mode 100644 arch/x86/lib/hweight.c
arch/alpha/include/asm/bitops.h +4 -0
index 296da1d..7fe6943 100644
@@ -409,21 +409,25 @@ static inline unsigned long __arch_hweight64(unsigned long w)
 {
 	return __kernel_ctpop(w);
 }
+#define __arch_hweight64 __arch_hweight64
 
 static inline unsigned int __arch_weight32(unsigned int w)
 {
 	return __arch_hweight64(w);
 }
+#define __arch_hweight32 __arch_hweight32
 
 static inline unsigned int __arch_hweight16(unsigned int w)
 {
 	return __arch_hweight64(w & 0xffff);
 }
+#define __arch_hweight16 __arch_hweight16
 
 static inline unsigned int __arch_hweight8(unsigned int w)
 {
 	return __arch_hweight64(w & 0xff);
 }
+#define __arch_hweight8 __arch_hweight8
 #else
 #include <asm-generic/bitops/arch_hweight.h>
 #endif
arch/ia64/include/asm/bitops.h +1 -0
index 9da3df6..9b64f59 100644
@@ -443,6 +443,7 @@ static __inline__ unsigned long __arch_hweight64(unsigned long x)
 	result = ia64_popcnt(x);
 	return result;
 }
+#define __arch_hweight64 __arch_hweight64
 
 #define __arch_hweight32(x) ((unsigned int) __arch_hweight64((x) & 0xfffffffful))
 #define __arch_hweight16(x) ((unsigned int) __arch_hweight64((x) & 0xfffful))
arch/sparc/include/asm/bitops_64.h +4 -0
index 766121a..4982bc4 100644
@@ -51,6 +51,7 @@ static inline unsigned int __arch_hweight64(unsigned long w)
 	__asm__ ("popc %1,%0" : "=r" (res) : "r" (w));
 	return res;
 }
+#define __arch_hweight64 __arch_hweight64
 
 static inline unsigned int __arch_hweight32(unsigned int w)
 {
@@ -59,6 +60,7 @@ static inline unsigned int __arch_hweight32(unsigned int w)
 	__asm__ ("popc %1,%0" : "=r" (res) : "r" (w & 0xffffffff));
 	return res;
 }
+#define __arch_hweight32 __arch_hweight32
 
 static inline unsigned int __arch_hweight16(unsigned int w)
 {
@@ -67,6 +69,7 @@ static inline unsigned int __arch_hweight16(unsigned int w)
 	__asm__ ("popc %1,%0" : "=r" (res) : "r" (w & 0xffff));
 	return res;
 }
+#define __arch_hweight16 __arch_hweight16
 
 static inline unsigned int __arch_hweight8(unsigned int w)
 {
@@ -75,6 +78,7 @@ static inline unsigned int __arch_hweight8(unsigned int w)
 	__asm__ ("popc %1,%0" : "=r" (res) : "r" (w & 0xff));
 	return res;
 }
+#define __arch_hweight8 __arch_hweight8
 
 #else
 
arch/x86/include/asm/bitops.h +10 -0
index 02b47a6..187defe 100644
@@ -444,6 +444,16 @@ static inline int fls(int x)
 
 #define ARCH_HAS_FAST_MULTIPLIER 1
 
+extern unsigned int __arch_hweight32(unsigned int w);
+extern unsigned int __arch_hweight16(unsigned int w);
+extern unsigned int __arch_hweight8(unsigned int w);
+extern unsigned long __arch_hweight64(__u64 w);
+
+#define __arch_hweight32 __arch_hweight32
+#define __arch_hweight16 __arch_hweight16
+#define __arch_hweight8 __arch_hweight8
+#define __arch_hweight64 __arch_hweight64
+
 #include <asm-generic/bitops/hweight.h>
 
 #endif /* __KERNEL__ */
arch/x86/lib/Makefile +7 -1
index cffd754..ddc32eb 100644
@@ -22,9 +22,11 @@ lib-y += usercopy_$(BITS).o getuser.o putuser.o
 lib-y += memcpy_$(BITS).o
 lib-$(CONFIG_KPROBES) += insn.o inat.o
 
-obj-y += msr.o msr-reg.o msr-reg-export.o
+obj-y += msr.o msr-reg.o msr-reg-export.o hweight.o
 
 ifeq ($(CONFIG_X86_32),y)
+	CFLAGS_hweight.o = -fcall-saved-ecx -fcall-saved-edx
+
         obj-y += atomic64_32.o
         lib-y += checksum_32.o
         lib-y += strstr_32.o
@@ -34,6 +36,10 @@ ifneq ($(CONFIG_X86_CMPXCHG64),y)
 endif
         lib-$(CONFIG_X86_USE_3DNOW) += mmx_32.o
 else
+	CFLAGS_hweight.o = -fcall-saved-rsi -fcall-saved-rdx -fcall-saved-rcx \
+			   -fcall-saved-r8 -fcall-saved-r9 -fcall-saved-r10 \
+			   -fcall-saved-r11
+
         obj-y += io_64.o iomap_copy_64.o
         lib-y += csum-partial_64.o csum-copy_64.o csum-wrappers_64.o
         lib-y += thunk_64.o clear_page_64.o copy_page_64.o
arch/x86/lib/hweight.c new file +72 -0

72 lines not on this page · raw message

include/asm-generic/bitops/arch_hweight.h +4 -4
index 3a7be84..c72de8b 100644
@@ -3,9 +3,9 @@
 
 #include <asm/types.h>
 
-extern unsigned int __arch_hweight32(unsigned int w);
-extern unsigned int __arch_hweight16(unsigned int w);
-extern unsigned int __arch_hweight8(unsigned int w);
-extern unsigned long __arch_hweight64(__u64 w);
+extern unsigned int __sw_hweight32(unsigned int w);
+extern unsigned int __sw_hweight16(unsigned int w);
+extern unsigned int __sw_hweight8(unsigned int w);
+extern unsigned long __sw_hweight64(__u64 w);
 
 #endif /* _ASM_GENERIC_BITOPS_HWEIGHT_H_ */
include/asm-generic/bitops/const_hweight.h +39 -4

52 lines not on this page · raw message

lib/hweight.c +10 -10
index 9ff86df..f9ce440 100644
@@ -9,7 +9,7 @@
  * The Hamming Weight of a number is the total number of bits set in it.
  */
 
-unsigned int __arch_hweight32(unsigned int w)
+unsigned int __sw_hweight32(unsigned int w)
 {
 	unsigned int res = w - ((w >> 1) & 0x55555555);
 	res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
@@ -17,30 +17,30 @@ unsigned int __arch_hweight32(unsigned int w)
 	res = res + (res >> 8);
 	return (res + (res >> 16)) & 0x000000FF;
 }
-EXPORT_SYMBOL(__arch_hweight32);
+EXPORT_SYMBOL(__sw_hweight32);
 
-unsigned int __arch_hweight16(unsigned int w)
+unsigned int __sw_hweight16(unsigned int w)
 {
 	unsigned int res = w - ((w >> 1) & 0x5555);
 	res = (res & 0x3333) + ((res >> 2) & 0x3333);
 	res = (res + (res >> 4)) & 0x0F0F;
 	return (res + (res >> 8)) & 0x00FF;
 }
-EXPORT_SYMBOL(__arch_hweight16);
+EXPORT_SYMBOL(__sw_hweight16);
 
-unsigned int __arch_hweight8(unsigned int w)
+unsigned int __sw_hweight8(unsigned int w)
 {
 	unsigned int res = w - ((w >> 1) & 0x55);
 	res = (res & 0x33) + ((res >> 2) & 0x33);
 	return (res + (res >> 4)) & 0x0F;
 }
-EXPORT_SYMBOL(__arch_hweight8);
+EXPORT_SYMBOL(__sw_hweight8);
 
-unsigned long __arch_hweight64(__u64 w)
+unsigned long __sw_hweight64(__u64 w)
 {
 #if BITS_PER_LONG == 32
-	return __arch_hweight32((unsigned int)(w >> 32)) +
-	       __arch_hweight32((unsigned int)w);
+	return __sw_hweight32((unsigned int)(w >> 32)) +
+	       __sw_hweight32((unsigned int)w);
 #elif BITS_PER_LONG == 64
 #ifdef ARCH_HAS_FAST_MULTIPLIER
 	w -= (w >> 1) & 0x5555555555555555ul;
@@ -57,4 +57,4 @@ unsigned long __arch_hweight64(__u64 w)
 #endif
 #endif
 }
-EXPORT_SYMBOL(__arch_hweight64);
+EXPORT_SYMBOL(__sw_hweight64);
Signature · 10 lines
1.6.6.1


-- 
Regards/Gruss,
Boris.

--
Advanced Micro Devices, Inc.
Operating Systems Research Center
#66 lore raw

Re: [PATCH 2/5] bitops: compile time optimization for hweight_long(CONSTANT)

Quoted 45 lines · Borislav Petkov
Quoted 5 lines · H. Peter Anvin

You don't do the push/pop inline -- if you're going to take the hit of pushing this into the caller, it's better to list them as explicit clobbers and let the compiler figure out how to do it. The point of doing an explicit push/pop is that it can be pushed into the out-of-line subroutine.

Doh! Of course, this was wrong. See below.

arch/x86/lib/hweight.c new file +30 -0
new file mode 100644
index 0000000..9b4bfa5
@@ -0,0 +1,72 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/bitops.h>
+
+#ifdef CONFIG_64BIT
+/* popcnt %rdi, %rax */
+#define POPCNT ".byte 0xf3\n\t.byte 0x48\n\t.byte 0x0f\n\t.byte 0xb8\n\t.byte 0xc7"
+#define REG_IN "D"
+#define REG_OUT "a"
+#else
+/* popcnt %eax, %eax */
+#define POPCNT ".byte 0xf3\n\t.byte 0x0f\n\t.byte 0xb8\n\t.byte 0xc0"
+#define REG_IN "a"
+#define REG_OUT "a"
+#endif
+
+/*
+ * Those are called out-of-line in the alternative below and are added here only
+ * so that gcc is able to figure out which registers have been clobbered by
+ * __sw_hweightXX so that it could restore their values before returning from
+ * the __arch_hweightXX versions. See also <arch/x86/lib/Makefile>.
+ */
+unsigned int _sw_hweight32(unsigned int w)
+{
+	return __sw_hweight32(w);
+}
+
+unsigned long _sw_hweight64(__u64 w)
+{
+	return __sw_hweight64(w);

arch/x86/lib/hweight.c line 40

Quoted 10 lines
arch/x86/lib/hweight.c new file +10 -0
+}
+
+unsigned int __arch_hweight32(unsigned int w)
+{
+	unsigned int res = 0;
+
+	asm (ALTERNATIVE("call _sw_hweight32", POPCNT, X86_FEATURE_POPCNT)
+		     : "="REG_OUT (res)
+		     : REG_IN (w));
+

Now you have no clobbers and no assembly wrapper. That really doesn't work.

-hpa

Signature · 2 lines
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel.  I don't speak on their behalf.
#67 lore raw

Re: [PATCH 2/5] bitops: compile time optimization for hweight_long(CONSTANT)

Quoted 50 lines · H. Peter Anvin
Quoted 49 lines · Borislav Petkov
Quoted 5 lines · H. Peter Anvin

You don't do the push/pop inline -- if you're going to take the hit of pushing this into the caller, it's better to list them as explicit clobbers and let the compiler figure out how to do it. The point of doing an explicit push/pop is that it can be pushed into the out-of-line subroutine.

Doh! Of course, this was wrong. See below.

arch/x86/lib/hweight.c new file +34 -0
new file mode 100644
index 0000000..9b4bfa5
@@ -0,0 +1,72 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/bitops.h>
+
+#ifdef CONFIG_64BIT
+/* popcnt %rdi, %rax */
+#define POPCNT ".byte 0xf3\n\t.byte 0x48\n\t.byte 0x0f\n\t.byte 0xb8\n\t.byte 0xc7"
+#define REG_IN "D"
+#define REG_OUT "a"
+#else
+/* popcnt %eax, %eax */
+#define POPCNT ".byte 0xf3\n\t.byte 0x0f\n\t.byte 0xb8\n\t.byte 0xc0"
+#define REG_IN "a"
+#define REG_OUT "a"
+#endif
+
+/*
+ * Those are called out-of-line in the alternative below and are added here only
+ * so that gcc is able to figure out which registers have been clobbered by
+ * __sw_hweightXX so that it could restore their values before returning from
+ * the __arch_hweightXX versions. See also <arch/x86/lib/Makefile>.
+ */
+unsigned int _sw_hweight32(unsigned int w)
+{
+	return __sw_hweight32(w);
+}
+
+unsigned long _sw_hweight64(__u64 w)
+{
+	return __sw_hweight64(w);
+}
+
+unsigned int __arch_hweight32(unsigned int w)
+{
Quoted 8 lines

arch/x86/lib/hweight.c line 40

Quoted 6 lines
arch/x86/lib/hweight.c new file +6 -0
+	unsigned int res = 0;
+
+	asm (ALTERNATIVE("call _sw_hweight32", POPCNT, X86_FEATURE_POPCNT)
+		     : "="REG_OUT (res)
+		     : REG_IN (w));
+

Now you have no clobbers and no assembly wrapper. That really doesn't work.

I see, this means we have to build lib/hweight.c with -fcall-saved*. I just did a test and it uses %rcx and %rdx temporarily by saving their values on the stack and restoring them before it returns.

However, this is generic code and for the above to work we have to enforce x86-specific CFLAGS for it. What is the preferred way to do that?

Signature · 6 lines
Regards/Gruss,
Boris.

--
Advanced Micro Devices, Inc.
Operating Systems Research Center
#68 lore raw

Re: [PATCH 2/5] bitops: compile time optimization for hweight_long(CONSTANT)

Quoted 5 lines · Borislav Petkov

However, this is generic code and for the above to work we have to enforce x86-specific CFLAGS for it. What is the preferred way to do that?

That's a question for Michal and the kbuild list. Michal?

-hpa

#69 lore raw

Re: [PATCH 2/5] bitops: compile time optimization for hweight_long(CONSTANT)

Quoted 8 lines · H. Peter Anvin
Quoted 5 lines · Borislav Petkov

However, this is generic code and for the above to work we have to enforce x86-specific CFLAGS for it. What is the preferred way to do that?

That's a question for Michal and the kbuild list. Michal?

(I was offline last week).

The _preferred_ way probably is not to do it :), but otherwise you can set CFLAGS_hweight.o depending on CONFIG_X86(_32|_64), just like you do in arch/x86/lib/Makefile already.

Michal

#70 lore raw

Re: [PATCH 2/5] bitops: compile time optimization for hweight_long(CONSTANT)

Quoted 8 lines · Michal Marek
Quoted 7 lines · H. Peter Anvin
Quoted 5 lines · Borislav Petkov

However, this is generic code and for the above to work we have to enforce x86-specific CFLAGS for it. What is the preferred way to do that?

Quoted 7 lines
Quoted 1 line

That's a question for Michal and the kbuild list. Michal?

(I was offline last week).

The _preferred_ way probably is not to do it :), but otherwise you can set CFLAGS_hweight.o depending on CONFIG_X86(_32|_64), just like you do in arch/x86/lib/Makefile already.

Wouldn't it be better if we had something like ARCH_CFLAGS_hweight.o which gets set in the arch Makefile instead?

Signature · 6 lines
Regards/Gruss,
Boris.

--
Advanced Micro Devices, Inc.
Operating Systems Research Center
#71 lore raw

Re: [PATCH 2/5] bitops: compile time optimization for hweight_long(CONSTANT)

Quoted 11 lines · Borislav Petkov
Quoted 10 lines · Michal Marek
Quoted 8 lines · H. Peter Anvin
Quoted 5 lines · Borislav Petkov

However, this is generic code and for the above to work we have to enforce x86-specific CFLAGS for it. What is the preferred way to do that?

That's a question for Michal and the kbuild list. Michal?

Quoted 8 lines
Quoted 5 lines

(I was offline last week).

The _preferred_ way probably is not to do it :), but otherwise you can set CFLAGS_hweight.o depending on CONFIG_X86(_32|_64), just like you do in arch/x86/lib/Makefile already.

Wouldn't it be better if we had something like ARCH_CFLAGS_hweight.o which gets set in the arch Makefile instead?

We could, but is it worth it if there is only one potential user so far? IMO just put the condition to lib/Makefile now and if there turn out to be more cases like this, we can add support for ARCH_CFLAGS_foo.o then.

Michal

#72 lore raw

Re: [PATCH 2/5] bitops: compile time optimization for hweight_long(CONSTANT)

Quoted 18 lines · Michal Marek
Quoted 17 lines · Borislav Petkov
Quoted 15 lines · Michal Marek
Quoted 8 lines · H. Peter Anvin
Quoted 5 lines · Borislav Petkov

However, this is generic code and for the above to work we have to enforce x86-specific CFLAGS for it. What is the preferred way to do that?

That's a question for Michal and the kbuild list. Michal?

(I was offline last week).

The _preferred_ way probably is not to do it :), but otherwise you can set CFLAGS_hweight.o depending on CONFIG_X86(_32|_64), just like you do in arch/x86/lib/Makefile already.

Quoted 6 lines
Quoted 2 lines

Wouldn't it be better if we had something like ARCH_CFLAGS_hweight.o which gets set in the arch Makefile instead?

We could, but is it worth it if there is only one potential user so far? IMO just put the condition to lib/Makefile now and if there turn out to be more cases like this, we can add support for ARCH_CFLAGS_foo.o then.

Ok, I'm fine with that too, thanks.

Signature · 6 lines
Regards/Gruss,
Boris.

--
Advanced Micro Devices, Inc.
Operating Systems Research Center
#73 lore raw

Re: [PATCH 2/5] bitops: compile time optimization for hweight_long(CONSTANT)

In reply to Michal Marek
Quoted 18 lines · Michal Marek
Quoted 17 lines · Borislav Petkov
Quoted 15 lines · Michal Marek
Quoted 8 lines · H. Peter Anvin
Quoted 5 lines · Borislav Petkov

However, this is generic code and for the above to work we have to enforce x86-specific CFLAGS for it. What is the preferred way to do that?

That's a question for Michal and the kbuild list. Michal?

(I was offline last week).

The _preferred_ way probably is not to do it :), but otherwise you can set CFLAGS_hweight.o depending on CONFIG_X86(_32|_64), just like you do in arch/x86/lib/Makefile already.

Quoted 6 lines
Quoted 2 lines

Wouldn't it be better if we had something like ARCH_CFLAGS_hweight.o which gets set in the arch Makefile instead?

We could, but is it worth it if there is only one potential user so far? IMO just put the condition to lib/Makefile now and if there turn out to be more cases like this, we can add support for ARCH_CFLAGS_foo.o then.

It wouldn't work actually, because such variable would then apply to all hweight.o targets in the tree. But another way would be:

arch/x86/Kconfig
config ARCH_HWEIGHT_CFLAGS

        string
        default "..." if X86_32
        default "..." if X86_64

lib/Makefile
CFLAGS_hweight.o = $(CONFIG_ARCH_HWEIGHT_CFLAGS)

Michal

#74 lore raw

Re: [PATCH 2/5] bitops: compile time optimization for hweight_long(CONSTANT)

Quoted 11 lines · Michal Marek

It wouldn't work actually, because such variable would then apply to all hweight.o targets in the tree. But another way would be:

arch/x86/Kconfig
config ARCH_HWEIGHT_CFLAGS

        string
        default "..." if X86_32
        default "..." if X86_64

lib/Makefile
CFLAGS_hweight.o = $(CONFIG_ARCH_HWEIGHT_CFLAGS)

Yep, this works, albeit with a small adjustment since CONFIG_ARCH_HWEIGHT_CFLAGS is quoted in the Kconfig and the quotes appear in the $(CC) call like this:

gcc -Wp,-MD,lib/.hweight.o.d ... "-fcall-saved-ecx..."

which I fixed like this (idea reused from the make manual):

---
source "init/Kconfig"

lib/Makefile +3 -0
index 3b0b4a6..e2ad17c 100644
@@ -39,7 +39,10 @@ lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
 lib-$(CONFIG_GENERIC_FIND_FIRST_BIT) += find_next_bit.o
 lib-$(CONFIG_GENERIC_FIND_NEXT_BIT) += find_next_bit.o
 obj-$(CONFIG_GENERIC_FIND_LAST_BIT) += find_last_bit.o
+
+CFLAGS_hweight.o = $(subst $(quote),,$(CONFIG_ARCH_HWEIGHT_CFLAGS))
 obj-$(CONFIG_GENERIC_HWEIGHT) += hweight.o
+
 obj-$(CONFIG_LOCK_KERNEL) += kernel_lock.o
 obj-$(CONFIG_DEBUG_PREEMPT) += smp_processor_id.o
 obj-$(CONFIG_DEBUG_LIST) += list_debug.o
scripts/Makefile.lib +4 -0
index f9bdf26..cbcd654 100644
@@ -245,3 +245,7 @@ quiet_cmd_lzo = LZO    $@
 cmd_lzo = (cat $(filter-out FORCE,$^) | \
 	lzop -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \
 	(rm -f $@ ; false)
+
+# misc stuff
+# ---------------------------------------------------------------------------
+quote:="

I'm open for better suggestions though.

Signature · 2 lines
Regards/Gruss,
    Boris.
#75 lore raw

PATCH 1/1 x86: Add optimized popcnt variants

From: Borislav Petkov <[email protected]>

Add support for the hardware version of the Hamming weight function, popcnt, present in CPUs which advertize it under CPUID, Function 0x0000_0001_ECX[23]. On CPUs which don't support it, we fallback to the default lib/hweight.c sw versions.

A synthetic benchmark comparing popcnt with __sw_hweight64 showed almost a 3x speedup on a F10h machine.

---
 arch/x86/Kconfig                          |    5 ++
 arch/x86/include/asm/bitops.h             |    7 +++-
 arch/x86/lib/Makefile                     |    2 +-
 arch/x86/lib/hweight.c                    |   62 +++++++++++++++++++++++++++++
 include/asm-generic/bitops/arch_hweight.h |   22 ++++++++--
 lib/Makefile                              |    3 +
 lib/hweight.c                             |   20 +++++-----
 scripts/Makefile.lib                      |    4 ++
 8 files changed, 109 insertions(+), 16 deletions(-)
 create mode 100644 arch/x86/lib/hweight.c
arch/x86/Kconfig +5 -0
index eb40925..176950e 100644
@@ -230,6 +230,11 @@ config X86_32_LAZY_GS
 	def_bool y
 	depends on X86_32 && !CC_STACKPROTECTOR
 
+config ARCH_HWEIGHT_CFLAGS
+	string
+	default "-fcall-saved-ecx -fcall-saved-edx" if X86_32
+	default "-fcall-saved-rsi -fcall-saved-rdx -fcall-saved-rcx -fcall-saved-r8 -fcall-saved-r9 -fcall-saved-r10 -fcall-saved-r11" if X86_64
+
 config KTIME_SCALAR
 	def_bool X86_32
 source "init/Kconfig"
arch/x86/include/asm/bitops.h +6 -1
index 02b47a6..5ec3bd8 100644
@@ -444,7 +444,12 @@ static inline int fls(int x)
 
 #define ARCH_HAS_FAST_MULTIPLIER 1
 
-#include <asm-generic/bitops/hweight.h>
+extern unsigned int __arch_hweight32(unsigned int w);
+extern unsigned int __arch_hweight16(unsigned int w);
+extern unsigned int __arch_hweight8(unsigned int w);
+extern unsigned long __arch_hweight64(__u64 w);
+
+#include <asm-generic/bitops/const_hweight.h>
 
 #endif /* __KERNEL__ */
 
arch/x86/lib/Makefile +1 -1
index cffd754..e811bbd 100644
@@ -22,7 +22,7 @@ lib-y += usercopy_$(BITS).o getuser.o putuser.o
 lib-y += memcpy_$(BITS).o
 lib-$(CONFIG_KPROBES) += insn.o inat.o
 
-obj-y += msr.o msr-reg.o msr-reg-export.o
+obj-y += msr.o msr-reg.o msr-reg-export.o hweight.o
 
 ifeq ($(CONFIG_X86_32),y)
         obj-y += atomic64_32.o
arch/x86/lib/hweight.c new file +62 -0

62 lines not on this page · raw message

include/asm-generic/bitops/arch_hweight.h +18 -4
index 3a7be84..1c82306 100644
@@ -3,9 +3,23 @@
 
 #include <asm/types.h>
 
-extern unsigned int __arch_hweight32(unsigned int w);
-extern unsigned int __arch_hweight16(unsigned int w);
-extern unsigned int __arch_hweight8(unsigned int w);
-extern unsigned long __arch_hweight64(__u64 w);
+unsigned int __arch_hweight32(unsigned int w)
+{
+	return __sw_hweight32(w);
+}
 
+unsigned int __arch_hweight16(unsigned int w)
+{
+	return __sw_hweight16(w);
+}
+
+unsigned int __arch_hweight8(unsigned int w)
+{
+	return __sw_hweight8(w);
+}
+
+unsigned long __arch_hweight64(__u64 w)
+{
+	return __sw_hweight64(w);
+}
 #endif /* _ASM_GENERIC_BITOPS_HWEIGHT_H_ */
lib/Makefile +3 -0
index 3b0b4a6..e2ad17c 100644
@@ -39,7 +39,10 @@ lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
 lib-$(CONFIG_GENERIC_FIND_FIRST_BIT) += find_next_bit.o
 lib-$(CONFIG_GENERIC_FIND_NEXT_BIT) += find_next_bit.o
 obj-$(CONFIG_GENERIC_FIND_LAST_BIT) += find_last_bit.o
+
+CFLAGS_hweight.o = $(subst $(quote),,$(CONFIG_ARCH_HWEIGHT_CFLAGS))
 obj-$(CONFIG_GENERIC_HWEIGHT) += hweight.o
+
 obj-$(CONFIG_LOCK_KERNEL) += kernel_lock.o
 obj-$(CONFIG_DEBUG_PREEMPT) += smp_processor_id.o
 obj-$(CONFIG_DEBUG_LIST) += list_debug.o
lib/hweight.c +10 -10
index 9ff86df..f9ce440 100644
@@ -9,7 +9,7 @@
  * The Hamming Weight of a number is the total number of bits set in it.
  */
 
-unsigned int __arch_hweight32(unsigned int w)
+unsigned int __sw_hweight32(unsigned int w)
 {
 	unsigned int res = w - ((w >> 1) & 0x55555555);
 	res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
@@ -17,30 +17,30 @@ unsigned int __arch_hweight32(unsigned int w)
 	res = res + (res >> 8);
 	return (res + (res >> 16)) & 0x000000FF;
 }
-EXPORT_SYMBOL(__arch_hweight32);
+EXPORT_SYMBOL(__sw_hweight32);
 
-unsigned int __arch_hweight16(unsigned int w)
+unsigned int __sw_hweight16(unsigned int w)
 {
 	unsigned int res = w - ((w >> 1) & 0x5555);
 	res = (res & 0x3333) + ((res >> 2) & 0x3333);
 	res = (res + (res >> 4)) & 0x0F0F;
 	return (res + (res >> 8)) & 0x00FF;
 }
-EXPORT_SYMBOL(__arch_hweight16);
+EXPORT_SYMBOL(__sw_hweight16);
 
-unsigned int __arch_hweight8(unsigned int w)
+unsigned int __sw_hweight8(unsigned int w)
 {
 	unsigned int res = w - ((w >> 1) & 0x55);
 	res = (res & 0x33) + ((res >> 2) & 0x33);
 	return (res + (res >> 4)) & 0x0F;
 }
-EXPORT_SYMBOL(__arch_hweight8);
+EXPORT_SYMBOL(__sw_hweight8);
 
-unsigned long __arch_hweight64(__u64 w)
+unsigned long __sw_hweight64(__u64 w)
 {
 #if BITS_PER_LONG == 32
-	return __arch_hweight32((unsigned int)(w >> 32)) +
-	       __arch_hweight32((unsigned int)w);
+	return __sw_hweight32((unsigned int)(w >> 32)) +
+	       __sw_hweight32((unsigned int)w);
 #elif BITS_PER_LONG == 64
 #ifdef ARCH_HAS_FAST_MULTIPLIER
 	w -= (w >> 1) & 0x5555555555555555ul;
@@ -57,4 +57,4 @@ unsigned long __arch_hweight64(__u64 w)
 #endif
 #endif
 }
-EXPORT_SYMBOL(__arch_hweight64);
+EXPORT_SYMBOL(__sw_hweight64);
scripts/Makefile.lib +4 -0
index f9bdf26..cbcd654 100644
@@ -245,3 +245,7 @@ quiet_cmd_lzo = LZO    $@
 cmd_lzo = (cat $(filter-out FORCE,$^) | \
 	lzop -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \
 	(rm -f $@ ; false)
+
+# misc stuff
+# ---------------------------------------------------------------------------
+quote:="
Signature · 9 lines
1.6.5.4

-- 
Regards/Gruss,
Boris.

-
Advanced Micro Devices, Inc.
Operating Systems Research Center
#76 lore raw

Re: [PATCH] x86: Add optimized popcnt variants

Quoted 54 lines · Borislav Petkov
arch/x86/lib/hweight.c new file +51 -0
@@ -0,0 +1,62 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/bitops.h>
+
+#ifdef CONFIG_64BIT
+/* popcnt %rdi, %rax */
+#define POPCNT ".byte 0xf3\n\t.byte 0x48\n\t.byte 0x0f\n\t.byte 0xb8\n\t.byte 0xc7"
+#define REG_IN "D"
+#define REG_OUT "a"
+#else
+/* popcnt %eax, %eax */
+#define POPCNT ".byte 0xf3\n\t.byte 0x0f\n\t.byte 0xb8\n\t.byte 0xc0"
+#define REG_IN "a"
+#define REG_OUT "a"
+#endif
+
+/*
+ * __sw_hweightXX are called from within the alternatives below
+ * and callee-clobbered registers need to be taken care of. See
+ * ARCH_HWEIGHT_CFLAGS in <arch/x86/Kconfig> for the respective
+ * compiler switches.
+ */
+unsigned int __arch_hweight32(unsigned int w)
+{
+	unsigned int res = 0;
+
+	asm (ALTERNATIVE("call __sw_hweight32", POPCNT, X86_FEATURE_POPCNT)
+		     : "="REG_OUT (res)
+		     : REG_IN (w));
+
+	return res;
+}
+EXPORT_SYMBOL(__arch_hweight32);
+
+unsigned int __arch_hweight16(unsigned int w)
+{
+	return __arch_hweight32(w & 0xffff);
+}
+EXPORT_SYMBOL(__arch_hweight16);
+
+unsigned int __arch_hweight8(unsigned int w)
+{
+	return __arch_hweight32(w & 0xff);
+}
+EXPORT_SYMBOL(__arch_hweight8);
+
+unsigned long __arch_hweight64(__u64 w)
+{
+	unsigned long res = 0;
+
+#ifdef CONFIG_X86_32

arch/x86/lib/hweight.c line 61

Quoted 10 lines
arch/x86/lib/hweight.c new file +10 -0
+	return  __arch_hweight32((u32)w) +
+		__arch_hweight32((u32)(w >> 32));
+#else
+	asm (ALTERNATIVE("call __sw_hweight64", POPCNT, X86_FEATURE_POPCNT)
+		     : "="REG_OUT (res)
+		     : REG_IN (w));
+#endif /* CONFIG_X86_32 */
+
+	return res;
+}

You're still not inlining these. They should be: there is absolutely no reason for code size to not inline them anymore.

Quoted 22 lines
include/asm-generic/bitops/arch_hweight.h +9 -4
index 3a7be84..1c82306 100644
@@ -3,9 +3,23 @@
 
 #include <asm/types.h>
 
-extern unsigned int __arch_hweight32(unsigned int w);
-extern unsigned int __arch_hweight16(unsigned int w);
-extern unsigned int __arch_hweight8(unsigned int w);
-extern unsigned long __arch_hweight64(__u64 w);
+unsigned int __arch_hweight32(unsigned int w)
+{
+	return __sw_hweight32(w);
+}
 
+unsigned int __arch_hweight16(unsigned int w)
+{
+	return __sw_hweight16(w);
+}
+

include/asm-generic/bitops/arch_hweight.h line 25

Quoted 10 lines
include/asm-generic/bitops/arch_hweight.h +9 -0
+unsigned int __arch_hweight8(unsigned int w)
+{
+	return __sw_hweight8(w);
+}
+
+unsigned long __arch_hweight64(__u64 w)
+{
+	return __sw_hweight64(w);
+}
 #endif /* _ASM_GENERIC_BITOPS_HWEIGHT_H_ */

and these are in a header file and *definitely* should be inlines.

-hpa

Signature · 2 lines
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel.  I don't speak on their behalf.
#77 lore raw

Re: [PATCH] x86: Add optimized popcnt variants

From: "H. Peter Anvin" <[email protected]>
Date: Fri, Feb 19, 2010 at 08:06:07AM -0800

<snip>

Quoted 10 lines
Quoted 10 lines
arch/x86/lib/hweight.c new file +10 -0
+unsigned long __arch_hweight64(__u64 w)
+{
+	unsigned long res = 0;
+
+#ifdef CONFIG_X86_32
+	return  __arch_hweight32((u32)w) +
+		__arch_hweight32((u32)(w >> 32));
+#else
+	asm (ALTERNATIVE("call __sw_hweight64", POPCNT, X86_FEATURE_POPCNT)
+		     : "="REG_OUT (res)
Quoted 8 lines

arch/x86/lib/hweight.c line 61

Quoted 5 lines
arch/x86/lib/hweight.c new file +5 -0
+		     : REG_IN (w));
+#endif /* CONFIG_X86_32 */
+
+	return res;
+}

You're still not inlining these. They should be: there is absolutely no reason for code size to not inline them anymore.

Isn't better to have only those 4 locations for apply_alternatives to patch wrt to popcnt instead of sprinkling alternatives sections around the kernel in every callsite of hweight and its users? Or is the aim to optimize even that "call __arch_hweightXX" away?

Quoted 7 lines

include/asm-generic/bitops/arch_hweight.h line 25

Quoted 5 lines
include/asm-generic/bitops/arch_hweight.h +4 -0
+unsigned long __arch_hweight64(__u64 w)
+{
+	return __sw_hweight64(w);
+}
 #endif /* _ASM_GENERIC_BITOPS_HWEIGHT_H_ */

and these are in a header file and *definitely* should be inlines.

Yep, done.

Signature · 6 lines
Regards/Gruss,
Boris.

-
Advanced Micro Devices, Inc.
Operating Systems Research Center
#78 lore raw

Re: [PATCH] x86: Add optimized popcnt variants

Quoted 9 lines · Borislav Petkov
Quoted 3 lines

You're still not inlining these. They should be: there is absolutely no reason for code size to not inline them anymore.

Isn't better to have only those 4 locations for apply_alternatives to patch wrt to popcnt instead of sprinkling alternatives sections around the kernel in every callsite of hweight and its users? Or is the aim to optimize even that "call __arch_hweightXX" away?

That's the idea, yes. We use inline alternatives in quite a few other places.

-hpa

Signature · 2 lines
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel.  I don't speak on their behalf.
#79 lore raw

Re: [PATCH] x86: Add optimized popcnt variants

From: "H. Peter Anvin" <[email protected]>
Date: Fri, Feb 19, 2010 at 08:53:32AM -0800

Quoted 2 lines

That's the idea, yes. We use inline alternatives in quite a few other places.

Ok, inlining results in circa 100+ replacements here both on 32- and 64-bit. Here we go:

--
From: Borislav Petkov <[email protected]>
Date: Thu, 11 Feb 2010 00:48:31 +0100
Subject: [PATCH] x86: Add optimized popcnt variants

Add support for the hardware version of the Hamming weight function, popcnt, present in CPUs which advertize it under CPUID, Function 0x0000_0001_ECX[23]. On CPUs which don't support it, we fallback to the default lib/hweight.c sw versions.

A synthetic benchmark comparing popcnt with __sw_hweight64 showed almost a 3x speedup on a F10h machine.

---
 arch/x86/Kconfig                          |    5 ++
 arch/x86/include/asm/alternative.h        |    9 +++-
 arch/x86/include/asm/arch_hweight.h       |   59 +++++++++++++++++++++++++++++
 arch/x86/include/asm/bitops.h             |    4 +-
 include/asm-generic/bitops/arch_hweight.h |   22 +++++++++--
 lib/Makefile                              |    3 +
 lib/hweight.c                             |   20 +++++-----
 scripts/Makefile.lib                      |    4 ++
 8 files changed, 108 insertions(+), 18 deletions(-)
 create mode 100644 arch/x86/include/asm/arch_hweight.h
arch/x86/Kconfig +5 -0
index eb40925..176950e 100644
@@ -230,6 +230,11 @@ config X86_32_LAZY_GS
 	def_bool y
 	depends on X86_32 && !CC_STACKPROTECTOR
 
+config ARCH_HWEIGHT_CFLAGS
+	string
+	default "-fcall-saved-ecx -fcall-saved-edx" if X86_32
+	default "-fcall-saved-rsi -fcall-saved-rdx -fcall-saved-rcx -fcall-saved-r8 -fcall-saved-r9 -fcall-saved-r10 -fcall-saved-r11" if X86_64
+
 config KTIME_SCALAR
 	def_bool X86_32
 source "init/Kconfig"
arch/x86/include/asm/alternative.h +6 -3
index 69b74a7..0720c96 100644
@@ -39,9 +39,6 @@
 #define LOCK_PREFIX ""
 #endif
 
-/* This must be included *after* the definition of LOCK_PREFIX */
-#include <asm/cpufeature.h>
-
 struct alt_instr {
 	u8 *instr;		/* original instruction */
 	u8 *replacement;
@@ -91,6 +88,12 @@ static inline void alternatives_smp_switch(int smp) {}
       ".previous"
 
 /*
+ * This must be included *after* the definition of ALTERNATIVE due to
+ * <asm/arch_hweight.h>
+ */
+#include <asm/cpufeature.h>
+
+/*
  * Alternative instructions for different CPU types or capabilities.
  *
  * This allows to use optimized instructions even on generic binary
arch/x86/include/asm/arch_hweight.h new file +59 -0

59 lines not on this page · raw message

arch/x86/include/asm/bitops.h +3 -1
index 02b47a6..545776e 100644
@@ -444,7 +444,9 @@ static inline int fls(int x)
 
 #define ARCH_HAS_FAST_MULTIPLIER 1
 
-#include <asm-generic/bitops/hweight.h>
+#include <asm/arch_hweight.h>
+
+#include <asm-generic/bitops/const_hweight.h>
 
 #endif /* __KERNEL__ */
 
include/asm-generic/bitops/arch_hweight.h +18 -4
index 3a7be84..9a81c1e 100644
@@ -3,9 +3,23 @@
 
 #include <asm/types.h>
 
-extern unsigned int __arch_hweight32(unsigned int w);
-extern unsigned int __arch_hweight16(unsigned int w);
-extern unsigned int __arch_hweight8(unsigned int w);
-extern unsigned long __arch_hweight64(__u64 w);
+inline unsigned int __arch_hweight32(unsigned int w)
+{
+	return __sw_hweight32(w);
+}
 
+inline unsigned int __arch_hweight16(unsigned int w)
+{
+	return __sw_hweight16(w);
+}
+
+inline unsigned int __arch_hweight8(unsigned int w)
+{
+	return __sw_hweight8(w);
+}
+
+inline unsigned long __arch_hweight64(__u64 w)
+{
+	return __sw_hweight64(w);
+}
 #endif /* _ASM_GENERIC_BITOPS_HWEIGHT_H_ */
lib/Makefile +3 -0
index 3b0b4a6..e2ad17c 100644
@@ -39,7 +39,10 @@ lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
 lib-$(CONFIG_GENERIC_FIND_FIRST_BIT) += find_next_bit.o
 lib-$(CONFIG_GENERIC_FIND_NEXT_BIT) += find_next_bit.o
 obj-$(CONFIG_GENERIC_FIND_LAST_BIT) += find_last_bit.o
+
+CFLAGS_hweight.o = $(subst $(quote),,$(CONFIG_ARCH_HWEIGHT_CFLAGS))
 obj-$(CONFIG_GENERIC_HWEIGHT) += hweight.o
+
 obj-$(CONFIG_LOCK_KERNEL) += kernel_lock.o
 obj-$(CONFIG_DEBUG_PREEMPT) += smp_processor_id.o
 obj-$(CONFIG_DEBUG_LIST) += list_debug.o
lib/hweight.c +10 -10
index 9ff86df..f9ce440 100644
@@ -9,7 +9,7 @@
  * The Hamming Weight of a number is the total number of bits set in it.
  */
 
-unsigned int __arch_hweight32(unsigned int w)
+unsigned int __sw_hweight32(unsigned int w)
 {
 	unsigned int res = w - ((w >> 1) & 0x55555555);
 	res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
@@ -17,30 +17,30 @@ unsigned int __arch_hweight32(unsigned int w)
 	res = res + (res >> 8);
 	return (res + (res >> 16)) & 0x000000FF;
 }
-EXPORT_SYMBOL(__arch_hweight32);
+EXPORT_SYMBOL(__sw_hweight32);
 
-unsigned int __arch_hweight16(unsigned int w)
+unsigned int __sw_hweight16(unsigned int w)
 {
 	unsigned int res = w - ((w >> 1) & 0x5555);
 	res = (res & 0x3333) + ((res >> 2) & 0x3333);
 	res = (res + (res >> 4)) & 0x0F0F;
 	return (res + (res >> 8)) & 0x00FF;
 }
-EXPORT_SYMBOL(__arch_hweight16);
+EXPORT_SYMBOL(__sw_hweight16);
 
-unsigned int __arch_hweight8(unsigned int w)
+unsigned int __sw_hweight8(unsigned int w)
 {
 	unsigned int res = w - ((w >> 1) & 0x55);
 	res = (res & 0x33) + ((res >> 2) & 0x33);
 	return (res + (res >> 4)) & 0x0F;
 }
-EXPORT_SYMBOL(__arch_hweight8);
+EXPORT_SYMBOL(__sw_hweight8);
 
-unsigned long __arch_hweight64(__u64 w)
+unsigned long __sw_hweight64(__u64 w)
 {
 #if BITS_PER_LONG == 32
-	return __arch_hweight32((unsigned int)(w >> 32)) +
-	       __arch_hweight32((unsigned int)w);
+	return __sw_hweight32((unsigned int)(w >> 32)) +
+	       __sw_hweight32((unsigned int)w);
 #elif BITS_PER_LONG == 64
 #ifdef ARCH_HAS_FAST_MULTIPLIER
 	w -= (w >> 1) & 0x5555555555555555ul;
@@ -57,4 +57,4 @@ unsigned long __arch_hweight64(__u64 w)
 #endif
 #endif
 }
-EXPORT_SYMBOL(__arch_hweight64);
+EXPORT_SYMBOL(__sw_hweight64);
scripts/Makefile.lib +4 -0
index f9bdf26..cbcd654 100644
@@ -245,3 +245,7 @@ quiet_cmd_lzo = LZO    $@
 cmd_lzo = (cat $(filter-out FORCE,$^) | \
 	lzop -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \
 	(rm -f $@ ; false)
+
+# misc stuff
+# ---------------------------------------------------------------------------
+quote:="
Signature · 10 lines
1.6.4.2


-- 
Regards/Gruss,
Boris.

-
Advanced Micro Devices, Inc.
Operating Systems Research Center
#80 lore raw

Re: [PATCH] x86: Add optimized popcnt variants

Quoted 5 lines · Borislav Petkov
arch/x86/Kconfig +4 -0
+config ARCH_HWEIGHT_CFLAGS
+	string
+	default "-fcall-saved-rsi -fcall-saved-rdx -fcall-saved-rcx -fcall-saved-r8 -fcall-saved-r9 -fcall-saved-r10 -fcall-saved-r11" if X86_64
+

[...]

arch/x86/include/asm/arch_hweight.h line 9

Quoted 7 lines
arch/x86/include/asm/arch_hweight.h new file +7 -0
+
+#ifdef CONFIG_64BIT
+/* popcnt %rdi, %rax */
+#define POPCNT ".byte 0xf3\n\t.byte 0x48\n\t.byte 0x0f\n\t.byte 0xb8\n\t.byte 0xc7"
+#define REG_IN "D"
+#define REG_OUT "a"
+#else

Just a note: this still means rdi is clobbered on x86-64, which is probably fine, but needs to be recorded as such. Since gcc doesn't support clobbers for registers used as operands (sigh), you have to create a dummy output and assign it a "=D" constraint.

I don't know if gcc would handle -fcall-saved-rdi here... and if so, how reliably.

-hpa

Signature · 2 lines
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel.  I don't speak on their behalf.
#81 lore raw

Re: [PATCH] x86: Add optimized popcnt variants

From: "H. Peter Anvin" <[email protected]>
Date: Mon, Feb 22, 2010 at 09:21:05AM -0800

Quoted 22 lines · Borislav Petkov
Quoted 5 lines
(quoted diff) +4 -0
+config ARCH_HWEIGHT_CFLAGS
+	string
+	default "-fcall-saved-rsi -fcall-saved-rdx -fcall-saved-rcx -fcall-saved-r8 -fcall-saved-r9 -fcall-saved-r10 -fcall-saved-r11" if X86_64
+

[...]

Review

Quoted 7 lines
(quoted diff) +7 -0
+
+#ifdef CONFIG_64BIT
+/* popcnt %rdi, %rax */
+#define POPCNT ".byte 0xf3\n\t.byte 0x48\n\t.byte 0x0f\n\t.byte 0xb8\n\t.byte 0xc7"
+#define REG_IN "D"
+#define REG_OUT "a"
+#else

Just a note: this still means rdi is clobbered on x86-64, which is probably fine, but needs to be recorded as such. Since gcc doesn't support clobbers for registers used as operands (sigh), you have to create a dummy output and assign it a "=D" constraint.

Quoted 2 lines

I don't know if gcc would handle -fcall-saved-rdi here... and if so, how reliably.

Ok, from looking at kernel/sched.s output it looks like it saves rdi content over the alternative where needed. I'll do some more testing just to make sure.

--
From: Borislav Petkov <[email protected]>
Date: Thu, 11 Feb 2010 00:48:31 +0100
Subject: [PATCH] x86: Add optimized popcnt variants

Add support for the hardware version of the Hamming weight function, popcnt, present in CPUs which advertize it under CPUID, Function 0x0000_0001_ECX[23]. On CPUs which don't support it, we fallback to the default lib/hweight.c sw versions.

A synthetic benchmark comparing popcnt with __sw_hweight64 showed almost a 3x speedup on a F10h machine.

---
 arch/x86/Kconfig                          |    5 ++
 arch/x86/include/asm/alternative.h        |    9 +++-
 arch/x86/include/asm/arch_hweight.h       |   59 +++++++++++++++++++++++++++++
 arch/x86/include/asm/bitops.h             |    4 +-
 include/asm-generic/bitops/arch_hweight.h |   22 +++++++++--
 lib/Makefile                              |    3 +
 lib/hweight.c                             |   20 +++++-----
 scripts/Makefile.lib                      |    4 ++
 8 files changed, 108 insertions(+), 18 deletions(-)
 create mode 100644 arch/x86/include/asm/arch_hweight.h
arch/x86/Kconfig +5 -0
index eb40925..176950e 100644
@@ -230,6 +230,11 @@ config X86_32_LAZY_GS
 	def_bool y
 	depends on X86_32 && !CC_STACKPROTECTOR
 
+config ARCH_HWEIGHT_CFLAGS
+	string
+	default "-fcall-saved-ecx -fcall-saved-edx" if X86_32
+	default "-fcall-saved-rsi -fcall-saved-rdx -fcall-saved-rcx -fcall-saved-r8 -fcall-saved-r9 -fcall-saved-r10 -fcall-saved-r11" if X86_64
+
 config KTIME_SCALAR
 	def_bool X86_32
 source "init/Kconfig"
arch/x86/include/asm/alternative.h +6 -3
index 69b74a7..0720c96 100644
@@ -39,9 +39,6 @@
 #define LOCK_PREFIX ""
 #endif
 
-/* This must be included *after* the definition of LOCK_PREFIX */
-#include <asm/cpufeature.h>
-
 struct alt_instr {
 	u8 *instr;		/* original instruction */
 	u8 *replacement;
@@ -91,6 +88,12 @@ static inline void alternatives_smp_switch(int smp) {}
       ".previous"
 
 /*
+ * This must be included *after* the definition of ALTERNATIVE due to
+ * <asm/arch_hweight.h>
+ */
+#include <asm/cpufeature.h>
+
+/*
  * Alternative instructions for different CPU types or capabilities.
  *
  * This allows to use optimized instructions even on generic binary
arch/x86/include/asm/arch_hweight.h new file +59 -0

59 lines not on this page · raw message

arch/x86/include/asm/bitops.h +3 -1
index 02b47a6..545776e 100644
@@ -444,7 +444,9 @@ static inline int fls(int x)
 
 #define ARCH_HAS_FAST_MULTIPLIER 1
 
-#include <asm-generic/bitops/hweight.h>
+#include <asm/arch_hweight.h>
+
+#include <asm-generic/bitops/const_hweight.h>
 
 #endif /* __KERNEL__ */
 
include/asm-generic/bitops/arch_hweight.h +18 -4
index 3a7be84..9a81c1e 100644
@@ -3,9 +3,23 @@
 
 #include <asm/types.h>
 
-extern unsigned int __arch_hweight32(unsigned int w);
-extern unsigned int __arch_hweight16(unsigned int w);
-extern unsigned int __arch_hweight8(unsigned int w);
-extern unsigned long __arch_hweight64(__u64 w);
+inline unsigned int __arch_hweight32(unsigned int w)
+{
+	return __sw_hweight32(w);
+}
 
+inline unsigned int __arch_hweight16(unsigned int w)
+{
+	return __sw_hweight16(w);
+}
+
+inline unsigned int __arch_hweight8(unsigned int w)
+{
+	return __sw_hweight8(w);
+}
+
+inline unsigned long __arch_hweight64(__u64 w)
+{
+	return __sw_hweight64(w);
+}
 #endif /* _ASM_GENERIC_BITOPS_HWEIGHT_H_ */
lib/Makefile +3 -0
index 3b0b4a6..e2ad17c 100644
@@ -39,7 +39,10 @@ lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
 lib-$(CONFIG_GENERIC_FIND_FIRST_BIT) += find_next_bit.o
 lib-$(CONFIG_GENERIC_FIND_NEXT_BIT) += find_next_bit.o
 obj-$(CONFIG_GENERIC_FIND_LAST_BIT) += find_last_bit.o
+
+CFLAGS_hweight.o = $(subst $(quote),,$(CONFIG_ARCH_HWEIGHT_CFLAGS))
 obj-$(CONFIG_GENERIC_HWEIGHT) += hweight.o
+
 obj-$(CONFIG_LOCK_KERNEL) += kernel_lock.o
 obj-$(CONFIG_DEBUG_PREEMPT) += smp_processor_id.o
 obj-$(CONFIG_DEBUG_LIST) += list_debug.o
lib/hweight.c +10 -10
index 9ff86df..f9ce440 100644
@@ -9,7 +9,7 @@
  * The Hamming Weight of a number is the total number of bits set in it.
  */
 
-unsigned int __arch_hweight32(unsigned int w)
+unsigned int __sw_hweight32(unsigned int w)
 {
 	unsigned int res = w - ((w >> 1) & 0x55555555);
 	res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
@@ -17,30 +17,30 @@ unsigned int __arch_hweight32(unsigned int w)
 	res = res + (res >> 8);
 	return (res + (res >> 16)) & 0x000000FF;
 }
-EXPORT_SYMBOL(__arch_hweight32);
+EXPORT_SYMBOL(__sw_hweight32);
 
-unsigned int __arch_hweight16(unsigned int w)
+unsigned int __sw_hweight16(unsigned int w)
 {
 	unsigned int res = w - ((w >> 1) & 0x5555);
 	res = (res & 0x3333) + ((res >> 2) & 0x3333);
 	res = (res + (res >> 4)) & 0x0F0F;
 	return (res + (res >> 8)) & 0x00FF;
 }
-EXPORT_SYMBOL(__arch_hweight16);
+EXPORT_SYMBOL(__sw_hweight16);
 
-unsigned int __arch_hweight8(unsigned int w)
+unsigned int __sw_hweight8(unsigned int w)
 {
 	unsigned int res = w - ((w >> 1) & 0x55);
 	res = (res & 0x33) + ((res >> 2) & 0x33);
 	return (res + (res >> 4)) & 0x0F;
 }
-EXPORT_SYMBOL(__arch_hweight8);
+EXPORT_SYMBOL(__sw_hweight8);
 
-unsigned long __arch_hweight64(__u64 w)
+unsigned long __sw_hweight64(__u64 w)
 {
 #if BITS_PER_LONG == 32
-	return __arch_hweight32((unsigned int)(w >> 32)) +
-	       __arch_hweight32((unsigned int)w);
+	return __sw_hweight32((unsigned int)(w >> 32)) +
+	       __sw_hweight32((unsigned int)w);
 #elif BITS_PER_LONG == 64
 #ifdef ARCH_HAS_FAST_MULTIPLIER
 	w -= (w >> 1) & 0x5555555555555555ul;
@@ -57,4 +57,4 @@ unsigned long __arch_hweight64(__u64 w)
 #endif
 #endif
 }
-EXPORT_SYMBOL(__arch_hweight64);
+EXPORT_SYMBOL(__sw_hweight64);
scripts/Makefile.lib +4 -0
index f9bdf26..cbcd654 100644
@@ -245,3 +245,7 @@ quiet_cmd_lzo = LZO    $@
 cmd_lzo = (cat $(filter-out FORCE,$^) | \
 	lzop -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \
 	(rm -f $@ ; false)
+
+# misc stuff
+# ---------------------------------------------------------------------------
+quote:="
Signature · 10 lines
1.6.4.2


-- 
Regards/Gruss,
Boris.

--
Advanced Micro Devices, Inc.
Operating Systems Research Center
#82 lore raw

Re: [PATCH] x86: Add optimized popcnt variants

Quoted 6 lines · Borislav Petkov
Quoted 6 lines

Just a note: this still means rdi is clobbered on x86-64, which is probably fine, but needs to be recorded as such. Since gcc doesn't support clobbers for registers used as operands (sigh), you have to create a dummy output and assign it a "=D" constraint.

Quoted 7 lines
Quoted 2 lines

I don't know if gcc would handle -fcall-saved-rdi here... and if so, how reliably.

Ok, from looking at kernel/sched.s output it looks like it saves rdi content over the alternative where needed. I'll do some more testing just to make sure.

No, you can't rely on behavioral observation. A different version of gcc could behave differently. We need to make sure we tell gcc what the requirements actually are, as opposed to thinking we can just fix them.

+#define POPCNT ".byte 0xf3\n\t.byte 0x48\n\t.byte 0x0f\n\t.byte 0xb8\n\t.byte 0xc7"

BTW, this can be written:

#define POPCNT ".byte 0xf3,0x48,0x0f,0xb8,0xc7"

-hpa

#83 lore raw

Re: [PATCH] x86: Add optimized popcnt variants

From: "H. Peter Anvin" <[email protected]>
Date: Mon, Feb 22, 2010 at 11:55:48AM -0800

Quoted 10 lines · Borislav Petkov
Quoted 9 lines
Quoted 8 lines

Just a note: this still means rdi is clobbered on x86-64, which is probably fine, but needs to be recorded as such. Since gcc doesn't support clobbers for registers used as operands (sigh), you have to create a dummy output and assign it a "=D" constraint.

I don't know if gcc would handle -fcall-saved-rdi here... and if so, how reliably.

Quoted 8 lines
Quoted 4 lines

Ok, from looking at kernel/sched.s output it looks like it saves rdi content over the alternative where needed. I'll do some more testing just to make sure.

No, you can't rely on behavioral observation. A different version of gcc could behave differently. We need to make sure we tell gcc what the requirements actually are, as opposed to thinking we can just fix them.

Ok, I've added the dummy "=D" constraint since it sounded like the more stable thing to do WRT gcc versions. BTW, I left the machine overnight and it is still alive cheerfully building randconfigs.

I'll try the -fcall-saved-rdi thing also later today.

Quoted 6 lines

+#define POPCNT ".byte 0xf3\n\t.byte 0x48\n\t.byte 0x0f\n\t.byte 0xb8\n\t.byte 0xc7"

BTW, this can be written:

#define POPCNT ".byte 0xf3,0x48,0x0f,0xb8,0xc7"

done, updated version coming up.

Signature · 2 lines
Regards/Gruss,
    Boris.
#84 lore raw

Re: [PATCH] x86: Add optimized popcnt variants

In reply to H. Peter Anvin

From: "H. Peter Anvin" <[email protected]>
Date: Mon, Feb 22, 2010 at 11:55:48AM -0800

Quoted 9 lines · Borislav Petkov
Quoted 8 lines
Quoted 8 lines

Just a note: this still means rdi is clobbered on x86-64, which is probably fine, but needs to be recorded as such. Since gcc doesn't support clobbers for registers used as operands (sigh), you have to create a dummy output and assign it a "=D" constraint.

I don't know if gcc would handle -fcall-saved-rdi here... and if so, how reliably.

Hmm, we cannot do that with the current design since __arch_hweight64 is being inlined into every callsite and AFAICT we would have to build every callsite with "-fcall-saved-rdi" which is clearly too much. The explicit "=D" dummy constraint is straightforward, instead.

Quoted 8 lines
Quoted 4 lines

Ok, from looking at kernel/sched.s output it looks like it saves rdi content over the alternative where needed. I'll do some more testing just to make sure.

No, you can't rely on behavioral observation. A different version of gcc could behave differently. We need to make sure we tell gcc what the requirements actually are, as opposed to thinking we can just fix them.

Just to make clear: those observations were referring to the version _with_ the dummy "=D" constraint - I was simply verifying the asm output and wasn't relying on behavioral observation.

Quoted 6 lines

+#define POPCNT ".byte 0xf3\n\t.byte 0x48\n\t.byte 0x0f\n\t.byte 0xb8\n\t.byte 0xc7"

BTW, this can be written:

#define POPCNT ".byte 0xf3,0x48,0x0f,0xb8,0xc7"

Done, here's the latest version, it boots fine and testing is ongoing:

--
From: Borislav Petkov <[email protected]>
Date: Thu, 11 Feb 2010 00:48:31 +0100
Subject: [PATCH] x86: Add optimized popcnt variants

Add support for the hardware version of the Hamming weight function, popcnt, present in CPUs which advertize it under CPUID, Function 0x0000_0001_ECX[23]. On CPUs which don't support it, we fallback to the default lib/hweight.c sw versions.

A synthetic benchmark comparing popcnt with __sw_hweight64 showed almost a 3x speedup on a F10h machine.

---
 arch/x86/Kconfig                          |    5 ++
 arch/x86/include/asm/alternative.h        |    9 +++-
 arch/x86/include/asm/arch_hweight.h       |   61 +++++++++++++++++++++++++++++
 arch/x86/include/asm/bitops.h             |    4 +-
 include/asm-generic/bitops/arch_hweight.h |   22 ++++++++--
 lib/Makefile                              |    3 +
 lib/hweight.c                             |   20 +++++-----
 scripts/Makefile.lib                      |    4 ++
 8 files changed, 110 insertions(+), 18 deletions(-)
 create mode 100644 arch/x86/include/asm/arch_hweight.h
arch/x86/Kconfig +5 -0
index eb40925..176950e 100644
@@ -230,6 +230,11 @@ config X86_32_LAZY_GS
 	def_bool y
 	depends on X86_32 && !CC_STACKPROTECTOR
 
+config ARCH_HWEIGHT_CFLAGS
+	string
+	default "-fcall-saved-ecx -fcall-saved-edx" if X86_32
+	default "-fcall-saved-rsi -fcall-saved-rdx -fcall-saved-rcx -fcall-saved-r8 -fcall-saved-r9 -fcall-saved-r10 -fcall-saved-r11" if X86_64
+
 config KTIME_SCALAR
 	def_bool X86_32
 source "init/Kconfig"
arch/x86/include/asm/alternative.h +6 -3
index 69b74a7..0720c96 100644
@@ -39,9 +39,6 @@
 #define LOCK_PREFIX ""
 #endif
 
-/* This must be included *after* the definition of LOCK_PREFIX */
-#include <asm/cpufeature.h>
-
 struct alt_instr {
 	u8 *instr;		/* original instruction */
 	u8 *replacement;
@@ -91,6 +88,12 @@ static inline void alternatives_smp_switch(int smp) {}
       ".previous"
 
 /*
+ * This must be included *after* the definition of ALTERNATIVE due to
+ * <asm/arch_hweight.h>
+ */
+#include <asm/cpufeature.h>
+
+/*
  * Alternative instructions for different CPU types or capabilities.
  *
  * This allows to use optimized instructions even on generic binary
arch/x86/include/asm/arch_hweight.h new file +61 -0

61 lines not on this page · raw message

arch/x86/include/asm/bitops.h +3 -1
index 02b47a6..545776e 100644
@@ -444,7 +444,9 @@ static inline int fls(int x)
 
 #define ARCH_HAS_FAST_MULTIPLIER 1
 
-#include <asm-generic/bitops/hweight.h>
+#include <asm/arch_hweight.h>
+
+#include <asm-generic/bitops/const_hweight.h>
 
 #endif /* __KERNEL__ */
 
include/asm-generic/bitops/arch_hweight.h +18 -4
index 3a7be84..9a81c1e 100644
@@ -3,9 +3,23 @@
 
 #include <asm/types.h>
 
-extern unsigned int __arch_hweight32(unsigned int w);
-extern unsigned int __arch_hweight16(unsigned int w);
-extern unsigned int __arch_hweight8(unsigned int w);
-extern unsigned long __arch_hweight64(__u64 w);
+inline unsigned int __arch_hweight32(unsigned int w)
+{
+	return __sw_hweight32(w);
+}
 
+inline unsigned int __arch_hweight16(unsigned int w)
+{
+	return __sw_hweight16(w);
+}
+
+inline unsigned int __arch_hweight8(unsigned int w)
+{
+	return __sw_hweight8(w);
+}
+
+inline unsigned long __arch_hweight64(__u64 w)
+{
+	return __sw_hweight64(w);
+}
 #endif /* _ASM_GENERIC_BITOPS_HWEIGHT_H_ */
lib/Makefile +3 -0
index 3b0b4a6..e2ad17c 100644
@@ -39,7 +39,10 @@ lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
 lib-$(CONFIG_GENERIC_FIND_FIRST_BIT) += find_next_bit.o
 lib-$(CONFIG_GENERIC_FIND_NEXT_BIT) += find_next_bit.o
 obj-$(CONFIG_GENERIC_FIND_LAST_BIT) += find_last_bit.o
+
+CFLAGS_hweight.o = $(subst $(quote),,$(CONFIG_ARCH_HWEIGHT_CFLAGS))
 obj-$(CONFIG_GENERIC_HWEIGHT) += hweight.o
+
 obj-$(CONFIG_LOCK_KERNEL) += kernel_lock.o
 obj-$(CONFIG_DEBUG_PREEMPT) += smp_processor_id.o
 obj-$(CONFIG_DEBUG_LIST) += list_debug.o
lib/hweight.c +10 -10
index 9ff86df..f9ce440 100644
@@ -9,7 +9,7 @@
  * The Hamming Weight of a number is the total number of bits set in it.
  */
 
-unsigned int __arch_hweight32(unsigned int w)
+unsigned int __sw_hweight32(unsigned int w)
 {
 	unsigned int res = w - ((w >> 1) & 0x55555555);
 	res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
@@ -17,30 +17,30 @@ unsigned int __arch_hweight32(unsigned int w)
 	res = res + (res >> 8);
 	return (res + (res >> 16)) & 0x000000FF;
 }
-EXPORT_SYMBOL(__arch_hweight32);
+EXPORT_SYMBOL(__sw_hweight32);
 
-unsigned int __arch_hweight16(unsigned int w)
+unsigned int __sw_hweight16(unsigned int w)
 {
 	unsigned int res = w - ((w >> 1) & 0x5555);
 	res = (res & 0x3333) + ((res >> 2) & 0x3333);
 	res = (res + (res >> 4)) & 0x0F0F;
 	return (res + (res >> 8)) & 0x00FF;
 }
-EXPORT_SYMBOL(__arch_hweight16);
+EXPORT_SYMBOL(__sw_hweight16);
 
-unsigned int __arch_hweight8(unsigned int w)
+unsigned int __sw_hweight8(unsigned int w)
 {
 	unsigned int res = w - ((w >> 1) & 0x55);
 	res = (res & 0x33) + ((res >> 2) & 0x33);
 	return (res + (res >> 4)) & 0x0F;
 }
-EXPORT_SYMBOL(__arch_hweight8);
+EXPORT_SYMBOL(__sw_hweight8);
 
-unsigned long __arch_hweight64(__u64 w)
+unsigned long __sw_hweight64(__u64 w)
 {
 #if BITS_PER_LONG == 32
-	return __arch_hweight32((unsigned int)(w >> 32)) +
-	       __arch_hweight32((unsigned int)w);
+	return __sw_hweight32((unsigned int)(w >> 32)) +
+	       __sw_hweight32((unsigned int)w);
 #elif BITS_PER_LONG == 64
 #ifdef ARCH_HAS_FAST_MULTIPLIER
 	w -= (w >> 1) & 0x5555555555555555ul;
@@ -57,4 +57,4 @@ unsigned long __arch_hweight64(__u64 w)
 #endif
 #endif
 }
-EXPORT_SYMBOL(__arch_hweight64);
+EXPORT_SYMBOL(__sw_hweight64);
scripts/Makefile.lib +4 -0
index f9bdf26..cbcd654 100644
@@ -245,3 +245,7 @@ quiet_cmd_lzo = LZO    $@
 cmd_lzo = (cat $(filter-out FORCE,$^) | \
 	lzop -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \
 	(rm -f $@ ; false)
+
+# misc stuff
+# ---------------------------------------------------------------------------
+quote:="
Signature · 10 lines
1.6.4.2


-- 
Regards/Gruss,
Boris.

--
Advanced Micro Devices, Inc.
Operating Systems Research Center
#85 lore raw

Re: [PATCH] x86: Add optimized popcnt variants

Quoted 6 lines · Borislav Petkov

Hmm, we cannot do that with the current design since __arch_hweight64 is being inlined into every callsite and AFAICT we would have to build every callsite with "-fcall-saved-rdi" which is clearly too much. The explicit "=D" dummy constraint is straightforward, instead.

Uh... the -fcall-saved-rdi would go with all the other ones. Assuming it can actually work and that gcc doesn't choke on an inbound argument being saved.

-hpa

#86 lore raw

Re: [PATCH] x86: Add optimized popcnt variants

From: "H. Peter Anvin" <[email protected]>
Date: Tue, Feb 23, 2010 at 09:34:04AM -0800

Quoted 11 lines · Borislav Petkov
Quoted 6 lines

Hmm, we cannot do that with the current design since __arch_hweight64 is being inlined into every callsite and AFAICT we would have to build every callsite with "-fcall-saved-rdi" which is clearly too much. The explicit "=D" dummy constraint is straightforward, instead.

Uh... the -fcall-saved-rdi would go with all the other ones. Assuming it can actually work and that gcc doesn't choke on an inbound argument being saved.

Right, doh. Ok, just added it and it builds fine with a gcc (Gentoo 4.4.1 p1.0) 4.4.1. If you have suspicion that some older gcc versions might choke on it, I could leave the "=D" dummy constraint in?

BTW, the current version screams

/usr/src/linux-2.6/arch/x86/include/asm/arch_hweight.h: In function ‘__arch_hweight64’:
/usr/src/linux-2.6/arch/x86/include/asm/arch_hweight.h:47: warning: unused variable ‘dummy’

on x86-32. I'll send a fixed version in a second.

Signature · 6 lines
Regards/Gruss,
Boris.

-
Advanced Micro Devices, Inc.
Operating Systems Research Center
#87 lore raw

Re: [PATCH] x86: Add optimized popcnt variants

Quoted 5 lines · Borislav Petkov

Right, doh. Ok, just added it and it builds fine with a gcc (Gentoo 4.4.1 p1.0) 4.4.1. If you have suspicion that some older gcc versions might choke on it, I could leave the "=D" dummy constraint in?

I can try it with gcc 3.4 here. -fcall-saved-rdi is cleaner, if it works.

-hpa

Signature · 2 lines
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel.  I don't speak on their behalf.
#88 lore raw

Re: [PATCH] x86: Add optimized popcnt variants

From: "H. Peter Anvin" <[email protected]>
Date: Tue, Feb 23, 2010 at 10:17:39AM -0800

Quoted 8 lines · Borislav Petkov
Quoted 5 lines

Right, doh. Ok, just added it and it builds fine with a gcc (Gentoo 4.4.1 p1.0) 4.4.1. If you have suspicion that some older gcc versions might choke on it, I could leave the "=D" dummy constraint in?

I can try it with gcc 3.4 here. -fcall-saved-rdi is cleaner, if it works.

Ok, here you go.

--
From: Borislav Petkov <[email protected]>
Date: Thu, 11 Feb 2010 00:48:31 +0100
Subject: [PATCH] x86: Add optimized popcnt variants

Add support for the hardware version of the Hamming weight function, popcnt, present in CPUs which advertize it under CPUID, Function 0x0000_0001_ECX[23]. On CPUs which don't support it, we fallback to the default lib/hweight.c sw versions.

A synthetic benchmark comparing popcnt with __sw_hweight64 showed almost a 3x speedup on a F10h machine.

---
 arch/x86/Kconfig                          |    5 ++
 arch/x86/include/asm/alternative.h        |    9 +++-
 arch/x86/include/asm/arch_hweight.h       |   59 +++++++++++++++++++++++++++++
 arch/x86/include/asm/bitops.h             |    4 +-
 include/asm-generic/bitops/arch_hweight.h |   22 +++++++++--
 lib/Makefile                              |    3 +
 lib/hweight.c                             |   20 +++++-----
 scripts/Makefile.lib                      |    4 ++
 8 files changed, 108 insertions(+), 18 deletions(-)
 create mode 100644 arch/x86/include/asm/arch_hweight.h
arch/x86/Kconfig +5 -0
index eb40925..4673dc5 100644
@@ -230,6 +230,11 @@ config X86_32_LAZY_GS
 	def_bool y
 	depends on X86_32 && !CC_STACKPROTECTOR
 
+config ARCH_HWEIGHT_CFLAGS
+	string
+	default "-fcall-saved-ecx -fcall-saved-edx" if X86_32
+	default "-fcall-saved-rdi -fcall-saved-rsi -fcall-saved-rdx -fcall-saved-rcx -fcall-saved-r8 -fcall-saved-r9 -fcall-saved-r10 -fcall-saved-r11" if X86_64
+
 config KTIME_SCALAR
 	def_bool X86_32
 source "init/Kconfig"
arch/x86/include/asm/alternative.h +6 -3
index 69b74a7..0720c96 100644
@@ -39,9 +39,6 @@
 #define LOCK_PREFIX ""
 #endif
 
-/* This must be included *after* the definition of LOCK_PREFIX */
-#include <asm/cpufeature.h>
-
 struct alt_instr {
 	u8 *instr;		/* original instruction */
 	u8 *replacement;
@@ -91,6 +88,12 @@ static inline void alternatives_smp_switch(int smp) {}
       ".previous"
 
 /*
+ * This must be included *after* the definition of ALTERNATIVE due to
+ * <asm/arch_hweight.h>
+ */
+#include <asm/cpufeature.h>
+
+/*
  * Alternative instructions for different CPU types or capabilities.
  *
  * This allows to use optimized instructions even on generic binary
arch/x86/include/asm/arch_hweight.h new file +59 -0

59 lines not on this page · raw message

arch/x86/include/asm/bitops.h +3 -1
index 02b47a6..545776e 100644
@@ -444,7 +444,9 @@ static inline int fls(int x)
 
 #define ARCH_HAS_FAST_MULTIPLIER 1
 
-#include <asm-generic/bitops/hweight.h>
+#include <asm/arch_hweight.h>
+
+#include <asm-generic/bitops/const_hweight.h>
 
 #endif /* __KERNEL__ */
 
include/asm-generic/bitops/arch_hweight.h +18 -4
index 3a7be84..9a81c1e 100644
@@ -3,9 +3,23 @@
 
 #include <asm/types.h>
 
-extern unsigned int __arch_hweight32(unsigned int w);
-extern unsigned int __arch_hweight16(unsigned int w);
-extern unsigned int __arch_hweight8(unsigned int w);
-extern unsigned long __arch_hweight64(__u64 w);
+inline unsigned int __arch_hweight32(unsigned int w)
+{
+	return __sw_hweight32(w);
+}
 
+inline unsigned int __arch_hweight16(unsigned int w)
+{
+	return __sw_hweight16(w);
+}
+
+inline unsigned int __arch_hweight8(unsigned int w)
+{
+	return __sw_hweight8(w);
+}
+
+inline unsigned long __arch_hweight64(__u64 w)
+{
+	return __sw_hweight64(w);
+}
 #endif /* _ASM_GENERIC_BITOPS_HWEIGHT_H_ */
lib/Makefile +3 -0
index 3b0b4a6..e2ad17c 100644
@@ -39,7 +39,10 @@ lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
 lib-$(CONFIG_GENERIC_FIND_FIRST_BIT) += find_next_bit.o
 lib-$(CONFIG_GENERIC_FIND_NEXT_BIT) += find_next_bit.o
 obj-$(CONFIG_GENERIC_FIND_LAST_BIT) += find_last_bit.o
+
+CFLAGS_hweight.o = $(subst $(quote),,$(CONFIG_ARCH_HWEIGHT_CFLAGS))
 obj-$(CONFIG_GENERIC_HWEIGHT) += hweight.o
+
 obj-$(CONFIG_LOCK_KERNEL) += kernel_lock.o
 obj-$(CONFIG_DEBUG_PREEMPT) += smp_processor_id.o
 obj-$(CONFIG_DEBUG_LIST) += list_debug.o
lib/hweight.c +10 -10
index 9ff86df..f9ce440 100644
@@ -9,7 +9,7 @@
  * The Hamming Weight of a number is the total number of bits set in it.
  */
 
-unsigned int __arch_hweight32(unsigned int w)
+unsigned int __sw_hweight32(unsigned int w)
 {
 	unsigned int res = w - ((w >> 1) & 0x55555555);
 	res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
@@ -17,30 +17,30 @@ unsigned int __arch_hweight32(unsigned int w)
 	res = res + (res >> 8);
 	return (res + (res >> 16)) & 0x000000FF;
 }
-EXPORT_SYMBOL(__arch_hweight32);
+EXPORT_SYMBOL(__sw_hweight32);
 
-unsigned int __arch_hweight16(unsigned int w)
+unsigned int __sw_hweight16(unsigned int w)
 {
 	unsigned int res = w - ((w >> 1) & 0x5555);
 	res = (res & 0x3333) + ((res >> 2) & 0x3333);
 	res = (res + (res >> 4)) & 0x0F0F;
 	return (res + (res >> 8)) & 0x00FF;
 }
-EXPORT_SYMBOL(__arch_hweight16);
+EXPORT_SYMBOL(__sw_hweight16);
 
-unsigned int __arch_hweight8(unsigned int w)
+unsigned int __sw_hweight8(unsigned int w)
 {
 	unsigned int res = w - ((w >> 1) & 0x55);
 	res = (res & 0x33) + ((res >> 2) & 0x33);
 	return (res + (res >> 4)) & 0x0F;
 }
-EXPORT_SYMBOL(__arch_hweight8);
+EXPORT_SYMBOL(__sw_hweight8);
 
-unsigned long __arch_hweight64(__u64 w)
+unsigned long __sw_hweight64(__u64 w)
 {
 #if BITS_PER_LONG == 32
-	return __arch_hweight32((unsigned int)(w >> 32)) +
-	       __arch_hweight32((unsigned int)w);
+	return __sw_hweight32((unsigned int)(w >> 32)) +
+	       __sw_hweight32((unsigned int)w);
 #elif BITS_PER_LONG == 64
 #ifdef ARCH_HAS_FAST_MULTIPLIER
 	w -= (w >> 1) & 0x5555555555555555ul;
@@ -57,4 +57,4 @@ unsigned long __arch_hweight64(__u64 w)
 #endif
 #endif
 }
-EXPORT_SYMBOL(__arch_hweight64);
+EXPORT_SYMBOL(__sw_hweight64);
scripts/Makefile.lib +4 -0
index f9bdf26..cbcd654 100644
@@ -245,3 +245,7 @@ quiet_cmd_lzo = LZO    $@
 cmd_lzo = (cat $(filter-out FORCE,$^) | \
 	lzop -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \
 	(rm -f $@ ; false)
+
+# misc stuff
+# ---------------------------------------------------------------------------
+quote:="
Signature · 10 lines
1.6.4.2


-- 
Regards/Gruss,
Boris.

-
Advanced Micro Devices, Inc.
Operating Systems Research Center
#89 lore raw

Re: [PATCH] x86: Add optimized popcnt variants

Quoted 13 lines · Borislav Petkov

Ok, here you go.

--
From: Borislav Petkov <[email protected]>
Date: Thu, 11 Feb 2010 00:48:31 +0100
Subject: [PATCH] x86: Add optimized popcnt variants

Add support for the hardware version of the Hamming weight function, popcnt, present in CPUs which advertize it under CPUID, Function 0x0000_0001_ECX[23]. On CPUs which don't support it, we fallback to the default lib/hweight.c sw versions.

Quoted 4 lines

A synthetic benchmark comparing popcnt with __sw_hweight64 showed almost a 3x speedup on a F10h machine.

OK, this patch looks pretty good now, but I'm completely lost as to what the baseline of this patch is supposed to be.

-hpa

Signature · 2 lines
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel.  I don't speak on their behalf.
#90 lore raw

Re: [PATCH] x86: Add optimized popcnt variants

From: "H. Peter Anvin" <[email protected]>
Date: Thu, Feb 25, 2010 at 09:27:25PM -0800

Quoted 2 lines

OK, this patch looks pretty good now, but I'm completely lost as to what the baseline of this patch is supposed to be.

Yeah, this is based on PeterZ's http://lkml.org/lkml/2010/2/4/119

But I'm not sure which tree has it...

Signature · 6 lines
Regards/Gruss,
Boris.

-
Advanced Micro Devices, Inc.
Operating Systems Research Center
#91 lore raw

Re: [PATCH] x86: Add optimized popcnt variants

Quoted 10 lines · Borislav Petkov

From: "H. Peter Anvin" <[email protected]>
Date: Thu, Feb 25, 2010 at 09:27:25PM -0800

Quoted 2 lines

OK, this patch looks pretty good now, but I'm completely lost as to what the baseline of this patch is supposed to be.

Yeah, this is based on PeterZ's http://lkml.org/lkml/2010/2/4/119

But I'm not sure which tree has it...

Looks like -mm, which really means that either Andrew has to take your patch, too, or we have to wait until that is upstream until we can merge your patch.

I'm a little nervous about just acking the patch and telling Andrew to test it, because I don't know what the fallout would look like. I'm particularly concerned about gcc version dependencies.

I guess, on the other hand, if it ends up not getting merged until .35 it's not a huge deal either.

-hpa

Signature · 2 lines
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel.  I don't speak on their behalf.
#92 lore raw

Re: [PATCH] x86: Add optimized popcnt variants

From: "H. Peter Anvin" <[email protected]>
Date: Fri, Feb 26, 2010 at 09:48:46AM -0800

Quoted 7 lines

Looks like -mm, which really means that either Andrew has to take your patch, too, or we have to wait until that is upstream until we can merge your patch.

I'm a little nervous about just acking the patch and telling Andrew to test it, because I don't know what the fallout would look like. I'm particularly concerned about gcc version dependencies.

I have the same concern. Actually, I'll be much more at ease if it saw a bit of wider testing without hitting mainline just yet. I'll try to give it some more testing with the machines and toolchains I can get my hands on next week.

Quoted 2 lines

I guess, on the other hand, if it ends up not getting merged until .35 it's not a huge deal either.

Yeah, let's give it another round of testing and queue it for .35 - AFAIR Ingo runs also a wide testing effort so it spending another cycle in -tip and being hammered on by us could give us a bit more certainty.

Thanks.

Signature · 6 lines
Regards/Gruss,
Boris.

-
Advanced Micro Devices, Inc.
Operating Systems Research Center
#93 lore raw

Re: [PATCH] x86: Add optimized popcnt variants

Quoted 8 lines · Borislav Petkov
Quoted 3 lines

I guess, on the other hand, if it ends up not getting merged until .35 it's not a huge deal either.

Yeah, let's give it another round of testing and queue it for .35 - AFAIR Ingo runs also a wide testing effort so it spending another cycle in -tip and being hammered on by us could give us a bit more certainty.

Yes, if we can get into -tip then we'll get more test coverage, so I'll queue it up for .35 as soon as the merge window closes. Please remind me if I forget.

-hpa

Signature · 2 lines
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel.  I don't speak on their behalf.
#94 lore raw

Re: [PATCH] x86: Add optimized popcnt variants

Quoted 9 lines · Borislav Petkov
Quoted 4 lines

Yeah, let's give it another round of testing and queue it for .35 - AFAIR Ingo runs also a wide testing effort so it spending another cycle in -tip and being hammered on by us could give us a bit more certainty.

Yes, if we can get into -tip then we'll get more test coverage, so I'll queue it up for .35 as soon as the merge window closes. Please remind me if I forget.

Hi Peter,

I see that you've added the HWEIGHT-capitalized interfaces for compile-time constants with fce877e3. Which means, the bits in <include/asm-generic/bitops/const_hweight.h> from your original patch at
http://lkml.org/lkml/2010/2/4/119 need changing (or have changed already but I've missed them).

IOW, where can I get the current version of that last patch so that I can base my __arch_hweightXX stuff ontop of it for testing?

Thanks.

Signature · 6 lines
Regards/Gruss,
Boris.

-
Advanced Micro Devices, Inc.
Operating Systems Research Center
maintainer
#95 lore raw

Re: [PATCH] x86: Add optimized popcnt variants

Quoted 12 lines · Borislav Petkov
Quoted 9 lines · Borislav Petkov
Quoted 4 lines

Yeah, let's give it another round of testing and queue it for .35 - AFAIR Ingo runs also a wide testing effort so it spending another cycle in -tip and being hammered on by us could give us a bit more certainty.

Yes, if we can get into -tip then we'll get more test coverage, so I'll queue it up for .35 as soon as the merge window closes. Please remind me if I forget.

Hi Peter,

Quoted 8 lines

I see that you've added the HWEIGHT-capitalized interfaces for compile-time constants with fce877e3. Which means, the bits in <include/asm-generic/bitops/const_hweight.h> from your original patch at
http://lkml.org/lkml/2010/2/4/119 need changing (or have changed already but I've missed them).

IOW, where can I get the current version of that last patch so that I can base my __arch_hweightXX stuff ontop of it for testing?

Should all be fine as it is, that patch
( http://lkml.org/lkml/2010/2/4/119 ) is against a kernel with fce877e3 in, I've just checked and it still applies to tip/master as of this writing (although it grew a single 2 line offset for 1 hunk).

#96 lore raw

Re: [PATCH] x86: Add optimized popcnt variants

From: Peter Zijlstra <[email protected]>
Date: Tue, Mar 09, 2010 at 04:50:40PM +0100

Quoted 4 lines

Should all be fine as it is, that patch
( http://lkml.org/lkml/2010/2/4/119 ) is against a kernel with fce877e3 in, I've just checked and it still applies to tip/master as of this writing (although it grew a single 2 line offset for 1 hunk).

Well, this way, I'm getting

...
In file included from include/linux/kernel.h:15,

                 from /home/linux-2.6/arch/x86/include/asm/percpu.h:45,
                 from /home/linux-2.6/arch/x86/include/asm/current.h:5,
                 from /home/linux-2.6/arch/x86/include/asm/processor.h:15,
                 from /home/linux-2.6/arch/x86/include/asm/atomic.h:6,
                 from include/linux/crypto.h:20,
                 from arch/x86/kernel/asm-offsets_64.c:8,
                 from arch/x86/kernel/asm-offsets.c:4:

include/linux/bitops.h:52:1: warning: "HWEIGHT8" redefined
...

due to the fact that we have multiple definitions of HWEIGHT*:

The one batch is in <include/linux/bitops.h> introduced by fce877e3.

The other is in <include/asm-generic/bitops/const_hweight.h> which is pulled in into <include/linux/bitops.h> through "#include <asm/bitops.h>", which, in turn, <includes asm/arch_hweight.h> and <include/asm-generic/bitops/const_hweight.h>.

The obvious resolution is to remove the HWEIGHT* batch from <include/asm-generic/bitops/const_hweight.h> since they're functionally identical with the ones in <include/linux/bitops.h>, no?

Signature · 6 lines
Regards/Gruss,
Boris.

-
Advanced Micro Devices, Inc.
Operating Systems Research Center
maintainer
#97 lore raw

Re: [PATCH] x86: Add optimized popcnt variants

Quoted 26 lines · Borislav Petkov

From: Peter Zijlstra <[email protected]>
Date: Tue, Mar 09, 2010 at 04:50:40PM +0100

Quoted 4 lines

Should all be fine as it is, that patch
( http://lkml.org/lkml/2010/2/4/119 ) is against a kernel with fce877e3 in, I've just checked and it still applies to tip/master as of this writing (although it grew a single 2 line offset for 1 hunk).

Well, this way, I'm getting

...
In file included from include/linux/kernel.h:15,

                 from /home/linux-2.6/arch/x86/include/asm/percpu.h:45,
                 from /home/linux-2.6/arch/x86/include/asm/current.h:5,
                 from /home/linux-2.6/arch/x86/include/asm/processor.h:15,
                 from /home/linux-2.6/arch/x86/include/asm/atomic.h:6,
                 from include/linux/crypto.h:20,
                 from arch/x86/kernel/asm-offsets_64.c:8,
                 from arch/x86/kernel/asm-offsets.c:4:

include/linux/bitops.h:52:1: warning: "HWEIGHT8" redefined
...

due to the fact that we have multiple definitions of HWEIGHT*:

The one batch is in <include/linux/bitops.h> introduced by fce877e3.

Quoted 8 lines

The other is in <include/asm-generic/bitops/const_hweight.h> which is pulled in into <include/linux/bitops.h> through "#include <asm/bitops.h>", which, in turn, <includes asm/arch_hweight.h> and <include/asm-generic/bitops/const_hweight.h>.

The obvious resolution is to remove the HWEIGHT* batch from <include/asm-generic/bitops/const_hweight.h> since they're functionally identical with the ones in <include/linux/bitops.h>, no?

I thought the patch did that, see this hunk (straight from
http://lkml.org/lkml/2010/2/4/119 ):

---

include/linux/bitops.h +0 -25
Index: linux-2.6/include/linux/bitops.h
===================================================================
@@ -45,31 +45,6 @@ static inline unsigned long hweight_long
 	return sizeof(w) == 4 ? hweight32(w) : hweight64(w);
 }
 
-/*
- * Clearly slow versions of the hweightN() functions, their benefit is
- * of course compile time evaluation of constant arguments.
- */
-#define HWEIGHT8(w)					\
-      (	BUILD_BUG_ON_ZERO(!__builtin_constant_p(w)) +	\
-	(!!((w) & (1ULL << 0))) +			\
-	(!!((w) & (1ULL << 1))) +			\
-	(!!((w) & (1ULL << 2))) +			\
-	(!!((w) & (1ULL << 3))) +			\
-	(!!((w) & (1ULL << 4))) +			\
-	(!!((w) & (1ULL << 5))) +			\
-	(!!((w) & (1ULL << 6))) +			\
-	(!!((w) & (1ULL << 7)))	)
-
-#define HWEIGHT16(w) (HWEIGHT8(w)  + HWEIGHT8((w) >> 8))
-#define HWEIGHT32(w) (HWEIGHT16(w) + HWEIGHT16((w) >> 16))
-#define HWEIGHT64(w) (HWEIGHT32(w) + HWEIGHT32((w) >> 32))
-
-/*
- * Type invariant version that simply casts things to the
- * largest type.
- */
-#define HWEIGHT(w)   HWEIGHT64((u64)(w))
-
 /**
  * rol32 - rotate a 32-bit value left
  * @word: value to rotate
#98 lore raw

Re: [PATCH] x86: Add optimized popcnt variants

From: Peter Zijlstra <[email protected]>
Date: Tue, Mar 09, 2010 at 05:32:49PM +0100

Quoted 2 lines

I thought the patch did that, see this hunk (straight from
http://lkml.org/lkml/2010/2/4/119 ):

Bollocks, I seem to have lost that hunk while applying the patch by foot, sorry for the noise.

By the way, I can't seem to find your patch in Andrew's tree, is it still going through his tree?

Signature · 6 lines
Regards/Gruss,
Boris.

-
Advanced Micro Devices, Inc.
Operating Systems Research Center
maintainer
#99 lore raw

Re: [PATCH] x86: Add optimized popcnt variants

Quoted 11 lines · Borislav Petkov

From: Peter Zijlstra <[email protected]>
Date: Tue, Mar 09, 2010 at 05:32:49PM +0100

Quoted 2 lines

I thought the patch did that, see this hunk (straight from
http://lkml.org/lkml/2010/2/4/119 ):

Bollocks, I seem to have lost that hunk while applying the patch by foot, sorry for the noise.

By the way, I can't seem to find your patch in Andrew's tree, is it still going through his tree?

I hope so, Andrew, need me to resend or do you still have a copy?

#100 lore raw

Re: [PATCH] x86: Add optimized popcnt variants

In reply to H. Peter Anvin

From: "H. Peter Anvin" <[email protected]>
Date: Sat, Feb 27, 2010 at 12:00:26PM -0800

Quoted 5 lines · Borislav Petkov
Quoted 4 lines
Quoted 3 lines

I guess, on the other hand, if it ends up not getting merged until .35 it's not a huge deal either.

Quoted 8 lines
Quoted 4 lines

Yeah, let's give it another round of testing and queue it for .35 - AFAIR Ingo runs also a wide testing effort so it spending another cycle in -tip and being hammered on by us could give us a bit more certainty.

Yes, if we can get into -tip then we'll get more test coverage, so I'll queue it up for .35 as soon as the merge window closes. Please remind me if I forget.

Ok, I've been pretty busy lately and this got pushed back on the todo list. I finally got around to do some build-testing with a bunch of compilers and -fcall-saved* seem to get accepted. I haven't stared at their asm output though, yet:

command:
make CC=gcc-<version> HOSTCC=gcc-<version> -j4

compile stats (64bit only):

not ok:
- gcc-3.3 (GCC) 3.3.5 (Debian 1:3.3.5-13): OOM KILLER goes off, gcc-3.3 leak maybe

ok:
- gcc-3.4 (GCC) 3.4.4 20050314 (prerelease) (Debian 3.4.3-13sarge1)
- gcc-4.1 (GCC) 4.1.3 20080704 (prerelease) (Debian 4.1.2-27)
- gcc-4.3 (Debian 4.3.4-6) 4.3.4
- gcc (Debian 4.4.2-6) 4.4.2
- gcc (Debian 4.4.3-3) 4.4.3

- gcc-3.4.6 (GCC) 3.4.6 (Gentoo 3.4.6-r2 p1.6, ssp-3.4.6-1.0, pie-8.7.10)
- gcc-4.1.2 (GCC) 4.1.2 (Gentoo 4.1.2 p1.3)

I'm attaching the versions of the patches I'm using. The first one by PeterZ touches a bunch of arches and Andrew hasn't picked it up yet so the question of getting the second (popcnt) patch to see wider testing in some tree is still unresolved. Suggestions, ideas?

Thanks.

Signature · 6 lines
Regards/Gruss,
Boris.

--
Advanced Micro Devices, Inc.
Operating Systems Research Center
#101 lore raw

PATCH 1/2 bitops: Optimize hweight() by making use of compile-time evaluation

In reply to H. Peter Anvin

From: Peter Zijlstra <[email protected]>
Date: Mon, 1 Feb 2010 15:03:07 +0100
Subject: [PATCH 1/2] bitops: Optimize hweight() by making use of compile-time evaluation

Rename the extisting runtime hweight() implementations to __arch_hweight(), rename the compile-time versions to __const_hweight() and then have hweight() pick between them.

LKML-Reference: <1265028224.24455.154.camel@laptop>

---
 arch/alpha/include/asm/bitops.h            |   18 ++++++-----
 arch/ia64/include/asm/bitops.h             |   11 ++++---
 arch/sparc/include/asm/bitops_64.h         |   11 ++++---
 include/asm-generic/bitops/arch_hweight.h  |   11 +++++++
 include/asm-generic/bitops/const_hweight.h |   42 ++++++++++++++++++++++++++++
 include/asm-generic/bitops/hweight.h       |    8 +----
 include/linux/bitops.h                     |   25 ----------------
 lib/hweight.c                              |   19 ++++++------
 8 files changed, 87 insertions(+), 58 deletions(-)
 create mode 100644 include/asm-generic/bitops/arch_hweight.h
 create mode 100644 include/asm-generic/bitops/const_hweight.h
arch/alpha/include/asm/bitops.h +10 -8
index 15f3ae2..296da1d 100644
@@ -405,29 +405,31 @@ static inline int fls(int x)
 
 #if defined(CONFIG_ALPHA_EV6) && defined(CONFIG_ALPHA_EV67)
 /* Whee.  EV67 can calculate it directly.  */
-static inline unsigned long hweight64(unsigned long w)
+static inline unsigned long __arch_hweight64(unsigned long w)
 {
 	return __kernel_ctpop(w);
 }
 
-static inline unsigned int hweight32(unsigned int w)
+static inline unsigned int __arch_weight32(unsigned int w)
 {
-	return hweight64(w);
+	return __arch_hweight64(w);
 }
 
-static inline unsigned int hweight16(unsigned int w)
+static inline unsigned int __arch_hweight16(unsigned int w)
 {
-	return hweight64(w & 0xffff);
+	return __arch_hweight64(w & 0xffff);
 }
 
-static inline unsigned int hweight8(unsigned int w)
+static inline unsigned int __arch_hweight8(unsigned int w)
 {
-	return hweight64(w & 0xff);
+	return __arch_hweight64(w & 0xff);
 }
 #else
-#include <asm-generic/bitops/hweight.h>
+#include <asm-generic/bitops/arch_hweight.h>
 #endif
 
+#include <asm-generic/bitops/const_hweight.h>
+
 #endif /* __KERNEL__ */
 
 #include <asm-generic/bitops/find.h>
arch/ia64/include/asm/bitops.h +6 -5
index 6ebc229..9da3df6 100644
@@ -437,17 +437,18 @@ __fls (unsigned long x)
  * hweightN: returns the hamming weight (i.e. the number
  * of bits set) of a N-bit word
  */
-static __inline__ unsigned long
-hweight64 (unsigned long x)
+static __inline__ unsigned long __arch_hweight64(unsigned long x)
 {
 	unsigned long result;
 	result = ia64_popcnt(x);
 	return result;
 }
 
-#define hweight32(x)	(unsigned int) hweight64((x) & 0xfffffffful)
-#define hweight16(x)	(unsigned int) hweight64((x) & 0xfffful)
-#define hweight8(x)	(unsigned int) hweight64((x) & 0xfful)
+#define __arch_hweight32(x) ((unsigned int) __arch_hweight64((x) & 0xfffffffful))
+#define __arch_hweight16(x) ((unsigned int) __arch_hweight64((x) & 0xfffful))
+#define __arch_hweight8(x)  ((unsigned int) __arch_hweight64((x) & 0xfful))
+
+#include <asm-generic/bitops/const_hweight.h>
 
 #endif /* __KERNEL__ */
 
arch/sparc/include/asm/bitops_64.h +6 -5
index e72ac9c..766121a 100644
@@ -44,7 +44,7 @@ extern void change_bit(unsigned long nr, volatile unsigned long *addr);
 
 #ifdef ULTRA_HAS_POPULATION_COUNT
 
-static inline unsigned int hweight64(unsigned long w)
+static inline unsigned int __arch_hweight64(unsigned long w)
 {
 	unsigned int res;
 
@@ -52,7 +52,7 @@ static inline unsigned int hweight64(unsigned long w)
 	return res;
 }
 
-static inline unsigned int hweight32(unsigned int w)
+static inline unsigned int __arch_hweight32(unsigned int w)
 {
 	unsigned int res;
 
@@ -60,7 +60,7 @@ static inline unsigned int hweight32(unsigned int w)
 	return res;
 }
 
-static inline unsigned int hweight16(unsigned int w)
+static inline unsigned int __arch_hweight16(unsigned int w)
 {
 	unsigned int res;
 
@@ -68,7 +68,7 @@ static inline unsigned int hweight16(unsigned int w)
 	return res;
 }
 
-static inline unsigned int hweight8(unsigned int w)
+static inline unsigned int __arch_hweight8(unsigned int w)
 {
 	unsigned int res;
 
@@ -78,9 +78,10 @@ static inline unsigned int hweight8(unsigned int w)
 
 #else
 
-#include <asm-generic/bitops/hweight.h>
+#include <asm-generic/bitops/arch_hweight.h>
 
 #endif
+#include <asm-generic/bitops/const_hweight.h>
 #include <asm-generic/bitops/lock.h>
 #endif /* __KERNEL__ */
 
include/asm-generic/bitops/arch_hweight.h new file +11 -0
new file mode 100644
index 0000000..3a7be84
@@ -0,0 +1,11 @@
+#ifndef _ASM_GENERIC_BITOPS_ARCH_HWEIGHT_H_
+#define _ASM_GENERIC_BITOPS_ARCH_HWEIGHT_H_
+
+#include <asm/types.h>
+
+extern unsigned int __arch_hweight32(unsigned int w);
+extern unsigned int __arch_hweight16(unsigned int w);
+extern unsigned int __arch_hweight8(unsigned int w);
+extern unsigned long __arch_hweight64(__u64 w);
+
+#endif /* _ASM_GENERIC_BITOPS_HWEIGHT_H_ */
include/asm-generic/bitops/const_hweight.h new file +42 -0

42 lines not on this page · raw message

include/asm-generic/bitops/hweight.h +2 -6
index fbbc383..a94d651 100644
@@ -1,11 +1,7 @@
 #ifndef _ASM_GENERIC_BITOPS_HWEIGHT_H_
 #define _ASM_GENERIC_BITOPS_HWEIGHT_H_
 
-#include <asm/types.h>
-
-extern unsigned int hweight32(unsigned int w);
-extern unsigned int hweight16(unsigned int w);
-extern unsigned int hweight8(unsigned int w);
-extern unsigned long hweight64(__u64 w);
+#include <asm-generic/bitops/arch_hweight.h>
+#include <asm-generic/bitops/const_hweight.h>
 
 #endif /* _ASM_GENERIC_BITOPS_HWEIGHT_H_ */
include/linux/bitops.h +0 -25
index b793898..c55d5bc 100644
@@ -47,31 +47,6 @@ static inline unsigned long hweight_long(unsigned long w)
 	return sizeof(w) == 4 ? hweight32(w) : hweight64(w);
 }
 
-/*
- * Clearly slow versions of the hweightN() functions, their benefit is
- * of course compile time evaluation of constant arguments.
- */
-#define HWEIGHT8(w)					\
-      (	BUILD_BUG_ON_ZERO(!__builtin_constant_p(w)) +	\
-	(!!((w) & (1ULL << 0))) +			\
-	(!!((w) & (1ULL << 1))) +			\
-	(!!((w) & (1ULL << 2))) +			\
-	(!!((w) & (1ULL << 3))) +			\
-	(!!((w) & (1ULL << 4))) +			\
-	(!!((w) & (1ULL << 5))) +			\
-	(!!((w) & (1ULL << 6))) +			\
-	(!!((w) & (1ULL << 7)))	)
-
-#define HWEIGHT16(w) (HWEIGHT8(w)  + HWEIGHT8((w) >> 8))
-#define HWEIGHT32(w) (HWEIGHT16(w) + HWEIGHT16((w) >> 16))
-#define HWEIGHT64(w) (HWEIGHT32(w) + HWEIGHT32((w) >> 32))
-
-/*
- * Type invariant version that simply casts things to the
- * largest type.
- */
-#define HWEIGHT(w)   HWEIGHT64((u64)(w))
-
 /**
  * rol32 - rotate a 32-bit value left
  * @word: value to rotate
lib/hweight.c +10 -9
index 63ee4eb..a6927e7 100644
@@ -9,7 +9,7 @@
  * The Hamming Weight of a number is the total number of bits set in it.
  */
 
-unsigned int hweight32(unsigned int w)
+unsigned int __arch_hweight32(unsigned int w)
 {
 #ifdef ARCH_HAS_FAST_MULTIPLIER
 	w -= (w >> 1) & 0x55555555;
@@ -24,29 +24,30 @@ unsigned int hweight32(unsigned int w)
 	return (res + (res >> 16)) & 0x000000FF;
 #endif
 }
-EXPORT_SYMBOL(hweight32);
+EXPORT_SYMBOL(__arch_hweight32);
 
-unsigned int hweight16(unsigned int w)
+unsigned int __arch_hweight16(unsigned int w)
 {
 	unsigned int res = w - ((w >> 1) & 0x5555);
 	res = (res & 0x3333) + ((res >> 2) & 0x3333);
 	res = (res + (res >> 4)) & 0x0F0F;
 	return (res + (res >> 8)) & 0x00FF;
 }
-EXPORT_SYMBOL(hweight16);
+EXPORT_SYMBOL(__arch_hweight16);
 
-unsigned int hweight8(unsigned int w)
+unsigned int __arch_hweight8(unsigned int w)
 {
 	unsigned int res = w - ((w >> 1) & 0x55);
 	res = (res & 0x33) + ((res >> 2) & 0x33);
 	return (res + (res >> 4)) & 0x0F;
 }
-EXPORT_SYMBOL(hweight8);
+EXPORT_SYMBOL(__arch_hweight8);
 
-unsigned long hweight64(__u64 w)
+unsigned long __arch_hweight64(__u64 w)
 {
 #if BITS_PER_LONG == 32
-	return hweight32((unsigned int)(w >> 32)) + hweight32((unsigned int)w);
+	return __arch_hweight32((unsigned int)(w >> 32)) +
+	       __arch_hweight32((unsigned int)w);
 #elif BITS_PER_LONG == 64
 #ifdef ARCH_HAS_FAST_MULTIPLIER
 	w -= (w >> 1) & 0x5555555555555555ul;
@@ -63,4 +64,4 @@ unsigned long hweight64(__u64 w)
 #endif
 #endif
 }
-EXPORT_SYMBOL(hweight64);
+EXPORT_SYMBOL(__arch_hweight64);
Signature · 9 lines
1.7.0.2

-- 
Regards/Gruss,
Boris.

--
Advanced Micro Devices, Inc.
Operating Systems Research Center
#102 lore raw

PATCH 2/2 x86: Add optimized popcnt variants

In reply to H. Peter Anvin

From: Borislav Petkov <[email protected]>
Date: Fri, 5 Mar 2010 17:34:46 +0100
Subject: [PATCH 2/2] x86: Add optimized popcnt variants

Add support for the hardware version of the Hamming weight function, popcnt, present in CPUs which advertize it under CPUID, Function 0x0000_0001_ECX[23]. On CPUs which don't support it, we fallback to the default lib/hweight.c sw versions.

A synthetic benchmark comparing popcnt with __sw_hweight64 showed almost a 3x speedup on a F10h machine.

---
 arch/x86/Kconfig                          |    5 ++
 arch/x86/include/asm/alternative.h        |    9 +++-
 arch/x86/include/asm/arch_hweight.h       |   59 +++++++++++++++++++++++++++++
 arch/x86/include/asm/bitops.h             |    4 +-
 include/asm-generic/bitops/arch_hweight.h |   22 +++++++++--
 lib/Makefile                              |    3 +
 lib/hweight.c                             |   20 +++++-----
 scripts/Makefile.lib                      |    4 ++
 8 files changed, 108 insertions(+), 18 deletions(-)
 create mode 100644 arch/x86/include/asm/arch_hweight.h
arch/x86/Kconfig +5 -0
index 0eacb1f..89d8c54 100644
@@ -238,6 +238,11 @@ config X86_32_LAZY_GS
 	def_bool y
 	depends on X86_32 && !CC_STACKPROTECTOR
 
+config ARCH_HWEIGHT_CFLAGS
+	string
+	default "-fcall-saved-ecx -fcall-saved-edx" if X86_32
+	default "-fcall-saved-rdi -fcall-saved-rsi -fcall-saved-rdx -fcall-saved-rcx -fcall-saved-r8 -fcall-saved-r9 -fcall-saved-r10 -fcall-saved-r11" if X86_64
+
 config KTIME_SCALAR
 	def_bool X86_32
 source "init/Kconfig"
arch/x86/include/asm/alternative.h +6 -3
index b09ec55..67dae51 100644
@@ -39,9 +39,6 @@
 #define LOCK_PREFIX ""
 #endif
 
-/* This must be included *after* the definition of LOCK_PREFIX */
-#include <asm/cpufeature.h>
-
 struct alt_instr {
 	u8 *instr;		/* original instruction */
 	u8 *replacement;
@@ -96,6 +93,12 @@ static inline int alternatives_text_reserved(void *start, void *end)
       ".previous"
 
 /*
+ * This must be included *after* the definition of ALTERNATIVE due to
+ * <asm/arch_hweight.h>
+ */
+#include <asm/cpufeature.h>
+
+/*
  * Alternative instructions for different CPU types or capabilities.
  *
  * This allows to use optimized instructions even on generic binary
arch/x86/include/asm/arch_hweight.h new file +59 -0

59 lines not on this page · raw message

arch/x86/include/asm/bitops.h +3 -1
index 02b47a6..545776e 100644
@@ -444,7 +444,9 @@ static inline int fls(int x)
 
 #define ARCH_HAS_FAST_MULTIPLIER 1
 
-#include <asm-generic/bitops/hweight.h>
+#include <asm/arch_hweight.h>
+
+#include <asm-generic/bitops/const_hweight.h>
 
 #endif /* __KERNEL__ */
 
include/asm-generic/bitops/arch_hweight.h +18 -4
index 3a7be84..9a81c1e 100644
@@ -3,9 +3,23 @@
 
 #include <asm/types.h>
 
-extern unsigned int __arch_hweight32(unsigned int w);
-extern unsigned int __arch_hweight16(unsigned int w);
-extern unsigned int __arch_hweight8(unsigned int w);
-extern unsigned long __arch_hweight64(__u64 w);
+inline unsigned int __arch_hweight32(unsigned int w)
+{
+	return __sw_hweight32(w);
+}
 
+inline unsigned int __arch_hweight16(unsigned int w)
+{
+	return __sw_hweight16(w);
+}
+
+inline unsigned int __arch_hweight8(unsigned int w)
+{
+	return __sw_hweight8(w);
+}
+
+inline unsigned long __arch_hweight64(__u64 w)
+{
+	return __sw_hweight64(w);
+}
 #endif /* _ASM_GENERIC_BITOPS_HWEIGHT_H_ */
lib/Makefile +3 -0
index 2e152ae..abe63a8 100644
@@ -39,7 +39,10 @@ lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
 lib-$(CONFIG_GENERIC_FIND_FIRST_BIT) += find_next_bit.o
 lib-$(CONFIG_GENERIC_FIND_NEXT_BIT) += find_next_bit.o
 obj-$(CONFIG_GENERIC_FIND_LAST_BIT) += find_last_bit.o
+
+CFLAGS_hweight.o = $(subst $(quote),,$(CONFIG_ARCH_HWEIGHT_CFLAGS))
 obj-$(CONFIG_GENERIC_HWEIGHT) += hweight.o
+
 obj-$(CONFIG_LOCK_KERNEL) += kernel_lock.o
 obj-$(CONFIG_BTREE) += btree.o
 obj-$(CONFIG_DEBUG_PREEMPT) += smp_processor_id.o
lib/hweight.c +10 -10
index a6927e7..3c79d50 100644
@@ -9,7 +9,7 @@
  * The Hamming Weight of a number is the total number of bits set in it.
  */
 
-unsigned int __arch_hweight32(unsigned int w)
+unsigned int __sw_hweight32(unsigned int w)
 {
 #ifdef ARCH_HAS_FAST_MULTIPLIER
 	w -= (w >> 1) & 0x55555555;
@@ -24,30 +24,30 @@ unsigned int __arch_hweight32(unsigned int w)
 	return (res + (res >> 16)) & 0x000000FF;
 #endif
 }
-EXPORT_SYMBOL(__arch_hweight32);
+EXPORT_SYMBOL(__sw_hweight32);
 
-unsigned int __arch_hweight16(unsigned int w)
+unsigned int __sw_hweight16(unsigned int w)
 {
 	unsigned int res = w - ((w >> 1) & 0x5555);
 	res = (res & 0x3333) + ((res >> 2) & 0x3333);
 	res = (res + (res >> 4)) & 0x0F0F;
 	return (res + (res >> 8)) & 0x00FF;
 }
-EXPORT_SYMBOL(__arch_hweight16);
+EXPORT_SYMBOL(__sw_hweight16);
 
-unsigned int __arch_hweight8(unsigned int w)
+unsigned int __sw_hweight8(unsigned int w)
 {
 	unsigned int res = w - ((w >> 1) & 0x55);
 	res = (res & 0x33) + ((res >> 2) & 0x33);
 	return (res + (res >> 4)) & 0x0F;
 }
-EXPORT_SYMBOL(__arch_hweight8);
+EXPORT_SYMBOL(__sw_hweight8);
 
-unsigned long __arch_hweight64(__u64 w)
+unsigned long __sw_hweight64(__u64 w)
 {
 #if BITS_PER_LONG == 32
-	return __arch_hweight32((unsigned int)(w >> 32)) +
-	       __arch_hweight32((unsigned int)w);
+	return __sw_hweight32((unsigned int)(w >> 32)) +
+	       __sw_hweight32((unsigned int)w);
 #elif BITS_PER_LONG == 64
 #ifdef ARCH_HAS_FAST_MULTIPLIER
 	w -= (w >> 1) & 0x5555555555555555ul;
@@ -64,4 +64,4 @@ unsigned long __arch_hweight64(__u64 w)
 #endif
 #endif
 }
-EXPORT_SYMBOL(__arch_hweight64);
+EXPORT_SYMBOL(__sw_hweight64);
scripts/Makefile.lib +4 -0
index f9bdf26..cbcd654 100644
@@ -245,3 +245,7 @@ quiet_cmd_lzo = LZO    $@
 cmd_lzo = (cat $(filter-out FORCE,$^) | \
 	lzop -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \
 	(rm -f $@ ; false)
+
+# misc stuff
+# ---------------------------------------------------------------------------
+quote:="
Signature · 9 lines
1.7.0.2

-- 
Regards/Gruss,
Boris.

--
Advanced Micro Devices, Inc.
Operating Systems Research Center
#103 lore raw

[tip:core/hweight] x86: Add optimized popcnt variants

Commit-ID:  d61931d89be506372d01a90d1755f6d0a9fafe2d
Gitweb:     http://git.kernel.org/tip/d61931d89be506372d01a90d1755f6d0a9fafe2d
Author:     Borislav Petkov <[email protected]>
AuthorDate: Fri, 5 Mar 2010 17:34:46 +0100
Committer:  H. Peter Anvin <[email protected]>
CommitDate: Tue, 6 Apr 2010 15:52:11 -0700

x86: Add optimized popcnt variants

Add support for the hardware version of the Hamming weight function, popcnt, present in CPUs which advertize it under CPUID, Function 0x0000_0001_ECX[23]. On CPUs which don't support it, we fallback to the default lib/hweight.c sw versions.

A synthetic benchmark comparing popcnt with __sw_hweight64 showed almost a 3x speedup on a F10h machine.

LKML-Reference: <20100318112015.GC11152@aftab>

---
 arch/x86/Kconfig                          |    5 ++
 arch/x86/include/asm/alternative.h        |    9 +++-
 arch/x86/include/asm/arch_hweight.h       |   59 +++++++++++++++++++++++++++++
 arch/x86/include/asm/bitops.h             |    4 +-
 include/asm-generic/bitops/arch_hweight.h |   22 +++++++++--
 lib/Makefile                              |    3 +
 lib/hweight.c                             |   20 +++++-----
 scripts/Makefile.lib                      |    4 ++
 8 files changed, 108 insertions(+), 18 deletions(-)
arch/x86/Kconfig +5 -0
index 0eacb1f..89d8c54 100644
@@ -238,6 +238,11 @@ config X86_32_LAZY_GS
 	def_bool y
 	depends on X86_32 && !CC_STACKPROTECTOR
 
+config ARCH_HWEIGHT_CFLAGS
+	string
+	default "-fcall-saved-ecx -fcall-saved-edx" if X86_32
+	default "-fcall-saved-rdi -fcall-saved-rsi -fcall-saved-rdx -fcall-saved-rcx -fcall-saved-r8 -fcall-saved-r9 -fcall-saved-r10 -fcall-saved-r11" if X86_64
+
 config KTIME_SCALAR
 	def_bool X86_32
 source "init/Kconfig"
arch/x86/include/asm/alternative.h +6 -3
index b09ec55..67dae51 100644
@@ -39,9 +39,6 @@
 #define LOCK_PREFIX ""
 #endif
 
-/* This must be included *after* the definition of LOCK_PREFIX */
-#include <asm/cpufeature.h>
-
 struct alt_instr {
 	u8 *instr;		/* original instruction */
 	u8 *replacement;
@@ -96,6 +93,12 @@ static inline int alternatives_text_reserved(void *start, void *end)
       ".previous"
 
 /*
+ * This must be included *after* the definition of ALTERNATIVE due to
+ * <asm/arch_hweight.h>
+ */
+#include <asm/cpufeature.h>
+
+/*
  * Alternative instructions for different CPU types or capabilities.
  *
  * This allows to use optimized instructions even on generic binary
arch/x86/include/asm/arch_hweight.h new file +59 -0

59 lines not on this page · raw message

arch/x86/include/asm/bitops.h +3 -1
index 02b47a6..545776e 100644
@@ -444,7 +444,9 @@ static inline int fls(int x)
 
 #define ARCH_HAS_FAST_MULTIPLIER 1
 
-#include <asm-generic/bitops/hweight.h>
+#include <asm/arch_hweight.h>
+
+#include <asm-generic/bitops/const_hweight.h>
 
 #endif /* __KERNEL__ */
 
include/asm-generic/bitops/arch_hweight.h +18 -4
index 3a7be84..9a81c1e 100644
@@ -3,9 +3,23 @@
 
 #include <asm/types.h>
 
-extern unsigned int __arch_hweight32(unsigned int w);
-extern unsigned int __arch_hweight16(unsigned int w);
-extern unsigned int __arch_hweight8(unsigned int w);
-extern unsigned long __arch_hweight64(__u64 w);
+inline unsigned int __arch_hweight32(unsigned int w)
+{
+	return __sw_hweight32(w);
+}
 
+inline unsigned int __arch_hweight16(unsigned int w)
+{
+	return __sw_hweight16(w);
+}
+
+inline unsigned int __arch_hweight8(unsigned int w)
+{
+	return __sw_hweight8(w);
+}
+
+inline unsigned long __arch_hweight64(__u64 w)
+{
+	return __sw_hweight64(w);
+}
 #endif /* _ASM_GENERIC_BITOPS_HWEIGHT_H_ */
lib/Makefile +3 -0
index 2e152ae..abe63a8 100644
@@ -39,7 +39,10 @@ lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
 lib-$(CONFIG_GENERIC_FIND_FIRST_BIT) += find_next_bit.o
 lib-$(CONFIG_GENERIC_FIND_NEXT_BIT) += find_next_bit.o
 obj-$(CONFIG_GENERIC_FIND_LAST_BIT) += find_last_bit.o
+
+CFLAGS_hweight.o = $(subst $(quote),,$(CONFIG_ARCH_HWEIGHT_CFLAGS))
 obj-$(CONFIG_GENERIC_HWEIGHT) += hweight.o
+
 obj-$(CONFIG_LOCK_KERNEL) += kernel_lock.o
 obj-$(CONFIG_BTREE) += btree.o
 obj-$(CONFIG_DEBUG_PREEMPT) += smp_processor_id.o
lib/hweight.c +10 -10
index a6927e7..3c79d50 100644
@@ -9,7 +9,7 @@
  * The Hamming Weight of a number is the total number of bits set in it.
  */
 
-unsigned int __arch_hweight32(unsigned int w)
+unsigned int __sw_hweight32(unsigned int w)
 {
 #ifdef ARCH_HAS_FAST_MULTIPLIER
 	w -= (w >> 1) & 0x55555555;
@@ -24,30 +24,30 @@ unsigned int __arch_hweight32(unsigned int w)
 	return (res + (res >> 16)) & 0x000000FF;
 #endif
 }
-EXPORT_SYMBOL(__arch_hweight32);
+EXPORT_SYMBOL(__sw_hweight32);
 
-unsigned int __arch_hweight16(unsigned int w)
+unsigned int __sw_hweight16(unsigned int w)
 {
 	unsigned int res = w - ((w >> 1) & 0x5555);
 	res = (res & 0x3333) + ((res >> 2) & 0x3333);
 	res = (res + (res >> 4)) & 0x0F0F;
 	return (res + (res >> 8)) & 0x00FF;
 }
-EXPORT_SYMBOL(__arch_hweight16);
+EXPORT_SYMBOL(__sw_hweight16);
 
-unsigned int __arch_hweight8(unsigned int w)
+unsigned int __sw_hweight8(unsigned int w)
 {
 	unsigned int res = w - ((w >> 1) & 0x55);
 	res = (res & 0x33) + ((res >> 2) & 0x33);
 	return (res + (res >> 4)) & 0x0F;
 }
-EXPORT_SYMBOL(__arch_hweight8);
+EXPORT_SYMBOL(__sw_hweight8);
 
-unsigned long __arch_hweight64(__u64 w)
+unsigned long __sw_hweight64(__u64 w)
 {
 #if BITS_PER_LONG == 32
-	return __arch_hweight32((unsigned int)(w >> 32)) +
-	       __arch_hweight32((unsigned int)w);
+	return __sw_hweight32((unsigned int)(w >> 32)) +
+	       __sw_hweight32((unsigned int)w);
 #elif BITS_PER_LONG == 64
 #ifdef ARCH_HAS_FAST_MULTIPLIER
 	w -= (w >> 1) & 0x5555555555555555ul;
@@ -64,4 +64,4 @@ unsigned long __arch_hweight64(__u64 w)
 #endif
 #endif
 }
-EXPORT_SYMBOL(__arch_hweight64);
+EXPORT_SYMBOL(__sw_hweight64);
scripts/Makefile.lib +4 -0
index f9bdf26..cbcd654 100644
@@ -245,3 +245,7 @@ quiet_cmd_lzo = LZO    $@
 cmd_lzo = (cat $(filter-out FORCE,$^) | \
 	lzop -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \
 	(rm -f $@ ; false)
+
+# misc stuff
+# ---------------------------------------------------------------------------
+quote:="
#104 lore raw

Re: [tip:core/hweight] x86: Add optimized popcnt variants

From: tip-bot for Borislav Petkov <[email protected]>
Date: Tue, Apr 06, 2010 at 11:04:07PM +0000

Quoted 6 lines
Commit-ID:  d61931d89be506372d01a90d1755f6d0a9fafe2d
Gitweb:     http://git.kernel.org/tip/d61931d89be506372d01a90d1755f6d0a9fafe2d
Author:     Borislav Petkov <[email protected]>
AuthorDate: Fri, 5 Mar 2010 17:34:46 +0100
Committer:  H. Peter Anvin <[email protected]>
CommitDate: Tue, 6 Apr 2010 15:52:11 -0700

Just so you know, Andrew picked those up already, along with Peter's multi-arch-touching patch.

Signature · 6 lines
Regards/Gruss,
Boris.

--
Advanced Micro Devices, Inc.
Operating Systems Research Center
maintainer
#105 lore raw

Re: [PATCH 2/5] bitops: compile time optimization for hweight_long(CONSTANT)

In reply to Michal Marek
Quoted 8 lines · Michal Marek
Quoted 7 lines · H. Peter Anvin
Quoted 5 lines · Borislav Petkov

However, this is generic code and for the above to work we have to enforce x86-specific CFLAGS for it. What is the preferred way to do that?

Quoted 7 lines
Quoted 1 line

That's a question for Michal and the kbuild list. Michal?

(I was offline last week).

The _preferred_ way probably is not to do it :), but otherwise you can set CFLAGS_hweight.o depending on CONFIG_X86(_32|_64), just like you do in arch/x86/lib/Makefile already.

I guess one way to achieve that is to create a arch/x86/lib/hweight.c that includes lib/hweight.c and give the x86 one special compile flags and not build the lib on.

#106 lore raw

Re: [PATCH 2/5] bitops: compile time optimization for hweight_long(CONSTANT)

Quoted 3 lines · Peter Zijlstra

I guess one way to achieve that is to create a arch/x86/lib/hweight.c that includes lib/hweight.c and give the x86 one special compile flags and not build the lib on.

That's what I thought initially too but that won't fly because the lib/hweight.c helpers have to be inlined into arch/x86/lib/hweight.c so that gcc can take care of the clobbered registers. Otherwise, it just a "call __sw_hweightXX" that gets issued into asm.

Signature · 6 lines
Regards/Gruss,
Boris.

-
Advanced Micro Devices, Inc.
Operating Systems Research Center
maintainer
#107 lore raw

Re: [PATCH 2/5] bitops: compile time optimization for hweight_long(CONSTANT)

In reply to Borislav Petkov
Quoted 8 lines · Borislav Petkov
Quoted 2 lines · Borislav Petkov

Let me prep another version when I get back on Wed. (currently travelling) with all the stuff we discussed to see how it would turn.

Ok, here's another version ontop of PeterZ's patch at
http://lkml.org/lkml/2010/2/4/119. I need to handle 32- and 64-bit differently wrt to popcnt opcode so on 32-bit I do "popcnt %eax, %eax" while on 64-bit I do "popcnt %rdi, %rdi".

Right, so I don't like how you need to touch !x86 for this, and I think that is easily avoidable by not making x86 include asm-generic/bitops/arch_hweight.h.

If you then add __sw_hweightN() -> __arch_hweightN() wrappers in arch_hweight.h, then you can leave const_hweight.h use __arch_hweightN() and simply provide __arch_hweightN() from x86/include/asm/bitops.h

#108 lore raw

Re: [PATCH 2/5] bitops: compile time optimization for hweight_long(CONSTANT)

Quoted 10 lines · Peter Zijlstra
Quoted 8 lines · Borislav Petkov
Quoted 2 lines · Borislav Petkov

Let me prep another version when I get back on Wed. (currently travelling) with all the stuff we discussed to see how it would turn.

Ok, here's another version ontop of PeterZ's patch at
http://lkml.org/lkml/2010/2/4/119. I need to handle 32- and 64-bit differently wrt to popcnt opcode so on 32-bit I do "popcnt %eax, %eax" while on 64-bit I do "popcnt %rdi, %rdi".

Quoted 7 lines

Right, so I don't like how you need to touch !x86 for this, and I think that is easily avoidable by not making x86 include asm-generic/bitops/arch_hweight.h.

If you then add __sw_hweightN() -> __arch_hweightN() wrappers in arch_hweight.h, then you can leave const_hweight.h use __arch_hweightN() and simply provide __arch_hweightN() from x86/include/asm/bitops.h

Hmm, all these different names start to get a little confusing. Can we first agree on the naming please, here's my proposal:

__const_hweightN - for at compile time known constants as arguments __arch_hweightN - arch possibly has an optimized hweight version __sw_hweightN - fall back when nothing else is there, aka the functions in lib/hweight.c

Now, in the x86 case, when the compiler can't know that the argument is a constant, we call the __arch_hweightN versions. The alternative does call the __sw_hweightN version in case the CPU doesn't support popcnt. In this case, we need to build __sw_hweightN with -fcall-saved* for gcc to be able to take care of the regs clobbered ny __sw_hweightN.

So, if I understand you correctly, your suggestion might work, we simply need to rename the lib/hweight.c versions to __sw_hweightN and have <asm-generic/bitops/arch_hweight.h> have __arch_hweightN -> __sw_hweightN wrappers in the default case, all arches which have an optimized version will provide it in their respective bitops header...

Hows that?

Signature · 2 lines
Regards/Gruss,
    Boris.
maintainer
#109 lore raw

Re: [PATCH 2/5] bitops: compile time optimization for hweight_long(CONSTANT)

Quoted 7 lines · Borislav Petkov

So, if I understand you correctly, your suggestion might work, we simply need to rename the lib/hweight.c versions to __sw_hweightN and have <asm-generic/bitops/arch_hweight.h> have __arch_hweightN -> __sw_hweightN wrappers in the default case, all arches which have an optimized version will provide it in their respective bitops header...

I'm not quite sure what the last 'it' refers to, does that refer to:
1) an __arch_hweightN() implementation, or
2) __arch_hweightN() -> __sw_hweightN() wrappers ?

If you meant 1, then yes.

#110 lore raw

Re: [PATCH 2/5] bitops: compile time optimization for hweight_long(CONSTANT)

Quoted 8 lines · Peter Zijlstra
Quoted 7 lines · Borislav Petkov

So, if I understand you correctly, your suggestion might work, we simply need to rename the lib/hweight.c versions to __sw_hweightN and have <asm-generic/bitops/arch_hweight.h> have __arch_hweightN -> __sw_hweightN wrappers in the default case, all arches which have an optimized version will provide it in their respective bitops header...

Quoted 5 lines

I'm not quite sure what the last 'it' refers to, does that refer to:
1) an __arch_hweightN() implementation, or
2) __arch_hweightN() -> __sw_hweightN() wrappers ?

If you meant 1, then yes.

Yes, I mean all architectures which have an optimized hweight will use that optimized version in their __arch_hweightN while as a default fallback for the remaining architectures we'll have __arch_hweightN() -> __sw_hweightN() wrappers in <asm-generic/bitops/arch_hweight.h>.

Signature · 6 lines
Regards/Gruss,
Boris.

-
Advanced Micro Devices, Inc.
Operating Systems Research Center
#111 lore raw

Re: [PATCH 2/5] bitops: compile time optimization for hweight_long(CONSTANT)

In reply to Borislav Petkov
Quoted 12 lines · Borislav Petkov

__const_hweightN - for at compile time known constants as arguments __arch_hweightN - arch possibly has an optimized hweight version __sw_hweightN - fall back when nothing else is there, aka the functions in lib/hweight.c

Now, in the x86 case, when the compiler can't know that the argument is a constant, we call the __arch_hweightN versions. The alternative does call the __sw_hweightN version in case the CPU doesn't support popcnt. In this case, we need to build __sw_hweightN with -fcall-saved* for gcc to be able to take care of the regs clobbered ny __sw_hweightN.

Quoted 6 lines

So, if I understand you correctly, your suggestion might work, we simply need to rename the lib/hweight.c versions to __sw_hweightN and have <asm-generic/bitops/arch_hweight.h> have __arch_hweightN -> __sw_hweightN wrappers in the default case, all arches which have an optimized version will provide it in their respective bitops header...

I'm not entirely sure what you're asking; if what you're asking what to name an x86-specific fallback function, it presumably should be __arch_sw_hweightN (i.e. __arch prefix with a modifier.)

-hpa

Signature · 2 lines
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel.  I don't speak on their behalf.
#112 lore raw

Re: [PATCH 2/5] bitops: compile time optimization for hweight_long(CONSTANT)

Quoted 20 lines · H. Peter Anvin
Quoted 12 lines · Borislav Petkov

__const_hweightN - for at compile time known constants as arguments __arch_hweightN - arch possibly has an optimized hweight version __sw_hweightN - fall back when nothing else is there, aka the functions in lib/hweight.c

Now, in the x86 case, when the compiler can't know that the argument is a constant, we call the __arch_hweightN versions. The alternative does call the __sw_hweightN version in case the CPU doesn't support popcnt. In this case, we need to build __sw_hweightN with -fcall-saved* for gcc to be able to take care of the regs clobbered ny __sw_hweightN.

Quoted 6 lines

So, if I understand you correctly, your suggestion might work, we simply need to rename the lib/hweight.c versions to __sw_hweightN and have <asm-generic/bitops/arch_hweight.h> have __arch_hweightN -> __sw_hweightN wrappers in the default case, all arches which have an optimized version will provide it in their respective bitops header...

Quoted 3 lines

I'm not entirely sure what you're asking; if what you're asking what to name an x86-specific fallback function, it presumably should be __arch_sw_hweightN (i.e. __arch prefix with a modifier.)

Hmm, basically, what PeterZ suggested is that I drop one indirection under __arch_hweightN, which would make x86-specific fallback functions superfluous.

IOW, what we have so far is:

#define hweightN(w) (__builtin_constant_p(w) ? __const_hweightN(w) : __arch_hweightN(w))

and have <asm-generic/bitops/arch_hweight.h> provide __arch_hweightN() -> __sw_hweightN wrappers per default, where the __sw_hweightN are the lib/hweight.c generic versions.

On architectures/CPUs which provide popcnt in
hardware, we create __arch_hweightN implementations in <arch/[:ARCH_NAME:]/include/asm/bitops.h> overriding the <asm-generic/bitops/arch_hweight.h> versions by simply not including that last header.

Is that agreeable?

Signature · 2 lines
Regards/Gruss,
    Boris.
#113 lore raw

Re: [PATCH 2/5] bitops: compile time optimization for hweight_long(CONSTANT)

Quoted 13 lines · Borislav Petkov

Hmm, basically, what PeterZ suggested is that I drop one indirection under __arch_hweightN, which would make x86-specific fallback functions superfluous.

IOW, what we have so far is:

#define hweightN(w) (__builtin_constant_p(w) ? __const_hweightN(w) : __arch_hweightN(w))

and have <asm-generic/bitops/arch_hweight.h> provide __arch_hweightN() -> __sw_hweightN wrappers per default, where the __sw_hweightN are the lib/hweight.c generic versions.

Quoted 8 lines

On architectures/CPUs which provide popcnt in
hardware, we create __arch_hweightN implementations in <arch/[:ARCH_NAME:]/include/asm/bitops.h> overriding the <asm-generic/bitops/arch_hweight.h> versions by simply not including that last header.

Is that agreeable?

That makes sense... after all, that's a pretty typical use of asm-generic.

-hpa

Signature · 2 lines
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel.  I don't speak on their behalf.
#114 lore raw

Re: [PATCH 2/5] bitops: compile time optimization for hweight_long(CONSTANT)

In reply to Borislav Petkov
Quoted 13 lines · Borislav Petkov

Hmm, basically, what PeterZ suggested is that I drop one indirection under __arch_hweightN, which would make x86-specific fallback functions superfluous.

IOW, what we have so far is:

#define hweightN(w) (__builtin_constant_p(w) ? __const_hweightN(w) : __arch_hweightN(w))

and have <asm-generic/bitops/arch_hweight.h> provide __arch_hweightN() -> __sw_hweightN wrappers per default, where the __sw_hweightN are the lib/hweight.c generic versions.

Quoted 8 lines

On architectures/CPUs which provide popcnt in
hardware, we create __arch_hweightN implementations in <arch/[:ARCH_NAME:]/include/asm/bitops.h> overriding the <asm-generic/bitops/arch_hweight.h> versions by simply not including that last header.

Is that agreeable?

That makes sense... after all, that's a pretty typical use of asm-generic.

-hpa

Signature · 2 lines
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel.  I don't speak on their behalf.
#115 lore raw

Re: [PATCH 2/5] bitops: compile time optimization for hweight_long(CONSTANT)

In reply to Borislav Petkov
Quoted 13 lines · Borislav Petkov
Quoted 4 lines

Arguably the "best" option is to have the alternative being a jump to an out-of-line stub which does the necessary parameter marshalling before calling a stub. This technique is already used in a few other places.

Ok, here's a first alpha prototype and completely untested. The asm output looks ok though. I've added separate 32-bit and 64-bit helpers in order to dispense with the if-else tests. The hw-popcnt versions are the opcodes for "popcnt %eax, %eax" and "popcnt %rax, %rax", respectively, so %rAX has to be preloaded with the bitmask and the computed value has to be retrieved from there afterwards. And yes, it looks not that elegant so I'm open for suggestions.

Quoted 7 lines

The good thing is, this should work on any toolchain since we don't rely on the compiler to know about popcnt and we're protected by CPUID flag so that the hw-popcnt version is used only on processors which support it.

Please take a good look and let me know what do you guys think.

I think you misunderstood me. The idea was to use the alternatives mechanism to put the popcnt instruction inline instead of the call.

-hpa

Signature · 2 lines
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel.  I don't speak on their behalf.
#116 lore raw

Re: [PATCH 2/5] bitops: compile time optimization for hweight_long(CONSTANT)

In reply to Borislav Petkov

2010/2/4 Borislav Petkov <[email protected]>:

Quoted 74 lines · H. Peter Anvin
Quoted 5 lines · Peter Zijlstra
Quoted 4 lines · Borislav Petkov
Quoted 2 lines

alternative("call hweightXX", "popcnt", X86_FEATURE_POPCNT)

Quoted 8 lines
Quoted 4 lines

Make sure to apply a 0xff bitmask to the popcnt r16 call for hweight8(), and hweight64() needs a bit of magic for 32bit, but yes, something like that ought to work nicely.

Arguably the "best" option is to have the alternative being a jump to an out-of-line stub which does the necessary parameter marshalling before calling a stub.  This technique is already used in a few other places.

Ok, here's a first alpha prototype and completely untested. The asm output looks ok though. I've added separate 32-bit and 64-bit helpers in order to dispense with the if-else tests. The hw-popcnt versions are the opcodes for "popcnt %eax, %eax" and "popcnt %rax, %rax", respectively, so %rAX has to be preloaded with the bitmask and the computed value has to be retrieved from there afterwards. And yes, it looks not that elegant so I'm open for suggestions.

The good thing is, this should work on any toolchain since we don't rely on the compiler to know about popcnt and we're protected by CPUID flag so that the hw-popcnt version is used only on processors which support it.

Please take a good look and let me know what do you guys think.

Thanks.

--
 arch/x86/include/asm/bitops.h |    4 ++
 arch/x86/lib/Makefile         |    2 +-
 arch/x86/lib/popcnt.c         |   62 +++++++++++++++++++++++++++++++++++++++++

 3 files changed, 67 insertions(+), 1 deletions(-)

 create mode 100644 arch/x86/lib/popcnt.c

arch/x86/include/asm/bitops.h +4 -0
index 02b47a6..deb5013 100644
@@ -434,6 +434,10 @@ static inline int fls(int x)
  #endif
        return r + 1;
  }
+
+
+extern int arch_hweight_long(unsigned long);
+
  #endif /* __KERNEL__ */
 
  #undef ADDR
arch/x86/lib/Makefile +0 -0
index cffd754..c03fe2d 100644
@@ -22,7 +22,7 @@ lib-y += usercopy_$(BITS).o getuser.o putuser.o

 lib-y += memcpy_$(BITS).o
 lib-$(CONFIG_KPROBES) += insn.o inat.o

arch/x86/lib/Makefile +1 -1
-obj-y += msr.o msr-reg.o msr-reg-export.o
+obj-y += msr.o msr-reg.o msr-reg-export.o popcnt.o

 ifeq ($(CONFIG_X86_32),y)
        obj-y += atomic64_32.o

arch/x86/lib/popcnt.c new file +1 -0
new file mode 100644
index 0000000..179a6e8
@@ -0,0 +1,62 @@
+#include <linux/kernel.h>

arch/x86/lib/popcnt.c line 11

Quoted 10 lines
arch/x86/lib/popcnt.c new file +10 -0
+#include <linux/bitops.h>
+
+int _hweight32(void)
+{
+       unsigned long w;
+
+       asm volatile("" : "=a" (w));
+
+       return hweight32(w);
+

You should just use a normal parameter here (use %rdi for 64-bit). The way you have it written isn't guaranteed to work. GCC could clobber %eax/%rax before you read it, although it is highly unlikely. For a good example of how this should be written, look at __mutex_fastpath_lock().

--
Brian Gerst
--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#117 lore raw

Re: [PATCH 2/5] bitops: compile time optimization for hweight_long(CONSTANT)

In reply to Wu Fengguang
Quoted 5 lines · Wu Fengguang
Quoted 4 lines

(I wonder if it could have used __builtin_popcount)

(I wonder which gcc versions support __builtin_popcount)

I think 4.0 or later, but it often generates calls to libgcc, which would mean adding libgcc functions to the kernel (which some arches already do.)

Quoted 7 lines

This is how Jamie Lokier first recommended it to me:

Checked GCC 3.4.3 / 4.1 / 4.4: It expands as a compile-time constant if the argument is a compile-time constant, so can be used in BUILD_BUG_ON() and even for array sizes etc.

Is there an official lowest GCC version that Linux supports?

3.4, I believe.

-hpa

Signature · 2 lines
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel.  I don't speak on their behalf.
#118 lore raw

PATCH 3/5 vfs: O_* bit numbers uniqueness check

In reply to Wu Fengguang

The O_* bit numbers are defined in 20+ arch/*, and can silently overlap. Add a compile time check to ensure the uniqueness as suggested by David Miller.

v4: use the nice hweight_long() (suggested by Jamie)
split O_SYNC to (__O_SYNC | O_DSYNC) (suggested by Andreas) take away the FMODE_* and O_RANDOM bits
v3: change to BUILD_BUG_ON() (suggested by Roland)

CC David Miller <[email protected]>
CC Stephen Rothwell <[email protected]>
CC Al Viro <[email protected]>
CC Christoph Hellwig <[email protected]>
CC Eric Paris <[email protected]>
CC Roland Dreier <[email protected]>
CC Jamie Lokier <[email protected]>
CC Andreas Schwab <[email protected]>
---
 fs/fcntl.c                  |   14 ++++++++++++--
 include/asm-generic/fcntl.h |    2 ++
 2 files changed, 14 insertions(+), 2 deletions(-)
fs/fcntl.c +12 -2
@@ -741,11 +741,21 @@ void kill_fasync(struct fasync_struct **
 }
 EXPORT_SYMBOL(kill_fasync);
 
-static int __init fasync_init(void)
+static int __init fcntl_init(void)
 {
+	/* please add new bits here to ensure allocation uniqueness */
+	BUILD_BUG_ON(17 != hweight_long(
+		O_RDONLY	| O_WRONLY	| O_RDWR	|
+		O_CREAT		| O_EXCL	| O_NOCTTY	|
+		O_TRUNC		| O_APPEND	| O_NONBLOCK	|
+		__O_SYNC	| O_DSYNC	| FASYNC	|
+		O_DIRECT	| O_LARGEFILE	| O_DIRECTORY	|
+		O_NOFOLLOW	| O_NOATIME	| O_CLOEXEC
+		));
+
 	fasync_cache = kmem_cache_create("fasync_cache",
 		sizeof(struct fasync_struct), 0, SLAB_PANIC, NULL);
 	return 0;
 }
 
-module_init(fasync_init)
+module_init(fcntl_init)
include/asm-generic/fcntl.h +2 -0
@@ -4,6 +4,8 @@
 #include <linux/types.h>
 
 /*
+ * When introducing new O_* bits, please check its uniqueness in fcntl_init().
+ *
  * FMODE_EXEC is 0x20
  * FMODE_NONOTIFY is 0x1000000
  * These cannot be used by userspace O_* until internal and external open
#119 lore raw

PATCH 4/5 vfs: introduce FMODE_NEG_OFFSET for allowing negative f_pos

In reply to Wu Fengguang

From: KAMEZAWA Hiroyuki <[email protected]>

Now, rw_verify_area() checsk f_pos is negative or not. And if negative, returns -EINVAL.

But, some special files as /dev/(k)mem and /proc/<pid>/mem etc.. has negative offsets. And we can't do any access via read/write to the file(device).

So introduce FMODE_NEG_OFFSET to allow negative file offsets.

Changelog: v5->v6
- use FMODE_NEG_OFFSET (suggested by Al)
- rebased onto 2.6.33-rc1

Changelog: v4->v5
- clean up patches dor /dev/mem.
- rebased onto 2.6.32-rc1

Changelog: v3->v4
- make changes in mem.c aligned.
- change __negative_fpos_check() to return int.
- fixed bug in "pos" check.
- added comments.

Changelog: v2->v3
- fixed bug in rw_verify_area (it cannot be compiled)

---
 drivers/char/mem.c |    4 ++++
 fs/proc/base.c     |    2 ++
 fs/read_write.c    |   21 +++++++++++++++++++--
 include/linux/fs.h |    3 +++
 4 files changed, 28 insertions(+), 2 deletions(-)
fs/read_write.c +19 -2
@@ -205,6 +205,20 @@ bad:
 }
 #endif
 
+static int
+__negative_fpos_check(struct file *file, loff_t pos, size_t count)
+{
+	/*
+	 * pos or pos+count is negative here, check overflow.
+	 * too big "count" will be caught in rw_verify_area().
+	 */
+	if ((pos < 0) && (pos + count < pos))
+		return -EOVERFLOW;
+	if (file->f_mode & FMODE_NEG_OFFSET)
+		return 0;
+	return -EINVAL;
+}
+
 /*
  * rw_verify_area doesn't like huge counts. We limit
  * them to something that fits in "int" so that others
@@ -222,8 +236,11 @@ int rw_verify_area(int read_write, struc
 	if (unlikely((ssize_t) count < 0))
 		return retval;
 	pos = *ppos;
-	if (unlikely((pos < 0) || (loff_t) (pos + count) < 0))
-		return retval;
+	if (unlikely((pos < 0) || (loff_t) (pos + count) < 0)) {
+		retval = __negative_fpos_check(file, pos, count);
+		if (retval)
+			return retval;
+	}
 
 	if (unlikely(inode->i_flock && mandatory_lock(inode))) {
 		retval = locks_mandatory_area(
include/linux/fs.h +3 -0
@@ -93,6 +93,9 @@ struct inodes_stat_t {
 /* File was opened by fanotify and shouldn't generate fanotify events */
 #define FMODE_NONOTIFY		((__force fmode_t)0x1000000)
 
+/* File is huge (eg. /dev/kmem): treat loff_t as unsigned */
+#define FMODE_NEG_OFFSET	((__force fmode_t)0x2000)
+
 /*
  * The below are the various read and write types that we support. Some of
  * them include behavioral modifiers that send information down to the
drivers/char/mem.c +4 -0
@@ -882,6 +882,10 @@ static int memory_open(struct inode *ino
 	if (dev->dev_info)
 		filp->f_mapping->backing_dev_info = dev->dev_info;
 
+	/* Is /dev/mem or /dev/kmem ? */
+	if (dev->dev_info == &directly_mappable_cdev_bdi)
+		filp->f_mode |= FMODE_NEG_OFFSET;
+
 	if (dev->fops->open)
 		return dev->fops->open(inode, filp);
 
fs/proc/base.c +2 -0
@@ -880,6 +880,8 @@ static const struct file_operations proc
 static int mem_open(struct inode* inode, struct file* file)
 {
 	file->private_data = (void*)((long)current->self_exec_id);
+	/* OK to pass negative loff_t, we can catch out-of-range */
+	file->f_mode |= FMODE_NEG_OFFSET;
 	return 0;
 }
 
#120 lore raw

PATCH 5/5 devmem: dont allow seek to last page

In reply to Wu Fengguang

So as to return a uniform error -EOVERFLOW instead of a random one:

# kmem-seek 0xfffffffffffffff0
seek /dev/kmem: Device or resource busy
# kmem-seek 0xfffffffffffffff1
seek /dev/kmem: Block device required

Suggested by OGAWA Hirofumi.

---
 drivers/char/mem.c |   19 +++++++++++++------
 1 file changed, 13 insertions(+), 6 deletions(-)
drivers/char/mem.c +13 -6
@@ -721,16 +721,23 @@ static loff_t memory_lseek(struct file *
 
 	mutex_lock(&file->f_path.dentry->d_inode->i_mutex);
 	switch (orig) {
-		case 0:
+		case SEEK_CUR:
+			offset += file->f_pos;
+			if ((unsigned long long)offset <
+			    (unsigned long long)file->f_pos) {
+				ret = -EOVERFLOW;
+				break;
+			}
+		case SEEK_SET:
+			/* to avoid userland mistaking f_pos=-9 as -EBADF=-9 */
+			if ((unsigned long long)offset >= ~0xFFFULL) {
+				ret = -EOVERFLOW;
+				break;
+			}
 			file->f_pos = offset;
 			ret = file->f_pos;
 			force_successful_syscall_return();
 			break;
-		case 1:
-			file->f_pos += offset;
-			ret = file->f_pos;
-			force_successful_syscall_return();
-			break;
 		default:
 			ret = -EINVAL;
 	}