virtcontainers/qemu: reduce memory footprint#296
virtcontainers/qemu: reduce memory footprint#296egernst merged 2 commits intokata-containers:masterfrom
Conversation
063f4f4 to
ded5fad
Compare
|
Nice findings! I wasn't aware the maxcpus limit can have so much impact on memory footprint! Thanks @devimc ! And it LGTM! |
|
Awesome Never noticed the impaction of |
|
This is a great improvement! |
|
Von meinem iPhone gesendet
Am 10.05.2018 um 15:50 schrieb zhangwei_cs <notifications@github.com>:
This is a great improvement!
One question, should we make this configurable ? Then the service provider can choose to make the VM smaller via a smaller maxcpus
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub, or mute the thread.
|
|
@WeiZhang555 @ChristophSGR - Yes I think we should. @devimc is OOO today -- I'm sure he can take a look tomorrow (unless someone wants to add a patch to this PR in the meantime!) |
|
I thought about this ("make this configurable") as well, but I'd like to accept this patch and have another patch on configurable things if @devimc do not have a slot on this. |
|
@gnawux - sure this is fine. I think we shoudl get this in ASAP for sure. I want to wait until we can get the tests update (seems like a legit CI failure) |
|
@egernst agree |
virtcontainers/qemu_amd64.go
Outdated
| // returns the maximum number of vCPUs supported | ||
| func maxQemuVCPUs() uint32 { | ||
| return uint32(240) | ||
| return uint32(runtime.NumCPU()) |
There was a problem hiding this comment.
There will be some problems if the physical machine has more than 240 physical CPUs, right?
I think we should choose MAX(runtime.NumCPU(), 240) here
|
Sounds fair enough to merge this first, after fixing the CI problem. |
ded5fad to
b958d95
Compare
|
CI is not happy because of Azure VM has 4 CPUs and CRIO tries to create a container with 5 vCPUs hence I need to make |
5444864 to
ff26a40
Compare
|
please take a look, all these changes are needed to reduce memory footprint and make CRIO happy |
cli/config.go
Outdated
| return uint32(numcpus) | ||
| } | ||
|
|
||
| if h.DefaultMaxVCPUs > int32(numcpus) { |
There was a problem hiding this comment.
yes, in case of user value is greater than the actual number of physical CPUs, we need to check this values doesn't exceed the maximum number of vCPUs supported by QEMU/KVM.
Adding a comment in the code.
Thanks
There was a problem hiding this comment.
ohhh wait.. docker and kubernetes don't allow you to create containers with a number of CPUs greater than the actual number of physical CPUs, hence we don't need this condition, thanks
$ docker run --cpus 10 -ti centos bash
docker: Error response from daemon: Range of CPUs is from 0.01 to 8.00, as there are only 8 CPUs available.
egernst
left a comment
There was a problem hiding this comment.
A few queries here. Looks good in general, and like the additional commit.
virtcontainers/qemu.go
Outdated
| // to reach out max vCPUs | ||
| if currentVCPUs+amount > q.config.DefaultMaxVCPUs { | ||
| return fmt.Errorf("Unable to hotplug %d CPUs, currently this SB has %d CPUs and the maximum amount of CPUs is %d", | ||
| q.Logger().Warnf("Cannot to hotplug %d CPUs, currently this SB has %d CPUs and the maximum amount of CPUs is %d", |
cli/config.go
Outdated
| KernelParams string `toml:"kernel_params"` | ||
| MachineType string `toml:"machine_type"` | ||
| DefaultVCPUs int32 `toml:"default_vcpus"` | ||
| DefaultMaxVCPUs int32 `toml:"default_maxvcpus"` |
There was a problem hiding this comment.
Why signed int? Is there a scenario where you'd have a negative number number of CPUs?
There was a problem hiding this comment.
this is part of configuration file, if this value is <= 0 then the actual number of vCPUs will be used
There was a problem hiding this comment.
my question is why negative needs to be supported? Seems == 0 should be enough here?
There was a problem hiding this comment.
yep, it should be enough, do you prefer to have an uint32 here?
There was a problem hiding this comment.
I used an int32 to support negative values and be similar to default_vcpus
cli/config.go
Outdated
| numcpus := goruntime.NumCPU() | ||
| maxvcpus := vc.MaxQemuVCPUs() | ||
|
|
||
| if h.DefaultMaxVCPUs <= 0 { |
virtcontainers/container.go
Outdated
| return c.sandbox.agent.onlineCPUMem(uint32(vCPUs)) | ||
| vcpusAdded, ok := data.(uint32) | ||
| if !ok { | ||
| return fmt.Errorf("Could not get the number of vCPUs added") |
There was a problem hiding this comment.
This error is used multiple times so you could create a global for it maybe?
var errVCPUs = errors.New("Could not get the number of vCPUs added")
Having said that, it might be more useful to add the container ID to the returned error (which would justify using fmt.Errorf() rather than just errors.New(), which is all that is currently required).
There was a problem hiding this comment.
I'll include data in the error, thanks
virtcontainers/container.go
Outdated
| } | ||
|
|
||
| vCPUs := utils.ConstraintsToVCPUs(c.config.Resources.CPUQuota, c.config.Resources.CPUPeriod) | ||
| // fetch current configuration |
There was a problem hiding this comment.
This block is almost identical to the one added in addResources(). Could you refactor to create a new function they can both call. Something like:
// if add is true, add the VCPUs in the container config, else remove them.
func (c *Container) handleVCPUs(add bool) error
There was a problem hiding this comment.
you're right, updating commit, thanks
ff26a40 to
2023f3c
Compare
Codecov Report
@@ Coverage Diff @@
## master #296 +/- ##
==========================================
- Coverage 64.35% 64.35% -0.01%
==========================================
Files 86 86
Lines 8430 8469 +39
==========================================
+ Hits 5425 5450 +25
- Misses 2429 2441 +12
- Partials 576 578 +2
Continue to review full report at Codecov.
|
cli/config.go
Outdated
| return uint32(numcpus) | ||
| } | ||
|
|
||
| return uint32(h.DefaultMaxVCPUs) |
There was a problem hiding this comment.
This logic is still a bit odd to me. What happens if default-provided is not greater than numcpus, but it is still greater than is greater than maxvcpus?
e.g., max-from-hypervisor is 100, number of physical cores is 120, but our configured default is 110?
Also I think you should s/QEMU/hypervisor?
There was a problem hiding this comment.
e.g., max-from-hypervisor is 100, number of physical cores is 120, but our configured default is 110?
to avoid issues with KVM, the maximum number of CPUs supported by KVM is used, in this example 100
Also I think you should s/QEMU/hypervisor?
sure, I can do it, but in another PR, wdyt?
|
@egernst @jodh-intel @gnawux changes applied, thanks |
2023f3c to
92b57f7
Compare
|
@egernst changes applied |
92b57f7 to
e2db932
Compare
cli/config.go
Outdated
|
|
||
| // Don't exceed the maximum number of vCPUs supported by hypervisor | ||
| if h.DefaultMaxVCPUs >= maxvcpus { | ||
| return maxvcpus |
There was a problem hiding this comment.
what if the default is also greater than numcpus? I think what you want is:
reqVCPUS := h.DefaultMaxVCPUS
//don't exceed the number of physical CPUs. If a default is not provided, use the
// numbers of physical CPUs
if reqVCPUS >= numcpus || reqVCPUS == 0 {
reqVCPUS := numcpus
}
// Don't exceed the maximum number of vCPUs supported by hypervisor
if (reqVCPUS > maxvcpus ) {
return maxvcpus
}
return reqVCPUS
There was a problem hiding this comment.
actually is the same, but your code looks better, updating pr, thanks
There is a relation between the maximum number of vCPUs and the
memory footprint, if QEMU maxcpus option and kernel nr_cpus
cmdline argument are big, then memory footprint is big, this
issue only occurs if CPU hotplug support is enabled in the kernel,
might be because of kernel needs to allocate resources to watch all
sockets waiting for a CPU to be connected (ACPI event).
For example
```
+---------------+-------------------------+
| | Memory Footprint (KB) |
+---------------+-------------------------+
| NR_CPUS=240 | 186501 |
+---------------+-------------------------+
| NR_CPUS=8 | 110684 |
+---------------+-------------------------+
```
In order to do not affect CPU hotplug and allow to users to have containers
with the same number of physical CPUs, this patch tries to mitigate the
big memory footprint by using the actual number of physical CPUs as the
maximum number of vCPUs for each container if `default_maxvcpus` is <= 0 in
the runtime configuration file, otherwise `default_maxvcpus` is used as the
maximum number of vCPUs.
Before this patch a container with 256MB of RAM
```
total used free shared buff/cache available
Mem: 195M 40M 113M 26M 41M 112M
Swap: 0B 0B 0B
```
With this patch
```
total used free shared buff/cache available
Mem: 236M 11M 188M 26M 36M 186M
Swap: 0B 0B 0B
```
fixes kata-containers#295
Signed-off-by: Julio Montes <julio.montes@intel.com>
Don't fail if a new container with a CPU constraint was added to a POD and no more vCPUs are available, instead apply the constraint and let kernel balance the resources. Signed-off-by: Julio Montes <julio.montes@intel.com>
e2db932 to
4527a80
Compare
There is a relation between the maximum number of vCPUs and the
memory footprint, if QEMU maxcpus option and kernel nr_cpus
cmdline argument are big, then memory footprint is big, this
issue only occurs if CPU hotplug support is enabled in the kernel,
might be because of kernel needs to allocate resources to watch all
sockets waiting for a CPU to be connected (ACPI event).
For example
In order to do not affect CPU hotplug and allow to users to have containers
with the same number of physical CPUs, this patch tries to mitigate the
big memory footprint by using the actual number of physical CPUs as the
maximum number of vCPUs for each container.
Before this patch a container with 256MB of RAM
With this patch
fixes #295
Signed-off-by: Julio Montes julio.montes@intel.com