On 2011-08-30 AM 5:23, Christopher Faylor wrote:
endif
...
...
+endif
+#if !defined(PROFILE)
void *rv = malloc(size);
+#else
+ void *rv = LocalAlloc(LMEM_FIXED,size);
+#endif
Since the code is in gmon.c then I don't see a reason to #ifdef it but I
still don't understand the motivation for the change. This is a major
amount of code and it is desperately missing comments.
Maybe Corinna will disagree but I think there is way too much code
change here for me to be comfortable with including it. It looks like
it would be an ongoing maintenance issue, requiring constant vigilance
to avoid code rot. And, it would have to be very carefully studied to
make sure there aren't more gotchas like 'if "" ""'.
Sorry, but I don't see us including this.
cgf
Yes, I see. but there would be months for the missing comments, and i
have not enough time to test this patch for now.
and there were bugs in previous patch. so i attach the revised one.
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 29 Aug 2011 21:01:56 -0000
@@ -59,7 +59,11 @@ MT_SAFE:=@MT_SAFE@
DEFS:=@DEFS@
CCEXTRA:=
CFLAGS?=@CFLAGS@
-override CFLAGS+=-MMD ${$(*F)_CFLAGS} -Werror -fmerge-constants -ftracer \
+ifeq '$(profile)' '1'
+CFLAGS_SAVE:=$(CFLAGS)
+CFLAGS=
+endif
+override CFLAGS+=-MMD ${$(*F)_CFLAGS} -fmerge-constants -ftracer \
-mno-use-libstdc-wrappers $(CCEXTRA)
CXX=@CXX@
override CXXFLAGS=@CXXFLAGS@
@@ -234,6 +238,7 @@ INSTOBJS:=automode.o binmode.o textmode.
TARGET_LIBS:=$(LIB_NAME) $(CYGWIN_START) $(GMON_START) $(LIBGMON_A) $(SUBLIBS)
$(INSTOBJS) $(EXTRALIBS)
ifneq "${filter -O%,$(CFLAGS)}" ""
+ifneq '$(profile)' '1'
cygheap_CFLAGS:=-fomit-frame-pointer
cygthread_CFLAGS:=-fomit-frame-pointer
cygtls_CFLAGS:=-fomit-frame-pointer
@@ -286,6 +291,17 @@ syscalls_CFLAGS:=-fomit-frame-pointer
sysconf_CFLAGS:=-fomit-frame-pointer
uinfo_CFLAGS:=-fomit-frame-pointer
endif
+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'
+PROFILE_OPT_OUT=$(EXTRA_DEPENDENCIES_1:.o=) pthread kernel32 malloc_wrapper
pseudo-reloc libstdcxx_wrapper cxx sync
+override CFLAGS+=-DPROFILE ${PROFILE_CFLAGS_${shell echo
$(PROFILE_OPT_OUT)|grep -q "$(*F)";ret=$$?;echo $$ret;}}
+PROFILE_CFLAGS_1=$(subst -fomit-frame-pointer,,$(CFLAGS_SAVE)) -g -pg
-finstrument-functions
+PROFILE_CFLAGS_0=$(subst -finstrument-functions,,$(subst -pg,,$(CFLAGS_SAVE)))
-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`\""
@@ -393,12 +409,12 @@ maintainer-clean realclean: clean
# 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 29 Aug 2011 21:01:56 -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 29 Aug 2011 21:01:56 -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 29 Aug 2011 21:01:56 -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 29 Aug 2011 21:01:58 -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 29 Aug 2011 21:01:58 -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,7 +53,11 @@ 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;
/* see profil(2) where this is describe (incorrectly) */
@@ -60,7 +70,11 @@ void moncontrol __P((int));
static void *
fake_sbrk(int size)
{
+#if !defined(PROFILE)
void *rv = malloc(size);
+#else
+ void *rv = LocalAlloc(LMEM_FIXED,size);
+#endif
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,11 @@ 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;
+ memset(p->comm_kcount,0,4*p->kcountsize);
+#endif
p->froms = (u_short *)cp;
/* XXX minbrk needed? */
@@ -136,6 +158,9 @@ monstartup(lowpc, highpc)
void
_mcleanup()
{
+#ifdef PROFILE
+ unsigned i;
+#endif
int fd;
int hz;
int fromindex;
@@ -204,8 +229,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 +257,56 @@ _mcleanup()
p->kcount, p->kcountsize);
write(log, dbuf, len);
#endif
+#ifdef PROFILE
+ u_int64_t maxcount = 1;
+ 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 coeff_to_maximize_kcount = logmaxcount - logperffreq +
floorlogperffreq;
+ /*
+ * To maximize kcount, we cover the case where upper bound is 9999.
+ */
+ if (coeff_to_maximize_kcount <= 3)
+ {
+ coeff_to_maximize_kcount = 0;
+ }
+ else if (coeff_to_maximize_kcount > 3)
+ {
+ /*
+ * and cover the case up to 65535.
+ */
+ coeff_to_maximize_kcount -= 3;
+ if ((logperffreq - floorlogperffreq) < log10(6.55))
+ coeff_to_maximize_kcount--;
+ }
+ else
+ {
+ coeff_to_maximize_kcount = 0;
+ }
+ hz = (int) pow(10, floor(floorlogperffreq - coeff_to_maximize_kcount));
+ perffreq /= hz;
+#if 0
+ printf("%d %d maxcount %lld logmaxcnt %f maxpreq %f hz %d perffreq %d\n",
GetCurrentProcessId(), GetCurrentThreadId(), maxcount, logmaxcount,
coeff_to_maximize_kcount, 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 29 Aug 2011 21:01:58 -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 29 Aug 2011 21:01:58 -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 29 Aug 2011 21:01:58 -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 29 Aug 2011 21:01:58 -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,50 @@ 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)
DWORD thrid;
/* get handle for this thread */
@@ -117,6 +157,13 @@ profile_on (struct profinfo *p)
errno = EAGAIN;
return -1;
}
+#else
+ extern void init_global_security() asm("_Z20init_global_securityv");
+ init_global_security();
+ 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 29 Aug 2011 21:01:58 -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 29 Aug 2011 21:01:58 -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-28 23:29:31.000000000 +0900
+++ winsup/cygwin/boundbuffer.h 2011-08-25 01:33:21.943255000 +0900
@@ -0,0 +1,66 @@
+/* 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-28 23:29:31.000000000 +0900
+++ winsup/cygwin/boundbuffer.c 2011-08-28 14:15:22.281250000 +0900
@@ -0,0 +1,179 @@
+/* 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.
+ * as long as profile_thread_off is issued before every ExitProcess, it is
okay if the timeout is INFINITE.
+ */
+#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;
+ }
+ EnterCriticalSection(&prof.queue.member[MUTEX].s);
+ prof.queue.worker_enabled = 1;
+ ReleaseSemaphore(prof.operational, 1, 0);
+ 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);
+#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;
+ EnterCriticalSection(&prof.queue.member[MUTEX].s);
+ buffermethod(enqueue_nolock)(this, obj);
+#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)
+{
+ int ret = this->member[FRONT].i == this->member[BACK].i;
+ return ret;
+}
+int buffermethod(full)(struct boundbuffer* this)
+{
+ int ret = (this->member[FRONT].i + this->member[BACK].i) == (SZBUF - 1);
+ 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;
+ EnterCriticalSection(&prof.queue.member[MUTEX].s);
+ buffermethod(dequeue_nolock)(this, result);
+#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)
+{
+ (*result) = this->buffer[this->member[FRONT].i];
+ this->member[FRONT].i = (this->member[FRONT].i + 1) % SZBUF;
+}
+#undef buffermethod
--- /dev/null 2011-08-28 23:29:31.000000000 +0900
+++ winsup/cygwin/instrument.c 2011-08-26 05:45:15.234375000 +0900
@@ -0,0 +1,119 @@
+/* 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(LMEM_ZEROINIT, sizeof(struct clk));
+ 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;
+}
+/*
+ * It would be better if it does either bound checks and some assertion about
caller.
+ * For the issue of bound check, it is assumed that cygwin's call stack grows
less than CALLSTACKBOUND.
+ * For the issue of caller, it is belived that gcc does right thing so that we
have matching enter/exit pair.
+ */
+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;
+ 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;
+ 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-28 23:29:32.000000000 +0900
+++ winsup/cygwin/instrument.h 2011-08-26 05:32:14.718375000 +0900
@@ -0,0 +1,42 @@
+/* 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
+ {
+ /*
+ * FIXME: CALLSTACKBOUND should be less than maximum call stack size.
+ */
+#define CALLSTACKBOUND 0x10000
+ unsigned idx;
+ void* pc[CALLSTACKBOUND];
+ unsigned long long tsc[CALLSTACKBOUND];
+ };
+ 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_ */