public inbox for cygwin-patches@cygwin.com
 help / color / mirror / Atom feed
* Re: [PATCH] profile support
       [not found] ` <20110820084946.GA30978@calimero.vinschen.de>
@ 2011-08-23  5:02   ` jojelino
  2011-08-23  5:40     ` Christopher Faylor
  0 siblings, 1 reply; 6+ messages in thread
From: jojelino @ 2011-08-23  5:02 UTC (permalink / raw)
  To: cygwin-patches

[-- Attachment #1: Type: text/plain, Size: 3411 bytes --]

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.

[-- Attachment #2: winsup-profile-support-2.diff --]
[-- Type: text/plain, Size: 30205 bytes --]

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_ */

[-- Attachment #3: winsup-makefile.diff --]
[-- Type: text/plain, Size: 651 bytes --]

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

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] profile support
  2011-08-23  5:02   ` [PATCH] profile support jojelino
@ 2011-08-23  5:40     ` Christopher Faylor
  2011-08-29 20:07       ` jojelino
  0 siblings, 1 reply; 6+ messages in thread
From: Christopher Faylor @ 2011-08-23  5:40 UTC (permalink / raw)
  To: cygwin-patches

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

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] profile support
  2011-08-23  5:40     ` Christopher Faylor
@ 2011-08-29 20:07       ` jojelino
  2011-08-29 20:24         ` Christopher Faylor
  0 siblings, 1 reply; 6+ messages in thread
From: jojelino @ 2011-08-29 20:07 UTC (permalink / raw)
  To: cygwin-patches

[-- Attachment #1: Type: text/plain, Size: 2951 bytes --]

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.

[-- Attachment #2: winsup-profile-support-3.diff --]
[-- Type: text/plain, Size: 30176 bytes --]

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_ */

[-- Attachment #3: winsup-makefile.diff --]
[-- Type: text/plain, Size: 651 bytes --]

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

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] profile support
  2011-08-29 20:07       ` jojelino
@ 2011-08-29 20:24         ` Christopher Faylor
  2011-08-29 21:12           ` jojelino
  0 siblings, 1 reply; 6+ messages in thread
From: Christopher Faylor @ 2011-08-29 20:24 UTC (permalink / raw)
  To: cygwin-patches

On Tue, Aug 30, 2011 at 05:10:39AM +0900, jojelino wrote:
>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'

That would be an 'ifdef'.

>  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

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] profile support
  2011-08-29 20:24         ` Christopher Faylor
@ 2011-08-29 21:12           ` jojelino
  2011-08-30 16:29             ` Ryan Johnson
  0 siblings, 1 reply; 6+ messages in thread
From: jojelino @ 2011-08-29 21:12 UTC (permalink / raw)
  To: cygwin-patches

[-- Attachment #1: Type: text/plain, Size: 1014 bytes --]

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.

[-- Attachment #2: winsup-profile-support.diff --]
[-- Type: text/plain, Size: 30277 bytes --]

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_ */

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] profile support
  2011-08-29 21:12           ` jojelino
@ 2011-08-30 16:29             ` Ryan Johnson
  0 siblings, 0 replies; 6+ messages in thread
From: Ryan Johnson @ 2011-08-30 16:29 UTC (permalink / raw)
  To: cygwin-patches

On 29/08/2011 2:15 PM, jojelino wrote:
> On 2011-08-30 AM 5:23, Christopher Faylor wrote:
>> 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 "" ""'.
>>
> 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.

I haven't been studying the code, but the phrases "lots of code", "no 
comments" and "not tested" ring major alarm bells for me...

$0.02
Ryan

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2011-08-30 16:29 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <CADEiHqLZAuJkDJKh4pJ4AOJ1JwUwV06RSkq3GdNihSKhiUswGw@mail.gmail.com>
     [not found] ` <20110820084946.GA30978@calimero.vinschen.de>
2011-08-23  5:02   ` [PATCH] profile support jojelino
2011-08-23  5:40     ` Christopher Faylor
2011-08-29 20:07       ` jojelino
2011-08-29 20:24         ` Christopher Faylor
2011-08-29 21:12           ` jojelino
2011-08-30 16:29             ` Ryan Johnson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).