For use in production you are right, we need some benchmarking. Both
memory overhead and startup latency as mentioned by Dominig are
relevant. Do we have tools in Tizen for measuring shared vs. unshared
memory mappings? More specifically, how did you identify the 1.5 MB
number above?
I fixed the Tizen-specific issues that I mentioned in my announcement,
so I can run some benchmarks on a VTC1010 now.
I used simple test script (hello.py):
#! /usr/bin/python
print 'Hello World'
raw_input()
On the second terminal I ran:
top -p $(pgrep hello.py)
I got such results:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
2507 root 20 0 5956 3080 1452 S 0.0 0.1 0:00.01 hello.py
RES column denotes how much physical memory given process uses. SHR
shows how much physical memory is shareable. I assume that the rest is
private to the process (about 1.6 MB).
This is consistent with what /proc/<pid>/smaps contains. It gives
information such as resident set size and how much memory is shared or
private for each mapping.
Before I was made aware that /proc/<pid>/smaps contains these useful
information I wrote a python script that parses information from
/proc/<pid>/maps and /proc/<pid>/pagemap files (attached) and output it
shows also confirms figure I talked about.
Best regards,
--
Jacek Bukarewicz
Samsung R&D Institute Poland
Samsung Electronics
[email protected]
#! /usr/bin/python
# Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License
import subprocess
import struct
import argparse
def get_vmem_region(range_string):
virtual_memory_region=range_string.split("-")
start=int(virtual_memory_region[0], 16)
end=int(virtual_memory_region[1], 16)
return (start, end)
def page_info_range(pagemap_file, virtual_pfn_start, virtual_pfn_end):
for pfn in xrange(virtual_pfn_start, virtual_pfn_end):
pagemap_file.seek(8*pfn)
tmp=pagemap_file.read(8)
if (len(tmp) == 8): # reading pagemap file fails for [vsyscall] region
page_info=struct.unpack('Q', tmp)
yield pfn, page_info[0]
# heap or stack(s)
def is_data(map_line_parsed):
return len(map_line_parsed) == 6 and (map_line_parsed[5].startswith('[stack') or \
map_line_parsed[5] == '[heap]')
def is_anonymous(map_line_parsed):
return len(map_line_parsed) < 6 or map_line_parsed[5].startswith('/dev/zero')
def print_map_info():
with open(proc_maps_path) as f:
proc_maps = f.readlines()
virt_total=0
phys_total=0
virt_data_total=0
phys_data_total=0
swapped_total=0
data_swapped_total=0
phys_shared_total=0
phys_private_total=0
phys_anon_total=0
print "%025s %06s %08s %05s %8s %8s %6s %4s %4s %s" % ('VIRTUAL ADDRESS RANGE', \
'PERMS', 'OFFSET', 'DEV', 'INODE', 'VIRT', 'PHYS', 'SHR', 'PRIV', 'PATHNAME')
with open(proc_pagemap_path) as f:
for map_line in proc_maps:
map_line_parsed = map_line.split()
vmem_region = get_vmem_region(map_line_parsed[0])
virt_pfn_start = vmem_region[0]/page_size
virt_pfn_end = vmem_region[1]/page_size
virt_size = vmem_region[1] - vmem_region[0]
phys_pages_count = 0
swapped_count = 0
shared_pages_count = 0
private_pages_count = 0
for virt_pfn, page_info in page_info_range(f, virt_pfn_start, virt_pfn_end):
if page_info & (0x3 << 62): # 'page present' or 'page swapped' bit set
phys_pages_count += 1
if page_info & (0x1 << 62): # 'page swapped' bit set
swapped_count += 1
if (page_info & (0x1 << 61)): # 'page is file-page or shared-anon' (kernel >= 3.5)
shared_pages_count += 1
else:
private_pages_count += 1
phys_size = page_size*phys_pages_count
swapped_size = page_size*swapped_count
virt_total += virt_size
phys_total += phys_size
swapped_total += swapped_size
shared_size = shared_pages_count*page_size
phys_shared_total += shared_size
private_size = private_pages_count*page_size
phys_private_total += private_size
if is_data(map_line_parsed):
virt_data_total += virt_size
phys_data_total += phys_size
data_swapped_total += swapped_size
if is_anonymous(map_line_parsed):
phys_anon_total += phys_size
path = ''
if len(map_line_parsed) >= 6:
path=map_line_parsed[5]
print "%025s %06s %08s %05s %8s %8dK %6dK %4dK %4dK %s" % (map_line_parsed[0],
map_line_parsed[1], map_line_parsed[2],
map_line_parsed[3], map_line_parsed[4],virt_size/1024,
phys_size/1024, shared_size/1024, private_size/1024,
path)
print
print 'Virtual memory:'
print ' Total: %dK' % (virt_total/1024)
print
print 'Physical memory:'
print ' Total: %dK' % (phys_total/1024)
print ' Swapped: %dK' % (swapped_total/1024)
print ' Shared: %dK' % (phys_shared_total/1024)
print ' Private: %dK' % (phys_private_total/1024)
print ' Heap + stacks: %dK' % (phys_data_total/1024)
print ' Anonymous mappings: %dK' % (phys_anon_total/1024)
def dump_mmu_mappings(virt_pfn_start, virt_pfn_end):
with open(proc_pagemap_path) as f:
for virt_pfn, page_info in page_info_range(f, virt_pfn_start, virt_pfn_end):
if page_info & (0x1 << 62):
print "%012X -> (swapped)" % (virt_pfn*page_size)
else:
phys_pfn = page_info & ((0x1 << 55) - 1)
print "%012X -> %010X " % (virt_pfn*page_size, phys_pfn*page_size)
def print_interactive_commands():
print 'q - quit'
print 'r - refresh'
print 'd virt_start-virt_end - dump MMU mappings for the given virtual address range'
def process_commands():
while True:
line = raw_input()
parsed = line.split()
if len(parsed) > 0:
if parsed[0] == 'q':
break
elif parsed[0] == 'r':
print_map_info()
continue
elif parsed[0] == 'd':
if len(parsed) == 2:
vmem_range=get_vmem_region(parsed[1])
dump_mmu_mappings(int(vmem_range[0])/page_size, int(vmem_range[1])/page_size)
continue
print_interactive_commands()
if __name__ == "__main__":
interactive = True
parser = argparse.ArgumentParser(description='Print detailed memory mappings for given process')
parser.add_argument('-n', action='store_true', help='non-interactive mode')
parser.add_argument('pid', help='process id')
args = parser.parse_args()
if args.n:
interactive = False
pid = args.pid
page_size = int(subprocess.check_output(['getconf', 'PAGESIZE']))
proc_maps_path = '/proc/' + pid + '/maps'
proc_pagemap_path = '/proc/' + pid + '/pagemap'
print_map_info()
if interactive:
print
print_interactive_commands()
process_commands()
_______________________________________________
Dev mailing list
[email protected]
https://lists.tizen.org/listinfo/dev