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 19 Aug 2011 21:31:25 -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 -g -pg -finstrument-functions +PROFILE_CFLAGS_0=-O4 -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 19 Aug 2011 21:31:25 -0000 @@ -37,7 +37,7 @@ details. */ #include "cygxdr.h" #include "fenv.h" #include "ntdll.h" - +#include "profil.h" #define MAX_AT_FILE_LEVEL 10 #define PREMAIN_LEN (sizeof (user_data->premain) / sizeof (user_data->premain[0])) @@ -648,12 +648,16 @@ init_windows_system_directory () windows_system_directory[windows_system_directory_length++] = L'\\'; windows_system_directory[windows_system_directory_length] = L'\0'; } - +extern "C" { + void _monstartup (void); + void _mcleanup (void); +} void dll_crt0_0 () { init_windows_system_directory (); init_global_security (); + _monstartup(); initial_env (); SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); @@ -695,6 +699,9 @@ dll_crt0_0 () break; } } +#ifdef PROFILE + 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 19 Aug 2011 21:31:25 -0000 @@ -31,7 +31,7 @@ details. */ #include "child_info.h" #include "ntdll.h" #include "exception.h" - +#include "profil.h" #define CALL_HANDLER_RETRY_OUTER 10 #define CALL_HANDLER_RETRY_INNER 10 @@ -937,6 +937,7 @@ 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); + profile_thread_off(); 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 19 Aug 2011 21:31:25 -0000 @@ -30,7 +30,7 @@ details. */ #include #include #include - +#include "profil.h" child_info *get_cygwin_startup_info (); static void exit_process (UINT, bool) __attribute__((noreturn)); @@ -180,6 +180,7 @@ sync_winenv () static void exit_process (UINT status, bool useTerminateProcess) { + profile_thread_off(); 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 19 Aug 2011 21:31:25 -0000 @@ -15,9 +15,9 @@ extern u_char etext asm ("etext"); extern u_char eprol asm ("__eprol"); extern void _mcleanup (void); extern void monstartup (u_long, u_long); - +#ifndef PROFILE void _monstartup (void) __attribute__((__constructor__)); - +#endif /* startup initialization for -pg support */ void @@ -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 19 Aug 2011 21:31:25 -0000 @@ -34,11 +34,12 @@ #if !defined(lint) && defined(LIBC_SCCS) static char rcsid[] = "$OpenBSD: gmon.c,v 1.8 1997/07/23 21:11:27 kstailey Exp $"; #endif - +#include "winsup.h" #include "winlean.h" #include #include #include +#include #include #include @@ -47,9 +48,9 @@ static char rcsid[] = "$OpenBSD: gmon.c, /* XXX needed? */ //extern char *minbrk __asm ("minbrk"); -struct gmonparam _gmonparam = { GMON_PROF_OFF }; +struct gmonparam NO_COPY_INIT _gmonparam = { GMON_PROF_OFF }; -static int s_scale; +int NO_COPY_INIT s_scale; /* see profil(2) where this is describe (incorrectly) */ #define SCALE_1_TO_1 0x10000L @@ -60,7 +61,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 @@ -93,7 +94,7 @@ monstartup(lowpc, highpc) p->tolimit = MAXARCS; p->tossize = p->tolimit * sizeof(struct tostruct); - cp = fake_sbrk(p->kcountsize + p->fromssize + p->tossize); + cp = fake_sbrk(5*p->kcountsize + p->fromssize + p->tossize); if (cp == (char *)-1) { ERR("monstartup: out of memory\n"); return; @@ -105,6 +106,8 @@ monstartup(lowpc, highpc) cp += p->tossize; p->kcount = (u_short *)cp; cp += p->kcountsize; + p->comm_kcount=(u_int64_t*)cp; + cp += 4*p->kcountsize; p->froms = (u_short *)cp; /* XXX minbrk needed? */ @@ -136,6 +139,7 @@ monstartup(lowpc, highpc) void _mcleanup() { + unsigned i; int fd; int hz; int fromindex; @@ -204,8 +208,11 @@ _mcleanup() } #else { - char gmon_out[] = "gmon.out"; - proffile = gmon_out; + 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; } #endif @@ -230,6 +237,15 @@ _mcleanup() hdr->ncnt = p->kcountsize + sizeof(gmonhdr); hdr->version = GMONVERSION; hdr->profrate = hz; + for ( i = 0; i < p->kcountsize / 2; i++ ) + { + if ( p->comm_kcount[i] < prof.perffreq ) + continue; + else + { + p->kcount[i] = p->comm_kcount[i] / prof.perffreq; + } + } write(fd, (char *)hdr, sizeof *hdr); write(fd, p->kcount, p->kcountsize); endfrom = p->fromssize / sizeof(*p->froms); 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 19 Aug 2011 21:31:25 -0000 @@ -134,6 +134,7 @@ struct rawarc { struct gmonparam { int state; u_short *kcount; + u_int64_t *comm_kcount; 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 19 Aug 2011 21:31:25 -0000 @@ -13,6 +13,8 @@ details. */ #include "cygtls.h" #include "ntdll.h" #include "shared_info.h" +#include "profil.h" +#include "instrument.h" static DWORD _my_oldfunc; @@ -29,7 +31,8 @@ threadfunc_fe (VOID *arg) asm volatile ("andl $-16,%%esp" ::: "%esp"); _cygtls::call ((DWORD (*) (void *, void *)) TlsGetValue (_my_oldfunc), arg); } - +extern "C" DWORD __stdcall + worker_consumer(void* arg); /* If possible, redirect the thread entry point to a cygwin routine which adds tls stuff to the stack. */ static void @@ -106,6 +109,7 @@ respawn_wow64_process () api_fatal ("Waiting for process %d failed, %E", pi.dwProcessId); GetExitCodeProcess (pi.hProcess, &ret); CloseHandle (pi.hProcess); + profile_thread_off(); ExitProcess (ret); } } @@ -120,6 +124,8 @@ dll_entry (HANDLE h, DWORD reason, void switch (reason) { case DLL_PROCESS_ATTACH: + __cyg_profile_func_ctor(); + __cyg_profile_tls_ctor(); wincap.init (); init_console_handler (false); @@ -143,8 +149,11 @@ dll_entry (HANDLE h, DWORD reason, void case DLL_PROCESS_DETACH: if (dynamically_loaded) shared_destroy (); + __cyg_profile_tls_dtor(); + __cyg_profile_func_dtor(); break; case DLL_THREAD_ATTACH: + __cyg_profile_tls_ctor(); if (dll_finished_loading) munge_threadfunc (); break; @@ -153,6 +162,7 @@ dll_entry (HANDLE h, DWORD reason, void && (PVOID) &_my_tls > (PVOID) &wow64_test_stack_marker && _my_tls.isinitialized ()) _my_tls.remove (0); + __cyg_profile_tls_dtor(); /* 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 19 Aug 2011 21:31:25 -0000 @@ -29,7 +29,7 @@ details. */ #include "cygtls.h" #include "tls_pbuf.h" #include "child_info.h" - +#include "profil.h" class pinfo_basic: public _pinfo { public: @@ -204,6 +204,7 @@ pinfo::exit (DWORD n) if (!self->cygstarted) exitcode = ((exitcode & 0xff) << 8) | ((exitcode >> 8) & 0xff); sigproc_printf ("Calling ExitProcess n %p, exitcode %p", n, exitcode); + profile_thread_off(); 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 19 Aug 2011 21:31:25 -0000 @@ -7,17 +7,18 @@ This software is a copyrighted work licensed under the terms of the Cygwin license. Please consult the file "CYGWIN_LICENSE" for details. */ - +#include "winsup.h" #include "winlean.h" #include #include - +#include "gmon.h" #include #define SLEEPTIME (1000 / PROF_HZ) +extern SECURITY_ATTRIBUTES sec_none_nih; /* global profinfo for profil() call */ -static struct profinfo prof; +struct profinfo NO_COPY prof; /* Get the pc for thread THR */ @@ -85,21 +86,44 @@ profile_off (struct profinfo *p) { if (p->profthr) { - TerminateThread (p->profthr, 0); - CloseHandle (p->profthr); + 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; + } +#if 0 if (p->targthr) CloseHandle (p->targthr); +#endif return 0; } - +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); +} /* Create a timer thread and pass it a pointer P to the profiling buffer. */ static int profile_on (struct profinfo *p) { - DWORD thrid; - +#if 0 /* get handle for this thread */ if (!DuplicateHandle (GetCurrentProcess (), GetCurrentThread (), GetCurrentProcess (), &p->targthr, 0, FALSE, @@ -108,15 +132,12 @@ profile_on (struct profinfo *p) errno = ESRCH; return -1; } - - p->profthr = CreateThread (0, 0, profthr_func, (void *) p, 0, &thrid); - if (!p->profthr) - { - CloseHandle (p->targthr); - p->targthr = 0; - errno = EAGAIN; - return -1; - } +#endif + QueryPerformanceFrequency((PLARGE_INTEGER) &prof.perffreq); + prof.perffreq /= PROF_HZ; + boundbuffer_initial(&prof.queue); + prof.operational = CreateSemaphoreA(&sec_none_nih, 0, 1, 0); + QueueUserAPC(apc_spawnthread, GetCurrentThread(), p); return 0; } @@ -170,4 +191,11 @@ profil (char *samples, size_t size, u_lo { return profile_ctl (&prof, samples, size, offset, scale); } +void +profile_thread_off() +{ + int enabled = __sync_fetch_and_and(&prof.queue.worker_enabled, 0); + if (enabled) + WaitForSingleObject(prof.profthr, INFINITE); +} 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 19 Aug 2011 21:31:25 -0000 @@ -7,10 +7,14 @@ 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 - +#define PROF_HZ 1000UL +#include "boundbuffer.h" /* convert an addr to an index */ #define PROFIDX(pc, base, scale) \ ({ \ @@ -37,8 +41,21 @@ struct profinfo { u_short *counter; /* profiling counters */ u_long lowpc, highpc; /* range to be profiled */ u_int scale; /* scale value of bins */ + u_int64_t perffreq; + struct boundbuffer queue; + _WINHANDLE operational; }; - +extern struct profinfo prof; int profile_ctl(struct profinfo *, char *, size_t, u_long, u_int); int profil(char *, size_t, u_long, u_int); - +extern void profile_thread_off(); +struct clk +{ + unsigned idx; + void* pc[0x10000]; + unsigned long long tsc[0x10000]; +}; +#ifdef __cplusplus +} +#endif +#endif