hello world takes almost 1MB of RAM


(Karl Pickett) #1

On ubuntu 14.4,
$ swiftc -v
Swift version 3.0-dev (LLVM b361b0fc05, Clang 11493b0f62, Swift 24a0c3de75)
Target: x86_64-unknown-linux-gnu

Sample program, compiled with simply "swiftc t.swift".

$ cat t.swift
import Foundation
print("hello, world\n")
while true {
    sleep(1)
}

pmap -XX <pid> shows me 4870KB RSS, 880KB of which is private dirty /
anonymous. So every additional copy you start takes 880KB of RAM. (Our
use case has thousands of processes running)

For compariso:
- a dynamically linked C/glibc program takes 88KB
- a dynamically linked C++/glibc,libstdc++ program takes 172KB
- a statically linked C++/glibc,libstdc++ program takes 64KB
- a statically linked musl c program takes just 16KB

Is this on the roadmap for improvement?

- Karl


(Dmitri Gribenko) #2

+Nadav

···

On Fri, Mar 4, 2016 at 1:30 PM, Karl Pickett via swift-users <swift-users@swift.org> wrote:

On ubuntu 14.4,
$ swiftc -v
Swift version 3.0-dev (LLVM b361b0fc05, Clang 11493b0f62, Swift 24a0c3de75)
Target: x86_64-unknown-linux-gnu

Sample program, compiled with simply "swiftc t.swift".

$ cat t.swift
import Foundation
print("hello, world\n")
while true {
    sleep(1)
}

pmap -XX <pid> shows me 4870KB RSS, 880KB of which is private dirty /
anonymous. So every additional copy you start takes 880KB of RAM. (Our
use case has thousands of processes running)

For compariso:
- a dynamically linked C/glibc program takes 88KB
- a dynamically linked C++/glibc,libstdc++ program takes 172KB
- a statically linked C++/glibc,libstdc++ program takes 64KB
- a statically linked musl c program takes just 16KB

Is this on the roadmap for improvement?

- Karl

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

--
main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if
(j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr@gmail.com>*/


(Nadav Rotem) #3

Hi Karl,

On ubuntu 14.4,
$ swiftc -v
Swift version 3.0-dev (LLVM b361b0fc05, Clang 11493b0f62, Swift 24a0c3de75)
Target: x86_64-unknown-linux-gnu

Thanks for reporting this.

Sample program, compiled with simply "swiftc t.swift".

$ cat t.swift
import Foundation
print("hello, world\n")
while true {
    sleep(1)
}

pmap -XX <pid> shows me 4870KB RSS, 880KB of which is private dirty / anonymous. So every additional copy you start takes 880KB of RAM. (Our use case has thousands of processes running)

I compiled your program on my mac and I am seeing different numbers. On my machine, "vmmap -dirty” reports ~120K of dirty memory. I wonder why there's a big difference between Mac and Linux.

Swift has memory overhead that’s related to caching of protocol conformances and generic metadata. Basically, Swift does not recompute type properties and does not check protocol conformances over and over again, because these operations are expensive in terms of runtime. Instead, Swift maintains a cache.

The ‘print’ function is a pretty big function, so in order to reduce code size in the user app we decided to keep ‘print' in the standard library and not clone-and-optimize it into every single user app. The problem is that the optimizer can’t clone-and-specialize print, so print has to work with generic types. When swift works with generic types it has to access generic metadata and allocate memory for this metadata.

Let’s try to figure out what’s taking all the memory. Try placing a breakpoint in “main”, and then after you stop at main you can place another breakpoint in “malloc”. This will allow you to separate between allocations that happen before ‘main’ and allocations made by Swift. On my machine I am seeing allocations that come from “swift_getExistentialTypeMetadata”, “swift_getGenericMetadata”, and “swift_conformsToProtocol”. This is expected. Are you seeing other memory allocations?

Why are you running thousands of processes? What are you trying to build?

For compariso:
- a dynamically linked C/glibc program takes 88KB
- a dynamically linked C++/glibc,libstdc++ program takes 172KB
- a statically linked C++/glibc,libstdc++ program takes 64KB
- a statically linked musl c program takes just 16KB

Is this on the roadmap for improvement?

Yes, we would like to reduce Swift’s memory usage, but there is no plan to remove the protocol conformance/metadata caches.

Thanks,
Nadav

···

On Mar 4, 2016, at 1:30 PM, Karl Pickett via swift-users <swift-users@swift.org> wrote:

- Karl

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Joe Groff) #4

We might be able to bypass the protocol conformance cache in common cases. Strings are by far the most common thing printed, so if print did an early check for String operands and directly dispatched it, we'd avoid warming up the conformance cache on something simple like print("Hello world"). We might want to consider alternative designs for customized printing that rely less on expensive runtime machinery too.

-Joe

···

On Mar 4, 2016, at 2:43 PM, Nadav Rotem via swift-users <swift-users@swift.org> wrote:

Hi Karl,

On Mar 4, 2016, at 1:30 PM, Karl Pickett via swift-users <swift-users@swift.org> wrote:

On ubuntu 14.4,
$ swiftc -v
Swift version 3.0-dev (LLVM b361b0fc05, Clang 11493b0f62, Swift 24a0c3de75)
Target: x86_64-unknown-linux-gnu

Thanks for reporting this.

Sample program, compiled with simply "swiftc t.swift".

$ cat t.swift
import Foundation
print("hello, world\n")
while true {
   sleep(1)
}

pmap -XX <pid> shows me 4870KB RSS, 880KB of which is private dirty / anonymous. So every additional copy you start takes 880KB of RAM. (Our use case has thousands of processes running)

I compiled your program on my mac and I am seeing different numbers. On my machine, "vmmap -dirty” reports ~120K of dirty memory. I wonder why there's a big difference between Mac and Linux.

Swift has memory overhead that’s related to caching of protocol conformances and generic metadata. Basically, Swift does not recompute type properties and does not check protocol conformances over and over again, because these operations are expensive in terms of runtime. Instead, Swift maintains a cache.

The ‘print’ function is a pretty big function, so in order to reduce code size in the user app we decided to keep ‘print' in the standard library and not clone-and-optimize it into every single user app. The problem is that the optimizer can’t clone-and-specialize print, so print has to work with generic types. When swift works with generic types it has to access generic metadata and allocate memory for this metadata.

Let’s try to figure out what’s taking all the memory. Try placing a breakpoint in “main”, and then after you stop at main you can place another breakpoint in “malloc”. This will allow you to separate between allocations that happen before ‘main’ and allocations made by Swift. On my machine I am seeing allocations that come from “swift_getExistentialTypeMetadata”, “swift_getGenericMetadata”, and “swift_conformsToProtocol”. This is expected. Are you seeing other memory allocations?

Why are you running thousands of processes? What are you trying to build?

For compariso:
- a dynamically linked C/glibc program takes 88KB
- a dynamically linked C++/glibc,libstdc++ program takes 172KB
- a statically linked C++/glibc,libstdc++ program takes 64KB
- a statically linked musl c program takes just 16KB

Is this on the roadmap for improvement?

Yes, we would like to reduce Swift’s memory usage, but there is no plan to remove the protocol conformance/metadata caches.