On 2011-08-20 PM 5:49, Corinna Vinschen wrote:
Hi Jin-woo,
On Aug 20 06:59, jojelino wrote:
On 2011-08-20 AM 6:48, jojelino wrote:
cd i686-pc-cygwin/winsup/cygwin;rm *.o;make profile=1
it would work.
Please ignore attachment from 6:48, i have mistaken by attaching
invalid winsup-profile-support.diff
So i am replying.
Yes, but to the wrong list ;-)
Would you mind to resend your patches as a reply to your original
threada on the cygwin-patches list? That's where the official
patch submissions are suppsoed to go.
Btw., you don't have to attach the ChangeLog. For the lazy reader
it's easier if the ChangeLog is just inline in your mail. If you
want to avoid more spam, just omit your email address from the
ChangeLog date/name/email header.
Yes, I see.
But there's something I don't grok in your patch:
Yes, I need to spend more time.
In dll_crt0_0:
+ _monstartup();
but
+#ifdef PROFILE
+ atexit (&_mcleanup);
+#endif
Shouldn't the call to _monstartup also be guarded with #ifdef PROFILE?
Same question for calls to profile_thread_off and any other profiling
code in other places.
Yes i was supposed to do that. thanks for pointing it out.
In gcrt0.c:
+#ifndef PROFILE
void _monstartup (void) __attribute__((__constructor__));
-
+#endif
#if*n*def? Is that a typo?
No, it's not typo. it is assumed that PROFILE is defined iff make is
invoked with profile=1, and when PROFILE defined, the patch need to have
different invocation of _monstartup. the only reason doing this is that
the patch make use of sec_none_nih on profile_on.
and diff you mentioned in gcrt0.c doesn't exist any longer.
changelog of winsup-profile-support-2.diff
Following patch are not effective unless you 'make profile=1'
* profil.h: (struct profinfo::{queue,operational}): New member.
(struct clk): New struct.
* gmon.h: (struct gmonparam::comm_kcount): New member.
* gmon.c: (s_scale): Add NO_COPY_INIT.
(_gmonparam): Ditto.
* profil.c: (prof): Ditto.
(profile_off): Finish profiling request.
(apc_spawnthread): New function.
(profile_on): Initialize init_global_security prior to use it, and
spawn the consumer thread by issuing APC call.
(fake_sbrk): Use LocalAlloc instead of malloc.
(monstartup): Claim memory for comm_kcount.
(_mcleanup): Alter formatting of cleanup filename, decide hz which
maximizes kcount, calculate kcount using comm_kcount.
* gcrt0.c (PROFILE): Define.
(_monstartup): Use it.
* exceptions.cc (ctrl_c_handler): Stop the consumer thread explicitly
to avoid deadlock.
* external.cc (exit_process): Ditto.
* pinfo.cc (pinfo::exit): Ditto.
* init.cc (respawn_wow64_process): Ditto.
(dll_entry): call __cyg_profile_{func,tls}_{ctor,dtor} to initialize
instrument function.
* dcrt0.cc (dll_crt0_0): call _monstartup,atexit in proper order,
* Makefile.in (EXTRA_DEPENDENCIES_1): Define variable.
(EXTRA_LDFLAGS_1): Ditto.
(profile): Ditto
(CFLAGS): Redefine.
(gcrt1.o): use gcrt0.c as prerequisite.
(TEST_DLL_NAME): use EXTRA_DEPENDENCIES_?, EXTRA_LDFLAGS_?.
* sec_helper.cc (init_global_security): Check if called twice.
* boundbuffer.c: New file.
* boundbuffer.h: Ditto.
* instrument.c: Ditto.
* instrument.h: Ditto.
changelog of winsup-makefile.diff
* Makefile.common (ALL_CFLAGS): Replace simple expansion to recursive
expansion.
Index: winsup/cygwin/Makefile.in
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/Makefile.in,v
retrieving revision 1.248
diff -u -p -r1.248 Makefile.in
--- winsup/cygwin/Makefile.in 2 May 2011 19:14:39 -0000 1.248
+++ winsup/cygwin/Makefile.in 22 Aug 2011 20:27:57 -0000
@@ -233,7 +233,7 @@ EXTRALIBS:=libautomode.a libbinmode.a li
INSTOBJS:=automode.o binmode.o textmode.o textreadmode.o
TARGET_LIBS:=$(LIB_NAME) $(CYGWIN_START) $(GMON_START) $(LIBGMON_A) $(SUBLIBS)
$(INSTOBJS) $(EXTRALIBS)
-ifneq "${filter -O%,$(CFLAGS)}" ""
+ifneq "" ""
cygheap_CFLAGS:=-fomit-frame-pointer
cygthread_CFLAGS:=-fomit-frame-pointer
cygtls_CFLAGS:=-fomit-frame-pointer
@@ -286,6 +286,16 @@ syscalls_CFLAGS:=-fomit-frame-pointer
sysconf_CFLAGS:=-fomit-frame-pointer
uinfo_CFLAGS:=-fomit-frame-pointer
endif
+EXTRA_DEPENDENCIES_1=gcrt1.o boundbuffer.o instrument.o gmon.o mcount.o
profil.o
+EXTRA_LDFLAGS_1=../w32api/lib/libkernel32.a
+ifeq '$(profile)' '1'
+override CFLAGS=-MMD -DPROFILE ${$(*F)_CFLAGS} ${PROFILE_CFLAGS_${shell echo
$(EXTRA_DEPENDENCIES_1:.o=) pthread kernel32 malloc_wrapper pseudo-reloc
libstdcxx_wrapper cxx sync|grep -q "$(*F)";ret=$$?;echo $$ret;echo $(*F) $$ret
1>&2}} -fmerge-constants -ftracer \
+ -mno-use-libstdc-wrappers $(CCEXTRA)
+PROFILE_CFLAGS_1=-O4 -march=core2 -mfpmath=sse -mstackrealign -g -pg
-finstrument-functions
+PROFILE_CFLAGS_0=-O4 -march=core2 -mfpmath=sse -mstackrealign -g
-fomit-frame-pointer -Wno-error=unused-but-set-variable
+gcrt1.o: $(srcdir)/gcrt0.c
+ $(COMPILE_CC) -o $(@D)/$(*F)$o $<
+endif
fhandler_proc_CFLAGS+=-DUSERNAME="\"$(USER)\"" -DHOSTNAME="\"$(HOSTNAME)\""
fhandler_proc_CFLAGS+=-DGCC_VERSION="\"`$(CC) -v 2>&1 | tail -n 1`\""
@@ -390,15 +400,13 @@ maintainer-clean realclean: clean
@echo "This command is intended for maintainers to use;"
@echo "it deletes files that may require special tools to rebuild."
-rm -fr configure
-
-
# Rule to build cygwin.dll
-$(TEST_DLL_NAME): $(LDSCRIPT) dllfixdbg $(DLL_OFILES) $(DLL_IMPORTS)
$(LIBSERVER) $(LIBC) $(LIBM) $(API_VER) Makefile winver_stamp
+$(TEST_DLL_NAME): $(LDSCRIPT) dllfixdbg $(EXTRA_DEPENDENCIES_$(profile))
$(DLL_OFILES) $(DLL_IMPORTS) $(LIBSERVER) $(LIBC) $(LIBM) $(API_VER) Makefile
winver_stamp
$(CXX) $(CXXFLAGS) -Wl,--gc-sections $(nostdlib) -Wl,-T$(firstword $^) \
-Wl,--heap=0 -Wl,--out-implib,cygdll.a -shared -o $@ \
- -e $(DLL_ENTRY) $(DEF_FILE) $(DLL_OFILES) version.o winver.o \
+ -e $(DLL_ENTRY) $(DEF_FILE) $(EXTRA_DEPENDENCIES_$(profile))
$(DLL_OFILES) version.o winver.o \
$(MALLOC_OBJ) $(LIBSERVER) $(LIBM) $(LIBC) \
- -lgcc $(DLL_IMPORTS) -Wl,-Map,cygwin.map
+ -lgcc $(EXTRA_LDFLAGS_$(profile)) $(DLL_IMPORTS) -Wl,-Map,cygwin.map
@$(word 2,$^) $(OBJDUMP) $(OBJCOPY) $@ ${patsubst %0.dll,%1.dbg,$@}
@ln -f $@ new-$(DLL_NAME)
Index: winsup/cygwin/dcrt0.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/dcrt0.cc,v
retrieving revision 1.406
diff -u -p -r1.406 dcrt0.cc
--- winsup/cygwin/dcrt0.cc 18 Aug 2011 15:59:16 -0000 1.406
+++ winsup/cygwin/dcrt0.cc 22 Aug 2011 20:27:57 -0000
@@ -37,7 +37,9 @@ details. */
#include "cygxdr.h"
#include "fenv.h"
#include "ntdll.h"
-
+#ifdef PROFILE
+#include "profil.h"
+#endif
#define MAX_AT_FILE_LEVEL 10
#define PREMAIN_LEN (sizeof (user_data->premain) / sizeof
(user_data->premain[0]))
@@ -648,7 +650,11 @@ init_windows_system_directory ()
windows_system_directory[windows_system_directory_length++] = L'\\';
windows_system_directory[windows_system_directory_length] = L'\0';
}
-
+#ifdef PROFILE
+extern "C" {
+ void _mcleanup (void);
+}
+#endif
void
dll_crt0_0 ()
{
@@ -695,6 +701,10 @@ dll_crt0_0 ()
break;
}
}
+#ifdef PROFILE
+ if (!in_forkee)
+ atexit(&_mcleanup);
+#endif
user_data->threadinterface->Init ();
Index: winsup/cygwin/exceptions.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/exceptions.cc,v
retrieving revision 1.360
diff -u -p -r1.360 exceptions.cc
--- winsup/cygwin/exceptions.cc 3 Aug 2011 16:40:47 -0000 1.360
+++ winsup/cygwin/exceptions.cc 22 Aug 2011 20:27:57 -0000
@@ -31,7 +31,9 @@ details. */
#include "child_info.h"
#include "ntdll.h"
#include "exception.h"
-
+#ifdef PROFILE
+#include "profil.h"
+#endif
#define CALL_HANDLER_RETRY_OUTER 10
#define CALL_HANDLER_RETRY_INNER 10
@@ -937,6 +939,9 @@ ctrl_c_handler (DWORD type)
if (myself->cygstarted) /* Was this process created by a cygwin
process? */
return TRUE; /* Yes. Let the parent eventually handle
CTRL-C issues. */
debug_printf ("exiting with status %p", STATUS_CONTROL_C_EXIT);
+#ifdef PROFILE
+ profile_thread_off();
+#endif
ExitProcess (STATUS_CONTROL_C_EXIT);
}
Index: winsup/cygwin/external.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/external.cc,v
retrieving revision 1.123
diff -u -p -r1.123 external.cc
--- winsup/cygwin/external.cc 1 Jun 2011 01:20:27 -0000 1.123
+++ winsup/cygwin/external.cc 22 Aug 2011 20:27:57 -0000
@@ -30,7 +30,9 @@ details. */
#include <stdlib.h>
#include <wchar.h>
#include <iptypes.h>
-
+#ifdef PROFILE
+#include "profil.h"
+#endif
child_info *get_cygwin_startup_info ();
static void exit_process (UINT, bool) __attribute__((noreturn));
@@ -180,6 +182,9 @@ sync_winenv ()
static void
exit_process (UINT status, bool useTerminateProcess)
{
+#ifdef PROFILE
+ profile_thread_off();
+#endif
pid_t pid = getpid ();
external_pinfo * ep = fillout_pinfo (pid, 1);
DWORD dwpid = ep ? ep->dwProcessId : pid;
Index: winsup/cygwin/gcrt0.c
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/gcrt0.c,v
retrieving revision 1.5
diff -u -p -r1.5 gcrt0.c
--- winsup/cygwin/gcrt0.c 11 Sep 2001 20:01:00 -0000 1.5
+++ winsup/cygwin/gcrt0.c 22 Aug 2011 20:28:00 -0000
@@ -33,7 +33,9 @@ _monstartup (void)
return;
monstartup ((u_long) &eprol, (u_long) &etext);
+#ifndef PROFILE
atexit (&_mcleanup);
+#endif
}
asm (".text");
Index: winsup/cygwin/gmon.c
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/gmon.c,v
retrieving revision 1.7
diff -u -p -r1.7 gmon.c
--- winsup/cygwin/gmon.c 30 Aug 2010 01:57:36 -0000 1.7
+++ winsup/cygwin/gmon.c 22 Aug 2011 20:28:00 -0000
@@ -34,11 +34,17 @@
#if !defined(lint) && defined(LIBC_SCCS)
static char rcsid[] = "$OpenBSD: gmon.c,v 1.8 1997/07/23 21:11:27 kstailey Exp
$";
#endif
-
+#ifdef PROFILE
+#include "winsup.h"
+#endif
#include "winlean.h"
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
+#ifdef PROFILE
+#include <string.h>
+#include <math.h>
+#endif
#include <gmon.h>
#include <stdlib.h>
@@ -47,9 +53,17 @@ static char rcsid[] = "$OpenBSD: gmon.c,
/* XXX needed? */
//extern char *minbrk __asm ("minbrk");
-struct gmonparam _gmonparam = { GMON_PROF_OFF };
+struct gmonparam
+#ifdef PROFILE
+NO_COPY_INIT
+#endif
+_gmonparam = { GMON_PROF_OFF };
-static int s_scale;
+static int
+#ifdef PROFILE
+NO_COPY_INIT
+#endif
+s_scale;
/* see profil(2) where this is describe (incorrectly) */
#define SCALE_1_TO_1 0x10000L
@@ -60,7 +74,7 @@ void moncontrol __P((int));
static void *
fake_sbrk(int size)
{
- void *rv = malloc(size);
+ void *rv = LocalAlloc(0x40,size);
if (rv)
return rv;
else
@@ -92,8 +106,11 @@ monstartup(lowpc, highpc)
else if (p->tolimit > MAXARCS)
p->tolimit = MAXARCS;
p->tossize = p->tolimit * sizeof(struct tostruct);
-
+#ifdef PROFILE
+ cp = fake_sbrk(5 * p->kcountsize + p->fromssize + p->tossize);
+#else
cp = fake_sbrk(p->kcountsize + p->fromssize + p->tossize);
+#endif
if (cp == (char *)-1) {
ERR("monstartup: out of memory\n");
return;
@@ -105,6 +122,10 @@ monstartup(lowpc, highpc)
cp += p->tossize;
p->kcount = (u_short *)cp;
cp += p->kcountsize;
+#ifdef PROFILE
+ p->comm_kcount=(u_int64_t*)cp;
+ cp += 4*p->kcountsize;
+#endif
p->froms = (u_short *)cp;
/* XXX minbrk needed? */
@@ -136,6 +157,9 @@ monstartup(lowpc, highpc)
void
_mcleanup()
{
+#ifdef PROFILE
+ unsigned i;
+#endif
int fd;
int hz;
int fromindex;
@@ -204,8 +228,16 @@ _mcleanup()
}
#else
{
+#ifdef PROFILE
+ char gmon_out[1024];
+ char proc_modulename[1024];
+ GetModuleFileNameA(0, proc_modulename, 1024);
+ sprintf(gmon_out, "gmon.%s.%d.out", strrchr(proc_modulename, '\\') +
1, (int) GetCurrentProcessId());
+ proffile = gmon_out;
+#else
char gmon_out[] = "gmon.out";
proffile = gmon_out;
+#endif
}
#endif
@@ -224,6 +256,39 @@ _mcleanup()
p->kcount, p->kcountsize);
write(log, dbuf, len);
#endif
+#ifdef PROFILE
+ u_int64_t maxcount = 0;
+ for (i = 0; i < p->kcountsize / 2; i++)
+ {
+ if (p->comm_kcount[i] > maxcount)
+ {
+ maxcount = p->comm_kcount[i];
+ }
+ }
+ u_int64_t perffreq;
+ QueryPerformanceFrequency((PLARGE_INTEGER) &perffreq);
+ double logperffreq = log10(perffreq), logmaxcount = log10(maxcount);
+ double floorlogperffreq = floor(logperffreq);
+ double maxcounttimeunit = logmaxcount - logperffreq + floorlogperffreq;
+ if (maxcounttimeunit > 3)
+ maxcounttimeunit -= 3;
+ if ((logperffreq - floorlogperffreq) < log10(6.55))
+ maxcounttimeunit--;
+ hz = (int) pow(10, floor(floorlogperffreq - maxcounttimeunit));
+ perffreq /= hz;
+#if 0
+ printf("%d %d maxcount %lld logmaxcnt %f maxpreq %f hz %d perffreq %d\n",
GetCurrentProcessId(), GetCurrentThreadId(), maxcount, logmaxcount,
maxcounttimeunit, hz, perffreq);
+#endif
+ for (i = 0; i < p->kcountsize / 2; i++)
+ {
+ if (p->comm_kcount[i] < perffreq)
+ continue;
+ else
+ {
+ p->kcount[i] = p->comm_kcount[i] / perffreq;
+ }
+ }
+#endif
hdr = (struct gmonhdr *)&gmonhdr;
hdr->lpc = p->lowpc;
hdr->hpc = p->highpc;
Index: winsup/cygwin/gmon.h
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/gmon.h,v
retrieving revision 1.2
diff -u -p -r1.2 gmon.h
--- winsup/cygwin/gmon.h 24 Jun 2001 22:26:51 -0000 1.2
+++ winsup/cygwin/gmon.h 22 Aug 2011 20:28:00 -0000
@@ -134,6 +134,9 @@ struct rawarc {
struct gmonparam {
int state;
u_short *kcount;
+#ifdef PROFILE
+ u_int64_t *comm_kcount;
+#endif
u_long kcountsize;
u_short *froms;
u_long fromssize;
Index: winsup/cygwin/init.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/init.cc,v
retrieving revision 1.84
diff -u -p -r1.84 init.cc
--- winsup/cygwin/init.cc 18 Aug 2011 15:59:16 -0000 1.84
+++ winsup/cygwin/init.cc 22 Aug 2011 20:28:01 -0000
@@ -13,6 +13,10 @@ details. */
#include "cygtls.h"
#include "ntdll.h"
#include "shared_info.h"
+#ifdef PROFILE
+#include "profil.h"
+#include "instrument.h"
+#endif
static DWORD _my_oldfunc;
@@ -106,6 +110,9 @@ respawn_wow64_process ()
api_fatal ("Waiting for process %d failed, %E", pi.dwProcessId);
GetExitCodeProcess (pi.hProcess, &ret);
CloseHandle (pi.hProcess);
+#ifdef PROFILE
+ profile_thread_off();
+#endif
ExitProcess (ret);
}
}
@@ -120,6 +127,10 @@ dll_entry (HANDLE h, DWORD reason, void
switch (reason)
{
case DLL_PROCESS_ATTACH:
+#ifdef PROFILE
+ __cyg_profile_func_ctor();
+ __cyg_profile_tls_ctor();
+#endif
wincap.init ();
init_console_handler (false);
@@ -143,8 +154,15 @@ dll_entry (HANDLE h, DWORD reason, void
case DLL_PROCESS_DETACH:
if (dynamically_loaded)
shared_destroy ();
+#ifdef PROFILE
+ __cyg_profile_tls_dtor();
+ __cyg_profile_func_dtor();
+#endif
break;
case DLL_THREAD_ATTACH:
+#ifdef PROFILE
+ __cyg_profile_tls_ctor();
+#endif
if (dll_finished_loading)
munge_threadfunc ();
break;
@@ -153,6 +171,9 @@ dll_entry (HANDLE h, DWORD reason, void
&& (PVOID) &_my_tls > (PVOID) &wow64_test_stack_marker
&& _my_tls.isinitialized ())
_my_tls.remove (0);
+#ifdef PROFILE
+ __cyg_profile_tls_dtor();
+#endif
/* Windows 2000 has a bug in NtTerminateThread. Instead of releasing
the stack at teb->DeallocationStack it uses the value of
teb->Tib.StackLimit to evaluate the stack address. So we just claim
Index: winsup/cygwin/pinfo.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/pinfo.cc,v
retrieving revision 1.279
diff -u -p -r1.279 pinfo.cc
--- winsup/cygwin/pinfo.cc 13 Aug 2011 10:28:15 -0000 1.279
+++ winsup/cygwin/pinfo.cc 22 Aug 2011 20:28:02 -0000
@@ -29,7 +29,9 @@ details. */
#include "cygtls.h"
#include "tls_pbuf.h"
#include "child_info.h"
-
+#ifdef PROFILE
+#include "profil.h"
+#endif
class pinfo_basic: public _pinfo
{
public:
@@ -204,6 +206,9 @@ pinfo::exit (DWORD n)
if (!self->cygstarted)
exitcode = ((exitcode & 0xff) << 8) | ((exitcode >> 8) & 0xff);
sigproc_printf ("Calling ExitProcess n %p, exitcode %p", n, exitcode);
+#ifdef PROFILE
+ profile_thread_off();
+#endif
ExitProcess (exitcode);
}
# undef self
Index: winsup/cygwin/profil.c
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/profil.c,v
retrieving revision 1.8
diff -u -p -r1.8 profil.c
--- winsup/cygwin/profil.c 30 Aug 2010 01:57:36 -0000 1.8
+++ winsup/cygwin/profil.c 22 Aug 2011 20:28:02 -0000
@@ -7,18 +7,27 @@
This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
-
+#ifdef PROFILE
+#include "winsup.h"
+#endif
#include "winlean.h"
#include <sys/types.h>
#include <errno.h>
-
+#ifdef PROFILE
+#include "gmon.h"
+#endif
#include <profil.h>
#define SLEEPTIME (1000 / PROF_HZ)
-
+#ifdef PROFILE
+extern SECURITY_ATTRIBUTES sec_none_nih;
+#endif
/* global profinfo for profil() call */
+#ifdef PROFILE
+struct profinfo NO_COPY prof;
+#else
static struct profinfo prof;
-
+#endif
/* Get the pc for thread THR */
static u_long
@@ -85,19 +94,52 @@ profile_off (struct profinfo *p)
{
if (p->profthr)
{
+#ifdef PROFILE
+ if (prof.queue.worker_enabled)
+ {
+ profile_thread_off();
+ boundbuffer_dtor(&p->queue);
+ while (boundbuffer_empty(&p->queue))
+ {
+ message msg;
+ boundbuffer_dequeue_nolock(&p->queue, &msg);
+ unsigned idx = PROFIDX ((unsigned)msg.pv, p->lowpc,
p->scale);
+ if (!msg.ullval)
+ continue;
+ _gmonparam.comm_kcount[idx] += msg.ullval;
+ }
+ }
+ CloseHandle(p->profthr);
+ CloseHandle(prof.operational);
+ p->profthr = 0;
+#else
TerminateThread (p->profthr, 0);
CloseHandle (p->profthr);
+#endif
}
+#if !defined(PROFILE)
if (p->targthr)
CloseHandle (p->targthr);
+#endif
return 0;
}
-
+#ifdef PROFILE
+static void __stdcall
+apc_spawnthread(unsigned long arg)
+{
+ struct profinfo* p = (struct profinfo*) arg;
+ p->profthr = CreateThread(&sec_none_nih, 0, worker_consumer, (void *) p, 0,
+ 0);
+}
+#endif
/* Create a timer thread and pass it a pointer P to the profiling buffer. */
static int
profile_on (struct profinfo *p)
{
+#if !defined(PROFILE)
+ extern void init_global_security() asm("_Z20init_global_securityv");
+ init_global_security();
DWORD thrid;
/* get handle for this thread */
@@ -117,6 +159,11 @@ profile_on (struct profinfo *p)
errno = EAGAIN;
return -1;
}
+#else
+ boundbuffer_initial(&prof.queue);
+ prof.operational = CreateSemaphoreA(&sec_none_nih, 0, 1, 0);
+ QueueUserAPC(apc_spawnthread, GetCurrentThread(), (ULONG_PTR) p);
+#endif
return 0;
}
Index: winsup/cygwin/profil.h
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/profil.h,v
retrieving revision 1.4
diff -u -p -r1.4 profil.h
--- winsup/cygwin/profil.h 28 Apr 2003 20:10:53 -0000 1.4
+++ winsup/cygwin/profil.h 22 Aug 2011 20:28:02 -0000
@@ -7,10 +7,16 @@ 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. */
-
+#ifndef PROFIL_H
+#define PROFIL_H
+#ifdef __cplusplus
+extern "C"{
+#endif
/* profiling frequency. (No larger than 1000) */
#define PROF_HZ 100
-
+#if defined(PROFILE)
+#include "boundbuffer.h"
+#endif
/* convert an addr to an index */
#define PROFIDX(pc, base, scale) \
({ \
@@ -37,8 +43,17 @@ struct profinfo {
u_short *counter; /* profiling counters */
u_long lowpc, highpc; /* range to be profiled */
u_int scale; /* scale value of bins */
+#ifdef PROFILE
+ struct boundbuffer queue;
+ _WINHANDLE operational;
+#endif
};
-
+#ifdef PROFILE
+extern struct profinfo prof;
+#endif
int profile_ctl(struct profinfo *, char *, size_t, u_long, u_int);
int profil(char *, size_t, u_long, u_int);
-
+#ifdef __cplusplus
+}
+#endif
+#endif
Index: winsup/cygwin/sec_helper.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/sec_helper.cc,v
retrieving revision 1.93
diff -u -p -r1.93 sec_helper.cc
--- winsup/cygwin/sec_helper.cc 29 Apr 2011 10:38:12 -0000 1.93
+++ winsup/cygwin/sec_helper.cc 22 Aug 2011 20:28:02 -0000
@@ -476,6 +476,11 @@ get_null_sd ()
void
init_global_security ()
{
+#ifdef PROFILE
+ static int called;
+ if (called++)
+ return;
+#endif
sec_none.nLength = sec_none_nih.nLength =
sec_all.nLength = sec_all_nih.nLength = sizeof (SECURITY_ATTRIBUTES);
sec_none.bInheritHandle = sec_all.bInheritHandle = TRUE;
--- /dev/null 2011-08-23 13:56:06.000000000 +0900
+++ winsup/cygwin/boundbuffer.h 2011-08-22 05:57:05.109375000 +0900
@@ -0,0 +1,67 @@
+/* boundbuffer.h
+
+ THIS SOFTWARE IS NOT COPYRIGHTED
+
+ This source code is offered for use in the public domain. You may
+ use, modify or distribute it freely.
+
+ This code is distributed in the hope that it will be useful but
+ WITHOUT ANY WARRANTY. ALL WARRENTIES, EXPRESS OR IMPLIED ARE HEREBY
+ DISCLAMED. This includes but is not limited to warrenties of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#ifndef BOUNDBUFFER_H_
+#define BOUNDBUFFER_H_
+#include <stdio.h>
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+ extern void
+ profile_thread_off();
+ struct message
+ {
+#if 0
+ unsigned long long ldata;
+ unsigned long idata[2];
+#endif
+ void* pv;
+ unsigned long long ullval;
+ };
+ typedef struct message message;
+ extern DWORD __stdcall
+ worker_consumer(void* arg);
+ union avoidtypecheck
+ {
+ HANDLE h;
+ CRITICAL_SECTION s;
+ int i;
+ };
+ enum bconst
+ {
+ MUTEX, FILL, EMPTY, FRONT, BACK, SZMEMBER, SZBUF = 16384
+ };
+ struct boundbuffer
+ {
+ union avoidtypecheck member[SZMEMBER];
+ message buffer[SZBUF];
+ int worker_enabled;
+ int initial;
+ };
+#define reg(x) __attribute__((regparm((x))))
+#define buffermethod(x) boundbuffer_##x
+ extern void buffermethod(ctor)(struct boundbuffer*);
+ extern void buffermethod(initial)(struct boundbuffer*);
+ extern void buffermethod(dtor)(struct boundbuffer*);
+ extern reg(2) int buffermethod(enqueue)(struct boundbuffer*, message);
+ extern reg(2) int buffermethod(dequeue)(struct boundbuffer*, message*);
+ extern reg(2) void buffermethod(dequeue_nolock)(struct boundbuffer*,
+ message*);
+ extern int buffermethod(empty)(struct boundbuffer*);
+ extern int buffermethod(full)(struct boundbuffer*);
+#undef buffermethod
+#undef reg
+#ifdef __cplusplus
+}
+#endif
+#endif /* BOUNDBUFFER_H_ */
--- /dev/null 2011-08-23 13:56:06.000000000 +0900
+++ winsup/cygwin/boundbuffer.c 2011-08-23 13:22:31.781250000 +0900
@@ -0,0 +1,201 @@
+/* boundbuffer.c
+
+ THIS SOFTWARE IS NOT COPYRIGHTED
+
+ This source code is offered for use in the public domain. You may
+ use, modify or distribute it freely.
+
+ This code is distributed in the hope that it will be useful but
+ WITHOUT ANY WARRANTY. ALL WARRENTIES, EXPRESS OR IMPLIED ARE HEREBY
+ DISCLAMED. This includes but is not limited to warrenties of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#include "winsup.h"
+#include "winlean.h"
+#include "profil.h"
+#include "gmon.h"
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include "boundbuffer.h"
+/* Use
+ * 0: semaphore
+ * 1: event
+ */
+#define USE_EVENT 1
+/*
+ * There are cases where the bounded buffer is blocked and not operational.
+ * as a workaround, give maximum timeout to WFSO.
+ */
+#define WFSO_TIMEOUT_MS INFINITE
+/*
+ * http://msdn.microsoft.com/en-us/library/ms687032.aspx
+ * Current thread and process handles are special cased
+ */
+#define INVALID_FOR_SURE -3
+extern SECURITY_ATTRIBUTES sec_none_nih;
+DWORD __stdcall
+worker_consumer(void* arg)
+{
+ if (prof.queue.initial)
+ {
+ boundbuffer_ctor(&prof.queue);
+ prof.queue.initial = 0;
+ }
+ //WaitForSingleObject(prof.queue.member[MUTEX].h, INFINITE);
+ EnterCriticalSection(&prof.queue.member[MUTEX].s);
+ prof.queue.worker_enabled = 1;
+ ReleaseSemaphore(prof.operational, 1, 0);
+ //ReleaseMutex(prof.queue.member[MUTEX].h);
+ LeaveCriticalSection(&prof.queue.member[MUTEX].s);
+ while (prof.queue.worker_enabled)
+ {
+ message msg;
+ if (!boundbuffer_dequeue(&prof.queue, &msg))
+ continue;
+ unsigned idx = PROFIDX ((unsigned)msg.pv, prof.lowpc, prof.
+ scale);
+ if (!msg.ullval)
+ continue;
+ _gmonparam.comm_kcount[idx] += msg.ullval;
+ }
+ return 0;
+}
+#ifdef PROFILE
+void
+profile_thread_off()
+{
+ int enabled = __sync_fetch_and_and(&prof.queue.worker_enabled, 0);
+ if (enabled)
+ {
+ ReleaseSemaphore(prof.queue.member[FILL].h, 1, 0);
+ WaitForSingleObject(prof.profthr, INFINITE);
+ }
+}
+#endif
+#define buffermethod(x) boundbuffer_##x
+void buffermethod(ctor)(struct boundbuffer* this)
+{
+ this->member[FRONT].i = this->member[BACK].i = 0;
+ InitializeCriticalSectionAndSpinCount(&this->member[MUTEX].s, 0x08000000);
+ //this->member[MUTEX].h = CreateMutexA(&sec_none_nih, 0, 0);
+#if USE_EVENT
+ this->member[EMPTY].h = CreateEventA(&sec_none_nih, 1, 1, 0);
+#else
+ this->member[EMPTY].h = CreateSemaphoreA(&sec_none_nih, SZBUF, SZBUF, 0);
+#endif
+ this->member[FILL].h = CreateSemaphoreA(&sec_none_nih, 0, SZBUF, 0);
+}
+void buffermethod(initial)(struct boundbuffer* this)
+{
+ this->initial = 1;
+ this->member[MUTEX].i = this->member[EMPTY].i = this->member[FILL].i =
+ INVALID_FOR_SURE;
+}
+void buffermethod(dtor)(struct boundbuffer* this)
+{
+ CloseHandle(this->member[MUTEX].h);
+ CloseHandle(this->member[EMPTY].h);
+ CloseHandle(this->member[FILL].h);
+ this->member[MUTEX].i = this->member[EMPTY].i = this->member[FILL].i =
+ INVALID_FOR_SURE;
+}
+static __attribute__((used)) void buffermethod(check)(struct boundbuffer* this)
+{
+ if (!((this->member[FRONT].i > -1) && (this->member[FRONT].i < SZBUF)))
+ asm volatile("int $3\t\n");
+ if (!((this->member[BACK].i > -1) && (this->member[BACK].i < SZBUF)))
+ asm volatile("int $3\t\n");
+}
+__attribute__((always_inline,regparm(2))) void buffermethod(enqueue_nolock)(
+ struct boundbuffer*, message);
+int __attribute__((regparm(2))) buffermethod(enqueue)(struct boundbuffer* this,
+ message obj)
+{
+ if (prof.queue.initial)
+ {
+ buffermethod(enqueue_nolock)(this, obj);
+ return 1;
+ }
+ int ret = WaitForSingleObject(this->member[EMPTY].h, WFSO_TIMEOUT_MS);
+ if ((ret != WAIT_OBJECT_0) || !this->worker_enabled)
+ return 0;
+ /*ret = WaitForSingleObject(this->member[MUTEX].h, WFSO_TIMEOUT_MS);
+ if (ret != WAIT_OBJECT_0
+ )
+ return 0;
+ */
+ EnterCriticalSection(&prof.queue.member[MUTEX].s);
+ buffermethod(enqueue_nolock)(this, obj);
+ //ReleaseMutex(this->member[MUTEX].h);
+#if USE_EVENT
+ long avail_to_dequeue;
+ ReleaseSemaphore(this->member[FILL].h,0,&avail_to_dequeue);
+ avail_to_dequeue=avail_to_dequeue==(SZBUF-1);
+#endif
+ LeaveCriticalSection(&prof.queue.member[MUTEX].s);
+#if USE_EVENT
+ if (avail_to_dequeue)
+ ResetEvent(this->member[EMPTY].h);
+#endif
+ ReleaseSemaphore(this->member[FILL].h, 1, 0);
+ return 1;
+}
+
+int buffermethod(empty)(struct boundbuffer* this)
+{
+ //if(WaitForSingleObject(this->member[MUTEX].h, 0)!=WAIT_OBJECT_0) return -1;
+ int ret = this->member[FRONT].i == this->member[BACK].i;
+ //ReleaseSemaphore(this->member[MUTEX].h, 1, 0);
+ return ret;
+}
+int buffermethod(full)(struct boundbuffer* this)
+{
+ //if(WaitForSingleObject(this->member[MUTEX].h, 0)!=WAIT_OBJECT_0) return -1;
+ int ret = (this->member[FRONT].i + this->member[BACK].i) == (SZBUF - 1);
+ //ReleaseSemaphore(this->member[MUTEX].h, 1, 0);
+ return ret;
+}
+int __attribute__((regparm(2))) buffermethod(dequeue)(struct boundbuffer* this,
+ message* result)
+{
+ if (prof.queue.initial)
+ {
+ buffermethod(dequeue_nolock)(this, result);
+ return 1;
+ }
+ int ret = WaitForSingleObject(this->member[FILL].h, WFSO_TIMEOUT_MS);
+ if ((ret != WAIT_OBJECT_0) || !this->worker_enabled)
+ return 0;
+ //WaitForSingleObject(this->member[MUTEX].h, INFINITE);
+ EnterCriticalSection(&prof.queue.member[MUTEX].s);
+ buffermethod(dequeue_nolock)(this, result);
+ //ReleaseMutex(this->member[MUTEX].h);
+#if USE_EVENT
+ long avail_to_enqueue;
+ ReleaseSemaphore(this->member[FILL].h,0,&avail_to_enqueue);
+ avail_to_enqueue=avail_to_enqueue<=0;
+#endif
+ LeaveCriticalSection(&prof.queue.member[MUTEX].s);
+#if USE_EVENT
+ if (avail_to_enqueue)
+ SetEvent(this->member[EMPTY].h);
+#else
+ ReleaseSemaphore(this->member[EMPTY].h, 1, 0);
+#endif
+ return 1;
+}
+__attribute__((always_inline,regparm(2))) void buffermethod(enqueue_nolock)(
+ struct boundbuffer* this, message obj)
+{
+ this->buffer[this->member[BACK].i] = obj;
+ this->member[BACK].i = (this->member[BACK].i + 1) % SZBUF;
+}
+__attribute__((always_inline,regparm(2))) void buffermethod(dequeue_nolock)(
+ struct boundbuffer* this, message* result)
+{
+ /*boundbuffer_check(this);*/
+ (*result) = this->buffer[this->member[FRONT].i];
+ this->member[FRONT].i = (this->member[FRONT].i + 1) % SZBUF;
+}
+#undef buffermethod
--- /dev/null 2011-08-23 13:56:06.000000000 +0900
+++ winsup/cygwin/instrument.c 2011-08-22 06:37:40.062500000 +0900
@@ -0,0 +1,125 @@
+/* instrument.c
+
+ THIS SOFTWARE IS NOT COPYRIGHTED
+
+ This source code is offered for use in the public domain. You may
+ use, modify or distribute it freely.
+
+ This code is distributed in the hope that it will be useful but
+ WITHOUT ANY WARRANTY. ALL WARRENTIES, EXPRESS OR IMPLIED ARE HEREBY
+ DISCLAMED. This includes but is not limited to warrenties of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Created on: 2011. 3. 2.
+ */
+#include <stdint.h>
+#include "winsup.h"
+#include "winlean.h"
+#include "profil.h"
+#include "instrument.h"
+#include "boundbuffer.h"
+#include "gmon.h"
+DWORD NO_COPY tlskey;
+extern DWORD WINAPI
+GetLastError(void);
+void WINAPI
+SetLastError(DWORD);
+void
+__attribute__((no_instrument_function))
+__cyg_profile_func_ctor()
+{
+ tlskey = TlsAlloc();
+}
+void __attribute__ ((no_instrument_function))
+__cyg_profile_tls_ctor()
+{
+ void * map = (void*) LocalAlloc(0x40, sizeof(struct clk));
+#if 0
+ assert(map)
+#endif
+ TlsSetValue(tlskey, map);
+ struct clk* clkinfo = (struct clk*) map;
+ clkinfo->idx = 0;
+}
+void __attribute__ ((no_instrument_function))
+__cyg_profile_tls_dtor()
+{
+ void * map = TlsGetValue(tlskey);
+ if (map)
+ LocalFree(map);
+ TlsSetValue(tlskey, 0);
+
+}
+void __attribute__ ((no_instrument_function))
+__cyg_profile_func_dtor()
+{
+ TlsFree(tlskey);
+ tlskey = -1;
+}
+extern int s_scale;
+static void __attribute__ ((always_inline,no_instrument_function,regparm(3)))
+__cyg_set_clk(struct clk* clkinfo, void *caller, int state)
+{
+ register int idx;
+ register message msg;
+ switch (state)
+ {
+ case 0:
+ if (!clkinfo->idx)
+ goto skip;
+ idx = --clkinfo->idx;
+#if 0
+ assert((idx>=0)&&(idx<0xffff))
+ assert(clkinfo->pc[idx] == caller)
+#endif
+ clkinfo->tsc[idx] = __builtin_ia32_rdtsc() - clkinfo->tsc[idx];
+ msg.pv = clkinfo->pc[idx];
+ msg.ullval = clkinfo->tsc[idx];
+ if (&prof.queue.worker_enabled)
+ boundbuffer_enqueue(&prof.queue, msg);
+ break;
+ case 1:
+ idx = clkinfo->idx;
+#if 0
+ assert((idx>=0)&&(idx<0xffff))
+#endif
+ clkinfo->pc[idx] = caller;
+ clkinfo->tsc[idx] = __builtin_ia32_rdtsc();
+ clkinfo->idx++;
+ break;
+ default:
+ goto skip;
+ break;
+ };
+ skip: do
+ {
+ }
+ while (0);
+}
+/*
+ * GetLastError / SetLastError is needed because Tls* alter last error code
+ */
+void __attribute__ ((no_instrument_function))
+__cyg_profile_func_enter(void* caller, void* site)
+{
+ DWORD err = GetLastError();
+ struct clk* clkinfo = (struct clk*) TlsGetValue(tlskey);
+ if (!clkinfo)
+ {
+ goto trap;
+ }
+ __cyg_set_clk(clkinfo, caller, 1);
+ trap: SetLastError(err);
+}
+void __attribute__ ((no_instrument_function))
+__cyg_profile_func_exit(void* caller, void* site)
+{
+ DWORD err = GetLastError();
+ struct clk* clkinfo = (struct clk*) TlsGetValue(tlskey);
+ if (!clkinfo)
+ {
+ goto trap;
+ }
+ __cyg_set_clk(clkinfo, caller, 0);
+ trap: SetLastError(err);
+}
--- /dev/null 2011-08-23 13:56:06.000000000 +0900
+++ winsup/cygwin/instrument.h 2011-08-22 05:57:41.312500000 +0900
@@ -0,0 +1,38 @@
+/* instrument.c
+
+ THIS SOFTWARE IS NOT COPYRIGHTED
+
+ This source code is offered for use in the public domain. You may
+ use, modify or distribute it freely.
+
+ This code is distributed in the hope that it will be useful but
+ WITHOUT ANY WARRANTY. ALL WARRENTIES, EXPRESS OR IMPLIED ARE HEREBY
+ DISCLAMED. This includes but is not limited to warrenties of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Created on: 2011. 3. 18.
+ */
+#ifndef INSTRUMENT_H_
+#define INSTRUMENT_H_
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+ struct clk
+ {
+ unsigned idx;
+ void* pc[0x10000];
+ unsigned long long tsc[0x10000];
+ };
+ void __attribute__ ((no_instrument_function))
+ __cyg_profile_func_ctor();
+ void __attribute__ ((no_instrument_function))
+ __cyg_profile_func_dtor();
+ void __attribute__ ((no_instrument_function))
+ __cyg_profile_tls_ctor();
+ void __attribute__ ((no_instrument_function))
+ __cyg_profile_tls_dtor();
+#ifdef __cplusplus
+}
+#endif
+#endif /* INSTRUMENT_H_ */
Index: winsup/Makefile.common
===================================================================
RCS file: /cvs/src/src/winsup/Makefile.common,v
retrieving revision 1.56
diff -u -r1.56 Makefile.common
--- winsup/Makefile.common 7 Jul 2009 20:12:43 -0000 1.56
+++ winsup/Makefile.common 19 Aug 2011 20:22:40 -0000
@@ -113,7 +113,7 @@
LIBM:=$(newlib_build)/libm/libm.a
CRT0:=$(cygwin_build)/crt0.o
-ALL_CFLAGS:=$(DEFS) $(MALLOC_DEBUG) $(CFLAGS) $(GCC_DEFAULT_OPTIONS)
+ALL_CFLAGS=$(DEFS) $(MALLOC_DEBUG) $(CFLAGS) $(GCC_DEFAULT_OPTIONS)
ALL_CXXFLAGS=$(DEFS) $(MALLOC_DEBUG) $(CXXFLAGS) $(GCC_DEFAULT_OPTIONS)
ifndef PREPROCESS