2026-03-12 20:23:15

This commit is contained in:
root
2026-03-12 21:23:47 +01:00
parent eab4b36eca
commit 93039b8489
3332 changed files with 699614 additions and 0 deletions

View File

@@ -0,0 +1,10 @@
#!/bin/bash
# A little helper script for finding ORACLE_HOMEs for all running instances in a Linux server
# by Tanel Poder (http://blog.tanelpoder.com)
printf "%6s %-20s %-80s\n" "PID" "NAME" "ORACLE_HOME"
pgrep -lf _pmon_ |
while read pid pname y ; do
printf "%6s %-20s %-80s\n" $pid $pname `ls -l /proc/$pid/exe | awk -F'>' '{ print $2 }' | sed 's/bin\/oracle$//' | sort | uniq`
done

View File

@@ -0,0 +1,58 @@
#!/bin/ksh
################################################################################
## Copyright 2018 Tanel Poder. All rights reserved. More info at http://tanelpoder.com
## Licensed under the Apache License, Version 2.0. See LICENSE.txt for terms & conditions.
##
## File name: heapdump_analyzer
## Purpose: Script for aggregating Oracle heapdump chunk sizes
##
## Author: Tanel Poder
## Copyright: (c) http://www.tanelpoder.com
##
## Usage: 1) Take a heapdump ( read http://www.juliandyke.com )
##
## 2) run ./heapdump_analyzer <heapdump tracefile name>
## For example: ./heapdump_analyzer ORCL_ora_4345.trc
##
## Other: Only take heapdumps when you know what you're doing!
## Taking a heapdump on shared pool (when bit 2 in heapdump event
## level is enabled) can hang your database for a while as it
## holds shared pool latches for a long time if your shared pool
## is big and heavily active.
##
## Private memory heapdumps are safer as only the dumped process is
## affected.
##
## On Solaris you may need to replace awk with nawk in this script
##
################################################################################
if [ "$1" == "-t" ]; then
EXCLUDE='dummy_nonexistent_12345'
shift
else
EXCLUDE='Total heap size$'
fi
echo
echo " -- Heapdump Analyzer v1.03 by Tanel Poder ( https://blog.tanelpoder.com )"
echo
echo " Total_size #Chunks Chunk_size, From_heap, Chunk_type, Alloc_reason"
echo " ------------ ------- ------------ ----------------- ----------------- -----------------"
cat $1 | awk '
/^HEAP DUMP heap name=/ { split($0,ht,"\""); HTYPE=ht[2]; doPrintOut = 1; }
/Chunk/{ if ( doPrintOut == 1 ) {
split($0,sf,"\"");
printf "%12.0f , %16s, %16s, %16s\n", $4, HTYPE, $5, sf[2];
}
}
/Total heap size/ {
printf "%12.0f , %16s, %16s, %16s\n", $5, HTYPE, "TOTAL", "Total heap size";
doPrintOut=0;
}
' | grep -v "$EXCLUDE" | sort -n | uniq -c | awk '{ printf " %12.0f %s\n", $1*$2, $0 }' | sort -nr
echo

190
tpt/tools/unix/os_explain Normal file
View File

