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 #include #include - +#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 #include #include +#ifdef PROFILE +#include +#include +#endif #include #include @@ -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 #include - +#ifdef PROFILE +#include "gmon.h" +#endif #include #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 +#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 +#include +#include +#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 +#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_ */