65845: sr=leaf r=waterson
adding code coverage into the make system. generates order files to rearrange the functions in the dll. reduces the resident set size of the app while running. git-svn-id: svn://10.0.0.236/trunk@86435 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
283
mozilla/config/trace.cpp
Normal file
283
mozilla/config/trace.cpp
Normal file
@@ -0,0 +1,283 @@
|
||||
/* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
This is part of a MOZ_COVERAGE build. (set MOZ_COVERAGE=1 and rebuild)
|
||||
When trace.dll is linked in to the build, it counts the number of times
|
||||
each function is called. When the program exits, it breaks out the
|
||||
functions by module, sorts them by number of calls, then dumps them into
|
||||
win32.order where the module is built. The order files are used by the
|
||||
liker to rearrange the functions in the library.
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <imagehlp.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "pldhash.h"
|
||||
|
||||
class Reporter {
|
||||
public:
|
||||
~Reporter();
|
||||
};
|
||||
|
||||
static Reporter theReporter;
|
||||
|
||||
/*
|
||||
Hash of function names, and call counts]
|
||||
*/
|
||||
static PLDHashTable Calls;
|
||||
|
||||
struct CallEntry {
|
||||
struct PLDHashEntryHdr hdr;
|
||||
const void* addr;
|
||||
unsigned count;
|
||||
};
|
||||
|
||||
static PLDHashTableOps Ops = {
|
||||
PL_DHashAllocTable,
|
||||
PL_DHashFreeTable,
|
||||
PL_DHashGetKeyStub,
|
||||
PL_DHashVoidPtrKeyStub,
|
||||
PL_DHashMatchEntryStub,
|
||||
PL_DHashMoveEntryStub,
|
||||
PL_DHashClearEntryStub,
|
||||
PL_DHashFinalizeStub
|
||||
};
|
||||
|
||||
class Node {
|
||||
public:
|
||||
Node() {function = 0; count = 0; next = 0;};
|
||||
char* function;
|
||||
int count;
|
||||
Node* next;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
Hash of each module. Contains a sorted linked list of each function and
|
||||
its number of calls for that module.
|
||||
*/
|
||||
|
||||
static PLDHashTable Modules;
|
||||
|
||||
struct ModulesEntry {
|
||||
struct PLDHashEntryHdr hdr;
|
||||
char* moduleName;
|
||||
Node* byCount;
|
||||
};
|
||||
|
||||
BOOL CRT_CALL
|
||||
ModuleMatchEntry(PLDHashTable* aTable,
|
||||
const PLDHashEntryHdr* aEntry,
|
||||
const void* aKey)
|
||||
{
|
||||
ModulesEntry* mod = (ModulesEntry*) aEntry;
|
||||
return ( !strcmp(mod->moduleName,(char*)aKey) );
|
||||
}
|
||||
|
||||
static PLDHashTableOps ModOps = {
|
||||
PL_DHashAllocTable,
|
||||
PL_DHashFreeTable,
|
||||
PL_DHashGetKeyStub,
|
||||
PL_DHashStringKey,
|
||||
ModuleMatchEntry, // PL_DHashMatchEntryStub,
|
||||
PL_DHashMoveEntryStub,
|
||||
PL_DHashClearEntryStub,
|
||||
PL_DHashFinalizeStub
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
Counts the number of times a function is called.
|
||||
*/
|
||||
extern "C"
|
||||
static void
|
||||
Log(void* addr)
|
||||
{
|
||||
static int initialized = 0;
|
||||
|
||||
addr = (void*) ((unsigned) addr - 5);
|
||||
|
||||
if (! initialized) {
|
||||
initialized = 1;
|
||||
PL_DHashTableInit(&Calls, &Ops, 0, sizeof(CallEntry), 16);
|
||||
}
|
||||
|
||||
CallEntry* entry
|
||||
= (CallEntry*) PL_DHashTableOperate(&Calls, addr, PL_DHASH_LOOKUP);
|
||||
if (PL_DHASH_ENTRY_IS_FREE(&entry->hdr)) {
|
||||
entry = (CallEntry*) PL_DHashTableOperate(&Calls, addr, PL_DHASH_ADD);
|
||||
entry->addr = addr;
|
||||
entry->count = 0;
|
||||
}
|
||||
|
||||
++entry->count;
|
||||
}
|
||||
|
||||
/*
|
||||
assembly to call Log, and count this function
|
||||
*/
|
||||
|
||||
extern "C"
|
||||
__declspec(naked dllexport)
|
||||
void _penter()
|
||||
{
|
||||
__asm {
|
||||
push ecx // save ecx for caller
|
||||
push dword ptr [esp+4] // the caller's address is the only param
|
||||
call Log // ...to Log()
|
||||
add esp,4
|
||||
pop ecx // restore ecx for caller
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Steps through the hash of modules and dumps the function counts out to
|
||||
win32.order
|
||||
*/
|
||||
|
||||
static PLDHashOperator CRT_CALL
|
||||
DumpFiles(PLDHashTable* table, PLDHashEntryHdr* hdr,
|
||||
PRUint32 number, void* arg)
|
||||
{
|
||||
ModulesEntry* entry = (ModulesEntry*) hdr;
|
||||
Node* cur = entry->byCount;
|
||||
char dest[256];
|
||||
char ilkName[256];
|
||||
FILE* orderFile;
|
||||
|
||||
strcpy(ilkName, entry->moduleName);
|
||||
strcat(ilkName, ".ilk");
|
||||
|
||||
if ( !::FindExecutableImage(ilkName, MOZ_SRC, dest) ) {
|
||||
printf("+++ERROR Could not find %s\n",ilkName);
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
dest[strlen(dest)-strlen(ilkName)-strlen("WIN32_D.OBJ\\")] = 0;
|
||||
strcat(dest,"win32.order");
|
||||
orderFile = fopen(dest,"w");
|
||||
printf("Creating order file %s\n",dest);
|
||||
|
||||
while( cur ) {
|
||||
fprintf(orderFile,"%s ; %d\n", cur->function, cur->count );
|
||||
cur = cur->next;
|
||||
}
|
||||
|
||||
fflush(orderFile);
|
||||
fclose(orderFile);
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
/*
|
||||
We have a function name. Figure out which module it is from. Then add that
|
||||
function and its call count into the module's sorted list.
|
||||
*/
|
||||
|
||||
static PLDHashOperator CRT_CALL
|
||||
ListCounts(PLDHashTable* table, PLDHashEntryHdr* hdr,
|
||||
PRUint32 number, void* arg)
|
||||
{
|
||||
BOOL ok;
|
||||
CallEntry* entry = (CallEntry*) hdr;
|
||||
|
||||
IMAGEHLP_MODULE module;
|
||||
module.SizeOfStruct = sizeof(module);
|
||||
|
||||
ok = ::SymGetModuleInfo(::GetCurrentProcess(),
|
||||
(unsigned) entry->addr,
|
||||
&module);
|
||||
|
||||
char buf[sizeof(IMAGEHLP_SYMBOL) + 512];
|
||||
PIMAGEHLP_SYMBOL symbol = (PIMAGEHLP_SYMBOL) buf;
|
||||
symbol->SizeOfStruct = sizeof(buf);
|
||||
symbol->MaxNameLength = 512;
|
||||
|
||||
DWORD displacement;
|
||||
ok = ::SymGetSymFromAddr(::GetCurrentProcess(),
|
||||
(unsigned) entry->addr,
|
||||
&displacement,
|
||||
symbol);
|
||||
|
||||
if (ok)
|
||||
{
|
||||
static int modInitialized = 0;
|
||||
if (! modInitialized) {
|
||||
modInitialized = 1;
|
||||
PL_DHashTableInit(&Modules, &ModOps, 0, sizeof(ModulesEntry), 16);
|
||||
}
|
||||
|
||||
ModulesEntry* mod
|
||||
= (ModulesEntry*) PL_DHashTableOperate(&Modules,
|
||||
module.ModuleName,
|
||||
PL_DHASH_LOOKUP);
|
||||
|
||||
if (PL_DHASH_ENTRY_IS_FREE(&mod->hdr)) {
|
||||
mod = (ModulesEntry*) PL_DHashTableOperate(&Modules,
|
||||
module.ModuleName,
|
||||
PL_DHASH_ADD);
|
||||
mod->moduleName = strdup(module.ModuleName);
|
||||
mod->byCount = new Node();
|
||||
mod->byCount->function = strdup(symbol->Name);
|
||||
mod->byCount->count = entry->count;
|
||||
} else {
|
||||
// insertion sort.
|
||||
Node* cur = mod->byCount;
|
||||
Node* foo = new Node();
|
||||
foo->function = strdup(symbol->Name);
|
||||
foo->count = entry->count;
|
||||
|
||||
if ( cur->count < entry->count ) {
|
||||
foo->next = mod->byCount;
|
||||
mod->byCount = foo;
|
||||
} else {
|
||||
while ( cur->next ) {
|
||||
if ( cur->next->count > entry->count ) { cur = cur->next; }
|
||||
else { break; }
|
||||
}
|
||||
foo->next = cur->next;
|
||||
cur->next = foo;
|
||||
}
|
||||
}
|
||||
} // if (ok)
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
Reporter::~Reporter()
|
||||
{
|
||||
SymInitialize(GetCurrentProcess(), 0, TRUE);
|
||||
|
||||
DWORD options = SymGetOptions();
|
||||
|
||||
// We want the nasty name, as we'll have to pass it back to the
|
||||
// linker.
|
||||
options &= ~SYMOPT_UNDNAME;
|
||||
|
||||
SymSetOptions(options);
|
||||
|
||||
// break the function names out by module and sort them.
|
||||
PL_DHashTableEnumerate(&Calls, ListCounts, NULL);
|
||||
// dump the order files for each module.
|
||||
PL_DHashTableEnumerate(&Modules, DumpFiles, NULL);
|
||||
|
||||
SymCleanup(GetCurrentProcess());
|
||||
}
|
||||
Reference in New Issue
Block a user