sample.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 646 行 · 第 1/2 页

C
646
字号
/****************************************************************************
*
*                            Open Watcom Project
*
*    Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
*  ========================================================================
*
*    This file contains Original Code and/or Modifications of Original
*    Code as defined in and that are subject to the Sybase Open Watcom
*    Public License version 1.0 (the 'License'). You may not use this file
*    except in compliance with the License. BY USING THIS FILE YOU AGREE TO
*    ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
*    provided with the Original Code and Modifications, and is also
*    available at www.sybase.com/developer/opensource.
*
*    The Original Code and all software distributed under the License are
*    distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
*    EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
*    ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
*    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
*    NON-INFRINGEMENT. Please see the License for the specific language
*    governing rights and limitations under the License.
*
*  ========================================================================
*
* Description:  Execution Sampler mainline.
*
****************************************************************************/


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
#include <string.h>
#ifdef __WATCOMC__
    #include <process.h>
#else
    #include "clibext.h"
#endif
#include <malloc.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "banner.h"
#include "os.h"
#include "sample.h"
#include "wmsg.h"
#include "smpstuff.h"
#include "digtypes.h"

#ifdef __WINDOWS__
#include "sampwin.h"
#define Info SharedMemory->Info
#define SampleIndex SharedMemory->SampleIndex
#define SampleCount SharedMemory->SampleCount
#define LastSampleIndex SharedMemory->LastSampleIndex
#define FarWriteProblem SharedMemory->FarWriteProblem
#define CurrTick SharedMemory->CurrTick
#define LostData SharedMemory->LostData
#endif

#define NL      "\r\n"

samp_header             Header = {
                                SAMP_SIGNATURE,
                                SAMP_MAJOR_VER,
                                SAMP_MINOR_VER,
                                sizeof( PREFIX_STRING )
                                };

samp_block_prefix       Last = {
                                0,
                                sizeof( samp_block_prefix ),
                                SAMP_LAST
                               };

bool                    FirstSample = TRUE;
static int              stackSize = 0;


void WriteMark( char FAR_PTR *str, seg_offset where )
{
    struct {
        struct samp_block_prefix    pref;
        struct samp_mark            mark;
    }           proto;
    unsigned    size;
    char        FAR_PTR *ptr;

    SamplerOff++;
    size = 1;
    for( ptr = str; *ptr != '\0'; ++ptr, ++size )
        ;
#if defined(__WINDOWS__)
    proto.pref.tick = WinGetCurrTick();
#else
    proto.pref.tick = CurrTick;
#endif
    proto.pref.length = (sizeof( proto ) - 1) + size;
    proto.pref.kind = SAMP_MARK;
    proto.mark.addr.segment = where.segment;
    proto.mark.addr.offset  = where.offset;
    proto.mark.thread_id = 1;
    Info.d.count[ SAMP_MARK ].size += proto.pref.length;
    Info.d.count[ SAMP_MARK ].number++;
    SampWrite( &proto, sizeof( proto ) - 1 );
    SampWrite( str, size );
    SamplerOff--;
}

void WriteCodeLoad( seg_offset ovl_tbl, char *name, samp_block_kinds kind )
{
    struct {
        struct samp_block_prefix    pref;
        struct samp_code_load       d;
    }                       *code;
    unsigned                len;

    len = strlen( name );
    code = alloca( sizeof( *code ) + len );
    code->pref.tick = 0;
    code->pref.length = sizeof( *code ) + len;
    code->pref.kind = kind;
    code->d.ovl_tab.segment = ovl_tbl.segment;
    code->d.ovl_tab.offset = ovl_tbl.offset;
#ifndef __NETWARE__
    {
    struct  stat            state;

    stat( name, (struct stat *)&state );
    code->d.time_stamp = state.st_mtime;
    }
#else
    code->d.time_stamp = 0;
#endif
    memcpy( code->d.name, name, len + 1 ); /* including NULLCHAR */
    Info.d.count[ kind ].size += code->pref.length;
    Info.d.count[ kind ].number += 1;
    SampWrite( code, code->pref.length );
}


void WriteAddrMap( seg map_start,  seg load_start, off load_offset )
{
    struct {
        struct samp_block_prefix    pref;
        struct samp_addr_map        d;
    }                       addr;

    addr.pref.tick = 0;
    addr.pref.length = sizeof( addr );
    addr.pref.kind = SAMP_ADDR_MAP;
    addr.d.data[0].map.segment = map_start;
    addr.d.data[0].map.offset = 0;
    addr.d.data[0].actual.segment = load_start;
    addr.d.data[0].actual.offset = load_offset;
    Info.d.count[ SAMP_ADDR_MAP ].size += sizeof( addr );
    Info.d.count[ SAMP_ADDR_MAP ].number += 1;
    SampWrite( &addr, sizeof( addr ) );
}


void StopAndSave( void )
/* called from int08_handler, int21_handler, and int28_handler */
{
    /*  We don't want our int08_handler to interfere at this time;
        We are running here on a stolen time.
    */
    SamplerOff++;
    SaveSamples();
    SamplerOff--;
}


