[coreboot-gerrit] Change in coreboot[master]: cpu/x86/mtrr: Optimize optimize_var_mtrr_hole()

Nico Huber (Code Review) gerrit at coreboot.org
Fri Oct 20 16:03:32 CEST 2017


Nico Huber has uploaded this change for review. ( https://review.coreboot.org/22119


Change subject: cpu/x86/mtrr: Optimize optimize_var_mtrr_hole()
......................................................................

cpu/x86/mtrr: Optimize optimize_var_mtrr_hole()

This alternative implementation reduces runtime complexity a lot. But
as numbers are small, it only gains us about 1us. Also, the original
implementation is more explicit about what is done.

Change-Id: Idcdc0f3a4cc9be8592454bf977feb99deb0f529e
Signed-off-by: Nico Huber <nico.h at gmx.de>
---
M src/cpu/x86/mtrr/mtrr.c
1 file changed, 38 insertions(+), 27 deletions(-)



  git pull ssh://review.coreboot.org:29418/coreboot refs/changes/19/22119/1

diff --git a/src/cpu/x86/mtrr/mtrr.c b/src/cpu/x86/mtrr/mtrr.c
index 6f1aef0..6bcc8c0 100644
--- a/src/cpu/x86/mtrr/mtrr.c
+++ b/src/cpu/x86/mtrr/mtrr.c
@@ -457,8 +457,7 @@
 	}
 }
 
-static uint32_t optimize_var_mtrr_hole(struct var_mtrr_state *const var_state,
-				       const uint32_t base,
+static uint32_t optimize_var_mtrr_hole(const uint32_t base,
 				       const uint32_t hole,
 				       const uint64_t limit,
 				       const int carve_hole)
@@ -468,7 +467,7 @@
 	 * range with unaligned upper end, by aligning it up and
 	 * carving the added "hole" out again.
 	 *
-	 * To optimize the upper end of the hole, we will test
+	 * To optimize the upper end of the hole, we will predict
 	 * how many MTRRs calc_var_mtrr_range() will spend for any
 	 * alignment of the hole's upper end.
 	 *
@@ -479,34 +478,47 @@
 	 * for carving the hole out. We return the optimal upper end
 	 * for the hole (which may be the same as the end of the WB
 	 * range in case we don't gain anything by aligning up).
+	 *
+	 * We don't have to exercise all the MTRR calculations for
+	 * each alignment. Instead, we can predict the gain (and loss)
+	 * for each alignment by looking at the bit pattern in `hole`.
+	 * Every time we align further up, one or more bits will flip
+	 * to `0`. We save one MTRR for each cleared bit for the en-
+	 * larged WB range. OTOH, for every `0` bit in the pattern,
+	 * we have to spend one MTRR to carve the hole out.
+	 *
+	 * Last but not least, we'd have to spend an additional MTRR
+	 * for each bit flipped above the biggest MTRR entry that
+	 * calc_var_mtrr_range(base, hole - base) implies. So we won't
+	 * try any bits above that alignment at all.
 	 */
 
-	unsigned int align, best_count;
+	/* The minimum `base` has to be aligned up to during MTRR filling. */
+	const int minimum_alignment = MAX(fms(~base & hole), fls(base));
+
+	/* The final carry bit, capped by `minimum_alignment`. */
+	const int final = MIN(fms(hole) + 1, minimum_alignment);
+	/* We start search at the least significant bit in `hole`. */
+	const int first = fls(hole);
+
+	/* Get us started by forcing the first bit. */
+	uint64_t hole_end = hole + (1 << first);
+
+	/* Start gain, account for the first addition. */
+	int gain = -carve_hole;
+	int best_gain = 0, bit;
 	uint32_t best_end = hole;
 
-	/* calculate MTRR count for the WB range alone (w/o a hole) */
-	calc_var_mtrr_range(var_state, base, hole - base, MTRR_TYPE_WRBACK);
-	best_count = var_state->mtrr_index;
-	var_state->mtrr_index = 0;
-
-	for (align = fls(hole) + 1; align <= fms(hole) + 1; ++align) {
-		const uint32_t hole_end = ALIGN_UP(hole, 1 << align);
-		if (hole_end > limit)
-			break;
-
-		/* calculate MTRR count for this alignment */
-		calc_var_mtrr_range(var_state,
-				base, hole_end - base, MTRR_TYPE_WRBACK);
-		if (carve_hole) {
-			calc_var_mtrr_range(var_state, hole, hole_end - hole,
-					    MTRR_TYPE_UNCACHEABLE);
-		}
-
-		if (var_state->mtrr_index < best_count) {
-			best_count = var_state->mtrr_index;
+	/* Count 1s that will flip as gain, 0s we have to force as loss. */
+	for (bit = first + 1; bit < final && hole_end <= limit; ++bit) {
+		if (!(hole & 1 << bit)) {
+			/* Have to force a 0 to 1. */
+			hole_end += 1 << bit;
+			gain -= carve_hole;
+		} else if (++gain > best_gain) {
+			best_gain = gain;
 			best_end = hole_end;
 		}
-		var_state->mtrr_index = 0;
 	}
 
 	return best_end;
@@ -596,8 +608,7 @@
 			b2_limit = range_entry_base_mtrr_addr(next);
 			carve_hole = 1;
 		}
-		b2 = optimize_var_mtrr_hole(
-				var_state, a1, b1, b2_limit, carve_hole);
+		b2 = optimize_var_mtrr_hole(a1, b1, b2_limit, carve_hole);
 	}
 
 	calc_var_mtrr_range(var_state, a1, b2 - a1, mtrr_type);

-- 
To view, visit https://review.coreboot.org/22119
To unsubscribe, visit https://review.coreboot.org/settings

Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-MessageType: newchange
Gerrit-Change-Id: Idcdc0f3a4cc9be8592454bf977feb99deb0f529e
Gerrit-Change-Number: 22119
Gerrit-PatchSet: 1
Gerrit-Owner: Nico Huber <nico.h at gmx.de>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.coreboot.org/pipermail/coreboot-gerrit/attachments/20171020/b4b21464/attachment.html>


More information about the coreboot-gerrit mailing list