~ubuntu-branches/ubuntu/precise/kompozer/precise

« back to all changes in this revision

Viewing changes to mozilla/config/trace.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Anthony Yarusso
  • Date: 2007-08-27 01:11:03 UTC
  • Revision ID: james.westby@ubuntu.com-20070827011103-2jgf4s6532gqu2ka
Tags: upstream-0.7.10
ImportĀ upstreamĀ versionĀ 0.7.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* The contents of this file are subject to the Netscape Public */
 
2
/* ***** BEGIN LICENSE BLOCK *****
 
3
 * Version: NPL 1.1/GPL 2.0/LGPL 2.1
 
4
 *
 
5
 * The contents of this file are subject to the Netscape Public License
 
6
 * Version 1.1 (the "License"); you may not use this file except in
 
7
 * compliance with the License. You may obtain a copy of the License at
 
8
 * http://www.mozilla.org/NPL/
 
9
 *
 
10
 * Software distributed under the License is distributed on an "AS IS" basis,
 
11
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 
12
 * for the specific language governing rights and limitations under the
 
13
 * License.
 
14
 *
 
15
 * The Original Code is mozilla.org code.
 
16
 *
 
17
 * The Initial Developer of the Original Code is 
 
18
 * Netscape Communications Corporation.
 
19
 * Portions created by the Initial Developer are Copyright (C) 1998
 
20
 * the Initial Developer. All Rights Reserved.
 
21
 *
 
22
 * Contributor(s):
 
23
 *  Garrett Arch Blythe, 03/04/2002  Added interval hit counting.
 
24
 *
 
25
 *
 
26
 * Alternatively, the contents of this file may be used under the terms of
 
27
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 
28
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 
29
 * in which case the provisions of the GPL or the LGPL are applicable instead
 
30
 * of those above. If you wish to allow use of your version of this file only
 
31
 * under the terms of either the GPL or the LGPL, and not to allow others to
 
32
 * use your version of this file under the terms of the NPL, indicate your
 
33
 * decision by deleting the provisions above and replace them with the notice
 
34
 * and other provisions required by the GPL or the LGPL. If you do not delete
 
35
 * the provisions above, a recipient may use your version of this file under
 
36
 * the terms of any one of the NPL, the GPL or the LGPL.
 
37
 *
 
38
 * ***** END LICENSE BLOCK ***** */
 
39
 
 
40
/* 
 
41
   This is part of a MOZ_COVERAGE build.  (set MOZ_COVERAGE=1 and rebuild)
 
42
   When trace.dll is linked in to the build, it counts the number of times 
 
43
   each function is called.  When the program exits, it breaks out the 
 
44
   functions by module, sorts them by number of calls, then dumps them into 
 
45
   win32.order where the module is built.  The order files are used by the
 
46
   liker to rearrange the functions in the library.  
 
47
*/
 
48
 
 
49
#include <windows.h>
 
50
#include <imagehlp.h>
 
51
#include <stdio.h>
 
52
 
 
53
#include "pldhash.h"
 
54
 
 
55
//
 
56
//  HIT_INTERVAL
 
57
//
 
58
//  Interval for which we will count hits, in milliseconds.
 
59
//  This tends to sample the need for a particular function over time.
 
60
//
 
61
//  Decreasing the interval makes the code act more like call count
 
62
//      ordering.
 
63
//  Increasing the interval makes the code act more like no ordering
 
64
//      at all.
 
65
//  Some middle ground in between is best.  Tweak away....
 
66
//
 
67
//  We all know that not ordering the link order at all is not an
 
68
//      optimal scenario.
 
69
//  The folly of call count sorting is that you may group together
 
70
//      methods which are rarely used but often called with rountines that
 
71
//      are actually needed during the entire run of the application.
 
72
//      If you can apply a time filter to smooth out the "page level" or
 
73
//      "working set" needs to have a function in memory, then you should
 
74
//      get a much better real world ordering.
 
75
//
 
76
#define HIT_INTERVAL 1000
 
77
 
 
78
class Reporter {
 
79
public:
 
80
    ~Reporter();
 
81
};
 
82
 
 
83
static Reporter theReporter;
 
84
static FILE* logfile;
 
85
 
 
86
/* 
 
87
   Hash of function names, and call counts]
 
88
 */
 
89
static PLDHashTable Calls;
 
90
 
 
91
struct CallEntry {
 
92
    struct PLDHashEntryHdr hdr;
 
93
    const void*            addr;
 
94
    unsigned               count;
 
95
    unsigned               hits; // interval hits.
 
96
    DWORD                  tick; // last valid tick, used to count hits.
 
97
};
 
98
 
 
99
static PLDHashTableOps Ops = {
 
100
    PL_DHashAllocTable,
 
101
    PL_DHashFreeTable,
 
102
    PL_DHashGetKeyStub,
 
103
    PL_DHashVoidPtrKeyStub,
 
104
    PL_DHashMatchEntryStub,
 
105
    PL_DHashMoveEntryStub,
 
106
    PL_DHashClearEntryStub,
 
107
    PL_DHashFinalizeStub
 
108
};
 
