On 2011-08-23 PM 2:40, Christopher Faylor wrote:
On Tue, Aug 23, 2011 at 02:05:06PM +0900, jojelino wrote:
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 "" ""
- void *rv = malloc(size);
+ void *rv = LocalAlloc(0x40,size);
There are a few things in your patch which make no sense. The above are
two of them. I am not going to look further. The patch certainly can't
go in as is.
cgf
The two of them is now
ifneq "${filter -O%,$(CFLAGS)}" ""
+ifneq '$(profile)' '1'
endif
...
...
+endif
+#if !defined(PROFILE)
void *rv = malloc(size);
+#else
+ void *rv = LocalAlloc(LMEM_FIXED,size);
+#endif
changelog of winsup-profile-support-3.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: (_gmonparam): Add NO_COPY_INIT.
* profil.c: (prof): Ditto.
(profile_off): Flush profiling request.
(apc_spawnthread): New function.
(profile_on): Initialize init_global_security prior to use it, and
spawn the consumer 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
{un}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.
(PROFILE_OPT_OUT): Ditto.
(CFLAGS_SAVE): Clobber CFLAGS.
(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 28 Aug 2011 00:33:55 -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 28 Aug 2011 00:33: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 28 Aug 2011 00:33: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 28 Aug 2011 00:33: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 28 Aug 2011 00:33:56 -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 28 Aug 2011 00:33:56 -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,50 @@ _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 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 -= 3;
+ /*
+ * and cover the case up to 65535.
+ */
+ 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 28 Aug 2011 00:33:56 -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 28 Aug 2011 00:33:56 -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 28 Aug 2011 00:33:57 -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 28 Aug 2011 00:33:57 -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 28 Aug 2011 00:33:57 -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 28 Aug 2011 00:33:57 -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_ */
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