2
0

analyze-debug-alloc.pl 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. #!/usr/bin/perl
  2. # analyze-debug-alloc.pl
  3. # generate allocation report by processing log files
  4. # Note that this script is only useful when run against freeswitch log files
  5. # produced when server is running with DEBUG_ALLOC and DEBUG_ALLOC2 set.
  6. # It's purely for diagnosing memory leaks.
  7. use strict;
  8. use JSON;
  9. my $debug = 0;
  10. my @logs = sort glob("freeswitch.log.*");
  11. push( @logs, "freeswitch.log" );
  12. my %pools = ();
  13. foreach my $file (@logs) {
  14. open( my $in, "<$file" );
  15. while ( defined( my $line = <$in> ) ) {
  16. if ( $line =~ /(0x[0-9A-Fa-f]+) DESTROY POOL$/o ) {
  17. my $paddr = $1;
  18. if ( !$pools{$paddr} ) {
  19. $debug && print "WARN: No ref to pool $paddr.\n";
  20. }
  21. else {
  22. foreach my $alloc ( @{ $pools{$paddr}->{allocs} } ) {
  23. # debug, might not be needed
  24. }
  25. delete $pools{$paddr};
  26. }
  27. }
  28. elsif ( $line =~ /(0x[0-9A-Fa-f]+) Free Pool/o ) {
  29. my $paddr = $1;
  30. if ( !$pools{$paddr} ) {
  31. $debug && print "WARN: No ref to pool $paddr.\n";
  32. }
  33. else {
  34. foreach my $alloc ( @{ $pools{$paddr}->{allocs} } ) {
  35. # debug, might not be needed
  36. }
  37. delete $pools{$paddr};
  38. }
  39. }
  40. elsif ( $line =~ /(0x[0-9A-Fa-f]+) New Pool (.*)$/o ) {
  41. my $paddr = $1;
  42. my $where = $2;
  43. if ( $pools{$paddr} ) {
  44. $debug && print "WARN: Duplicate pool $paddr at $where.\n";
  45. }
  46. $pools{$paddr}->{where} = $where;
  47. if ( !$pools{$paddr}->{allocs} ) {
  48. $pools{$paddr}->{allocs} = [];
  49. }
  50. }
  51. elsif ( $line =~ /CONSOLE\] \s*(.*?:\d+) (0x[0-9A-Fa-f]+) Core Allocate (.*:\d+)\s+(\d+)$/o ) {
  52. my $where = $1;
  53. my $paddr = $2;
  54. my $pwhere = $3;
  55. my $size = $4;
  56. if ( !$pools{$paddr} ) {
  57. $debug && print "WARN: Missing pool ref for alloc of $size from $paddr at $where (pool $pwhere)\n";
  58. }
  59. $pools{$paddr}->{where} = $where;
  60. push( @{ $pools{$paddr}->{allocs} }, { size => $size, where => $where } );
  61. }
  62. elsif ( $line =~ /CONSOLE\] \s*(.*?:\d+) (0x[0-9A-Fa-f]+) Core Strdup Allocate (.*:\d+)\s+(\d+)$/o ) {
  63. my $where = $1;
  64. my $paddr = $2;
  65. my $pwhere = $3;
  66. my $size = $4;
  67. if ( !$pools{$paddr} ) {
  68. $debug
  69. && print "WARN: Missing pool ref for strdup alloc of $size from $paddr at $where (pool $pwhere)\n";
  70. }
  71. $pools{$paddr}->{where} = $where;
  72. push( @{ $pools{$paddr}->{allocs} }, { size => $size, where => $where } );
  73. }
  74. }
  75. }
  76. my $used = 0;
  77. my $pcount = 0;
  78. my $acount = 0;
  79. my %pool_cnt_by_where = ();
  80. my %alloc_size_by_where = ();
  81. my %alloc_cnt_by_where = ();
  82. foreach my $pool ( keys %pools ) {
  83. my $where = $pools{$pool}->{where};
  84. $pcount++;
  85. $pool_cnt_by_where{$where}++;
  86. foreach my $alloc ( @{ $pools{$pool}->{allocs} } ) {
  87. my $sz = $alloc->{size};
  88. my $where = $alloc->{where};
  89. $acount++;
  90. $alloc_size_by_where{$where} += $sz;
  91. $alloc_cnt_by_where{$where}++;
  92. $used += $sz;
  93. }
  94. }
  95. print "Used: $used\n";
  96. print "Pool Count: $pcount\n";
  97. print "Alloc Count: $acount\n";
  98. my $json = new JSON;
  99. $json->pretty(1);
  100. $json->canonical(1);
  101. print "Pool Count by Where:\n";
  102. foreach my $pool ( sort { $pool_cnt_by_where{$a} <=> $pool_cnt_by_where{$b} || $a cmp $b } keys %pool_cnt_by_where ) {
  103. print $pool_cnt_by_where{$pool}, "\t", $pool, "\n";
  104. }
  105. print "\n";
  106. print "Alloc Count by Where:\n";
  107. foreach my $pool ( sort { $alloc_cnt_by_where{$a} <=> $alloc_cnt_by_where{$b} || $a cmp $b } keys %alloc_cnt_by_where )
  108. {
  109. print $alloc_cnt_by_where{$pool}, "\t", $pool, "\n";
  110. }
  111. print "\n";
  112. print "Alloc Size by Where:\n";
  113. foreach
  114. my $pool ( sort { $alloc_size_by_where{$a} <=> $alloc_size_by_where{$b} || $a cmp $b } keys %alloc_size_by_where )
  115. {
  116. print $alloc_size_by_where{$pool}, "\t", $pool, "\n";
  117. }
  118. print "\n";