util: Remove homegrown Windows KM profiler.
It's not sampling based so its results are biased towards functions called many times.
This commit is contained in:
parent
767bc8eb5a
commit
0b4ea45e8a
|
@ -1,309 +0,0 @@
|
||||||
#!/usr/bin/env python
|
|
||||||
##########################################################################
|
|
||||||
#
|
|
||||||
# Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
|
|
||||||
# All Rights Reserved.
|
|
||||||
#
|
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining a
|
|
||||||
# copy of this software and associated documentation files (the
|
|
||||||
# "Software"), to deal in the Software without restriction, including
|
|
||||||
# without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
# distribute, sub license, and/or sell copies of the Software, and to
|
|
||||||
# permit persons to whom the Software is furnished to do so, subject to
|
|
||||||
# the following conditions:
|
|
||||||
#
|
|
||||||
# The above copyright notice and this permission notice (including the
|
|
||||||
# next paragraph) shall be included in all copies or substantial portions
|
|
||||||
# of the Software.
|
|
||||||
#
|
|
||||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
||||||
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
|
|
||||||
# IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
|
|
||||||
# ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
||||||
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
||||||
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
#
|
|
||||||
##########################################################################
|
|
||||||
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import optparse
|
|
||||||
import re
|
|
||||||
import struct
|
|
||||||
|
|
||||||
from gprof2dot import Call, Function, Profile
|
|
||||||
from gprof2dot import CALLS, SAMPLES, TIME, TIME_RATIO, TOTAL_TIME, TOTAL_TIME_RATIO
|
|
||||||
from gprof2dot import DotWriter, TEMPERATURE_COLORMAP
|
|
||||||
|
|
||||||
|
|
||||||
__version__ = '0.1'
|
|
||||||
|
|
||||||
|
|
||||||
class ParseError(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class MsvcDemangler:
|
|
||||||
# http://www.kegel.com/mangle.html
|
|
||||||
|
|
||||||
def __init__(self, symbol):
|
|
||||||
self._symbol = symbol
|
|
||||||
self._pos = 0
|
|
||||||
|
|
||||||
def lookahead(self):
|
|
||||||
return self._symbol[self._pos]
|
|
||||||
|
|
||||||
def consume(self):
|
|
||||||
ret = self.lookahead()
|
|
||||||
self._pos += 1
|
|
||||||
return ret
|
|
||||||
|
|
||||||
def match(self, c):
|
|
||||||
if self.lookahead() != c:
|
|
||||||
raise ParseError
|
|
||||||
self.consume()
|
|
||||||
|
|
||||||
def parse(self):
|
|
||||||
self.match('?')
|
|
||||||
name = self.parse_name()
|
|
||||||
qualifications = self.parse_qualifications()
|
|
||||||
return '::'.join(qualifications + [name])
|
|
||||||
|
|
||||||
def parse_name(self):
|
|
||||||
if self.lookahead() == '?':
|
|
||||||
return self.consume() + self.consume()
|
|
||||||
else:
|
|
||||||
name = self.parse_id()
|
|
||||||
self.match('@')
|
|
||||||
return name
|
|
||||||
|
|
||||||
def parse_qualifications(self):
|
|
||||||
qualifications = []
|
|
||||||
while self.lookahead() != '@':
|
|
||||||
name = self.parse_id()
|
|
||||||
qualifications.append(name)
|
|
||||||
self.match('@')
|
|
||||||
return qualifications
|
|
||||||
|
|
||||||
def parse_id(self):
|
|
||||||
s = ''
|
|
||||||
while True:
|
|
||||||
c = self.lookahead()
|
|
||||||
if c.isalnum() or c in '_':
|
|
||||||
s += c
|
|
||||||
self.consume()
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
return s
|
|
||||||
|
|
||||||
|
|
||||||
def demangle(name):
|
|
||||||
if name.startswith('_'):
|
|
||||||
name = name[1:]
|
|
||||||
idx = name.rfind('@')
|
|
||||||
if idx != -1 and name[idx+1:].isdigit():
|
|
||||||
name = name[:idx]
|
|
||||||
return name
|
|
||||||
if name.startswith('?'):
|
|
||||||
demangler = MsvcDemangler(name)
|
|
||||||
return demangler.parse()
|
|
||||||
return name
|
|
||||||
|
|
||||||
|
|
||||||
class Reader:
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
self.symbols = []
|
|
||||||
self.symbol_cache = {}
|
|
||||||
self.base_addr = None
|
|
||||||
|
|
||||||
def read_map(self, mapfile):
|
|
||||||
# See http://msdn.microsoft.com/en-us/library/k7xkk3e2.aspx
|
|
||||||
last_addr = 0
|
|
||||||
last_name = 0
|
|
||||||
for line in file(mapfile, "rt"):
|
|
||||||
fields = line.split()
|
|
||||||
try:
|
|
||||||
section_offset, name, addr, type, lib_object = fields
|
|
||||||
except ValueError:
|
|
||||||
continue
|
|
||||||
if type != 'f':
|
|
||||||
continue
|
|
||||||
section, offset = section_offset.split(':')
|
|
||||||
addr = int(offset, 16)
|
|
||||||
self.symbols.append((addr, name))
|
|
||||||
last_addr = addr
|
|
||||||
last_name = name
|
|
||||||
|
|
||||||
# sort symbols
|
|
||||||
self.symbols.sort(key = lambda (addr, name): addr)
|
|
||||||
|
|
||||||
def lookup_addr(self, addr):
|
|
||||||
try:
|
|
||||||
return self.symbol_cache[addr]
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
tolerance = 4196
|
|
||||||
s, e = 0, len(self.symbols)
|
|
||||||
while s != e:
|
|
||||||
i = (s + e)//2
|
|
||||||
start_addr, name = self.symbols[i]
|
|
||||||
try:
|
|
||||||
end_addr, next_name = self.symbols[i + 1]
|
|
||||||
except IndexError:
|
|
||||||
end_addr = start_addr + tolerance
|
|
||||||
if addr < start_addr:
|
|
||||||
e = i
|
|
||||||
continue
|
|
||||||
if addr == end_addr:
|
|
||||||
return next_name, addr - start_addr
|
|
||||||
if addr > end_addr:
|
|
||||||
s = i
|
|
||||||
continue
|
|
||||||
return name, addr - start_addr
|
|
||||||
raise ValueError
|
|
||||||
|
|
||||||
def lookup_symbol(self, name):
|
|
||||||
for symbol_addr, symbol_name in self.symbols:
|
|
||||||
if name == symbol_name:
|
|
||||||
return symbol_addr
|
|
||||||
return 0
|
|
||||||
|
|
||||||
def read_data(self, data):
|
|
||||||
profile = Profile()
|
|
||||||
|
|
||||||
fp = file(data, "rb")
|
|
||||||
entry_format = "IIII"
|
|
||||||
entry_size = struct.calcsize(entry_format)
|
|
||||||
caller = None
|
|
||||||
caller_stack = []
|
|
||||||
while True:
|
|
||||||
entry = fp.read(entry_size)
|
|
||||||
if len(entry) < entry_size:
|
|
||||||
break
|
|
||||||
caller_addr, callee_addr, samples_lo, samples_hi = struct.unpack(entry_format, entry)
|
|
||||||
if caller_addr == 0 and callee_addr == 0:
|
|
||||||
continue
|
|
||||||
|
|
||||||
if self.base_addr is None:
|
|
||||||
ref_addr = self.lookup_symbol('___debug_profile_reference@0')
|
|
||||||
if ref_addr:
|
|
||||||
self.base_addr = (caller_addr - ref_addr) & ~(options.align - 1)
|
|
||||||
else:
|
|
||||||
self.base_addr = 0
|
|
||||||
sys.stderr.write('Base addr: %08x\n' % self.base_addr)
|
|
||||||
|
|
||||||
samples = (samples_hi << 32) | samples_lo
|
|
||||||
|
|
||||||
try:
|
|
||||||
caller_raddr = caller_addr - self.base_addr
|
|
||||||
caller_sym, caller_ofs = self.lookup_addr(caller_raddr)
|
|
||||||
|
|
||||||
try:
|
|
||||||
caller = profile.functions[caller_sym]
|
|
||||||
except KeyError:
|
|
||||||
caller_name = demangle(caller_sym)
|
|
||||||
caller = Function(caller_sym, caller_name)
|
|
||||||
profile.add_function(caller)
|
|
||||||
caller[CALLS] = 0
|
|
||||||
caller[SAMPLES] = 0
|
|
||||||
except ValueError:
|
|
||||||
caller = None
|
|
||||||
|
|
||||||
if not callee_addr:
|
|
||||||
if caller:
|
|
||||||
caller[SAMPLES] += samples
|
|
||||||
else:
|
|
||||||
callee_raddr = callee_addr - self.base_addr
|
|
||||||
callee_sym, callee_ofs = self.lookup_addr(callee_raddr)
|
|
||||||
|
|
||||||
try:
|
|
||||||
callee = profile.functions[callee_sym]
|
|
||||||
except KeyError:
|
|
||||||
callee_name = demangle(callee_sym)
|
|
||||||
callee = Function(callee_sym, callee_name)
|
|
||||||
profile.add_function(callee)
|
|
||||||
callee[CALLS] = samples
|
|
||||||
callee[SAMPLES] = 0
|
|
||||||
else:
|
|
||||||
callee[CALLS] += samples
|
|
||||||
|
|
||||||
if caller is not None:
|
|
||||||
try:
|
|
||||||
call = caller.calls[callee.id]
|
|
||||||
except KeyError:
|
|
||||||
call = Call(callee.id)
|
|
||||||
call[CALLS] = samples
|
|
||||||
caller.add_call(call)
|
|
||||||
else:
|
|
||||||
call[CALLS] += samples
|
|
||||||
|
|
||||||
if options.verbose:
|
|
||||||
if not callee_addr:
|
|
||||||
sys.stderr.write('%s+%u: %u\n' % (caller_sym, caller_ofs, samples))
|
|
||||||
else:
|
|
||||||
sys.stderr.write('%s+%u -> %s+%u: %u\n' % (caller_sym, caller_ofs, callee_sym, callee_ofs, samples))
|
|
||||||
|
|
||||||
# compute derived data
|
|
||||||
profile.validate()
|
|
||||||
profile.find_cycles()
|
|
||||||
profile.aggregate(SAMPLES)
|
|
||||||
profile.ratio(TIME_RATIO, SAMPLES)
|
|
||||||
profile.call_ratios(CALLS)
|
|
||||||
profile.integrate(TOTAL_TIME_RATIO, TIME_RATIO)
|
|
||||||
|
|
||||||
return profile
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
parser = optparse.OptionParser(
|
|
||||||
usage="\n\t%prog [options] [file] ...",
|
|
||||||
version="%%prog %s" % __version__)
|
|
||||||
parser.add_option(
|
|
||||||
'-a', '--align', metavar='NUMBER',
|
|
||||||
type="int", dest="align", default=16,
|
|
||||||
help="section alignment")
|
|
||||||
parser.add_option(
|
|
||||||
'-m', '--map', metavar='FILE',
|
|
||||||
type="string", dest="map",
|
|
||||||
help="map file")
|
|
||||||
parser.add_option(
|
|
||||||
'-b', '--base', metavar='FILE',
|
|
||||||
type="string", dest="base",
|
|
||||||
help="base addr")
|
|
||||||
parser.add_option(
|
|
||||||
'-n', '--node-thres', metavar='PERCENTAGE',
|
|
||||||
type="float", dest="node_thres", default=0.5,
|
|
||||||
help="eliminate nodes below this threshold [default: %default]")
|
|
||||||
parser.add_option(
|
|
||||||
'-e', '--edge-thres', metavar='PERCENTAGE',
|
|
||||||
type="float", dest="edge_thres", default=0.1,
|
|
||||||
help="eliminate edges below this threshold [default: %default]")
|
|
||||||
parser.add_option(
|
|
||||||
'-v', '--verbose',
|
|
||||||
action="count",
|
|
||||||
dest="verbose", default=0,
|
|
||||||
help="verbose output")
|
|
||||||
|
|
||||||
global options
|
|
||||||
(options, args) = parser.parse_args(sys.argv[1:])
|
|
||||||
|
|
||||||
reader = Reader()
|
|
||||||
if options.base is not None:
|
|
||||||
reader.base_addr = int(options.base, 16)
|
|
||||||
if options.map is not None:
|
|
||||||
reader.read_map(options.map)
|
|
||||||
for arg in args:
|
|
||||||
profile = reader.read_data(arg)
|
|
||||||
profile.prune(options.node_thres/100.0, options.edge_thres/100.0)
|
|
||||||
output = sys.stdout
|
|
||||||
dot = DotWriter(output)
|
|
||||||
colormap = TEMPERATURE_COLORMAP
|
|
||||||
dot.graph(profile, colormap)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
||||||
|
|
|
@ -392,11 +392,6 @@ def generate(env):
|
||||||
'/O2', # optimize for speed
|
'/O2', # optimize for speed
|
||||||
#'/fp:fast', # fast floating point
|
#'/fp:fast', # fast floating point
|
||||||
]
|
]
|
||||||
if env['profile']:
|
|
||||||
ccflags += [
|
|
||||||
'/Gh', # enable _penter hook function
|
|
||||||
'/GH', # enable _pexit hook function
|
|
||||||
]
|
|
||||||
ccflags += [
|
ccflags += [
|
||||||
'/W3', # warning level
|
'/W3', # warning level
|
||||||
#'/Wp64', # enable 64 bit porting warnings
|
#'/Wp64', # enable 64 bit porting warnings
|
||||||
|
|
|
@ -406,8 +406,6 @@ def generate(env):
|
||||||
ccflags += ['-O0', '-g3'] # mingw 4.2.1 optimizer is broken
|
ccflags += ['-O0', '-g3'] # mingw 4.2.1 optimizer is broken
|
||||||
else:
|
else:
|
||||||
ccflags += ['-O3', '-g0']
|
ccflags += ['-O3', '-g0']
|
||||||
if env['profile']:
|
|
||||||
ccflags += ['-pg']
|
|
||||||
if env['machine'] == 'x86':
|
if env['machine'] == 'x86':
|
||||||
ccflags += [
|
ccflags += [
|
||||||
'-m32',
|
'-m32',
|
||||||
|
@ -450,11 +448,6 @@ def generate(env):
|
||||||
'/Ot', # favor code speed
|
'/Ot', # favor code speed
|
||||||
#'/fp:fast', # fast floating point
|
#'/fp:fast', # fast floating point
|
||||||
]
|
]
|
||||||
if env['profile']:
|
|
||||||
ccflags += [
|
|
||||||
'/Gh', # enable _penter hook function
|
|
||||||
'/GH', # enable _pexit hook function
|
|
||||||
]
|
|
||||||
ccflags += [
|
ccflags += [
|
||||||
'/W3', # warning level
|
'/W3', # warning level
|
||||||
#'/Wp64', # enable 64 bit porting warnings
|
#'/Wp64', # enable 64 bit porting warnings
|
||||||
|
|
|
@ -28,7 +28,6 @@ util = env.ConvenienceLibrary(
|
||||||
'u_debug.c',
|
'u_debug.c',
|
||||||
'u_debug_dump.c',
|
'u_debug_dump.c',
|
||||||
'u_debug_memory.c',
|
'u_debug_memory.c',
|
||||||
'u_debug_profile.c',
|
|
||||||
'u_debug_stack.c',
|
'u_debug_stack.c',
|
||||||
'u_debug_symbol.c',
|
'u_debug_symbol.c',
|
||||||
'u_draw_quad.c',
|
'u_draw_quad.c',
|
||||||
|
|
|
@ -351,17 +351,6 @@ void
|
||||||
debug_memory_end(unsigned long beginning);
|
debug_memory_end(unsigned long beginning);
|
||||||
|
|
||||||
|
|
||||||
#if defined(PROFILE) && defined(PIPE_SUBSYSTEM_WINDOWS_DISPLAY)
|
|
||||||
|
|
||||||
void
|
|
||||||
debug_profile_start(void);
|
|
||||||
|
|
||||||
void
|
|
||||||
debug_profile_stop(void);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
struct pipe_surface;
|
struct pipe_surface;
|
||||||
struct pipe_transfer;
|
struct pipe_transfer;
|
||||||
|
|
|
@ -1,320 +0,0 @@
|
||||||
/**************************************************************************
|
|
||||||
*
|
|
||||||
* Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
|
|
||||||
* All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
||||||
* copy of this software and associated documentation files (the
|
|
||||||
* "Software"), to deal in the Software without restriction, including
|
|
||||||
* without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
* distribute, sub license, and/or sell copies of the Software, and to
|
|
||||||
* permit persons to whom the Software is furnished to do so, subject to
|
|
||||||
* the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice (including the
|
|
||||||
* next paragraph) shall be included in all copies or substantial portions
|
|
||||||
* of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
||||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
|
|
||||||
* IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
|
|
||||||
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
||||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
||||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
*
|
|
||||||
**************************************************************************/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
* Poor-man profiling.
|
|
||||||
*
|
|
||||||
* @author José Fonseca <jrfonseca@tungstengraphics.com>
|
|
||||||
*
|
|
||||||
* @sa http://blogs.msdn.com/joshpoley/archive/2008/03/12/poor-man-s-profiler.aspx
|
|
||||||
* @sa http://www.johnpanzer.com/aci_cuj/index.html
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "pipe/p_config.h"
|
|
||||||
|
|
||||||
#if defined(PROFILE) && defined(PIPE_SUBSYSTEM_WINDOWS_DISPLAY)
|
|
||||||
|
|
||||||
#include <windows.h>
|
|
||||||
#include <winddi.h>
|
|
||||||
|
|
||||||
#include "util/u_debug.h"
|
|
||||||
#include "util/u_string.h"
|
|
||||||
|
|
||||||
|
|
||||||
#define PROFILE_TABLE_SIZE (1024*1024)
|
|
||||||
#define FILE_NAME_SIZE 256
|
|
||||||
|
|
||||||
struct debug_profile_entry
|
|
||||||
{
|
|
||||||
uintptr_t caller;
|
|
||||||
uintptr_t callee;
|
|
||||||
uint64_t samples;
|
|
||||||
};
|
|
||||||
|
|
||||||
static unsigned long enabled = 0;
|
|
||||||
|
|
||||||
static WCHAR wFileName[FILE_NAME_SIZE] = L"\\??\\c:\\00000000.prof";
|
|
||||||
static ULONG_PTR iFile = 0;
|
|
||||||
|
|
||||||
static struct debug_profile_entry *table = NULL;
|
|
||||||
static unsigned long free_table_entries = 0;
|
|
||||||
static unsigned long max_table_entries = 0;
|
|
||||||
|
|
||||||
uint64_t start_stamp = 0;
|
|
||||||
uint64_t end_stamp = 0;
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
debug_profile_entry(uintptr_t caller, uintptr_t callee, uint64_t samples)
|
|
||||||
{
|
|
||||||
unsigned hash = ( caller + callee ) & PROFILE_TABLE_SIZE - 1;
|
|
||||||
|
|
||||||
while(1) {
|
|
||||||
if(table[hash].caller == 0 && table[hash].callee == 0) {
|
|
||||||
table[hash].caller = caller;
|
|
||||||
table[hash].callee = callee;
|
|
||||||
table[hash].samples = samples;
|
|
||||||
--free_table_entries;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if(table[hash].caller == caller && table[hash].callee == callee) {
|
|
||||||
table[hash].samples += samples;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
++hash;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static uintptr_t caller_stack[1024];
|
|
||||||
static unsigned last_caller = 0;
|
|
||||||
|
|
||||||
|
|
||||||
static int64_t delta(void) {
|
|
||||||
int64_t result = end_stamp - start_stamp;
|
|
||||||
if(result > UINT64_C(0xffffffff))
|
|
||||||
result = 0;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void __cdecl
|
|
||||||
debug_profile_enter(uintptr_t callee)
|
|
||||||
{
|
|
||||||
uintptr_t caller = last_caller ? caller_stack[last_caller - 1] : 0;
|
|
||||||
|
|
||||||
if (caller)
|
|
||||||
debug_profile_entry(caller, 0, delta());
|
|
||||||
debug_profile_entry(caller, callee, 1);
|
|
||||||
caller_stack[last_caller++] = callee;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void __cdecl
|
|
||||||
debug_profile_exit(uintptr_t callee)
|
|
||||||
{
|
|
||||||
debug_profile_entry(callee, 0, delta());
|
|
||||||
if(last_caller)
|
|
||||||
--last_caller;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called at the start of every method or function.
|
|
||||||
*
|
|
||||||
* @sa http://msdn.microsoft.com/en-us/library/c63a9b7h.aspx
|
|
||||||
*/
|
|
||||||
void __declspec(naked) __cdecl
|
|
||||||
_penter(void) {
|
|
||||||
_asm {
|
|
||||||
push eax
|
|
||||||
mov eax, [enabled]
|
|
||||||
test eax, eax
|
|
||||||
jz skip
|
|
||||||
|
|
||||||
push edx
|
|
||||||
|
|
||||||
rdtsc
|
|
||||||
mov dword ptr [end_stamp], eax
|
|
||||||
mov dword ptr [end_stamp+4], edx
|
|
||||||
|
|
||||||
xor eax, eax
|
|
||||||
mov [enabled], eax
|
|
||||||
|
|
||||||
mov eax, [esp+8]
|
|
||||||
|
|
||||||
push ebx
|
|
||||||
push ecx
|
|
||||||
push ebp
|
|
||||||
push edi
|
|
||||||
push esi
|
|
||||||
|
|
||||||
push eax
|
|
||||||
call debug_profile_enter
|
|
||||||
add esp, 4
|
|
||||||
|
|
||||||
pop esi
|
|
||||||
pop edi
|
|
||||||
pop ebp
|
|
||||||
pop ecx
|
|
||||||
pop ebx
|
|
||||||
|
|
||||||
mov eax, 1
|
|
||||||
mov [enabled], eax
|
|
||||||
|
|
||||||
rdtsc
|
|
||||||
mov dword ptr [start_stamp], eax
|
|
||||||
mov dword ptr [start_stamp+4], edx
|
|
||||||
|
|
||||||
pop edx
|
|
||||||
skip:
|
|
||||||
pop eax
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called at the end of Calls the end of every method or function.
|
|
||||||
*
|
|
||||||
* @sa http://msdn.microsoft.com/en-us/library/xc11y76y.aspx
|
|
||||||
*/
|
|
||||||
void __declspec(naked) __cdecl
|
|
||||||
_pexit(void) {
|
|
||||||
_asm {
|
|
||||||
push eax
|
|
||||||
mov eax, [enabled]
|
|
||||||
test eax, eax
|
|
||||||
jz skip
|
|
||||||
|
|
||||||
push edx
|
|
||||||
|
|
||||||
rdtsc
|
|
||||||
mov dword ptr [end_stamp], eax
|
|
||||||
mov dword ptr [end_stamp+4], edx
|
|
||||||
|
|
||||||
xor eax, eax
|
|
||||||
mov [enabled], eax
|
|
||||||
|
|
||||||
mov eax, [esp+8]
|
|
||||||
|
|
||||||
push ebx
|
|
||||||
push ecx
|
|
||||||
push ebp
|
|
||||||
push edi
|
|
||||||
push esi
|
|
||||||
|
|
||||||
push eax
|
|
||||||
call debug_profile_exit
|
|
||||||
add esp, 4
|
|
||||||
|
|
||||||
pop esi
|
|
||||||
pop edi
|
|
||||||
pop ebp
|
|
||||||
pop ecx
|
|
||||||
pop ebx
|
|
||||||
|
|
||||||
mov eax, 1
|
|
||||||
mov [enabled], eax
|
|
||||||
|
|
||||||
rdtsc
|
|
||||||
mov dword ptr [start_stamp], eax
|
|
||||||
mov dword ptr [start_stamp+4], edx
|
|
||||||
|
|
||||||
pop edx
|
|
||||||
skip:
|
|
||||||
pop eax
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reference function for calibration.
|
|
||||||
*/
|
|
||||||
void __declspec(naked)
|
|
||||||
__debug_profile_reference(void) {
|
|
||||||
_asm {
|
|
||||||
call _penter
|
|
||||||
call _pexit
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
debug_profile_start(void)
|
|
||||||
{
|
|
||||||
WCHAR *p;
|
|
||||||
|
|
||||||
/* increment starting from the less significant digit */
|
|
||||||
p = &wFileName[14];
|
|
||||||
while(1) {
|
|
||||||
if(*p == '9') {
|
|
||||||
*p-- = '0';
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
*p += 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
table = EngMapFile(wFileName,
|
|
||||||
PROFILE_TABLE_SIZE*sizeof(struct debug_profile_entry),
|
|
||||||
&iFile);
|
|
||||||
if(table) {
|
|
||||||
unsigned i;
|
|
||||||
|
|
||||||
free_table_entries = max_table_entries = PROFILE_TABLE_SIZE;
|
|
||||||
memset(table, 0, PROFILE_TABLE_SIZE*sizeof(struct debug_profile_entry));
|
|
||||||
|
|
||||||
table[0].caller = (uintptr_t)&__debug_profile_reference;
|
|
||||||
table[0].callee = 0;
|
|
||||||
table[0].samples = 0;
|
|
||||||
--free_table_entries;
|
|
||||||
|
|
||||||
_asm {
|
|
||||||
push edx
|
|
||||||
push eax
|
|
||||||
|
|
||||||
rdtsc
|
|
||||||
mov dword ptr [start_stamp], eax
|
|
||||||
mov dword ptr [start_stamp+4], edx
|
|
||||||
|
|
||||||
pop edx
|
|
||||||
pop eax
|
|
||||||
}
|
|
||||||
|
|
||||||
last_caller = 0;
|
|
||||||
|
|
||||||
enabled = 1;
|
|
||||||
|
|
||||||
for(i = 0; i < 8; ++i) {
|
|
||||||
_asm {
|
|
||||||
call __debug_profile_reference
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
debug_profile_stop(void)
|
|
||||||
{
|
|
||||||
enabled = 0;
|
|
||||||
|
|
||||||
if(iFile)
|
|
||||||
EngUnmapFile(iFile);
|
|
||||||
iFile = 0;
|
|
||||||
table = NULL;
|
|
||||||
free_table_entries = max_table_entries = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* PROFILE */
|
|
Loading…
Reference in New Issue