109
 
 
110
class Node {
 
111
public:
 
112
    Node() {function = 0; count = 0; hits = 0; next = 0;};
 
113
    char* function;
 
114
    unsigned   count;
 
115
    unsigned   hits;
 
116
    Node* next;
 
117
};
 
118
 
 
119
 
 
120
/* 
 
121
   Hash of each module.  Contains a sorted linked list of each function and
 
122
   its number of calls for that module.
 
123
*/
 
124
 
 
125
static PLDHashTable Modules;
 
126
 
 
127
struct ModulesEntry {
 
128
    struct PLDHashEntryHdr hdr;
 
129
    char*                  moduleName;
 
130
    Node*                  byCount;
 
131
};
 
132
 
 
133
static PLDHashTableOps ModOps = {
 
134
    PL_DHashAllocTable,
 
135
    PL_DHashFreeTable,
 
136
    PL_DHashGetKeyStub,
 
137
    PL_DHashStringKey,
 
138
    PL_DHashMatchStringKey,
 
139
    PL_DHashMoveEntryStub,
 
140
    PL_DHashClearEntryStub,
 
141
    PL_DHashFinalizeStub
 
142
};
 
143
 
 
144
 
 
145
/*
 
146
   Counts the number of times a function is called.
 
147
*/
 
148
extern "C"
 
149
static void
 
150
Log(void* addr)
 
151
{
 
152
static int initialized = 0;
 
153
 
 
154
    addr = (void*) ((unsigned) addr - 5);
 
155
 
 
156
    if (!initialized) {
 
157
        initialized = PL_DHashTableInit(&Calls, &Ops, 0, sizeof(CallEntry), 16);
 
158
        if (!initialized) 
 
159
            return;
 
160
    }
 
161
 
 
162
    entry = (CallEntry*) PL_DHashTableOperate(&Calls, addr, PL_DHASH_ADD);
 
163
    if (!entry)
 
164
        return; // OOM
 
165
 
 
166
    if (!entry->addr)
 
167
        entry->addr = addr;
 
168
 
 
169
    //
 
170
    //  Another call recorded.
 
171
    //
 
172
    ++entry->count;
 
173
 
 
174
    //
 
175
    // Only record a hit if the appropriate amount of time has passed.
 
176
    //
 
177
    DWORD curtick = GetTickCount();
 
178
    if(curtick >= (entry->tick + HIT_INTERVAL))
 
179
    {
 
180
        //
 
181
        //  Record the interval hit.
 
182
        //  Update the tick.
 
183
        //
 
184
        entry->hits++;
 
185
        entry->tick = curtick;
 
186
    }
 
187
}
 
188
 
 
189
/*
 
190
   assembly to call Log, and count this function
 
191
*/
 
192
 
 
193
extern "C"
 
194
__declspec(naked dllexport)
 
195
void _penter()
 
196
{
 
197
    __asm {
 
198
        push ecx               // save ecx for caller
 
199
        push dword ptr [esp+4] // the caller's address is the only param
 
200
        call Log               // ...to Log()
 
201
        add  esp,4
 
202
        pop  ecx               // restore ecx for caller
 
203
        ret
 
204
    }
 
205
}
 
206
 
 
207
/*
 
208
   Steps through the hash of modules and dumps the function counts out to 
 
209
   win32.order
 
210
*/
 
211
 
 
212
static PLDHashOperator PR_CALLBACK
 
213
DumpFiles(PLDHashTable* table, PLDHashEntryHdr* hdr,
 
214
          PRUint32 number, void* arg)
 
215
{
 
216
    ModulesEntry* entry = (ModulesEntry*) hdr;    
 
217
    Node*         cur = entry->byCount;
 
218
    char          dest[MAX_PATH];
 
219
    char          pdbName[MAX_PATH];
 
220
    FILE*         orderFile;
 
221
 
 
222
    strcpy(pdbName, entry->moduleName);
 
223
    strcat(pdbName, ".pdb");
 
224
 
 
225
    if (!::SearchTreeForFile(MOZ_SRC, pdbName, dest) ) {
 
226
        fprintf(logfile,"+++ERROR Could not find %s\n",pdbName);
 
227
        return PL_DHASH_NEXT;
 
228
    }
 
229
    dest[strlen(dest)-strlen(pdbName)-strlen("WIN32_D.OBJ\\")] = 0;
 
230
    strcat(dest,"win32.order");
 
231
    orderFile = fopen(dest,"w");
 
232
    fprintf(logfile,"Creating order file %s\n",dest);
 
233
    
 
234
    while (cur) {
 
235
        if (cur->function[0] == '_')  // demangle "C" style function names
 
236
            fprintf(orderFile,"%s ; %d %d\n", cur->function+1, cur->hits, cur->count );
 
237
        else
 
238
            fprintf(orderFile,"%s ; %d %d\n", cur->function, cur->hits, cur->count );
 
239
        cur = cur->next;
 
240
    }
 
241
 
 
242
    fflush(orderFile);
 
243
    fclose(orderFile);
 
244
    return PL_DHASH_NEXT;
 
245
}
 
