/* Move the given node up through the heap to the appropriate position. */ static inline void mm_move_up_large(mm_node **heap, idx_t window, idx_t idx, mm_node *node) { mm_node *child; ai_t ai = node->ai; idx_t c_idx = mm_get_smallest_child(heap, window, idx, &child); while (ai > child->ai) { SWAP_NODES(heap, idx, node, c_idx, child); c_idx = mm_get_smallest_child(heap, window, idx, &child); } }
/* Move the given node down through the heap to the appropriate position. */ static inline void mm_move_down_large(mm_node **heap, idx_t idx, mm_node *node, idx_t p_idx, mm_node *parent) { do { SWAP_NODES(heap, idx, node, p_idx, parent); if (idx == 0) { break; } p_idx = P_IDX(idx); parent = heap[p_idx]; } while (node->ai < parent->ai); }
void MedianSplitSegment(std::vector<T>& segment, int sNodeNum, int eNodeNum, int newMedianIdx, int splitAxisIdx) { int sIdx = sNodeNum; int eIdx = eNodeNum; assert(sIdx >= 0); assert(eIdx < int(segment.size())); #define SWAP_NODES(segment, idxA, idxB) { T n = segment[idxA]; segment[idxA] = segment[idxB]; segment[idxB] = n; } while (eIdx > sIdx) { const float v = segment[eIdx]->GetPos()[splitAxisIdx]; // make sure (++i == sIdx) in the first iteration int i = sIdx - 1; int j = eIdx; for (;;) { // increase i until we find a farther node along splitAxisIdx // decrease j until we find a closer node along splitAxisIdx // swap the nodes at indices i and j unless they are in-order while (segment[++i]->GetPos()[splitAxisIdx] < v) {} while (segment[--j]->GetPos()[splitAxisIdx] > v && (j > sIdx)) {} if (i >= j) { break; } SWAP_NODES(segment, i, j); } SWAP_NODES(segment, i, eIdx); if (i >= newMedianIdx) { eIdx = i - 1; } if (i < newMedianIdx) { sIdx = i + 1; } } #undef swap }
/* * Copyright (c) 2013 Citrix Systems, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // balloon.c // // This module supports the Xen balloon functionality, that is, dynamic memory // assignment and removal from a domain. // // Copyright (c) 2007, XenSource, Inc. - All rights reserved. // //-- #pragma warning (push, 3) #include <ntddk.h> #include <ntstrsafe.h> #include "xsapi.h" #include "scsiboot.h" #include "hvm.h" #include "hypercall.h" #include "xenbus.h" #include "xenutl.h" #include <xen_types.h> #include <memory.h> #include <hvm_params.h> #include "balloon.h" #pragma warning (pop) #define range_set_index_t PFN_NUMBER #include "rangeset.c" #define MIN(a, b) ((a) < (b) ? (a) : (b)) #define TIME_US(_us) ((_us) * 10) #define TIME_MS(_ms) (TIME_US((_ms) * 1000)) #define TIME_S(_s) (TIME_MS((_s) * 1000)) #define TIME_RELATIVE(_t) (-(_t)) // Keep a made up MDL up our sleeve with room for the maximal number of // PFN_NUMBERs. // // We also need an array of PFN_NUMBERs when communicating to Xen which pages // are being returned or reclaimed, and that memory must be locked. We could // use the list as it exists in the page of pages and do the following every // time we talk to Xen (for each page of pages)- // // . Allocate an MDL // . Probe and Lock pages // . Virtual Lock // . Talk to Xen // . Virtual unlock // . Unlock pages // . Free MDL // // but that all seems like a lot of code, or in particular, a lot of guest // OS calls. Instead we'll reuse(/overload) the PFN array. // // Fortunately the native size of a Windows PFN is the same as the native // (guest) size of a Xen PFN. #define SHORT_MAX (1 << 15) #define MAX_PAGES_PER_MDL ((SHORT_MAX - sizeof(MDL)) / sizeof(PFN_NUMBER)) #define BALLOON_PFN_ARRAY_SIZE (MAX_PAGES_PER_MDL) typedef struct _BALLOON { ULONG TopPage; // We aim for CurrentPages == TargetPages. ULONG CurrentPages; ULONG TargetPages; ULONG MaxPages; // Various interesting statistics ULONG AllocateFail; ULONG PartialAllocate; ULONG PartialPopulate; struct range_set PfnsBalloonedOut; // Our pre-built MDL MDL Mdl; PFN_NUMBER PfnArray[BALLOON_PFN_ARRAY_SIZE]; KEVENT WorkerDoneEvent; struct xm_thread *WorkerThread; // Failure insertion and self-test flags BOOLEAN FIST_inflation; BOOLEAN FIST_deflation; // State flags BOOLEAN Frozen; BOOLEAN Initialized; BOOLEAN Advertized; ULONG AdvertizedSuspendCount; BOOLEAN Active; ULONG ActiveSuspendCount; } BALLOON; // There's only one balloon in a domain so make it global to make debugging // easier. static BALLOON Balloon; static NTSTATUS BalloonReadTargetPages( OUT ULONG *TargetPages ) { ULONG64 Target; NTSTATUS status; status = xenbus_read_int(XBT_NIL, "memory", "target", &Target); if (!NT_SUCCESS(status)) goto fail1; *TargetPages = (ULONG)(Target / 4); return STATUS_SUCCESS; fail1: TraceError(("%s: fail1 (%08x)\n", __FUNCTION__, status)); return status; } static NTSTATUS BalloonReadMaxPages( OUT ULONG *MaxPages ) { ULONG64 StaticMax; NTSTATUS status; status = xenbus_read_int(XBT_NIL, "memory", "static-max", &StaticMax); if (!NT_SUCCESS(status)) goto fail1; *MaxPages = (ULONG)(StaticMax / 4); return STATUS_SUCCESS; fail1: TraceError(("%s: fail1 (%08x)\n", __FUNCTION__, status)); return status; } static ULONG BalloonGetTopPage( VOID ) { PHYSICAL_MEMORY_RANGE *Range; PHYSICAL_ADDRESS TopAddress; ULONG Index; Range = MmGetPhysicalMemoryRanges(); TopAddress.QuadPart = 0ull; for (Index = 0; Range[Index].BaseAddress.QuadPart != 0 || Range[Index].NumberOfBytes.QuadPart != 0; Index++) { PHYSICAL_ADDRESS EndAddress; CHAR Key[32]; EndAddress.QuadPart = Range[Index].BaseAddress.QuadPart + Range[Index].NumberOfBytes.QuadPart; TraceInfo(("PHYSICAL MEMORY: RANGE[%u] %08x.%08x - %08x.%08x\n", Index, Range[Index].BaseAddress.HighPart, Range[Index].BaseAddress.LowPart, EndAddress.HighPart, EndAddress.LowPart)); (VOID) Xmsnprintf(Key, sizeof (Key), "data/physical-memory/range%u", Index); (VOID) xenbus_printf(XBT_NIL, Key, "base", "%08x.%08x", Range[Index].BaseAddress.HighPart, Range[Index].BaseAddress.LowPart); (VOID) xenbus_printf(XBT_NIL, Key, "end", "%08x.%08x", EndAddress.HighPart, EndAddress.LowPart); if (EndAddress.QuadPart > TopAddress.QuadPart) TopAddress.QuadPart = EndAddress.QuadPart; } TraceNotice(("PHYSICAL MEMORY: TOP = %08x.%08x\n", TopAddress.HighPart, TopAddress.LowPart)); return (ULONG)(TopAddress.QuadPart >> PAGE_SHIFT); } typedef MDL * (*PMM_ALLOCATE_PAGES_FOR_MDL_EX)( IN LARGE_INTEGER, IN LARGE_INTEGER, IN LARGE_INTEGER, IN SIZE_T, IN MEMORY_CACHING_TYPE, IN ULONG); PMM_ALLOCATE_PAGES_FOR_MDL_EX __MmAllocatePagesForMdlEx; BOOLEAN AllocatorInitialized = FALSE; static VOID BalloonInitializeAllocator( VOID ) { UNICODE_STRING Name; XM_ASSERT(__MmAllocatePagesForMdlEx == NULL); RtlInitUnicodeString(&Name, L"MmAllocatePagesForMdlEx"); __MmAllocatePagesForMdlEx = (PMM_ALLOCATE_PAGES_FOR_MDL_EX)(ULONG_PTR)MmGetSystemRoutineAddress(&Name); AllocatorInitialized = TRUE; } // Look at index @Start in the heap, and push it down into its // children so as to make it the root of a heap, assuming that both of // its children are already heaps. */ static VOID BalloonHeapPushDown( IN PFN_NUMBER *Heap, IN ULONG Start, IN ULONG Count ) { ULONG LeftChild; ULONG RightChild; #define SWAP_NODES(_x, _y) \ do { \ PFN_NUMBER __val = Heap[(_y)]; \ \ Heap[(_y)] = Heap[(_x)]; \ Heap[(_x)] = __val; \ } while (FALSE) again: LeftChild = Start * 2 + 1; RightChild = Start * 2 + 2; if (RightChild < Count) { XM_ASSERT(Heap[LeftChild] != Heap[Start]); XM_ASSERT(Heap[RightChild] != Heap[Start]); XM_ASSERT(Heap[LeftChild] != Heap[RightChild]); if (Heap[LeftChild] < Heap[Start] && Heap[RightChild] < Heap[Start]) return; if (Heap[LeftChild] < Heap[Start] && Heap[RightChild] > Heap[Start]) { SWAP_NODES(RightChild, Start); XM_ASSERT(Heap[RightChild] < Heap[Start]); Start = RightChild; goto again; } if (Heap[RightChild] < Heap[Start] && Heap[LeftChild] > Heap[Start]) { SWAP_NODES(LeftChild, Start); XM_ASSERT(Heap[LeftChild] < Heap[Start]); Start = LeftChild; goto again; } // (Heap[LeftChild] > Heap[Start] && // Heap[RightChild] > Heap[Start]) if (Heap[LeftChild] > Heap[RightChild]) { SWAP_NODES(LeftChild, Start); XM_ASSERT(Heap[LeftChild] < Heap[Start]); Start = LeftChild; } else { SWAP_NODES(RightChild, Start); XM_ASSERT(Heap[RightChild] < Heap[Start]); Start = RightChild; } goto again; } if (LeftChild < Count) { // Only one child XM_ASSERT(Heap[LeftChild] != Heap[Start]); if (Heap[LeftChild] < Heap[Start]) return; SWAP_NODES(LeftChild, Start); XM_ASSERT(Heap[LeftChild] < Heap[Start]); Start = LeftChild; goto again; } #undef SWAP_NODES }