void SaveSamples( void )
/* called from StopAndSave, and report */
{
    unsigned size;
    unsigned tid;
    unsigned i, j;
    cgraph_sample xfer;

    tid = 0;
    while( (tid = NextThread( tid )) ) {
        if( !CallGraphMode ) {         /* record actual sample only */
            if( SampleIndex > 0 ) {
                size = sizeof( samp_block_prefix ) + sizeof( struct samp_samples )
                            + (SampleIndex - 1) * sizeof( samp_address );
                Samples->pref.length = size;
                if( SampWrite( Samples, size ) == 0 ) {
                    Info.d.count[ SAMP_SAMPLES ].size += size;
                    Info.d.count[ SAMP_SAMPLES ].number += 1;
                }
                SampleIndex = 0;
            }
        } else {        /* record sample and callgraph information */
            for( i=0; i < SampleIndex; i++ )
            if( SampleCount > 0 ) {
                /* write sample record */
                size = SIZE_PREFIX + SIZE_SAMPLE + SampleCount * SIZE_SAMP_ADDR;
                Samples->pref.length = size;
                Info.d.count[ SAMP_SAMPLES ].size += size;
                Info.d.count[ SAMP_SAMPLES ].number += 1;
                SampWrite( Samples, SIZE_PREFIX + SIZE_SAMPLE );
                for( i = 0, j = 0; i < SampleCount; i++ ) {
                    SampWrite( &Samples->d.sample.sample[ j ], SIZE_SAMP_ADDR );
                    j += ( Samples->d.sample.sample[ j+1 ].offset >> 16 ) + 2;
                }
                /* write callgraph record */
                size = SIZE_PREFIX + SIZE_CALLGRAPH +      /* prefix stuff */
                       SampleCount * SIZE_CGRAPH_SAMPLE +  /* push/pop info */
                       (SampleIndex - 2*SampleCount) *     /* cgraph samples */
                                            SIZE_SAMP_ADDR;
                CallGraph->pref.length = size;
                CallGraph->d.cgraph.number = SampleCount;
                Info.d.count[ SAMP_CALLGRAPH ].size += size;
                Info.d.count[ SAMP_CALLGRAPH ].number += 1;
                SampWrite( CallGraph, SIZE_PREFIX + SIZE_CALLGRAPH);
                for( i = 0, j = 1; i < SampleCount; i++ ) {
                    if( Samples->d.sample.sample[ j ].segment == 0 ) {
                        xfer.pop_n = (uint_16)
                                Samples->d.sample.sample[ j ].offset;
                        xfer.push_n =
                                Samples->d.sample.sample[ j ].offset >> 16;
                        stackSize -= xfer.pop_n;
                        if( stackSize < 0 ) {
                            xfer.pop_n += stackSize;
                        }
                        stackSize += xfer.push_n;
                        SampWrite( &xfer, SIZE_CGRAPH_SAMPLE );
                        SampWrite( &Samples->d.sample.sample[ j + 1 ],
                                                xfer.push_n * SIZE_SAMP_ADDR );
                        j += xfer.push_n + 2;
                    } else {    /* the callgraph info was not available */
                        xfer.pop_n = -1;        /* flag this condition for */
                        xfer.push_n = -1;       /* the profiler. */
                        SampWrite( &xfer, SIZE_CGRAPH_SAMPLE );
                        j += 2;
                    }
                }
                SampleIndex = 0;
                SampleCount = 0;
                LastSampleIndex = 0;
            }
        }
    }
}


void RecordCGraph( void )
/*
 *  Record the callgraph information.  It won't be written in this
 *  form, but it's easiest to store it with the actual samples and
 *  separate the information as it's written.
 */
{
    int         i;

    GetCommArea();

    if( Comm.in_hook ) {        /* we don't really want to sample here */
        SampleIndex--;
        SampleCount--;          /* forget about this sample */
        return;                 /* and quit */
    }

/* first, we record the push/pop values */
    if( FirstSample ) {
        FirstSample = FALSE;
        Comm.push_no++;
    } else if( Comm.push_no != 0 || Comm.pop_no != 0 ) {
        Comm.push_no++;
        Comm.pop_no++;
    }
    Samples->d.sample.sample[ SampleIndex ].segment = 0;
    Samples->d.sample.sample[ SampleIndex ].offset = Comm.push_no;
    Samples->d.sample.sample[ SampleIndex ].offset <<= 16;
    Samples->d.sample.sample[ SampleIndex ].offset += Comm.pop_no;
    SampleIndex++;

/* then we write the cs:ip of the last known routine */
    if( Comm.push_no ) {
        Samples->d.sample.sample[ SampleIndex ].offset
                                    = (off) Comm.top_ip;
        Samples->d.sample.sample[ SampleIndex ].segment
                                    = (seg) Comm.top_cs;
        SampleIndex++;
    }

/* finally, record the necessary callgraph information */
    for( i = 0; i < (int) Comm.push_no - 1; i++ ) {
        GetNextAddr();
        Samples->d.sample.sample[ SampleIndex ].offset = CGraphOff;
        Samples->d.sample.sample[ SampleIndex ].segment = CGraphSeg;
        SampleIndex++;
    }

/* and reset the communication area to prepare for next sample */
    ResetCommArea();
}


static void AllFull( void )
{
    SampClose();
    Output( MsgArray[ERR_DISK_FULL-ERR_FIRST_MESSAGE] );
    Output( "\r\n" );
    fatal();
}


void REPORT_TYPE report( void )
{
    StopProg();
    SaveSamples();

    /* write the header on the sample file */
    Info.d.count[ SAMP_LAST ].number++;
    if( SampWrite( &Last, sizeof( Last ) ) != 0 ) AllFull();
    if( SampWrite( &Header, sizeof( Header ) ) != 0 ) AllFull();
#if defined(__WINDOWS__)
    Info.pref.tick = WinGetCurrTick();

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?