URL
https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk
Subversion Repositories openrisc_me
Compare Revisions
- This comparison shows the changes necessary to convert path
/openrisc/trunk/rtos/ecos-2.0/packages/services/profile/gprof/v2_0/src
- from Rev 27 to Rev 174
- ↔ Reverse comparison
Rev 27 → Rev 174
/profile.c
0,0 → 1,242
//========================================================================== |
// |
// profile.c |
// |
// Application profiling support |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 2002 Gary Thomas |
// |
// eCos is free software; you can redistribute it and/or modify it under |
// the terms of the GNU General Public License as published by the Free |
// Software Foundation; either version 2 or (at your option) any later version. |
// |
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY |
// WARRANTY; without even the implied warranty of MERCHANTABILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// You should have received a copy of the GNU General Public License along |
// with eCos; if not, write to the Free Software Foundation, Inc., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. |
// |
// As a special exception, if other files instantiate templates or use macros |
// or inline functions from this file, or you compile this file and link it |
// with other works to produce a work based on this file, this file does not |
// by itself cause the resulting work to be covered by the GNU General Public |
// License. However the source code for this file must still be made available |
// in accordance with section (3) of the GNU General Public License. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): Gary Thomas |
// Contributors: |
// Date: 2002-11-14 |
// Purpose: Application profiling support |
// Description: |
// |
//####DESCRIPTIONEND#### |
// |
//=========================================================================== |
#include <pkgconf/profile_gprof.h> |
|
#include <stdlib.h> |
#include <cyg/infra/diag.h> |
#include <network.h> |
#include <tftp_support.h> |
#include <cyg/profile/profile.h> |
#include <cyg/profile/gmon_out.h> |
|
static int num_buckets; |
static unsigned short *profile; |
static int bucket_size, bucket_shift; |
static unsigned long start_addr, end_addr; |
static int enabled; |
static int tftp_server_id; |
static int prof_rate; |
|
static int profile_open(const char *, int); |
static int profile_close(int); |
static int profile_write(int, const void *, int); |
static int profile_read(int, void *, int); |
|
struct tftpd_fileops profile_fileops = { |
profile_open, profile_close, profile_write, profile_read |
}; |
|
struct _file { |
unsigned char *pos, *eof, *data; |
int flags; |
int mode; |
}; |
#define FILE_OPEN 0x0001 |
|
#define NUM_FILES 1 |
static struct _file files[NUM_FILES]; |
|
static inline struct _file * |
profile_fp(int fd) |
{ |
struct _file *fp; |
if ((fd < 0) || (fd >= NUM_FILES)) return (struct _file *)0; |
fp = &files[fd]; |
if (!(fp->flags & FILE_OPEN)) return (struct _file *)0; |
return fp; |
} |
|
static int |
profile_open(const char *fn, int flags) |
{ |
int fd = 0; |
struct _file *fp; |
int len = sizeof(struct gmon_hdr) + sizeof(struct gmon_hist_hdr) + (num_buckets*2) + 1; |
struct gmon_hdr _hdr; |
struct gmon_hist_hdr _hist_hdr; |
unsigned char *bp; |
int version = GMON_VERSION; |
int hist_size = num_buckets; |
int file_type = -1; |
|
fp = files; |
if (fp->flags & FILE_OPEN) { |
// File already open |
return -1; |
} |
if (!(flags & O_RDONLY)) { |
// Only read supported |
return -1; |
} |
if (strcmp(fn, "PROFILE.DAT") == 0) { |
file_type = 0; |
} |
if (file_type < 0) { |
// No supported file |
return -1; |
} |
// Set up file info |
enabled = 0; |
switch (file_type) { // In case another type ever supported |
case 0: // profile data |
fp->data = malloc(len); |
if (!fp->data) { |
diag_printf("Can't allocate buffer for profile data!\n"); |
return -1; |
} |
fp->flags = FILE_OPEN; |
fp->mode = flags; |
fp->pos = fp->data; |
fp->eof = fp->pos + len; |
// Fill in profile data |
bp = fp->data; |
memset(&_hdr, 0, sizeof(_hdr)); |
strcpy(_hdr.cookie, GMON_MAGIC); |
memcpy(_hdr.version, &version, sizeof(version)); |
memcpy(bp, &_hdr, sizeof(_hdr)); |
bp += sizeof(_hdr); |
memcpy(&_hist_hdr.low_pc, &start_addr, sizeof(start_addr)); |
memcpy(&_hist_hdr.high_pc, &end_addr, sizeof(end_addr)); |
memcpy(&_hist_hdr.hist_size, &hist_size, sizeof(hist_size)); |
memcpy(&_hist_hdr.prof_rate, &prof_rate, sizeof(prof_rate)); |
strcpy(_hist_hdr.dimen, "seconds"); |
_hist_hdr.dimen_abbrev = 's'; |
*bp++ = GMON_TAG_TIME_HIST; |
memcpy(bp, &_hist_hdr, sizeof(_hist_hdr)); |
bp += sizeof(_hist_hdr); |
memcpy(bp, profile, (num_buckets*2)); |
memset(profile, 0, (num_buckets*2)); |
break; |
} |
return fd; |
} |
|
static int |
profile_close(int fd) |
{ |
struct _file *fp = profile_fp(fd); |
if (!fp) return -1; |
if (fp->data) free(fp->data); |
fp->flags = 0; // No longer open |
enabled = 1; |
return 0; |
} |
|
static int |
profile_write(int fd, const void *buf, int len) |
{ |
return -1; |
} |
|
static int |
profile_read(int fd, void *buf, int len) |
{ |
struct _file *fp = profile_fp(fd); |
int res; |
if (!fp) return -1; |
res = fp->eof - fp->pos; // Number of bytes left in "file" |
if (res > len) res = len; |
if (res <= 0) return 0; // End of file |
bcopy(fp->pos, buf, res); |
fp->pos += res; |
return res; |
} |
|
void |
__profile_hit(unsigned long pc) |
{ |
int bucket; |
if (enabled) { |
if ((pc >= start_addr) && (pc <= end_addr)) { |
bucket = (pc - start_addr) >> bucket_shift; |
if (profile[bucket] < (unsigned short)0xFFFF) { |
profile[bucket]++; |
} |
} |
} |
} |
|
void |
profile_on(void *_start, void *_end, int _bucket_size, int resolution) |
{ |
start_addr = (unsigned long)_start; |
end_addr = (unsigned long)_end; |
// Adjust bucket size to be a power of 2 |
bucket_size = 1; |
bucket_shift = 0; |
while (bucket_size < _bucket_size) { |
bucket_size <<= 1; |
bucket_shift++; |
} |
if (bucket_size != _bucket_size) { |
bucket_size <<= 1; |
bucket_shift++; |
} |
// Calculate number of buckets |
num_buckets = ((end_addr - start_addr) + (bucket_size - 1)) / bucket_size; |
// Adjust end address so calculations come out |
end_addr = start_addr + (bucket_size * num_buckets); |
prof_rate = 1000000 / resolution; |
// Allocate buffer for profile data |
if (!(profile = malloc(num_buckets*2))) { |
diag_printf("Can't allocate profile buffer - ignored\n"); |
return; |
} |
enabled = 1; |
diag_printf("Profile from %p..%p[%p], in %d buckets of size %d\n", |
start_addr, end_addr, _end, num_buckets, bucket_size); |
|
hal_enable_profile_timer(resolution); |
|
// Create a TFTP server to provide the data |
tftp_server_id = tftpd_start(CYGNUM_PROFILE_TFTP_PORT, &profile_fileops); |
} |