From 1cd2234585deb19a8538f1f54b6e24e1d17f501c Mon Sep 17 00:00:00 2001 From: "dprice%netscape.com" Date: Wed, 7 Feb 2001 02:19:29 +0000 Subject: [PATCH] 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 --- mozilla/config/WIN32 | 10 +- mozilla/config/config.mak | 4 +- mozilla/config/dll.inc | 4 +- mozilla/config/makefile.win | 30 +++- mozilla/config/trace.cpp | 283 ++++++++++++++++++++++++++++++++++++ 5 files changed, 326 insertions(+), 5 deletions(-) create mode 100644 mozilla/config/trace.cpp diff --git a/mozilla/config/WIN32 b/mozilla/config/WIN32 index 321cd95f803..041f9703464 100644 --- a/mozilla/config/WIN32 +++ b/mozilla/config/WIN32 @@ -123,7 +123,7 @@ RTL_FLAGS=-MDd # Dynamically linked, multithreaded MSVC4.0 debug RTL #// #//------------------------------------------------------------------------ OS_CFLAGS=$(OPTIMIZER) $(RTL_FLAGS) -W3 -nologo -D_X86_ -D_WINDOWS -DWIN32 \ - -DXP_PC -DXP_WIN -DXP_WIN32 -DHW_THREADS -DWINVER=0x400 + -DXP_PC -DXP_WIN -DXP_WIN32 -DHW_THREADS -DWINVER=0x400 -Gy OS_CFLAGS=$(OS_CFLAGS) -DMSVC4 @@ -157,6 +157,10 @@ EXE_LFLAGS= !endif EXE_LIBS= +!if defined(MOZ_COVERAGE) && !defined(MOZ_NO_COVERAGE) +EXE_LIBS=$(EXE_LIBS) $(DIST)/lib/trace.lib +!endif + #//------------------------------------------------------------------------ #// #// Specify the special flags for creating DLLs @@ -166,6 +170,10 @@ DLL_CFLAGS= DLL_LFLAGS=/SUBSYSTEM:WINDOWS DLL_LIBS= +!if defined(MOZ_COVERAGE) && !defined(MOZ_NO_COVERAGE) +DLL_LIBS=$(DLL_LIBS) $(DIST)/lib/trace.lib +!endif + #//------------------------------------------------------------------------ #// #// rebase setting, msvc systems better have this diff --git a/mozilla/config/config.mak b/mozilla/config/config.mak index 48f383ef143..6d44812d2fa 100644 --- a/mozilla/config/config.mak +++ b/mozilla/config/config.mak @@ -317,8 +317,8 @@ include <$(DEPTH)/config/WIN$(MOZ_BITS)> !ifdef USERNAME CFLAGS = $(CFLAGS) -DDEBUG_$(USERNAME) !endif -!if defined(GLOWCODE) && defined(GLOWPROF) && "$(MOZ_BITS)"=="32" -CFLAGS = $(CFLAGS) -Gh +!if (defined(MOZ_COVERAGE) && !defined(MOZ_NO_COVERAGE)) || (defined(GLOWCODE) && defined(GLOWPROF) && "$(MOZ_BITS)"=="32") +CFLAGS = $(CFLAGS) /Gh !endif !endif diff --git a/mozilla/config/dll.inc b/mozilla/config/dll.inc index d28810ab384..ce31efb7e51 100644 --- a/mozilla/config/dll.inc +++ b/mozilla/config/dll.inc @@ -83,7 +83,9 @@ $(DLL): $(OBJDIR) $(OBJS) $(LLIBS) $(RESFILE) $(DEFFILE) $(MISCDEP) makefile.win !ifdef MAPFILE /MAP:$(MAPFILE) !endif - +!if exist(win32.order) + /ORDER:@win32.order +!endif $(LFLAGS) $(OBJS) $(RESFILE) diff --git a/mozilla/config/makefile.win b/mozilla/config/makefile.win index eb807bc9f6d..5ca3639e470 100644 --- a/mozilla/config/makefile.win +++ b/mozilla/config/makefile.win @@ -50,6 +50,10 @@ INSTALL_DIR=$(DIST)\bin GARBAGE = *.obj *.sbr *.pdb build_number nsBuildID.h +!ifdef MOZ_COVERAGE +GARBAGE = $(GARBAGE) trace.dll trace.lib trace.exp +!endif + #//------------------------------------------------------------------------ #// #// Include the common makefile rules @@ -97,8 +101,32 @@ bin2rc.exe:: bin2rc.c makedep.exe:: makedep.cpp $(CC) -MT /O2 /GB $** -export:: makecopy.exe mangle.exe mantomak.exe bin2rc.exe makedep.exe build_number nsBuildID.h +trace.dll:: trace.obj pldhash.obj + link /nologo /debug /libpath:$(DIST)/lib /dll /out:$@ $** nspr4.lib imagehlp.lib + +pldhash.obj:: $(DEPTH)/xpcom/ds/pldhash.c + $(CC) /c /nologo /Od /Z7 /I$(DEPTH)/xpcom/ds /I$(DIST)/include $** + +trace.obj:: trace.cpp + $(CC) /c /nologo /Od /Z7 /DMOZ_SRC=\"$(MOZ_SRC)\" /I$(DEPTH)/xpcom/ds /I$(DIST)/include $** + +export:: \ + makecopy.exe \ + mangle.exe \ + mantomak.exe \ + bin2rc.exe \ + makedep.exe \ + build_number \ + nsBuildID.h \ +!ifdef MOZ_COVERAGE + trace.dll \ +!endif + $(NULL) $(MAKE_INSTALL) nsBuildID.h $(PUBLIC) +!ifdef MOZ_COVERAGE + $(MAKE_INSTALL) trace.dll $(DIST)/bin + $(MAKE_INSTALL) trace.lib $(DIST)/lib +!endif !ifdef MOZ_FULLCIRCLE diff --git a/mozilla/config/trace.cpp b/mozilla/config/trace.cpp new file mode 100644 index 00000000000..a591833eba5 --- /dev/null +++ b/mozilla/config/trace.cpp @@ -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 +#include +#include + +#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()); +}