@@ -0,0 +1,190 @@
#!/bin/bash
################################################################################
## Copyright 2018 Tanel Poder. All rights reserved. More info at http://tanelpoder.com
## Licensed under the Apache License, Version 2.0. See LICENSE.txt for terms & conditions.
##
## File name: os_explain (version 1.1)
## Purpose: Script to explain the currently active branch of SQL plan
## execution from Oracle server process stack trace
##
## Author: Tanel Poder
## Copyright: (c) http://www.tanelpoder.com
##
## Usage: 1) Take a stack trace of an Oracle process (either by using a
## a debugger, pstack or extract the stack from a corefile,
## save it to a file (pstack.txt for example)
## 2) run ./os_explain <stack_trace_file>
## For example: ./os_explain pstack.txt
##
##
##
## Alternatively you can pipe pstack output directly to os_explain
## STDIN:
##
## pstack <SPID> | ./os_explain
##
## Other: Get stack using pstack on Solaris and Linux, using procstack
## on AIX and by using pstack on recent versions of HP-UX.
## Older HP-UX versions may require a debugger for getting stack
## from OS. As an alternative (especially on Windows) you could
## use ORADEBUG DUMP ERRORSTACK for dumping stack of a process.
## Note that ORADEBUG's stack dump mechanism is not 100% safe
## on active processes
##
## Most of Oracle kernel function prefix translations are based
## on Metalink note 175982.1 (google for it, it's gone from the
## Oracle site)
##
## On Solaris you may need to replace awk with nawk in this script
## I don't remember why anymore, but for some reason I used it
##
################################################################################
# LIFO line reverser
f_lifo() {
#echo Entering f_lifo()
MAX_ARRAY=1023 # Max stack array depth. You can use 4095 here but older linuxes and hp-ux shell may not like it
i=$MAX_ARRAY
IFS=^
while read input ; do
array[i]=$input
((i=i-1))
done
i=1
for output in ${array[@]} ; do
if test "$1" = "-n" ; then
printf "%4d %s\n" $i $output
else
printf "%s\n" $output
fi
((i=i+1))
done
}
TRANSLATION_STRING='
/----------------- lwp# 2/,$d;
s/(.*//;
s/ [[0-9][a-f]]{16} /./;
s/qerae/AND-EQUAL: /g;
s/qerba/BITMAP INDEXAND : /g;
s/qerbc/BITMAP INDEX COMPACTION: /g;
s/qerbi/BITMAP INDEX CREATION: /g;
s/qerbm/MINUS: /g;
s/qerbo/BITMAP INDEX OR: /g;
s/qerbt/BITMAP CONVERT: /g;
s/qerbu/BITMAP INDEX UNLIMITED-OR: /g;
s/qerbx/BITMAP INDEX ACCESS: /g;
s/qercb/CONNECT BY: /g;
s/qercbi/SUPPORT FOR CONNECT BY: /g;
s/qerco/COUNT: /g;
s/qerdl/DELETE: /g;
s/qerep/EXPLOSION: /g;
s/qerff/FIFO BUFFER: /g;
s/qerfi/FIRST ROW: /g;
s/qerfl/FILTER DEFINITION: /g;
s/qerfu/UPDATE: /g;
s/qerfx/FIXED TABLE: /g;
s/qergi/GRANULE ITERATOR: /g;
s/qergr/GROUP BY ROLLUP: /g;
s/qergs/GROUP BY SORT: /g;
s/qerhc/HASH CLUSTERS: /g;
s/qerhj/HASH JOIN: /g;
s/qeril/IN-LIST: /g;
s/qerim/INDEX MAINTENANCE: /g;
s/qerix/INDEX: /g;
s/qerjot/NESTED LOOP JOIN: /g;
s/qerjo/NESTED LOOP OUTER: /g;
s/qerle/LINEAR EXECUTION IMPLEMENTATION: /g;
s/qerli/PARALLEL CREATE INDEX: /g;
s/qerlt/LOAD TABLE: /g;
s/qerns/GROUP BY NO SORT: /g;
s/qeroc/OBJECT COLLECTION ITERATOR: /g;
s/qeroi/EXTENSIBLE INDEXING QUERY COMPONENT: /g;
s/qerpa/PARTITION: /g;
s/qerpf/QUERY EXECUTION PREFETCH: /g;
s/qerpx/PARALLELIZER: /g;
s/qerrm/REMOTE: /g;
s/qerse/SET IMPLEMENTATION: /g;
s/qerso/SORT: /g;
s/qersq/SEQUENCE NUMBER: /g;
s/qerst/QUERY EXECUTION STATISTICS: /g;
s/qertb/TABLE ACCESS: /g;
s/qertq/TABLE QUEUE: /g;
s/qerua/UNION-ALL: /g;
s/qerup/UPDATE: /g;
s/qerus/UPSERT: /g;
s/qervw/VIEW: /g;
s/qerwn/WINDOW: /g;
s/qerxt/EXTERNAL TABLE FETCH : /g;
s/opifch2/SELECT FETCH: /g
s/qergh/HASH GROUP BY: /g
'
# main()
case `uname -s` in
Linux)
FUNCPOS=4
;;
SunOS)
FUNCPOS=2
;;
*)
FUNCPOS=2
;;
esac
if [ "$1X" == "-aX" ] ; then
FILTER="^\$|oracle|----------"
INDENT=" "
shift
else
FILTER="^\$|\?\?|oracle|----------"
TRANSLATION_STRING="/opifch /,\$d;/opiefn0/,\$d;/opiodr/,\$d;/opiexe/,\$d; $TRANSLATION_STRING"
INDENT=" "
fi
if [ "$1X" == "-kX" ] ; then
FUNCPOS=2 # this is for linux kernel stack samples from /proc/PID/stack
TRANSLATION_STRING="s/+.*//g; $TRANSLATION_STRING"
shift
fi
if [ $# -eq 0 ] ; then
sed -e "$TRANSLATION_STRING" \
| egrep -v "$FILTER" \
| sed 's/^ *//g;s/__PGOSF[0-9]*_//' \
| awk -F" " "{ for (f=$FUNCPOS; f <= NF; f++) { printf \"%s \", \$f }; printf \"\n\" }" \
| f_lifo \
| awk "
BEGIN{ option=\" \" } /rwsfcd/{ option=\"* \" } !/rwsfcd/{ pref=(pref \"$INDENT\") ;
print pref option \$0 ; option=\" \" }
"
else
for i in $* ; do
sed -e "$TRANSLATION_STRING" < $i \
| egrep -v "$FILTER" \
| sed 's/^ *//g;s/__PGOSF[0-9]*_//' \
| awk -F" " "{ for (f=$FUNCPOS; f <= NF; f++) { printf \"%s \", \$f }; printf \"\n\" }" \
| f_lifo \
| awk "
BEGIN{ option=\" \" } /rwsfcd/{ option=\"* \" } !/rwsfcd/{ pref=(pref \"$INDENT\") ;
print pref option \$0 ; option=\" \" }
"
done
fi
# that's all!

24
tpt/tools/unix/procio.sh Normal file
View File

@@ -0,0 +1,24 @@
#!/bin/bash
# Tiny Linux /proc/<pid>/io demo script by Tanel Poder
# http://www.tanelpoder.com
PID=$1
TMPFILE1=/tmp/procio.${PID}.tmp1
TMPFILE2=/tmp/procio.${PID}.tmp2
SLEEP=5
trap 'rm -f $TMPFILE1 $TMPFILE2 ; exit 0' 0
echo Sampling process $PID IO every $SLEEP seconds...
cat /proc/$PID/io > $TMPFILE2
while true ; do
mv $TMPFILE2 $TMPFILE1
sleep $SLEEP
cat /proc/$PID/io > $TMPFILE2
paste $TMPFILE1 $TMPFILE2 | awk '{ printf "%30s %d\n", $1, $4-$2 }'
echo
done

170
tpt/tools/unix/procmm.py Normal file
View File

@@ -0,0 +1,170 @@
#!/bin/env python
# Copyright 2018 Tanel Poder. All rights reserved. More info at http://tanelpoder.com
# Licensed under the Apache License, Version 2.0. See LICENSE.txt for terms & conditions.
# perms
# r = read
# w = write
# x = execute
# s = shared
# p = private (copy on write)
import sys, os, pwd, re, json
re_mapheader = re.compile('[0-9a-f]+-[0-9a-f]+', re.IGNORECASE)
def readFileLines(name):
with file(name) as f:
s = f.readlines()
return s
def readFile(name):
x=readFileLines(name)
if x:
return x[0]
else:
return None
def getProcRec(pid):
try:
mr={}
mr['pid'] = pid
mr['comm'] = readFile('/proc/' + pid + '/comm')
mr['cmdline'] = readFile('/proc/' + pid + '/cmdline')
mr['username'] = pwd.getpwuid(os.stat('/proc/' + pid).st_uid).pw_name
except IOError as e:
print "Process gone"
except Exception as e:
print "error", e
raise
return mr
def getProcMemData(pid):
memseg={}
memdetail={}
allmemseg={}
allmemdetail={}
try:
for l in readFileLines('/proc/' + pid + '/smaps'):
if re_mapheader.match(l):
memseg['baddr_hex'] = l.split()[0].split('-')[0]
memseg['eaddr_hex'] = l.split()[0].split('-')[1]
memseg['perms'] = l.split()[1]
memseg['offset'] = l.split()[2]
memseg['dev'] = l.split()[3]
memseg['inode'] = l.split()[4]
if len(l.split()) >= 6:
s = l.split()[5]
if s.startswith('/dev/shm'):
s = '/dev/shm'
#re.sub('', '', s)
#print "s =", s
memseg['name'] = s
else:
memseg['name'] = '[anon]'
memseg['baddr'] = int(memseg['baddr_hex'], 16)
memseg['eaddr'] = int(memseg['eaddr_hex'], 16)
memseg['size'] = memseg['eaddr'] - memseg['baddr']
allmemseg[memseg['name']] = memseg
else:
# smaps format example:
# Size: 136 kB
# Rss: 40 kB ...
memdetail[l.split()[0].replace(':','')] = memdetail.get(l.split()[0].replace(':',''), 0) + int(l.split()[1])
allmemdetail[memseg['name']] = memdetail
return allmemseg, allmemdetail
except IOError as e:
print "Process gone"
except Exception as e:
print "error", e
raise
def getProcMemDataSum(pidlist):
memsum = {}
for p in pidlist:
procrec = getProcRec(p)
#print "\n============ PID: %d %s" % ( int(procrec['pid']), procrec['cmdline'].replace('\x00','') )
memseg, memdata = getProcMemData(p)
#print memseg
for ms in memseg:
memsum[ms] = memdata[ms]
#for i in memdata[ms]:
# #print "%-25s %10d kB %s" % ( i, memdata[ms][i], ms )
# memsum[(ms,i)] = memsum.get((ms,i), 0) + memdata[ms][i]
return memsum
def main(argv):
memdatasum = getProcMemDataSum(argv)
#print memdatasum
#print json.dumps(memdatasum, indent=4)
print "%10s %10s %10s %10s %10s %10s %10s %10s %10s %10s %10s %10s %s" % (
'VSize'
, 'PTE'
, 'Locked'
, 'MMUPages'
, 'Priv_Clean'
, 'Priv_Dirty'
, 'Pss'
, 'Referenced'
, 'Rss'
, 'Shr_Clean'
, 'Shr_Dirty'
, 'Swap'
, ' Segment_Name'
)
print "%10s %10s %10s %10s %10s %10s %10s %10s %10s %10s %10s %10s %s" % (
'----------'
, '----------'
, '----------'
, '----------'
, '----------'
, '----------'
, '----------'
, '----------'
, '----------'
, '----------'
, '----------'
, '----------'
, ' ----------------------------------------------------------------------'
)
for mseg in memdatasum:
m = memdatasum[mseg]
print "%10d %10d %10d %10d %10d %10d %10d %10d %10d %10d %10d %10d %s" % (
m.get('Size', 0)
, m.get('KernelPageSize', 0)
, m.get('Locked', 0)
, m.get('MMUPageSize', 0)
, m.get('Private_Clean', 0)
, m.get('Private_Dirty', 0)
, m.get('Pss', 0)
, m.get('Referenced', 0)
, m.get('Rss', 0)
, m.get('Shared_Clean', 0)
, m.get('Shared_Dirty', 0)
, m.get('Swap', 0)
, mseg
)
#for a in argv:
# procrec = getProcRec(a)
# print "\n============ PID: %d %s" % ( int(procrec['pid']), procrec['cmdline'].replace('\x00','') )
# memseg, memdata = getProcMemData(a)
# #for i in sorted(memdata, key=memdata.get, reverse=False):
# for i in sorted(memdata, reverse=False):
# print "%-25s %10d kB" % ( i, memdata[i] )
if __name__ == "__main__":
main(sys.argv[1:])

134
tpt/tools/unix/procmm.sh Normal file
View File

@@ -0,0 +1,134 @@
#!/usr/bin/sh
################################################################################
# Copyright 2018 Tanel Poder. All rights reserved. More info at http://tanelpoder.com
# Licensed under the Apache License, Version 2.0. See LICENSE.txt for terms & conditions.
#
# Script: procmm.sh (Process Memory Matrix) v1.03
#
# Purpose: Show process memory usage for different mappings and segment types
#
# Copyright: Copyright (c) 2010 Tanel Poder ( http://tech.e2sn.com )
# All rights reserved.
#
# ------------------------------------------------------------------------------
#
# Usage: procmm.sh [-t|-a] <pidlist>
#
# Without any special options procmm.sh will show you a matrix
# of the processes address space segment types and their respective
# memory usages/reservations, separately for every process in the
# pidlist.
#
# -t option will only show total memory usage of all processes
# listed in pidlist. Any ANON memory usage and swap reservation
# for *shared* mappings (mapped binaries, libraries, shared memory
# segments - Oracle SGA) is not shown.
# Note that pmap command is not cheap one, so you probably do not
# want to run it over many processes frequently
#
# -a option will list ANON memory usage and swap reservation also for
# shared mappings. The -t and -a options are mutually exclusive
# as it doesn not make sense to sum together the same shared mapping
# memory usage of multiple processes.
#
# Comments: This script currently only works on Solaris as the pmap command
# on other platforms doesnt currently show all required info. On
# Linux it will be possible to read this info from proc filesystem (TODO)
#
# If you are getting "address space is changing" errors from pmap then try
# again or suspend the process for duration of this script run.
# NB! Suspending processes may be dangerous in some cases (such as when
# it is holding a hot latch) so you better know what you are doing.
#
################################################################################
get_matrix() {
p_pid="$1"
#[ "$1" -eq 0 ] && p_pid="all" || p_pid=$1
#pmap -x $p_pid | tr '[]' ' ' | egrep -v "^ *Address|^---------|total Kb|^[0-9]*:" | nawk ''
join -j 1 /tmp/procmm-x.$$ /tmp/procmm-s.$$ > /tmp/blah
join -j 1 /tmp/procmm-x.$$ /tmp/procmm-s.$$ | sed 's/ism shmid/ism_shmid/g' | tr '[]' ' ' | egrep -v "^ *Address|^---------|total Kb|^[0-9]*:" | nawk '
{
item=$7
#print "before", s
sub(/.*\.so.*/, "lib", item)
#print "after", s
#item = gensub(/.*\.so.*/, "lib", "g", $7)
#item = gensub(/lib.+|ld\..+/, "lib", "g", $7)
#print $7 " = " item
vmem[item] += $2
rss[item] += $3
anon[item] += $4
locked[item] += $5
swap[item] += $9
#print $0
}
END {
printf "%6-s %20s %12s %12s %12s %12s %12s\n", "PID", "SEGMENT_TYPE", "VIRTUAL", "RSS", "ANON", "LOCKED", "SWAP_RSVD"
printf "------ -------------------- ------------ ------------ ------------ ------------ ------------\n"
for (x in vmem) {
printf "%6-d %20s %12d %12d %12d %12d %12d\n", '$p_pid', x, vmem[x], rss[x], anon[x], locked[x], swap[x]
total_vmem += vmem[x]
total_rss += rss[x]
total_anon += anon[x]
total_locked += locked[x]
total_swap += swap[x]
}
printf "------ -------------------- ------------ ------------ ------------ ------------ ------------\n"
printf "%6-d %20s %12d %12d %12d %12d %12d\n\n", '$p_pid', "TOTAL(kB)", total_vmem, total_rss, total_anon, total_locked, total_swap
}
'
}
echo "\n-- procmm.sh: Process Memory Matrix v1.03 by Tanel Poder ( http://tech.e2sn.com )"
if [ $# -lt 1 ] ; then
echo "\nUsage:\n"
echo " $0 [-a|-t] <pidlist>\n"
echo " Option -a would report swap reservations and anonymous memory"
echo " for shared mappings (like Oracle SGA) too\n"
exit 1
fi
# defaults
pmap_option=""
compute_total=0
case "$1" in
"-a") pmap_option="a" ; shift ;;
"-t") compute_total=1 ; shift ;;
esac
echo "-- All numbers are shown in kilobytes\n"
pidlist="$*"
#echo $pidlist
if [ $compute_total -eq 0 ]; then
for pid in $pidlist; do
# ps -opid,vsz,rss,args -p $pid | nawk '/ *[0-9]+/{ printf "-- ps info: PID=%d VSZ=%d RSS=%d ARGS=%s\n\n", $1,$2,$3,$4 }'
rm -f /tmp/procmm-x.$$ /tmp/procmm-s.$$
pmap -x$pmap_option $pid | sed 's/ism shmid/ism_shmid/g' | tr '[]' ' ' | egrep -v "^ *Address|^---------|total Kb|^[0-9]+:" > /tmp/procmm-x.$$
pmap -S$pmap_option $pid | sed 's/ism shmid/ism_shmid/g' | tr '[]' ' ' | egrep -v "^ *Address|^---------|total Kb|^[0-9]+:" > /tmp/procmm-s.$$
get_matrix $pid
rm -f /tmp/procmm-x.$$ /tmp/procmm-s.$$
done
else
rm -f /tmp/procmm-x.$$ /tmp/procmm-s.$$
printf "Total PIDs %d, working: " $#
for pid in $pidlist; do
# ps -opid,vsz,rss,args -p $pid | nawk '/ *[0-9]+/{ printf "-- ps info: PID=%d VSZ=%d RSS=%d ARGS=%s\n\n", $1,$2,$3,$4 }'
pmap -x$pmap_option $pid | sed 's/ism shmid/ism_shmid/g' | tr '[]' ' ' | egrep -v "^ *Address|^---------|total Kb|^[0-9]*:" >> /tmp/procmm-x.$$
pmap -S$pmap_option $pid | sed 's/ism shmid/ism_shmid/g' | tr '[]' ' ' | egrep -v "^ *Address|^---------|total Kb|^[0-9]*:" >> /tmp/procmm-s.$$
printf "."
done
printf "\n\n"
get_matrix 0
echo "-- Note that in Total (-t) calculation mode it makes sense to look into ANON and SWAP_RSVD"
echo "-- totals only as other numbers may be heavily \"doublecounted\" due to overlaps of shared mappings\n"
rm -f /tmp/procmm-x.$$ /tmp/procmm-s.$$
fi

32
tpt/tools/unix/runqlat.sh Normal file
View File

@@ -0,0 +1,32 @@
#!/bin/bash
# Tiny Linux /proc/<pid>/schedstat demo script by Tanel Poder
# https://tanelpoder.com
#
# You may want to run this with high priority:
# sudo nice -n -10 ./runqlat.sh PID
#
# currently this script assumes that it will speep exactly for $SLEEP
# seconds, but it can itself be affected by CPU overload and you may
# see values that don't add up to 1000 ms per sec
# (or negative percentages in the derived BLKD% column)
PID=$1
SLEEP=1
echo Sampling /proc/$PID/schedstat every $SLEEP seconds...
printf "%6s %6s %6s\n" "CPU%" "RUNQ%" "SLP%"
while true ; do
read -r CPU_NS_1 LAT_NS_1 SLICES_ON_THIS_CPU_1 < /proc/$PID/schedstat
sleep $SLEEP
read -r CPU_NS_2 LAT_NS_2 SLICES_ON_THIS_CPU_2 < /proc/$PID/schedstat
ON_CPU=$((($CPU_NS_2-$CPU_NS_1)/10000000))
ON_RUNQ=$((($LAT_NS_2-$LAT_NS_1)/10000000))
OTHER=$((100-($ON_CPU+ON_RUNQ)))
printf "%6d %6d %6d" $ON_CPU $ON_RUNQ $OTHER
echo
done

View File

@@ -0,0 +1,49 @@
#!/usr/bin/env bash
# System State Dump "explorer"
# It just adds links to parent State Object location in the file for easier navigation
# Copyright 2018 Tanel Poder. All rights reserved. More info at http://tanelpoder.com
# Licensed under the Apache License, Version 2.0. See LICENSE.txt for terms & conditions.
TRACEFILE=$1
OUTPUTFILE=$1.html
sed -e '
s/</\&lt;/g
s/>/\&gt;/g
s/SO: \(0x[A-Fa-f0-9]*\)/<a name="\1"><mark>SO: \1<\/mark><\/a>/
s/LIBRARY HANDLE:\(0x[A-Fa-f0-9]*\)/<a name="\1">LIBRARY HANDLE:\1<\/a>/
s/owner: \(0x[A-Fa-f0-9]*\)/owner: <a href="#\1">\1<\/a>/
s/handle=\(0x[A-Fa-f0-9]*\)/handle=<a href="#\1">\1<\/a>/
' $TRACEFILE | awk '
BEGIN { print "<html><head><title>System State Dump Explorer by Tanel Poder</title></head><body><pre><code>" }
{ print $0 }
END { print "</code></pre></body></html>" }
' > $OUTPUTFILE
echo Done writing into $OUTPUTFILE
echo
ls -l $OUTPUTFILE
#awk '
#
# BEGIN { print "<html><head><title>System State Dump Explorer by Tanel Poder</title></head><body><pre><code>" }
#
# /0x[A-Fa-f0-9]/ { gsub( /(0x[A-Fa-f0-9]*)/, "<a href=\"#&\">&</a>", $0 ) }
#
## /SO: 0x[A-Za-z0-9]/ {
## match($0, /(0x[A-Fa-f0-9]*),/ , arr)
## printf ("<a name=\"%s\"></a>%s\n", arr[1], gsub( /(0x[A-Fa-f0-9]*)/, "<a href=\"#&\">&</a>", $0 ) )
##
## }
## !/SO: 0x[A-Fa-f0-9]/ { gsub(/(0x[A-Fa-f0-9]*)/, "<a href=\"#&\">&</a>", $0) ; printf("%s\n", $0) }
#
#
# END { print "</code></pre></body></html>" }
#
#
#' | awk '/SO: / { sub( /<a href=/, "<a name=" ) }' > > $1.html

View File

@@ -0,0 +1,24 @@
#!/bin/ksh
#
# Copyright 2018 Tanel Poder. All rights reserved. More info at http://tanelpoder.com
# Licensed under the Apache License, Version 2.0. See LICENSE.txt for terms & conditions.
# strip_stack by Tanel Poder (www.tanelpoder.com)
#
# strips program counter function offsets and aggregates dtrace stack sampler output
#
# usage: strip_stack <filename>
#
cat $1 | sed 's/^ *//;s/+.*$//' | \
awk '/^$/{ printf "\n" }/^[0-9]*$/{ printf ";%s", $1 }/[a-z]/{ printf "%s<-", $1 }END{ printf "\n" }' | \
sort | \
awk -F";" '
/NR==1/{ sum=0; total=0; oldstack=$2 }
{
if (oldstack==$2) {sum+=$3;total+=$3}
else {printf "%d %s\n", sum, oldstack; oldstack=$2; sum=$3}
}
END {printf "%d %s\n%d total samples\n", sum, oldstack,total}
' | \
sort -bnr