Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <stdint.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <errno.h>
- #include <string.h>
- #include <getopt.h>
- #include <sysexits.h>
- static uint64_t const PAGE_SIZE = 4096;
- static uint64_t read_pagecount( uint64_t pfn );
- static uint64_t read_pagecgroup( uint64_t pfn );
- static int o_show_details = 0, o_show_cgroup = 0, o_print_refs = 0, o_print_map_name = 0;
- struct summary_t {
- uint64_t total_pages;
- uint64_t total_active_pages;
- uint64_t total_shared_pages;
- } g_summary;
- /* since we cannot use here C++ std::unordered_map
- we shall use just huge arrays for calculation
- */
- typedef struct var_array_t {
- uint64_t *ptr;
- uint64_t size;
- } var_array_t;
- static var_array_t a_per_cgroup_stats;
- void init_array( var_array_t *a )
- {
- a->ptr = NULL;
- a->size = 0;
- }
- void free_array( var_array_t *a )
- {
- if( a->ptr )
- free(a->ptr);
- a->size = 0;
- }
- void put_or_append( var_array_t *a, uint64_t idx, uint64_t value )
- {
- if( a->size < idx )
- {
- // realloc
- uint64_t new_size = idx * 1.5;
- a->ptr = realloc(a->ptr, new_size * sizeof(uint64_t));
- if( NULL == a->ptr )
- perror("failed to allocate buffer");
- // fill tail with zeroes
- memset(a->ptr + a->size, 0, (new_size - a->size) * sizeof(uint64_t));
- a->size = new_size;
- }
- a->ptr[idx] += value;
- }
- static void usage()
- {
- fprintf( stderr, "Usage: show-pagemap [options] <PID>\n" );
- fprintf( stderr, "options are following:\n" );
- fprintf( stderr, "\t-d|--details: show per page details.\n" );
- fprintf( stderr, "\t-g|--cgroup: show cgroup refs from /proc/kpagecgroup.\n" );
- fprintf( stderr, "\t-r|--refs: show sharing refs from /proc/kpagecount.\n" );
- fprintf( stderr, "\t-n|--names: show map name if found.\n" );
- }
- static void dump_page(uint64_t address, uint64_t data, const char *map_name)
- {
- uint64_t pfn = data & 0x7fffffffffffff;
- uint64_t cnt = o_print_refs ? (pfn ? read_pagecount(pfn) : 0) : 0;
- uint64_t page_is_present = (data >> 63) & 1;
- int64_t cgroup_id = o_show_cgroup ? read_pagecgroup(pfn) : -1;
- if( o_show_details )
- {
- printf("0x%-16lx : PFN %-16lx refs: %ld soft-dirty %ld ex-map: %ld shared %ld "
- "swapped %ld present %ld", address, pfn, cnt,
- (data >> 55) & 1,
- (data >> 56) & 1,
- (data >> 61) & 1,
- (data >> 62) & 1,
- page_is_present);
- if( cgroup_id != -1 )
- printf(" cgroup: %ld", cgroup_id);
- if( map_name )
- printf(" name: %s", map_name);
- printf("\n");
- }
- g_summary.total_pages += 1;
- g_summary.total_active_pages += page_is_present ? 1 : 0;
- g_summary.total_shared_pages += cnt > 1 ? 1 : 0;
- if( o_show_cgroup && cgroup_id > 0 && page_is_present )
- {
- put_or_append(&a_per_cgroup_stats, cgroup_id, 1);
- }
- }
- void print_summary()
- {
- printf("Summary:\n");
- printf("total pages: %16ld = %ld Kb\n", g_summary.total_pages, g_summary.total_pages * 4);
- printf("total active(RSS): %16ld = %ld Kb\n", g_summary.total_active_pages, g_summary.total_active_pages * 4);
- printf("total shared: %16ld = %ld Kb\n", g_summary.total_shared_pages, g_summary.total_shared_pages * 4);
- if( o_show_cgroup && a_per_cgroup_stats.size )
- {
- printf("cgroup active pages:\n");
- for( uint64_t i = 0; i < a_per_cgroup_stats.size; ++i )
- {
- if( a_per_cgroup_stats.ptr[i] )
- printf("cgroup-id: %8ld %8ld = %ld Kb\n", i, a_per_cgroup_stats.ptr[i], a_per_cgroup_stats.ptr[i] * 4);
- }
- }
- }
- void read_vma(int fd, uint64_t start, uint64_t end, const char *map_name)
- {
- for(uint64_t i, val; start < end; start += PAGE_SIZE)
- {
- i = (start / PAGE_SIZE) * sizeof(uint64_t);
- if(pread(fd, &val, sizeof(uint64_t), i) != sizeof(uint64_t))
- {
- if(errno) perror("vma pread");
- break;
- }
- dump_page(i, val, map_name);
- }
- }
- void parse_maps( const char *maps_file, const char *pagemap_file )
- {
- int maps = open(maps_file, O_RDONLY);
- if(maps < 0)
- perror("open /proc/maps failed");
- int pagemap = open(pagemap_file, O_RDONLY);
- if(pagemap < 0) {
- close(maps);
- perror("open /proc/pagemap failed");
- return;
- }
- char buffer[BUFSIZ];
- int offset = 0;
- size_t y;
- for(;;) {
- ssize_t length = read(maps, buffer + offset, sizeof buffer - offset);
- if(length <= 0) break;
- length += offset;
- for(size_t i = offset; i < (size_t)length; i ++)
- {
- uint64_t low = 0, high = 0;
- if(buffer[i] == '\n' && i)
- {
- size_t x = i - 1;
- while(x && buffer[x] != '\n') x --;
- if(buffer[x] == '\n') x ++;
- size_t beginning = x;
- while(buffer[x] != '-' && x+1 < sizeof buffer) {
- char c = buffer[x ++];
- low *= 16;
- if(c >= '0' && c <= '9') {
- low += c - '0';
- }
- else if(c >= 'a' && c <= 'f') {
- low += c - 'a' + 10;
- }
- else break;
- }
- while(buffer[x] != '-' && x+1 < sizeof buffer) x ++;
- if(buffer[x] == '-') x ++;
- while(buffer[x] != ' ' && x+1 < sizeof buffer)
- {
- char c = buffer[x ++];
- high *= 16;
- if(c >= '0' && c <= '9') {
- high += c - '0';
- }
- else if(c >= 'a' && c <= 'f') {
- high += c - 'a' + 10;
- }
- else break;
- }
- const char *lib_name = 0;
- if( o_print_map_name )
- {
- for(int field = 0; field < 4; field ++) {
- x ++; // skip space
- while(buffer[x] != ' ' && x+1 < sizeof buffer) x ++;
- }
- while(buffer[x] == ' ' && x+1 < sizeof buffer) x ++;
- y = x;
- while(buffer[y] != '\n' && y+1 < sizeof buffer) y ++;
- buffer[y] = 0;
- lib_name = buffer + x;
- }
- read_vma(pagemap, low, high, lib_name);
- if( o_print_map_name )
- buffer[y] = '\n';
- }
- }
- }
- close(maps);
- close(pagemap);
- print_summary();
- }
- int main( int argc, char *argv[] )
- {
- while( 1 )
- {
- static struct option long_options[] = {
- { "details", no_argument, NULL, 'd' },
- { "cgroup", no_argument, NULL, 'g' },
- { "refs", no_argument, NULL, 'r' },
- { "names", no_argument, NULL, 'n' },
- { NULL, 0, NULL, 0 }
- };
- int op_c = getopt_long( argc, argv, "dgrn", long_options, NULL );
- if( op_c == -1 )
- break;
- switch( op_c )
- {
- case 'd':
- o_show_details = 1;
- break;
- case 'g':
- o_show_cgroup = 1;
- break;
- case 'r':
- o_print_refs = 1;
- break;
- case 'n':
- o_print_map_name = 1;
- break;
- default:
- fprintf( stderr, "invalid argument\n");
- exit( EXIT_FAILURE );
- }
- }
- argc -= optind;
- argv += optind;
- if( argc < 1 )
- {
- usage();
- exit( EX_USAGE );
- }
- errno = 0;
- int pid = (int)strtol(*argv, NULL, 0);
- if( errno )
- {
- perror("failed to parse PID");
- return 1;
- }
- init_array(&a_per_cgroup_stats);
- char maps_file[BUFSIZ];
- char pagemap_file[BUFSIZ];
- snprintf(maps_file, sizeof(maps_file), "/proc/%lu/maps", (uint64_t)pid);
- snprintf(pagemap_file, sizeof(pagemap_file), "/proc/%lu/pagemap", (uint64_t)pid);
- parse_maps(maps_file, pagemap_file);
- free_array(&a_per_cgroup_stats);
- return 0;
- }
- static int fd_pagecount = -1;
- uint64_t read_pagecount( uint64_t pfn )
- {
- /* This file contains a 64-bit count of the number of
- times each page is mapped, indexed by PFN.
- */
- if( -1 == fd_pagecount )
- {
- fd_pagecount = open("/proc/kpagecount", O_RDONLY);
- if( fd_pagecount < 0 )
- {
- perror("open kpagecount");
- return 0;
- }
- }
- uint64_t data, index = pfn * sizeof(uint64_t);
- if(pread(fd_pagecount, &data, sizeof(data), index) != sizeof(data)) {
- perror("pread kpagecount");
- return 0;
- }
- return data;
- }
- static int fd_pagecgroup = -1;
- uint64_t read_pagecgroup( uint64_t pfn )
- {
- /* This file contains a 64-bit inode number of the memory
- cgroup each page is charged to, indexed by page frame
- number (see the discussion of /proc/pid/pagemap).
- */
- if( -1 == fd_pagecgroup )
- {
- fd_pagecgroup = open("/proc/kpagecgroup", O_RDONLY);
- if( fd_pagecgroup < 0 )
- {
- perror("open kpagecgroup");
- return 0;
- }
- }
- uint64_t data, index = pfn * sizeof(uint64_t);
- if(pread(fd_pagecgroup, &data, sizeof(data), index) != sizeof(data)) {
- perror("pread kpagecgroup");
- return 0;
- }
- return data;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement