Advertisement
Fen1848

show-pagemap , (c) s.kazak

Jun 19th, 2025
427
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 9.90 KB | Source Code | 0 0
  1. // By Sergey Kazak
  2.  
  3. #include <stdint.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <unistd.h>
  7. #include <fcntl.h>
  8. #include <errno.h>
  9. #include <string.h>
  10. #include <getopt.h>
  11. #include <sysexits.h>
  12.  
  13. static uint64_t     const PAGE_SIZE = 4096;
  14.  
  15. static uint64_t read_pagecount( uint64_t pfn );
  16. static uint64_t read_pagecgroup( uint64_t pfn );
  17.  
  18. static int o_show_details = 0, o_show_cgroup = 0, o_print_refs = 0, o_print_map_name = 0;
  19.  
  20. struct summary_t {
  21.     uint64_t total_pages;
  22.     uint64_t total_active_pages;
  23.     uint64_t total_shared_pages;
  24.  
  25. } g_summary;
  26.  
  27.  
  28. /*  since we cannot use here C++ std::unordered_map
  29.     we shall use just huge arrays for calculation
  30. */
  31.  
  32.  
  33. typedef struct var_array_t {
  34.     uint64_t *ptr;
  35.     uint64_t size;
  36. } var_array_t;
  37.  
  38. static var_array_t a_per_cgroup_stats;
  39.  
  40. void init_array( var_array_t *a )
  41. {
  42.     a->ptr = NULL;
  43.     a->size = 0;
  44. }
  45.  
  46. void free_array( var_array_t *a )
  47. {
  48.     if( a->ptr )
  49.         free(a->ptr);
  50.  
  51.     a->size = 0;
  52. }
  53.  
  54. void put_or_append( var_array_t *a, uint64_t idx, uint64_t value )
  55. {
  56.     if( a->size < idx )
  57.     {
  58.         // realloc
  59.         uint64_t new_size = idx * 1.5;
  60.         a->ptr = realloc(a->ptr, new_size * sizeof(uint64_t));
  61.         if( NULL == a->ptr )
  62.             perror("failed to allocate buffer");
  63.         // fill tail with zeroes
  64.         memset(a->ptr + a->size, 0, (new_size - a->size) * sizeof(uint64_t));
  65.         a->size = new_size;
  66.     }
  67.     a->ptr[idx] += value;
  68. }
  69.  
  70.  
  71. static void usage()
  72. {
  73.     fprintf( stderr, "Usage: show-pagemap [options] <PID>\n" );
  74.     fprintf( stderr, "options are following:\n" );
  75.     fprintf( stderr, "\t-d|--details:                  show per page details.\n" );
  76.     fprintf( stderr, "\t-g|--cgroup:                   show cgroup refs from /proc/kpagecgroup.\n" );
  77.     fprintf( stderr, "\t-r|--refs:                     show sharing refs from /proc/kpagecount.\n" );
  78.     fprintf( stderr, "\t-n|--names:                    show map name if found.\n" );
  79. }
  80.  
  81. static void dump_page(uint64_t address, uint64_t data, const char *map_name)
  82. {
  83.     uint64_t pfn = data & 0x7fffffffffffff;
  84.     uint64_t cnt = o_print_refs ? (pfn ? read_pagecount(pfn) : 0) : 0;
  85.  
  86.     uint64_t page_is_present = (data >> 63) & 1;
  87.  
  88.     int64_t cgroup_id = o_show_cgroup ? read_pagecgroup(pfn) : -1;
  89.  
  90.     if( o_show_details )
  91.     {
  92.         printf("0x%-16lx : PFN %-16lx refs: %ld soft-dirty %ld ex-map: %ld shared %ld "
  93.             "swapped %ld present %ld", address, pfn, cnt,
  94.             (data >> 55) & 1,
  95.             (data >> 56) & 1,
  96.             (data >> 61) & 1,
  97.             (data >> 62) & 1,
  98.             page_is_present);
  99.  
  100.         if( cgroup_id != -1 )
  101.             printf(" cgroup: %ld", cgroup_id);
  102.  
  103.         if( map_name )
  104.             printf(" name: %s", map_name);
  105.        
  106.         printf("\n");
  107.     }
  108.  
  109.     g_summary.total_pages += 1;
  110.     g_summary.total_active_pages += page_is_present ? 1 : 0;
  111.     g_summary.total_shared_pages += cnt > 1 ? 1 : 0;
  112.  
  113.     if( o_show_cgroup && cgroup_id > 0 && page_is_present )
  114.     {
  115.         put_or_append(&a_per_cgroup_stats, cgroup_id, 1);
  116.     }
  117. }
  118.  
  119. void print_summary()
  120. {
  121.     printf("Summary:\n");
  122.     printf("total pages:       %16ld = %ld Kb\n", g_summary.total_pages, g_summary.total_pages * 4);
  123.     printf("total active(RSS): %16ld = %ld Kb\n", g_summary.total_active_pages, g_summary.total_active_pages * 4);
  124.     printf("total shared:      %16ld = %ld Kb\n", g_summary.total_shared_pages, g_summary.total_shared_pages * 4);
  125.  
  126.     if( o_show_cgroup && a_per_cgroup_stats.size )
  127.     {
  128.         printf("cgroup active pages:\n");
  129.         for( uint64_t i = 0; i < a_per_cgroup_stats.size; ++i )
  130.         {
  131.             if( a_per_cgroup_stats.ptr[i] )
  132.                 printf("cgroup-id:       %8ld %8ld = %ld Kb\n", i, a_per_cgroup_stats.ptr[i], a_per_cgroup_stats.ptr[i] * 4);
  133.         }
  134.     }
  135. }
  136.  
  137. void read_vma(int fd, uint64_t start, uint64_t end, const char *map_name)
  138. {
  139.     for(uint64_t i, val; start < end; start += PAGE_SIZE)
  140.     {
  141.         i = (start / PAGE_SIZE) * sizeof(uint64_t);
  142.         if(pread(fd, &val, sizeof(uint64_t), i) != sizeof(uint64_t))
  143.         {
  144.             if(errno) perror("vma pread");
  145.             break;
  146.         }
  147.         dump_page(i, val, map_name);
  148.     }
  149. }
  150.  
  151. void parse_maps( const char *maps_file, const char *pagemap_file )
  152. {
  153.     int maps = open(maps_file, O_RDONLY);
  154.     if(maps < 0)
  155.         perror("open /proc/maps failed");
  156.  
  157.     int pagemap = open(pagemap_file, O_RDONLY);
  158.     if(pagemap < 0) {
  159.         close(maps);
  160.         perror("open /proc/pagemap failed");
  161.         return;
  162.     }
  163.  
  164.     char buffer[BUFSIZ];
  165.     int offset = 0;
  166.     size_t y;
  167.  
  168.     for(;;) {
  169.         ssize_t length = read(maps, buffer + offset, sizeof buffer - offset);
  170.         if(length <= 0) break;
  171.  
  172.         length += offset;
  173.  
  174.         for(size_t i = offset; i < (size_t)length; i ++)
  175.         {
  176.             uint64_t low = 0, high = 0;
  177.             if(buffer[i] == '\n' && i)
  178.             {
  179.                 size_t x = i - 1;
  180.                 while(x && buffer[x] != '\n') x --;
  181.                 if(buffer[x] == '\n') x ++;
  182.                 size_t beginning = x;
  183.  
  184.                 while(buffer[x] != '-' && x+1 < sizeof buffer) {
  185.                     char c = buffer[x ++];
  186.                     low *= 16;
  187.                     if(c >= '0' && c <= '9') {
  188.                         low += c - '0';
  189.                     }
  190.                     else if(c >= 'a' && c <= 'f') {
  191.                         low += c - 'a' + 10;
  192.                     }
  193.                     else break;
  194.                 }
  195.  
  196.                 while(buffer[x] != '-' && x+1 < sizeof buffer) x ++;
  197.                 if(buffer[x] == '-') x ++;
  198.  
  199.                 while(buffer[x] != ' ' && x+1 < sizeof buffer)
  200.                 {
  201.                     char c = buffer[x ++];
  202.                     high *= 16;
  203.                     if(c >= '0' && c <= '9') {
  204.                         high += c - '0';
  205.                     }
  206.                     else if(c >= 'a' && c <= 'f') {
  207.                         high += c - 'a' + 10;
  208.                     }
  209.                     else break;
  210.                 }
  211.  
  212.                 const char *lib_name = 0;
  213.                 if( o_print_map_name )
  214.                 {
  215.                     for(int field = 0; field < 4; field ++) {
  216.                         x ++;  // skip space
  217.                         while(buffer[x] != ' ' && x+1 < sizeof buffer) x ++;
  218.                     }
  219.                     while(buffer[x] == ' ' && x+1 < sizeof buffer) x ++;
  220.  
  221.                     y = x;
  222.                     while(buffer[y] != '\n' && y+1 < sizeof buffer) y ++;
  223.                     buffer[y] = 0;
  224.  
  225.                     lib_name = buffer + x;
  226.                 }
  227.  
  228.                 read_vma(pagemap, low, high, lib_name);
  229.  
  230.                 if( o_print_map_name )
  231.                     buffer[y] = '\n';
  232.             }
  233.         }
  234.     }
  235.  
  236.     close(maps);
  237.     close(pagemap);
  238.  
  239.     print_summary();
  240. }
  241.  
  242. int main( int argc, char *argv[] )
  243. {
  244.     while( 1 )
  245.     {
  246.  
  247.         static struct option long_options[] = {
  248.             { "details",              no_argument,    NULL, 'd' },
  249.             { "cgroup",               no_argument,    NULL, 'g' },
  250.             { "refs",                 no_argument,    NULL, 'r' },
  251.             { "names",                no_argument,    NULL, 'n' },
  252.             { NULL,                             0,    NULL, 0   }
  253.         };
  254.  
  255.         int op_c = getopt_long( argc, argv, "dgrn", long_options, NULL );
  256.         if( op_c == -1 )
  257.             break;
  258.  
  259.         switch( op_c )
  260.         {
  261.             case 'd':
  262.                 o_show_details = 1;
  263.                 break;
  264.             case 'g':
  265.                 o_show_cgroup = 1;
  266.                 break;
  267.             case 'r':
  268.                 o_print_refs = 1;
  269.                 break;
  270.             case 'n':
  271.                 o_print_map_name = 1;
  272.                 break;
  273.             default:
  274.                 fprintf( stderr, "invalid argument\n");
  275.                 exit( EXIT_FAILURE );
  276.         }
  277.     }
  278.  
  279.     argc -= optind;
  280.     argv += optind;
  281.  
  282.     if( argc < 1 )
  283.     {
  284.         usage();
  285.         exit( EX_USAGE );
  286.     }
  287.  
  288.     errno = 0;
  289.     int pid = (int)strtol(*argv, NULL, 0);
  290.     if( errno )
  291.     {
  292.         perror("failed to parse PID");
  293.         return 1;
  294.     }
  295.  
  296.     init_array(&a_per_cgroup_stats);
  297.    
  298.     char maps_file[BUFSIZ];
  299.     char pagemap_file[BUFSIZ];
  300.     snprintf(maps_file, sizeof(maps_file), "/proc/%lu/maps", (uint64_t)pid);
  301.     snprintf(pagemap_file, sizeof(pagemap_file), "/proc/%lu/pagemap", (uint64_t)pid);
  302.  
  303.     parse_maps(maps_file, pagemap_file);
  304.  
  305.     free_array(&a_per_cgroup_stats);
  306.  
  307.     return 0;
  308. }
  309.  
  310. static int fd_pagecount = -1;
  311.  
  312. uint64_t read_pagecount( uint64_t pfn )
  313. {
  314.    /* This file contains a 64-bit count of the number of
  315.    times each page is mapped, indexed by PFN.
  316.    */
  317.    if( -1 == fd_pagecount )
  318.    {
  319.       fd_pagecount = open("/proc/kpagecount", O_RDONLY);
  320.       if( fd_pagecount < 0 )
  321.       {
  322.          perror("open kpagecount");
  323.          return 0;
  324.       }
  325.    }
  326.  
  327.    uint64_t data, index = pfn * sizeof(uint64_t);
  328.  
  329.    if(pread(fd_pagecount, &data, sizeof(data), index) != sizeof(data)) {
  330.       perror("pread kpagecount");
  331.       return 0;
  332.    }
  333.  
  334.    return data;
  335. }
  336.  
  337. static int fd_pagecgroup = -1;
  338.  
  339. uint64_t read_pagecgroup( uint64_t pfn )
  340. {
  341.     /* This file contains a 64-bit inode number of the memory
  342.               cgroup each page is charged to, indexed by page frame
  343.               number (see the discussion of /proc/pid/pagemap).
  344.    */
  345.  
  346.    if( -1 == fd_pagecgroup )
  347.    {
  348.       fd_pagecgroup = open("/proc/kpagecgroup", O_RDONLY);
  349.       if( fd_pagecgroup < 0 )
  350.       {
  351.          perror("open kpagecgroup");
  352.          return 0;
  353.       }
  354.    }
  355.  
  356.    uint64_t data, index = pfn * sizeof(uint64_t);
  357.  
  358.    if(pread(fd_pagecgroup, &data, sizeof(data), index) != sizeof(data)) {
  359.       perror("pread kpagecgroup");
  360.       return 0;
  361.    }
  362.  
  363.    return data;
  364. }
  365.  
  366.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement