VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMAll/PDMAllNetShaper.cpp@ 93631

Last change on this file since 93631 was 93631, checked in by vboxsync, 3 years ago

VMM/PDMNetShaper: Don't start the unchoke thread unless there are are one or more bandwidth groups configured. Make the unchoke thread wait on an event sempahore so it can be woken up when needed and stop wasting cpu cycles and battery on lots of unnecessary wakups. Use a timer (real time clock) to wake up the unchoke timer when needed. bugref:10093 bugref:5582

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 5.6 KB
Line 
1/* $Id: PDMAllNetShaper.cpp 93631 2022-02-07 00:45:08Z vboxsync $ */
2/** @file
3 * PDM Network Shaper - Limit network traffic according to bandwidth group settings.
4 */
5
6/*
7 * Copyright (C) 2011-2022 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_NET_SHAPER
23#include <VBox/vmm/pdmnetshaper.h>
24#include "PDMInternal.h"
25#include <VBox/vmm/vmcc.h>
26
27#include <VBox/log.h>
28#include <iprt/time.h>
29
30
31/**
32 * Obtain bandwidth in a bandwidth group.
33 *
34 * @returns True if bandwidth was allocated, false if not.
35 * @param pVM The cross context VM structure.
36 * @param pFilter Pointer to the filter that allocates bandwidth.
37 * @param cbTransfer Number of bytes to allocate.
38 */
39VMM_INT_DECL(bool) PDMNetShaperAllocateBandwidth(PVMCC pVM, PPDMNSFILTER pFilter, size_t cbTransfer)
40{
41 AssertPtrReturn(pFilter, true);
42
43 /*
44 * If we haven't got a valid bandwidth group, we always allow the traffic.
45 */
46 bool fAllowed = true;
47 uint32_t iGroup = ASMAtomicUoReadU32(&pFilter->iGroup);
48 if (iGroup != 0)
49 {
50 if (iGroup <= RT_MIN(pVM->pdm.s.cNsGroups, RT_ELEMENTS(pVM->pdm.s.aNsGroups)))
51 {
52 PPDMNSBWGROUP pGroup = &pVM->pdm.s.aNsGroups[iGroup - 1];
53 int rc = PDMCritSectEnter(pVM, &pGroup->Lock, VINF_TRY_AGAIN);
54 if (rc == VINF_SUCCESS)
55 {
56 uint64_t const cbPerSecMax = pGroup->cbPerSecMax;
57 if (cbPerSecMax > 0)
58 {
59 /*
60 * Re-fill the bucket first
61 */
62 uint64_t const nsNow = RTTimeSystemNanoTS();
63 uint64_t const cNsDelta = nsNow - pGroup->tsUpdatedLast;
64 /** @todo r=bird: there might be an overflow issue here if the gap
65 * between two transfers is too large. */
66 uint32_t cTokensAdded = cNsDelta * cbPerSecMax / RT_NS_1SEC;
67
68 uint32_t const cbBucket = pGroup->cbBucket;
69 uint32_t const cbTokensLast = pGroup->cbTokensLast;
70 uint32_t const cTokens = RT_MIN(cbBucket, cTokensAdded + cbTokensLast);
71
72 /*
73 * Allowed?
74 */
75 if (cbTransfer <= cTokens)
76 {
77 pGroup->cbTokensLast = cTokens - (uint32_t)cbTransfer;
78 pGroup->tsUpdatedLast = nsNow;
79 Log2(("pdmNsAllocateBandwidth/%s: allowed - cbTransfer=%#zx cTokens=%#x cTokensAdded=%#x\n",
80 pGroup->szName, cbTransfer, cTokens, cTokensAdded));
81 }
82 else
83 {
84 /*
85 * No, we're choked. Arm the unchoke timer for the next period.
86 * Just do this on a simple PDM_NETSHAPER_MAX_LATENCY clock granularity.
87 * ASSUMES the timer uses millisecond resolution clock.
88 */
89 ASMAtomicWriteBool(&pFilter->fChoked, true);
90 if (ASMAtomicCmpXchgBool(&pVM->pdm.s.fNsUnchokeTimerArmed, true, false))
91 {
92 Assert(TMTimerGetFreq(pVM, pVM->pdm.s.hNsUnchokeTimer) == RT_MS_1SEC);
93 uint64_t const msNow = TMTimerGet(pVM, pVM->pdm.s.hNsUnchokeTimer);
94 uint64_t const msExpire = (msNow / PDM_NETSHAPER_MAX_LATENCY + 1) * PDM_NETSHAPER_MAX_LATENCY;
95 rc = TMTimerSet(pVM, pVM->pdm.s.hNsUnchokeTimer, msExpire);
96 AssertRC(rc);
97
98 Log2(("pdmNsAllocateBandwidth/%s: refused - cbTransfer=%#zx cTokens=%#x cTokensAdded=%#x cMsExpire=%u\n",
99 pGroup->szName, cbTransfer, cTokens, cTokensAdded, msExpire - msNow));
100 }
101 else
102 Log2(("pdmNsAllocateBandwidth/%s: refused - cbTransfer=%#zx cTokens=%#x cTokensAdded=%#x\n",
103 pGroup->szName, cbTransfer, cTokens, cTokensAdded));
104 fAllowed = false;
105 }
106 }
107 else
108 Log2(("pdmNsAllocateBandwidth/%s: disabled\n", pGroup->szName));
109
110 rc = PDMCritSectLeave(pVM, &pGroup->Lock);
111 AssertRCSuccess(rc);
112 }
113 else if (rc == VINF_TRY_AGAIN) /* (accounted for by the critsect stats) */
114 Log2(("pdmNsAllocateBandwidth/%s: allowed - lock contention\n", pGroup->szName));
115 else
116 PDM_CRITSECT_RELEASE_ASSERT_RC(pVM, &pGroup->Lock, rc);
117 }
118 else
119 AssertMsgFailed(("Invalid iGroup=%d\n", iGroup));
120 }
121 return fAllowed;
122}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette