On 2011-08-20 PM 5:49, Corinna Vinschen wrote:
Hi Jin-woo,

On Aug 20 06:59, jojelino wrote:
On 2011-08-20 AM 6:48, jojelino wrote:
cd i686-pc-cygwin/winsup/cygwin;rm *.o;make profile=1

it would work.
Please ignore attachment from 6:48, i have mistaken by attaching
invalid winsup-profile-support.diff

So i am replying.

Yes, but to the wrong list ;-)

Would you mind to resend your patches as a reply to your original
threada on the cygwin-patches list?  That's where the official
patch submissions are suppsoed to go.

Btw., you don't have to attach the ChangeLog.  For the lazy reader
it's easier if the ChangeLog is just inline in your mail.  If you
want to avoid more spam, just omit your email address from the
ChangeLog date/name/email header.
Yes, I see.

But there's something I don't grok in your patch:

Yes, I need to spend more time.
In dll_crt0_0:

   +  _monstartup();

but

   +#ifdef PROFILE
   +  atexit (&_mcleanup);
   +#endif

Shouldn't the call to _monstartup also be guarded with #ifdef PROFILE?
Same question for calls to profile_thread_off and any other profiling
code in other places.

Yes i was supposed to do that. thanks for pointing it out.
In gcrt0.c:

   +#ifndef PROFILE
   void _monstartup (void) __attribute__((__constructor__));
   -
   +#endif

#if*n*def?  Is that a typo?
No, it's not typo. it is assumed that PROFILE is defined iff make is invoked with profile=1, and when PROFILE defined, the patch need to have different invocation of _monstartup. the only reason doing this is that the patch make use of sec_none_nih on profile_on.
and diff you mentioned in gcrt0.c doesn't exist any longer.

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

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

 ifndef PREPROCESS

Reply via email to