1 /* $NetBSD: uvm_pdpolicy_clock.c,v 1.43 2026/09/05 16:53:05 tls Exp $ */ 2 /* NetBSD: uvm_pdaemon.c,v 1.72 2006/01/05 10:47:33 yamt Exp $ */ 3 4 /*- 5 * Copyright (c) 2019, 2020 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Andrew Doran. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * Copyright (c) 1997 Charles D. Cranor and Washington University. 35 * Copyright (c) 1991, 1993, The Regents of the University of California. 36 * 37 * All rights reserved. 38 * 39 * This code is derived from software contributed to Berkeley by 40 * The Mach Operating System project at Carnegie-Mellon University. 41 * 42 * Redistribution and use in source and binary forms, with or without 43 * modification, are permitted provided that the following conditions 44 * are met: 45 * 1. Redistributions of source code must retain the above copyright 46 * notice, this list of conditions and the following disclaimer. 47 * 2. Redistributions in binary form must reproduce the above copyright 48 * notice, this list of conditions and the following disclaimer in the 49 * documentation and/or other materials provided with the distribution. 50 * 3. Neither the name of the University nor the names of its contributors 51 * may be used to endorse or promote products derived from this software 52 * without specific prior written permission. 53 * 54 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 55 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 56 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 57 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 58 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 59 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 60 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 61 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 62 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 63 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 64 * SUCH DAMAGE. 65 * 66 * @(#)vm_pageout.c 8.5 (Berkeley) 2/14/94 67 * from: Id: uvm_pdaemon.c,v 1.1.2.32 1998/02/06 05:26:30 chs Exp 68 * 69 * 70 * Copyright (c) 1987, 1990 Carnegie-Mellon University. 71 * All rights reserved. 72 * 73 * Permission to use, copy, modify and distribute this software and 74 * its documentation is hereby granted, provided that both the copyright 75 * notice and this permission notice appear in all copies of the 76 * software, derivative works or modified versions, and any portions 77 * thereof, and that both notices appear in supporting documentation. 78 * 79 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 80 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 81 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 82 * 83 * Carnegie Mellon requests users of this software to return to 84 * 85 * Software Distribution Coordinator or Software.Distribution (at) CS.CMU.EDU 86 * School of Computer Science 87 * Carnegie Mellon University 88 * Pittsburgh PA 15213-3890 89 * 90 * any improvements or extensions that they make and grant Carnegie the 91 * rights to redistribute these changes. 92 */ 93 94 #if defined(PDSIM) 95 96 #include "pdsim.h" 97 98 #else /* defined(PDSIM) */ 99 100 #include <sys/cdefs.h> 101 __KERNEL_RCSID(0, "$NetBSD: uvm_pdpolicy_clock.c,v 1.43 2026/09/05 16:53:05 tls Exp $"); 102 103 #include <sys/param.h> 104 #include <sys/proc.h> 105 #include <sys/systm.h> 106 #include <sys/kernel.h> 107 #include <sys/kmem.h> 108 #include <sys/atomic.h> 109 110 #include <uvm/uvm.h> 111 #include <uvm/uvm_pdpolicy.h> 112 #include <uvm/uvm_pdpolicy_impl.h> 113 #include <uvm/uvm_stat.h> 114 115 #endif /* defined(PDSIM) */ 116 117 /* 118 * per-CPU queue of pending page status changes. 128 entries makes for a 119 * 1kB queue on _LP64 and has been found to be a reasonable compromise that 120 * keeps lock contention events and wait times low, while not using too much 121 * memory nor allowing global state to fall too far behind. 122 */ 123 #if !defined(CLOCK_PDQ_SIZE) 124 #define CLOCK_PDQ_SIZE 128 125 #endif /* !defined(CLOCK_PDQ_SIZE) */ 126 127 #define PQ_INACTIVE 0x00000010 /* page is in inactive list */ 128 #define PQ_ACTIVE 0x00000020 /* page is in active list */ 129 130 #if !defined(CLOCK_INACTIVEPCT) 131 #define CLOCK_INACTIVEPCT 33 132 #endif /* !defined(CLOCK_INACTIVEPCT) */ 133 134 struct uvmpdpol_globalstate { 135 kmutex_t lock; /* lock on state */ 136 /* <= compiler pads here */ 137 struct pglist s_activeq /* allocated pages, in use */ 138 __aligned(COHERENCY_UNIT); 139 struct pglist s_inactiveq; /* pages between the clock hands */ 140 int s_active; 141 int s_inactive; 142 int s_inactarg; 143 struct uvm_pctparam s_anonmin; 144 struct uvm_pctparam s_filemin; 145 struct uvm_pctparam s_execmin; 146 struct uvm_pctparam s_anonmax; 147 struct uvm_pctparam s_filemax; 148 struct uvm_pctparam s_execmax; 149 struct uvm_pctparam s_inactivepct; 150 }; 151 152 struct uvmpdpol_scanstate { 153 bool ss_anonreact, ss_filereact, ss_execreact; 154 struct vm_page ss_marker; 155 }; 156 157 static void uvmpdpol_pageactivate_locked(struct vm_page *); 158 static void uvmpdpol_pagedeactivate_locked(struct vm_page *); 159 static void uvmpdpol_pagedequeue_locked(struct vm_page *); 160 static bool uvmpdpol_pagerealize_locked(struct vm_page *); 161 static struct uvm_cpu *uvmpdpol_flush(void); 162 163 static struct uvmpdpol_globalstate pdpol_state __cacheline_aligned; 164 static struct uvmpdpol_scanstate pdpol_scanstate; 165 166 PDPOL_EVCNT_DEFINE(reactexec) 167 PDPOL_EVCNT_DEFINE(reactfile) 168 PDPOL_EVCNT_DEFINE(reactanon) 169 170 static void 171 clock_tune(void) 172 { 173 struct uvmpdpol_globalstate *s = &pdpol_state; 174 175 s->s_inactarg = UVM_PCTPARAM_APPLY(&s->s_inactivepct, 176 s->s_active + s->s_inactive); 177 if (s->s_inactarg <= uvmexp.freetarg) { 178 s->s_inactarg = uvmexp.freetarg + 1; 179 } 180 } 181 182 void 183 uvmpdpol_scaninit(void) 184 { 185 struct uvmpdpol_globalstate *s = &pdpol_state; 186 struct uvmpdpol_scanstate *ss = &pdpol_scanstate; 187 int t; 188 bool anonunder, fileunder, execunder; 189 bool anonover, fileover, execover; 190 bool anonreact, filereact, execreact; 191 int64_t freepg, anonpg, filepg, execpg; 192 193 /* 194 * decide which types of pages we want to reactivate instead of freeing 195 * to keep usage within the minimum and maximum usage limits. 196 * uvm_availmem() will sync the counters. 197 */ 198 199 freepg = uvm_availmem(false); 200 anonpg = cpu_count_get(CPU_COUNT_ANONCLEAN) + 201 cpu_count_get(CPU_COUNT_ANONDIRTY) + 202 cpu_count_get(CPU_COUNT_ANONUNKNOWN); 203 execpg = cpu_count_get(CPU_COUNT_EXECPAGES); 204 filepg = cpu_count_get(CPU_COUNT_FILECLEAN) + 205 cpu_count_get(CPU_COUNT_FILEDIRTY) + 206 cpu_count_get(CPU_COUNT_FILEUNKNOWN) - 207 execpg; 208 209 mutex_enter(&s->lock); 210 t = s->s_active + s->s_inactive + freepg; 211 anonunder = anonpg <= UVM_PCTPARAM_APPLY(&s->s_anonmin, t); 212 fileunder = filepg <= UVM_PCTPARAM_APPLY(&s->s_filemin, t); 213 execunder = execpg <= UVM_PCTPARAM_APPLY(&s->s_execmin, t); 214 anonover = anonpg > UVM_PCTPARAM_APPLY(&s->s_anonmax, t); 215 fileover = filepg > UVM_PCTPARAM_APPLY(&s->s_filemax, t); 216 execover = execpg > UVM_PCTPARAM_APPLY(&s->s_execmax, t); 217 anonreact = anonunder || (!anonover && (fileover || execover)); 218 filereact = fileunder || (!fileover && (anonover || execover)); 219 execreact = execunder || (!execover && (anonover || fileover)); 220 if (filereact && execreact && (anonreact || uvm_swapisfull())) { 221 anonreact = filereact = execreact = false; 222 } 223 ss->ss_anonreact = anonreact; 224 ss->ss_filereact = filereact; 225 ss->ss_execreact = execreact; 226 memset(&ss->ss_marker, 0, sizeof(ss->ss_marker)); 227 ss->ss_marker.flags = PG_MARKER; 228 TAILQ_INSERT_HEAD(&pdpol_state.s_inactiveq, &ss->ss_marker, pdqueue); 229 mutex_exit(&s->lock); 230 } 231 232 void 233 uvmpdpol_scanfini(void) 234 { 235 struct uvmpdpol_globalstate *s = &pdpol_state; 236 struct uvmpdpol_scanstate *ss = &pdpol_scanstate; 237 238 mutex_enter(&s->lock); 239 TAILQ_REMOVE(&pdpol_state.s_inactiveq, &ss->ss_marker, pdqueue); 240 mutex_exit(&s->lock); 241 } 242 243 struct vm_page * 244 uvmpdpol_selectvictim(krwlock_t **plock) 245 { 246 struct uvmpdpol_globalstate *s = &pdpol_state; 247 struct uvmpdpol_scanstate *ss = &pdpol_scanstate; 248 struct vm_page *pg; 249 krwlock_t *lock; 250 251 mutex_enter(&s->lock); 252 while (/* CONSTCOND */ 1) { 253 struct vm_anon *anon; 254 struct uvm_object *uobj; 255 256 pg = TAILQ_NEXT(&ss->ss_marker, pdqueue); 257 if (pg == NULL) { 258 break; 259 } 260 KASSERT((pg->flags & PG_MARKER) == 0); 261 uvmexp.pdscans++; 262 263 /* 264 * acquire interlock to stabilize page identity. 265 * if we have caught the page in a state of flux 266 * deal with it and retry. 267 */ 268 mutex_enter(&pg->interlock); 269 if (uvmpdpol_pagerealize_locked(pg)) { 270 mutex_exit(&pg->interlock); 271 continue; 272 } 273 274 /* 275 * now prepare to move on to the next page. 276 */ 277 TAILQ_REMOVE(&pdpol_state.s_inactiveq, &ss->ss_marker, 278 pdqueue); 279 TAILQ_INSERT_AFTER(&pdpol_state.s_inactiveq, pg, 280 &ss->ss_marker, pdqueue); 281 282 /* 283 * enforce the minimum thresholds on different 284 * types of memory usage. if reusing the current 285 * page would reduce that type of usage below its 286 * minimum, reactivate the page instead and move 287 * on to the next page. 288 */ 289 anon = pg->uanon; 290 uobj = pg->uobject; 291 if (uobj && UVM_OBJ_IS_VTEXT(uobj) && ss->ss_execreact) { 292 uvmpdpol_pageactivate_locked(pg); 293 mutex_exit(&pg->interlock); 294 PDPOL_EVCNT_INCR(reactexec); 295 continue; 296 } 297 if (uobj && UVM_OBJ_IS_VNODE(uobj) && 298 !UVM_OBJ_IS_VTEXT(uobj) && ss->ss_filereact) { 299 uvmpdpol_pageactivate_locked(pg); 300 mutex_exit(&pg->interlock); 301 PDPOL_EVCNT_INCR(reactfile); 302 continue; 303 } 304 if ((anon || UVM_OBJ_IS_AOBJ(uobj)) && ss->ss_anonreact) { 305 uvmpdpol_pageactivate_locked(pg); 306 mutex_exit(&pg->interlock); 307 PDPOL_EVCNT_INCR(reactanon); 308 continue; 309 } 310 311 /* 312 * try to lock the object that owns the page. 313 * 314 * with the page interlock held, we can drop s->lock, which 315 * could otherwise serve as a barrier to us getting the 316 * object locked, because the owner of the object's lock may 317 * be blocked on s->lock (i.e. a deadlock). 318 * 319 * whatever happens, uvmpd_trylockowner() will release the 320 * interlock. with the interlock dropped we can then 321 * re-acquire our own lock. the order is: 322 * 323 * object -> pdpol -> interlock. 324 */ 325 mutex_exit(&s->lock); 326 lock = uvmpd_trylockowner(pg); 327 /* pg->interlock now released */ 328 mutex_enter(&s->lock); 329 if (lock == NULL) { 330 /* didn't get it - try the next page. */ 331 continue; 332 } 333 334 /* 335 * There was a very brief interval with interlock and 336 * s_lock dropped. Check we would not now be scribbling 337 * on someone else's work. 338 */ 339 mutex_enter(&pg->interlock); 340 if (uvmpdpol_pagerealize_locked(pg) || 341 (pg->pqflags & PQ_INACTIVE) == 0 || 342 pg->wire_count != 0) { 343 mutex_exit(&pg->interlock); 344 rw_exit(lock); 345 continue; 346 } 347 mutex_exit(&pg->interlock); 348 349 /* 350 * move referenced pages back to active queue and skip to 351 * next page. 352 */ 353 if (pmap_is_referenced(pg)) { 354 mutex_enter(&pg->interlock); 355 uvmpdpol_pageactivate_locked(pg); 356 mutex_exit(&pg->interlock); 357 uvmexp.pdreact++; 358 rw_exit(lock); 359 continue; 360 } 361 362 /* we have a potential victim. */ 363 *plock = lock; 364 break; 365 } 366 mutex_exit(&s->lock); 367 return pg; 368 } 369 370 void 371 uvmpdpol_balancequeue(int swap_shortage) 372 { 373 struct uvmpdpol_globalstate *s = &pdpol_state; 374 int inactive_shortage; 375 struct vm_page *p, marker; 376 krwlock_t *lock; 377 378 /* 379 * we have done the scan to get free pages. now we work on meeting 380 * our inactive target. 381 */ 382 383 memset(&marker, 0, sizeof(marker)); 384 marker.flags = PG_MARKER; 385 386 mutex_enter(&s->lock); 387 TAILQ_INSERT_HEAD(&pdpol_state.s_activeq, &marker, pdqueue); 388 for (;;) { 389 inactive_shortage = 390 pdpol_state.s_inactarg - pdpol_state.s_inactive; 391 if (inactive_shortage <= 0 && swap_shortage <= 0) { 392 break; 393 } 394 p = TAILQ_NEXT(&marker, pdqueue); 395 if (p == NULL) { 396 break; 397 } 398 KASSERT((p->flags & PG_MARKER) == 0); 399 400 /* 401 * acquire interlock to stabilize page identity. 402 * if we have caught the page in a state of flux 403 * deal with it and retry. 404 */ 405 mutex_enter(&p->interlock); 406 if (uvmpdpol_pagerealize_locked(p)) { 407 mutex_exit(&p->interlock); 408 continue; 409 } 410 411 /* 412 * now prepare to move on to the next page. 413 */ 414 TAILQ_REMOVE(&pdpol_state.s_activeq, &marker, pdqueue); 415 TAILQ_INSERT_AFTER(&pdpol_state.s_activeq, p, &marker, 416 pdqueue); 417 418 /* 419 * try to lock the object that owns the page. see comments 420 * in uvmpdpol_selectvictim(). 421 */ 422 mutex_exit(&s->lock); 423 lock = uvmpd_trylockowner(p); 424 /* p->interlock now released */ 425 mutex_enter(&s->lock); 426 if (lock == NULL) { 427 /* didn't get it - try the next page. */ 428 continue; 429 } 430 431 /* 432 * As in selectvictim, check we would not now be scribbling 433 * on someone else's work. 434 */ 435 mutex_enter(&p->interlock); 436 if (uvmpdpol_pagerealize_locked(p) || 437 (p->pqflags & PQ_ACTIVE) == 0 || 438 p->wire_count != 0) { 439 mutex_exit(&p->interlock); 440 rw_exit(lock); 441 continue; 442 } 443 mutex_exit(&p->interlock); 444 445 /* 446 * if there's a shortage of swap slots, try to free it. 447 */ 448 if (swap_shortage > 0 && (p->flags & PG_SWAPBACKED) != 0 && 449 (p->flags & PG_BUSY) == 0) { 450 if (uvmpd_dropswap(p)) { 451 swap_shortage--; 452 } 453 } 454 455 /* 456 * if there's a shortage of inactive pages, deactivate. 457 */ 458 if (inactive_shortage > 0) { 459 pmap_clear_reference(p); 460 mutex_enter(&p->interlock); 461 uvmpdpol_pagedeactivate_locked(p); 462 mutex_exit(&p->interlock); 463 uvmexp.pddeact++; 464 inactive_shortage--; 465 } 466 rw_exit(lock); 467 } 468 TAILQ_REMOVE(&pdpol_state.s_activeq, &marker, pdqueue); 469 mutex_exit(&s->lock); 470 } 471 472 static void 473 uvmpdpol_pagedeactivate_locked(struct vm_page *pg) 474 { 475 struct uvmpdpol_globalstate *s __diagused = &pdpol_state; 476 477 KASSERT(mutex_owned(&s->lock)); 478 KASSERT(mutex_owned(&pg->interlock)); 479 KASSERT((pg->pqflags & (PQ_INTENT_MASK | PQ_INTENT_SET)) != 480 (PQ_INTENT_D | PQ_INTENT_SET)); 481 482 if (pg->pqflags & PQ_ACTIVE) { 483 TAILQ_REMOVE(&pdpol_state.s_activeq, pg, pdqueue); 484 KASSERT(pdpol_state.s_active > 0); 485 pdpol_state.s_active--; 486 } 487 if ((pg->pqflags & PQ_INACTIVE) == 0) { 488 KASSERT(pg->wire_count == 0); 489 TAILQ_INSERT_TAIL(&pdpol_state.s_inactiveq, pg, pdqueue); 490 pdpol_state.s_inactive++; 491 } 492 pg->pqflags &= ~(PQ_ACTIVE | PQ_INTENT_SET); 493 pg->pqflags |= PQ_INACTIVE; 494 } 495 496 void 497 uvmpdpol_pagedeactivate(struct vm_page *pg) 498 { 499 500 KASSERT(uvm_page_owner_locked_p(pg, false)); 501 KASSERT(mutex_owned(&pg->interlock)); 502 503 /* 504 * we have to clear the reference bit now, as when it comes time to 505 * realize the intent we won't have the object locked any more. 506 */ 507 pmap_clear_reference(pg); 508 uvmpdpol_set_intent(pg, PQ_INTENT_I); 509 } 510 511 static void 512 uvmpdpol_pageactivate_locked(struct vm_page *pg) 513 { 514 struct uvmpdpol_globalstate *s __diagused = &pdpol_state; 515 516 KASSERT(mutex_owned(&s->lock)); 517 KASSERT(mutex_owned(&pg->interlock)); 518 KASSERT((pg->pqflags & (PQ_INTENT_MASK | PQ_INTENT_SET)) != 519 (PQ_INTENT_D | PQ_INTENT_SET)); 520 521 uvmpdpol_pagedequeue_locked(pg); 522 TAILQ_INSERT_TAIL(&pdpol_state.s_activeq, pg, pdqueue); 523 pdpol_state.s_active++; 524 pg->pqflags &= ~(PQ_INACTIVE | PQ_INTENT_SET); 525 pg->pqflags |= PQ_ACTIVE; 526 } 527 528 void 529 uvmpdpol_pageactivate(struct vm_page *pg) 530 { 531 532 KASSERT(uvm_page_owner_locked_p(pg, false)); 533 KASSERT(mutex_owned(&pg->interlock)); 534 535 uvmpdpol_set_intent(pg, PQ_INTENT_A); 536 } 537 538 static void 539 uvmpdpol_pagedequeue_locked(struct vm_page *pg) 540 { 541 struct uvmpdpol_globalstate *s __diagused = &pdpol_state; 542 543 KASSERT(mutex_owned(&s->lock)); 544 KASSERT(mutex_owned(&pg->interlock)); 545 546 if (pg->pqflags & PQ_ACTIVE) { 547 TAILQ_REMOVE(&pdpol_state.s_activeq, pg, pdqueue); 548 KASSERT((pg->pqflags & PQ_INACTIVE) == 0); 549 KASSERT(pdpol_state.s_active > 0); 550 pdpol_state.s_active--; 551 } else if (pg->pqflags & PQ_INACTIVE) { 552 TAILQ_REMOVE(&pdpol_state.s_inactiveq, pg, pdqueue); 553 KASSERT(pdpol_state.s_inactive > 0); 554 pdpol_state.s_inactive--; 555 } 556 pg->pqflags &= ~(PQ_ACTIVE | PQ_INACTIVE | PQ_INTENT_SET); 557 } 558 559 void 560 uvmpdpol_pagedequeue(struct vm_page *pg) 561 { 562 563 KASSERT(uvm_page_owner_locked_p(pg, true)); 564 KASSERT(mutex_owned(&pg->interlock)); 565 566 uvmpdpol_set_intent(pg, PQ_INTENT_D); 567 } 568 569 void 570 uvmpdpol_pageenqueue(struct vm_page *pg) 571 { 572 573 KASSERT(uvm_page_owner_locked_p(pg, false)); 574 KASSERT(mutex_owned(&pg->interlock)); 575 576 uvmpdpol_set_intent(pg, PQ_INTENT_E); 577 } 578 579 void 580 uvmpdpol_anfree(struct vm_anon *an) 581 { 582 } 583 584 bool 585 uvmpdpol_pageisqueued_p(struct vm_page *pg) 586 { 587 uint32_t pqflags; 588 589 /* 590 * if there's an intent set, we have to consider it. otherwise, 591 * return the actual state. we may be called unlocked for the 592 * purpose of assertions, which is safe due to the page lifecycle. 593 */ 594 pqflags = atomic_load_relaxed(&pg->pqflags); 595 if ((pqflags & PQ_INTENT_SET) != 0) { 596 return (pqflags & PQ_INTENT_MASK) != PQ_INTENT_D; 597 } else { 598 return (pqflags & (PQ_ACTIVE | PQ_INACTIVE)) != 0; 599 } 600 } 601 602 bool 603 uvmpdpol_pageactivate_p(struct vm_page *pg) 604 { 605 uint32_t pqflags; 606 607 /* consider intent in preference to actual state. */ 608 pqflags = atomic_load_relaxed(&pg->pqflags); 609 if ((pqflags & PQ_INTENT_SET) != 0) { 610 pqflags &= PQ_INTENT_MASK; 611 return pqflags != PQ_INTENT_A && pqflags != PQ_INTENT_E; 612 } else { 613 /* 614 * TODO: Enabling this may be too much of a big hammer, 615 * since we do get useful information from activations. 616 * Think about it more and maybe come up with a heuristic 617 * or something. 618 * 619 * return (pqflags & PQ_ACTIVE) == 0; 620 */ 621 return true; 622 } 623 } 624 625 void 626 uvmpdpol_estimatepageable(int *active, int *inactive) 627 { 628 struct uvmpdpol_globalstate *s = &pdpol_state; 629 630 /* 631 * Don't take any locks here. This can be called from DDB, and in 632 * any case the numbers are stale the instant the lock is dropped, 633 * so it just doesn't matter. 634 */ 635 if (active) { 636 *active = s->s_active; 637 } 638 if (inactive) { 639 *inactive = s->s_inactive; 640 } 641 } 642 643 #if !defined(PDSIM) 644 static int 645 min_check(struct uvm_pctparam *pct, int t) 646 { 647 struct uvmpdpol_globalstate *s = &pdpol_state; 648 int total = t; 649 650 if (pct != &s->s_anonmin) { 651 total += uvm_pctparam_get(&s->s_anonmin); 652 } 653 if (pct != &s->s_filemin) { 654 total += uvm_pctparam_get(&s->s_filemin); 655 } 656 if (pct != &s->s_execmin) { 657 total += uvm_pctparam_get(&s->s_execmin); 658 } 659 if (total > 95) { 660 return EINVAL; 661 } 662 return 0; 663 } 664 #endif /* !defined(PDSIM) */ 665 666 void 667 uvmpdpol_init(void) 668 { 669 struct uvmpdpol_globalstate *s = &pdpol_state; 670 671 mutex_init(&s->lock, MUTEX_DEFAULT, IPL_NONE); 672 TAILQ_INIT(&s->s_activeq); 673 TAILQ_INIT(&s->s_inactiveq); 674 uvm_pctparam_init(&s->s_inactivepct, CLOCK_INACTIVEPCT, NULL); 675 uvm_pctparam_init(&s->s_anonmin, 10, min_check); 676 uvm_pctparam_init(&s->s_filemin, 10, min_check); 677 uvm_pctparam_init(&s->s_execmin, 5, min_check); 678 uvm_pctparam_init(&s->s_anonmax, 80, NULL); 679 uvm_pctparam_init(&s->s_filemax, 50, NULL); 680 uvm_pctparam_init(&s->s_execmax, 30, NULL); 681 } 682 683 void 684 uvmpdpol_init_cpu(struct uvm_cpu *ucpu) 685 { 686 687 ucpu->pdq = 688 kmem_alloc(CLOCK_PDQ_SIZE * sizeof(struct vm_page *), KM_SLEEP); 689 ucpu->pdqhead = CLOCK_PDQ_SIZE; 690 ucpu->pdqtail = CLOCK_PDQ_SIZE; 691 } 692 693 void 694 uvmpdpol_reinit(void) 695 { 696 } 697 698 bool 699 uvmpdpol_needsscan_p(void) 700 { 701 702 /* 703 * this must be an unlocked check: can be called from interrupt. 704 */ 705 return pdpol_state.s_inactive < pdpol_state.s_inactarg; 706 } 707 708 void 709 uvmpdpol_tune(void) 710 { 711 struct uvmpdpol_globalstate *s = &pdpol_state; 712 713 mutex_enter(&s->lock); 714 clock_tune(); 715 mutex_exit(&s->lock); 716 } 717 718 /* 719 * uvmpdpol_pagerealize_locked: take the intended state set on a page and 720 * make it real. return true if any work was done. 721 */ 722 static bool 723 uvmpdpol_pagerealize_locked(struct vm_page *pg) 724 { 725 struct uvmpdpol_globalstate *s __diagused = &pdpol_state; 726 727 KASSERT(mutex_owned(&s->lock)); 728 KASSERT(mutex_owned(&pg->interlock)); 729 730 switch (pg->pqflags & (PQ_INTENT_MASK | PQ_INTENT_SET)) { 731 case PQ_INTENT_A | PQ_INTENT_SET: 732 case PQ_INTENT_E | PQ_INTENT_SET: 733 uvmpdpol_pageactivate_locked(pg); 734 return true; 735 case PQ_INTENT_I | PQ_INTENT_SET: 736 uvmpdpol_pagedeactivate_locked(pg); 737 return true; 738 case PQ_INTENT_D | PQ_INTENT_SET: 739 uvmpdpol_pagedequeue_locked(pg); 740 return true; 741 default: 742 return false; 743 } 744 } 745 746 /* 747 * uvmpdpol_flush: return the current uvm_cpu with all of its pending 748 * updates flushed to the global queues. this routine may block, and 749 * so can switch cpu. the idea is to empty to queue on whatever cpu 750 * we finally end up on. 751 * Must be called at splsoftbio() 752 */ 753 static struct uvm_cpu * 754 uvmpdpol_flush(void) 755 { 756 struct uvmpdpol_globalstate *s __diagused = &pdpol_state; 757 struct uvm_cpu *ucpu; 758 struct vm_page *pg; 759 760 KASSERT(kpreempt_disabled()); 761 762 mutex_enter(&s->lock); 763 for (;;) { 764 /* 765 * prefer scanning forwards (even though mutex_enter() is 766 * serializing) so as to not defeat any prefetch logic in 767 * the CPU. that means elsewhere enqueuing backwards, like 768 * a stack, but not so important there as pages are being 769 * added singularly. 770 * 771 * prefetch the next "struct vm_page" while working on the 772 * current one. this has a measurable and very positive 773 * effect in reducing the amount of time spent here under 774 * the global lock. 775 */ 776 ucpu = curcpu()->ci_data.cpu_uvm; 777 KASSERT(ucpu->pdqhead <= ucpu->pdqtail); 778 if (__predict_false(ucpu->pdqhead == ucpu->pdqtail)) { 779 break; 780 } 781 pg = ucpu->pdq[ucpu->pdqhead++]; 782 if (__predict_true(ucpu->pdqhead != ucpu->pdqtail)) { 783 __builtin_prefetch(ucpu->pdq[ucpu->pdqhead]); 784 } 785 mutex_enter(&pg->interlock); 786 pg->pqflags &= ~PQ_INTENT_QUEUED; 787 (void)uvmpdpol_pagerealize_locked(pg); 788 mutex_exit(&pg->interlock); 789 } 790 mutex_exit(&s->lock); 791 return ucpu; 792 } 793 794 /* 795 * uvmpdpol_pagerealize: realize any intent set on the page. in this 796 * implementation, that means putting the page on a per-CPU queue to be 797 * dealt with later. 798 */ 799 void 800 uvmpdpol_pagerealize(struct vm_page *pg) 801 { 802 struct uvm_cpu *ucpu; 803 int s; 804 805 /* 806 * drain the per per-CPU queue if full, then enter the page. 807 */ 808 s = splsoftbio(); 809 ucpu = curcpu()->ci_data.cpu_uvm; 810 while (__predict_false(ucpu->pdqhead == 0)) { 811 ucpu = uvmpdpol_flush(); 812 } 813 ucpu->pdq[--(ucpu->pdqhead)] = pg; 814 splx(s); 815 } 816 817 /* 818 * uvmpdpol_idle: called from the system idle loop. periodically purge any 819 * pending updates back to the global queues. 820 */ 821 void 822 uvmpdpol_idle(struct uvm_cpu *ucpu) 823 { 824 struct uvmpdpol_globalstate *s = &pdpol_state; 825 struct vm_page *pg; 826 int s_spl; 827 828 KASSERT(kpreempt_disabled()); 829 830 /* 831 * if no pages in the queue, we have nothing to do. 832 */ 833 if (ucpu->pdqhead == ucpu->pdqtail) { 834 ucpu->pdqtime = getticks(); 835 return; 836 } 837 838 /* 839 * don't do this more than ~8 times a second as it would needlessly 840 * exert pressure. 841 */ 842 if (getticks() - ucpu->pdqtime < (hz >> 3)) { 843 return; 844 } 845 846 /* 847 * the idle LWP can't block, so we have to try for the lock. if we 848 * get it, purge the per-CPU pending update queue. continually 849 * check for a pending resched: in that case exit immediately. 850 */ 851 if (mutex_tryenter(&s->lock)) { 852 s_spl = splsoftbio(); 853 while (ucpu->pdqhead != ucpu->pdqtail) { 854 pg = ucpu->pdq[ucpu->pdqhead]; 855 if (!mutex_tryenter(&pg->interlock)) { 856 break; 857 } 858 ucpu->pdqhead++; 859 pg->pqflags &= ~PQ_INTENT_QUEUED; 860 (void)uvmpdpol_pagerealize_locked(pg); 861 mutex_exit(&pg->interlock); 862 if (curcpu()->ci_want_resched) { 863 break; 864 } 865 } 866 if (ucpu->pdqhead == ucpu->pdqtail) { 867 ucpu->pdqtime = getticks(); 868 } 869 splx(s_spl); 870 mutex_exit(&s->lock); 871 } 872 } 873 874 #if !defined(PDSIM) 875 876 #include <sys/sysctl.h> /* XXX SYSCTL_DESCR */ 877 878 void 879 uvmpdpol_sysctlsetup(void) 880 { 881 struct uvmpdpol_globalstate *s = &pdpol_state; 882 883 uvm_pctparam_createsysctlnode(&s->s_anonmin, "anonmin", 884 SYSCTL_DESCR("Percentage of physical memory reserved " 885 "for anonymous application data")); 886 uvm_pctparam_createsysctlnode(&s->s_filemin, "filemin", 887 SYSCTL_DESCR("Percentage of physical memory reserved " 888 "for cached file data")); 889 uvm_pctparam_createsysctlnode(&s->s_execmin, "execmin", 890 SYSCTL_DESCR("Percentage of physical memory reserved " 891 "for cached executable data")); 892 893 uvm_pctparam_createsysctlnode(&s->s_anonmax, "anonmax", 894 SYSCTL_DESCR("Percentage of physical memory which will " 895 "be reclaimed from other usage for " 896 "anonymous application data")); 897 uvm_pctparam_createsysctlnode(&s->s_filemax, "filemax", 898 SYSCTL_DESCR("Percentage of physical memory which will " 899 "be reclaimed from other usage for cached " 900 "file data")); 901 uvm_pctparam_createsysctlnode(&s->s_execmax, "execmax", 902 SYSCTL_DESCR("Percentage of physical memory which will " 903 "be reclaimed from other usage for cached " 904 "executable data")); 905 906 uvm_pctparam_createsysctlnode(&s->s_inactivepct, "inactivepct", 907 SYSCTL_DESCR("Percentage of inactive queue of " 908 "the entire (active + inactive) queue")); 909 } 910 911 #endif /* !defined(PDSIM) */ 912 913 #if defined(PDSIM) 914 void 915 pdsim_dump(const char *id) 916 { 917 #if defined(DEBUG) 918 /* XXX */ 919 #endif /* defined(DEBUG) */ 920 } 921 #endif /* defined(PDSIM) */ 922