On 2011-08-23 PM 2:40, Christopher Faylor wrote:
On Tue, Aug 23, 2011 at 02:05:06PM +0900, jojelino wrote:
Index: winsup/cygwin/Makefile.in
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/Makefile.in,v
retrieving revision 1.248
diff -u -p -r1.248 Makefile.in
--- winsup/cygwin/Makefile.in   2 May 2011 19:14:39 -0000       1.248
+++ winsup/cygwin/Makefile.in   22 Aug 2011 20:27:57 -0000
@@ -233,7 +233,7 @@ EXTRALIBS:=libautomode.a libbinmode.a li
INSTOBJS:=automode.o binmode.o textmode.o textreadmode.o
TARGET_LIBS:=$(LIB_NAME) $(CYGWIN_START) $(GMON_START) $(LIBGMON_A) $(SUBLIBS) 
$(INSTOBJS) $(EXTRALIBS)

-ifneq "${filter -O%,$(CFLAGS)}" ""
+ifneq "" ""

-    void *rv = malloc(size);
+    void *rv = LocalAlloc(0x40,size);

There are a few things in your patch which make no sense.  The above are
two of them.  I am not going to look further.  The patch certainly can't
go in as is.

cgf

The two of them is now

 ifneq "${filter -O%,$(CFLAGS)}" ""
+ifneq '$(profile)' '1'
 endif
...
...
+endif

+#if !defined(PROFILE)
     void *rv = malloc(size);
+#else
+    void *rv = LocalAlloc(LMEM_FIXED,size);
+#endif

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

-ALL_CFLAGS:=$(DEFS) $(MALLOC_DEBUG) $(CFLAGS) $(GCC_DEFAULT_OPTIONS)
+ALL_CFLAGS=$(DEFS) $(MALLOC_DEBUG) $(CFLAGS) $(GCC_DEFAULT_OPTIONS)
 ALL_CXXFLAGS=$(DEFS) $(MALLOC_DEBUG) $(CXXFLAGS) $(GCC_DEFAULT_OPTIONS)

 ifndef PREPROCESS

Reply via email to