Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

x86-64, NUMA: Don't call numa_set_distanc() for all possible node combinations during emulation

The distance transforming in numa_emulation() used to call
numa_set_distance() for all MAX_NUMNODES * MAX_NUMNODES node
combinations regardless of which are enabled. As numa_set_distance()
ignores all out-of-bound distance settings, this doesn't cause any
problem other than looping unnecessarily many times during boot.

However, as MAX_NUMNODES * MAX_NUMNODES can be pretty high, update the
code such that it iterates through only the enabled combinations.

Yinghai Lu identified the issue and provided an initial patch to
address the issue; however, the patch was incorrect in that it didn't
build emulated distance table when there's no physical distance table
and unnecessarily complex.

http://thread.gmane.org/gmane.linux.kernel/1107986/focus=1107988

Signed-off-by: Tejun Heo <tj@kernel.org>
Reported-by: Yinghai Lu <yinghai@kernel.org>
Acked-by: Yinghai Lu <yinghai@kernel.org>

Tejun Heo 56396e68 ca764aaf

+12 -11
+12 -11
arch/x86/mm/numa_emulation.c
··· 301 301 const u64 max_addr = max_pfn << PAGE_SHIFT; 302 302 u8 *phys_dist = NULL; 303 303 size_t phys_size = numa_dist_cnt * numa_dist_cnt * sizeof(phys_dist[0]); 304 - int dfl_phys_nid; 304 + int max_emu_nid, dfl_phys_nid; 305 305 int i, j, ret; 306 306 307 307 if (!emu_cmdline) ··· 358 358 node_distance(i, j); 359 359 } 360 360 361 - /* determine the default phys nid to use for unmapped nodes */ 361 + /* 362 + * Determine the max emulated nid and the default phys nid to use 363 + * for unmapped nodes. 364 + */ 365 + max_emu_nid = 0; 362 366 dfl_phys_nid = NUMA_NO_NODE; 363 367 for (i = 0; i < ARRAY_SIZE(emu_nid_to_phys); i++) { 364 368 if (emu_nid_to_phys[i] != NUMA_NO_NODE) { 365 - dfl_phys_nid = emu_nid_to_phys[i]; 366 - break; 369 + max_emu_nid = i; 370 + if (dfl_phys_nid == NUMA_NO_NODE) 371 + dfl_phys_nid = emu_nid_to_phys[i]; 367 372 } 368 373 } 369 374 if (dfl_phys_nid == NUMA_NO_NODE) { ··· 398 393 if (emu_nid_to_phys[i] == NUMA_NO_NODE) 399 394 emu_nid_to_phys[i] = dfl_phys_nid; 400 395 401 - /* 402 - * Transform distance table. numa_set_distance() ignores all 403 - * out-of-bound distances. Just call it for every possible node 404 - * combination. 405 - */ 396 + /* transform distance table */ 406 397 numa_reset_distance(); 407 - for (i = 0; i < MAX_NUMNODES; i++) { 408 - for (j = 0; j < MAX_NUMNODES; j++) { 398 + for (i = 0; i < max_emu_nid + 1; i++) { 399 + for (j = 0; j < max_emu_nid + 1; j++) { 409 400 int physi = emu_nid_to_phys[i]; 410 401 int physj = emu_nid_to_phys[j]; 411 402 int dist;