mirror of
https://github.com/adtools/clib2.git
synced 2025-12-08 14:59:05 +00:00
- Dropped unused stub code which is now redundant because of the constructor/destructor mechanism. git-svn-id: file:///Users/olsen/Code/migration-svn-zu-git/logical-line-staging/clib2/trunk@14891 87f5fb63-7c3d-0410-a384-fd976d0f7a62
349 lines
7.0 KiB
C
349 lines
7.0 KiB
C
/*
|
|
* $Id: sas_profile.c,v 1.5 2005-03-18 12:38:22 obarthel Exp $
|
|
*
|
|
* :ts=4
|
|
*
|
|
* Adapted from SAS/C runtime library code.
|
|
*/
|
|
|
|
#ifndef EXEC_MEMORY_H
|
|
#include <exec/memory.h>
|
|
#endif /* EXEC_MEMORY_H */
|
|
|
|
#ifndef EXEC_PORTS_H
|
|
#include <exec/ports.h>
|
|
#endif /* EXEC_PORTS_H */
|
|
|
|
#ifndef EXEC_DEVICES_H
|
|
#include <exec/devices.h>
|
|
#endif /* EXEC_DEVICES_H */
|
|
|
|
#ifndef DEVICES_TIMER_H
|
|
#include <devices/timer.h>
|
|
#endif /* DEVICES_TIMER_H */
|
|
|
|
/****************************************************************************/
|
|
|
|
#define __NOLIBBASE__
|
|
#define __NOGLOBALIFACE__
|
|
|
|
#ifndef PROTO_EXEC_H
|
|
#include <proto/exec.h>
|
|
#endif /* PROTO_EXEC_H */
|
|
|
|
#ifndef PROTO_TIMER_H
|
|
#include <proto/timer.h>
|
|
#endif /* PROTO_TIMER_H */
|
|
|
|
/****************************************************************************/
|
|
|
|
extern struct Library * SysBase;
|
|
|
|
/****************************************************************************/
|
|
|
|
#ifndef _STDLIB_CONSTRUCTOR_H
|
|
#include "stdlib_constructor.h"
|
|
#endif /* _STDLIB_CONSTRUCTOR_H */
|
|
|
|
/****************************************************************************/
|
|
|
|
#include "macros.h"
|
|
#include "debug.h"
|
|
|
|
/****************************************************************************/
|
|
|
|
struct SPROFMSG
|
|
{
|
|
struct Message message;
|
|
|
|
struct Process * process;
|
|
ULONG clock_value;
|
|
char * id;
|
|
ULONG stack_pointer;
|
|
ULONG flags;
|
|
};
|
|
|
|
/****************************************************************************/
|
|
|
|
/* Values for the 'flags' field of SPROFMSG */
|
|
#define SPROF_INIT 0x00000001 /* Initialize connection */
|
|
#define SPROF_ENTRY 0x00000002 /* Function entry */
|
|
#define SPROF_EXIT 0x00000004 /* Function exit */
|
|
#define SPROF_TERM 0x00000008 /* Terminate connection, program continues */
|
|
#define SPROF_ABORT 0x00000010 /* Abort program */
|
|
#define SPROF_DENIED 0x00000020 /* Connection refused */
|
|
|
|
/****************************************************************************/
|
|
|
|
static struct Library * TimerBase;
|
|
|
|
/****************************************************************************/
|
|
|
|
static struct MsgPort * profiler_port;
|
|
static struct MsgPort * reply_port;
|
|
|
|
static struct MsgPort * time_port;
|
|
static struct timerequest * time_request;
|
|
|
|
static struct Process * this_process;
|
|
|
|
static struct EClockVal start_time;
|
|
static ULONG eclock_frequency;
|
|
static struct EClockVal last_time;
|
|
static ULONG overhead;
|
|
|
|
static ULONG num_messages_allocated;
|
|
|
|
static BOOL initialized;
|
|
|
|
/****************************************************************************/
|
|
|
|
STATIC int send_profiler_message(ULONG clock_value, char *id, ULONG flags);
|
|
STATIC ULONG get_current_time(void);
|
|
STATIC void update_overhead(void);
|
|
STATIC void __profile_init(void);
|
|
STATIC void __profile_exit(void);
|
|
|
|
/****************************************************************************/
|
|
|
|
void ASM _PROLOG(REG(a0, char *id));
|
|
void ASM _EPILOG(REG(a0, char *id));
|
|
|
|
/****************************************************************************/
|
|
|
|
STATIC int
|
|
send_profiler_message(ULONG clock_value,char * id,ULONG flags)
|
|
{
|
|
extern long __builtin_getreg(int);
|
|
|
|
struct SPROFMSG * spm;
|
|
int result = -1;
|
|
|
|
spm = (struct SPROFMSG *)GetMsg(reply_port);
|
|
if(spm != NULL)
|
|
{
|
|
if(flags != SPROF_TERM && spm->flags == SPROF_TERM)
|
|
{
|
|
PutMsg(reply_port,(struct Message *)spm);
|
|
|
|
__profile_exit();
|
|
goto out;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
spm = AllocMem(sizeof(*spm),MEMF_ANY|MEMF_PUBLIC|MEMF_CLEAR);
|
|
if(spm == NULL)
|
|
{
|
|
__profile_exit();
|
|
goto out;
|
|
}
|
|
|
|
spm->message.mn_Length = sizeof(*spm);
|
|
spm->message.mn_ReplyPort = reply_port;
|
|
spm->process = this_process;
|
|
|
|
num_messages_allocated++;
|
|
}
|
|
|
|
spm->clock_value = clock_value;
|
|
spm->id = id;
|
|
spm->stack_pointer = __builtin_getreg(15); /* getreg(REG_A7) */
|
|
spm->flags = flags;
|
|
|
|
PutMsg(profiler_port,(struct Message *)spm);
|
|
WaitPort(reply_port);
|
|
|
|
result = 0;
|
|
|
|
out:
|
|
|
|
return(result);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
|
|
STATIC ULONG
|
|
get_current_time(void)
|
|
{
|
|
ULONG result;
|
|
|
|
ReadEClock(&last_time);
|
|
|
|
result = (last_time.ev_lo - start_time.ev_lo - overhead) / eclock_frequency;
|
|
|
|
return(result);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
|
|
STATIC void
|
|
update_overhead(void)
|
|
{
|
|
struct EClockVal ev;
|
|
|
|
ReadEClock(&ev);
|
|
|
|
overhead += (ev.ev_lo - last_time.ev_lo);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
|
|
void ASM
|
|
_PROLOG(REG(a0,char * id))
|
|
{
|
|
if(initialized)
|
|
{
|
|
if(send_profiler_message(get_current_time(),id,SPROF_ENTRY) == OK)
|
|
update_overhead();
|
|
}
|
|
}
|
|
|
|
/****************************************************************************/
|
|
|
|
void ASM
|
|
_EPILOG(REG(a0,char * id))
|
|
{
|
|
if(initialized)
|
|
{
|
|
if(send_profiler_message(get_current_time(),id,SPROF_EXIT) == OK)
|
|
update_overhead();
|
|
}
|
|
}
|
|
|
|
/****************************************************************************/
|
|
|
|
STATIC VOID
|
|
__profile_init(void)
|
|
{
|
|
struct SPROFMSG * spm;
|
|
BOOL ready = FALSE;
|
|
|
|
this_process = (struct Process *)FindTask(NULL);
|
|
|
|
time_port = CreateMsgPort();
|
|
if(time_port == NULL)
|
|
goto out;
|
|
|
|
time_request = (struct timerequest *)CreateIORequest(time_port,sizeof(*time_request));
|
|
if(time_request == NULL)
|
|
goto out;
|
|
|
|
if(OpenDevice(TIMERNAME,UNIT_ECLOCK,(struct IORequest *)time_request,0) != OK)
|
|
goto out;
|
|
|
|
TimerBase = (struct Library *)time_request->tr_node.io_Device;
|
|
|
|
reply_port = CreateMsgPort();
|
|
if(reply_port == NULL)
|
|
goto out;
|
|
|
|
Forbid();
|
|
|
|
profiler_port = FindPort("SPROF_Profiler");
|
|
if(profiler_port == NULL)
|
|
{
|
|
Permit();
|
|
|
|
goto out;
|
|
}
|
|
|
|
if(send_profiler_message(0,NULL,SPROF_INIT) != OK)
|
|
{
|
|
Permit();
|
|
|
|
goto out;
|
|
}
|
|
|
|
initialized = TRUE;
|
|
|
|
Permit();
|
|
|
|
while((spm = (struct SPROFMSG *)GetMsg(reply_port)) == NULL)
|
|
WaitPort(reply_port),
|
|
|
|
PutMsg(reply_port,(struct Message *)spm);
|
|
|
|
if(spm->flags == SPROF_DENIED || spm->flags == SPROF_TERM)
|
|
goto out;
|
|
|
|
eclock_frequency = ReadEClock(&start_time) / 1000;
|
|
|
|
ready = TRUE;
|
|
|
|
out:
|
|
|
|
if(NOT ready)
|
|
__profile_exit();
|
|
}
|
|
|
|
/****************************************************************************/
|
|
|
|
STATIC VOID
|
|
__profile_exit(void)
|
|
{
|
|
if(initialized)
|
|
{
|
|
send_profiler_message(0,NULL,SPROF_TERM);
|
|
|
|
initialized = FALSE;
|
|
}
|
|
|
|
if(reply_port != NULL)
|
|
{
|
|
struct SPROFMSG * spm;
|
|
|
|
while(num_messages_allocated > 0)
|
|
{
|
|
while((spm = (struct SPROFMSG *)GetMsg(reply_port)) == NULL)
|
|
WaitPort(reply_port),
|
|
|
|
FreeMem(spm,sizeof(*spm));
|
|
|
|
num_messages_allocated--;
|
|
}
|
|
|
|
DeleteMsgPort(reply_port);
|
|
reply_port = NULL;
|
|
}
|
|
|
|
if(time_request != NULL)
|
|
{
|
|
if(time_request->tr_node.io_Device != NULL)
|
|
CloseDevice((struct IORequest *)time_request);
|
|
|
|
DeleteIORequest((struct IORequest *)time_request);
|
|
time_request = NULL;
|
|
}
|
|
|
|
if(time_port != NULL)
|
|
{
|
|
DeleteMsgPort(time_port);
|
|
time_port = NULL;
|
|
}
|
|
}
|
|
|
|
/****************************************************************************/
|
|
|
|
PROFILE_CONSTRUCTOR(profile_init)
|
|
{
|
|
ENTER();
|
|
|
|
__profile_init();
|
|
|
|
LEAVE();
|
|
|
|
CONSTRUCTOR_SUCCEED();
|
|
}
|
|
|
|
/****************************************************************************/
|
|
|
|
PROFILE_DESTRUCTOR(profile_exit)
|
|
{
|
|
ENTER();
|
|
|
|
__profile_exit();
|
|
|
|
LEAVE();
|
|
}
|