diff options
author | Christopher Faylor <me@cgf.cx> | 2000-02-17 22:38:33 +0300 |
---|---|---|
committer | Christopher Faylor <me@cgf.cx> | 2000-02-17 22:38:33 +0300 |
commit | 1fd5e000ace55b323124c7e556a7a864b972a5c4 (patch) | |
tree | dc4fcf1e5e22a040716ef92c496b8d94959b2baa /winsup/mingw/profile/profil.c | |
parent | 369d8a8fd5e887eca547bf34bccfdf755c9e5397 (diff) |
import winsup-2000-02-17 snapshot
Diffstat (limited to 'winsup/mingw/profile/profil.c')
-rw-r--r-- | winsup/mingw/profile/profil.c | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/winsup/mingw/profile/profil.c b/winsup/mingw/profile/profil.c new file mode 100644 index 000000000..d2946210e --- /dev/null +++ b/winsup/mingw/profile/profil.c @@ -0,0 +1,185 @@ +/* profil.c -- win32 profil.c equivalent + + Copyright 1998 Cygnus Solutions. + + This file is part of Cygwin. + + This software is a copyrighted work licensed under the terms of the + Cygwin license. Please consult the file "CYGWIN_LICENSE" for + details. */ + +/* + * This file is taken from Cygwin distribution. Please keep it in sync. + * The differences should be within __MINGW32__ guard. + */ + +#include <windows.h> +#include <stdio.h> +#include <sys/types.h> +#include <errno.h> +#include <math.h> + +#include <profil.h> + +#define SLEEPTIME (1000 / PROF_HZ) + +/* global profinfo for profil() call */ +static struct profinfo prof; + +/* Get the pc for thread THR */ + +static u_long +get_thrpc (HANDLE thr) +{ + CONTEXT ctx; + u_long pc; + int res; + + res = SuspendThread (thr); + if (res == -1) + return (u_long) - 1; + ctx.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER; + pc = (u_long) - 1; + if (GetThreadContext (thr, &ctx)) + pc = ctx.Eip; + ResumeThread (thr); + return pc; +} + +/* Display cell of profile buffer */ +#if 0 +static void +print_prof (struct profinfo *p) +{ + printf ("profthr %x\ttarget thr %x\n", p->profthr, p->targthr); + printf ("pc: %x - %x\n", p->lowpc, p->highpc); + printf ("scale: %x\n", p->scale); + return; +} +#endif + +/* Everytime we wake up use the main thread pc to hash into the cell in the + profile buffer ARG. */ + +static DWORD CALLBACK +profthr_func (LPVOID arg) +{ + struct profinfo *p = (struct profinfo *) arg; + u_long pc, idx; + + for (;;) + { + pc = (u_long) get_thrpc (p->targthr); + if (pc >= p->lowpc && pc < p->highpc) + { + idx = PROFIDX (pc, p->lowpc, p->scale); + p->counter[idx]++; + } +#if 0 + print_prof (p); +#endif + Sleep (SLEEPTIME); + } + return 0; +} + +/* Stop profiling to the profiling buffer pointed to by P. */ + +static int +profile_off (struct profinfo *p) +{ + if (p->profthr) + { + TerminateThread (p->profthr, 0); + CloseHandle (p->profthr); + } + if (p->targthr) + CloseHandle (p->targthr); + return 0; +} + +/* Create a timer thread and pass it a pointer P to the profiling buffer. */ + +static int +profile_on (struct profinfo *p) +{ + DWORD thrid; + + /* get handle for this thread */ + if (!DuplicateHandle (GetCurrentProcess (), GetCurrentThread (), + GetCurrentProcess (), &p->targthr, 0, FALSE, + DUPLICATE_SAME_ACCESS)) + { + errno = ESRCH; + return -1; + } + + p->profthr = CreateThread (0, 0, profthr_func, (void *) p, 0, &thrid); + + /* Set profiler thread priority to highest to be sure that it gets the + processor as soon it request it (i.e. when the Sleep terminate) to get + the next data out of the profile. */ + + SetThreadPriority (p->profthr, THREAD_PRIORITY_TIME_CRITICAL); + + if (!p->profthr) + { + CloseHandle (p->targthr); + p->targthr = 0; + errno = EAGAIN; + return -1; + } + return 0; +} + +/* + * start or stop profiling + * + * profiling goes into the SAMPLES buffer of size SIZE (which is treated + * as an array of u_shorts of size size/2) + * + * each bin represents a range of pc addresses from OFFSET. The number + * of pc addresses in a bin depends on SCALE. (A scale of 65536 maps + * each bin to two addresses, A scale of 32768 maps each bin to 4 addresses, + * a scale of 1 maps each bin to 128k addreses). Scale may be 1 - 65536, + * or zero to turn off profiling + */ +int +profile_ctl (struct profinfo * p, char *samples, size_t size, + u_long offset, u_int scale) +{ + u_long maxbin; + + if (scale > 65536) + { + errno = EINVAL; + return -1; + } + + profile_off (p); + if (scale) + { + memset (samples, 0, size); + memset (p, 0, sizeof *p); + maxbin = size >> 1; + prof.counter = (u_short *) samples; + prof.lowpc = offset; + prof.highpc = PROFADDR (maxbin, offset, scale); + prof.scale = scale; + + return profile_on (p); + } + return 0; +} + +/* Equivalent to unix profil() + Every SLEEPTIME interval, the user's program counter (PC) is examined: + offset is subtracted and the result is multiplied by scale. + The word pointed to by this address is incremented. Buf is unused. */ + +int +profil (char *samples, size_t size, u_long offset, u_int scale) +{ + return profile_ctl (&prof, samples, size, offset, scale); +} + |