246
 
 
247
/*
 
248
   We have a function name.  Figure out which module it is from.  Then add that
 
249
   function and its call count into the module's sorted list.
 
250
*/
 
251
 
 
252
static PLDHashOperator PR_CALLBACK
 
253
ListCounts(PLDHashTable* table, PLDHashEntryHdr* hdr,
 
254
           PRUint32 number, void* arg)
 
255
{
 
256
    BOOL ok;
 
257
    CallEntry* entry = (CallEntry*) hdr;
 
258
 
 
259
    IMAGEHLP_MODULE module;
 
260
    module.SizeOfStruct = sizeof(module);
 
261
 
 
262
    ok = ::SymGetModuleInfo(::GetCurrentProcess(),
 
263
                            (unsigned) entry->addr,
 
264
                            &module);
 
265
 
 
266
    char buf[sizeof(IMAGEHLP_SYMBOL) + 512];
 
267
    PIMAGEHLP_SYMBOL symbol = (PIMAGEHLP_SYMBOL) buf;
 
268
    symbol->SizeOfStruct = sizeof(buf);
 
269
    symbol->MaxNameLength = 512;
 
270
 
 
271
    DWORD displacement;
 
272
    ok = ::SymGetSymFromAddr(::GetCurrentProcess(),
 
273
                             (unsigned) entry->addr,
 
274
                             &displacement,
 
275
                             symbol);
 
276
 
 
277
    if (ok)
 
278
    {
 
279
        if (displacement > 0) 
 
280
            return PL_DHASH_NEXT;
 
281
        static int modInitialized = 0;
 
282
        if (!modInitialized) {
 
283
            modInitialized = PL_DHashTableInit(&Modules, &ModOps, 0, sizeof(ModulesEntry), 16);
 
284
            if (!modInitialized)
 
285
                return PL_DHASH_NEXT;
 
286
        }
 
287
 
 
288
        ModulesEntry* mod
 
289
            = (ModulesEntry*) PL_DHashTableOperate(&Modules,
 
290
                                                   module.ModuleName,
 
291
                                                   PL_DHASH_ADD);
 
292
        if (!mod)
 
293
            return PL_DHASH_STOP;       // OOM
 
294
 
 
295
        if (!mod->moduleName) {
 
296
            mod->moduleName = strdup(module.ModuleName);
 
297
            mod->byCount = new Node();
 
298
            mod->byCount->function = strdup(symbol->Name);
 
299
            mod->byCount->count = entry->count;
 
300
            mod->byCount->hits = entry->hits;
 
301
        } else {
 
302
            // insertion sort.
 
303
            Node* cur = mod->byCount;
 
304
            Node* foo = new Node();
 
305
            foo->function = strdup(symbol->Name);
 
306
            foo->count = entry->count;
 
307
            foo->hits = entry->hits;
 
308
 
 
309
            if
 
310
#if defined(SORT_BY_CALL_COUNT)
 
311
                (cur->count < entry->count)
 
312
#else
 
313
                ((cur->hits < entry->hits) || (cur->hits == entry->hits && cur->count < entry->count))
 
314
#endif
 
315
            {
 
316
                if (!strcmp(cur->function,symbol->Name)) 
 
317
                    return PL_DHASH_NEXT;
 
318
                foo->next = mod->byCount;
 
319
                mod->byCount = foo;                
 
320
            } else {
 
321
                while (cur->next) {
 
322
                    if (!strcmp(cur->function,symbol->Name)) 
 
323
                        return PL_DHASH_NEXT;
 
324
                    if
 
325
#if defined(SORT_BY_CALL_COUNT)
 
326
                        (cur->next->count > entry->count)
 
327
#else
 
328
                        ((cur->next->hits > entry->hits) || (cur->next->hits == entry->hits && cur->next->count > entry->count))
 
329
#endif
 
330
                    { cur = cur->next; }
 
331
                    else { break; }
 
332
                }
 
333
                foo->next = cur->next;  
 
334
                cur->next = foo;
 
335
            }
 
336
        }
 
337
    } // if (ok)
 
338
    return PL_DHASH_NEXT;
 
339
}
 
340
 
 
341
Reporter::~Reporter()
 
342
{
 
343
    SymInitialize(GetCurrentProcess(), 0, TRUE);
 
344
    
 
345
    DWORD options = SymGetOptions();
 
346
 
 
347
    // We want the nasty name, as we'll have to pass it back to the
 
348
    // linker.
 
349
    options &= ~SYMOPT_UNDNAME;
 
350
    SymSetOptions(options);
 
351
 
 
352
    char logName[MAX_PATH];
 
353
    strcpy(logName,MOZ_SRC);
 
354
    strcat(logName,"\\tracelog");
 
355
    logfile = fopen(logName,"w");
 
356
 
 
357
    // break the function names out by module and sort them.
 
358
    PL_DHashTableEnumerate(&Calls, ListCounts, NULL);
 
359
    // dump the order files for each module.
 
360
    PL_DHashTableEnumerate(&Modules, DumpFiles, NULL);
 
361
 
 
362
    fclose(logfile);
 
363
    SymCleanup(GetCurrentProcess());
 
364
}