#define TI_NO_SRCPOS #include "backend.h" #include /* Statistical collection and reporting for AMUDP/AMMPI backends */ #if defined(COMM_AMUDP) || defined(COMM_AMMPI) #ifdef COMM_AMUDP #define P(fnname) TIC_CONCAT(AMUDP_,fnname) #define p(fnname) TIC_CONCAT(amudp_,fnname) #else #define P(fnname) TIC_CONCAT(AMMPI_,fnname) #define p(fnname) TIC_CONCAT(ammpi_,fnname) #endif static int statscalls = 0; static p(stats_t) globalStats; TI_INLINE(amstats_request) void amstats_request(tic_amtoken_t token, void *buf, size_t nbytes, int procnum) { assert(nbytes == sizeof(p(stats_t))); TIC_AM_Safe(P(AggregateStatistics)(&globalStats, (p(stats_t) *)buf)); statscalls++; } TIC_AMMEDIUM(amstats_request, 1, 1, (token,addr,nbytes, a0), (token,addr,nbytes, a0)); static void printGlobalStats() { p(stats_t) stats; statscalls = 0; globalStats = P(initial_stats); /* make sure we're done sending msgs for now */ barrier(); if (MYBOXPROC == 0) { if (usingAMSPMD) { P(SPMDBarrier)(); /* try to minimize impact of monitoring */ #ifdef COMM_AMMPI { /* problem - AMMPI uses messages to implement above barrier - * make sure P0 gets all the barrier replies, or above counts won't match up */ ti_time_t tm; ti_set_wait_timer(&tm, 100); /* spin-poll for 100 milliseconds */ tic_poll_while(ti_millisuntil(&tm) >= 0); } #endif } TIC_AM_Safe(P(GetEndpointStatistics)(TIC_AM_ENDPOINT, &stats)); /* get statistics */ /* don't let stats msgs interfere with display */ if (usingAMSPMD) P(SPMDBarrier)(); assert(sizeof(p(stats_t)) < AM_MaxMedium()); /* send to zero */ tic_AMRequestI(1,1,(0, TIC_AMIDX(amstats_request), &stats, sizeof(p(stats_t)), MYBOX)); if (MYPROC == 0) { tic_poll_while(statscalls < BOXES); fprintf(stderr, "--------------------------------------------------\n" "Global AM2 usage statistics:\n"); P(DumpStatistics)(stderr, &globalStats, 1); fprintf(stderr, "--------------------------------------------------\n"); fflush(stderr); sleep(1); /* HACK: give a little time for this output to reach user's console before shutdown */ } } barrier(); /* just to keep things clean */ } #else static void printGlobalStats() { } #endif static int TI_GCSTATS = 0; static int TI_PAGESTATS = 0; static int TI_AMSTATS = 0; int dynamicCallCount_staticNative = 0; int dynamicCallCount_staticSpecial = 0; int dynamicCallCount_staticTitanium = 0; int dynamicCallCount_dynamic = 0; void stats_init(void) { /* read environment info at startup, because it may not be available later (AMUDP backends) */ TI_GCSTATS = !!getenvMaster("TI_GCSTATS"); TI_PAGESTATS = !!getenvMaster("TI_PAGESTATS"); TI_AMSTATS = !!getenvMaster("TI_AMSTATS"); } static void nodeid(char *buf) { if (MYBOXPROCS > 1) { int firstproc = COMM_GetProxyProcNumberForBoxNumber(MYBOX); sprintf(buf,"Box %i (P%i..P%i)", MYBOX, firstproc, firstproc + MYBOXPROCS-1); } else sprintf(buf,"P%i", MYPROC); } void print_page_stats(char *header); extern char *beautify_numbers(char *buf); void print_mem_stats(int gcstats, int regionstats) { char node_identifier[40]; char buf[1024]; nodeid(node_identifier); #ifndef USE_GC_NONE if (gcstats) { sprintf(buf, "%s: GC Heap size: %lu bytes used, %lu bytes free.\n", node_identifier, (unsigned long)(jlong)ti_gc_usedheapsize(), (unsigned long)(jlong)ti_gc_freeheapsize()); #if defined(USE_DISTRIBUTED_GC) sprintf(buf+strlen(buf), "%s: Escaped global pointers (upper bound): %i\n", node_identifier, dgc_numhashed()); #endif printf("%s", beautify_numbers(buf)); } #endif if (regionstats) print_page_stats(node_identifier); fflush(NULL); } void print_outofmem(int sz) { char *msg = "Out of memory.\n"; write(2, msg, strlen(msg)); fflush(stderr); { char node_identifier[40]; char buf[1024]; nodeid(node_identifier); sprintf(buf,"Titanium process %s has run out of memory,\n" " while trying to allocate %i bytes.\n", node_identifier, sz); beautify_numbers(buf); fprintf(stderr,"%s",buf); fflush(stderr); } print_mem_stats(1,1); sleep(1); /* pause to ensure output reaches console */ fflush(NULL); exit(-1); /* don't dump a huge core - may just exacerbate the problem */ abort(); } /* printExitStats(int sglobal): * should be called whenever exiting a Titanium program via any means * handles the output of any requested runtime statistics * sglobal indicates whether all processors are running this and sglobal operations are permitted */ extern void printExitStats(int sglobal) { if (MYBOXPROC == 0 || !sglobal) { /* exit stats which should run once per box */ char node_identifier[40]; nodeid(node_identifier); print_mem_stats(TI_GCSTATS, TI_PAGESTATS); if (dynamicCallCount_staticNative || dynamicCallCount_staticSpecial || dynamicCallCount_staticTitanium || dynamicCallCount_dynamic) { printf("%s: Method call stats: %i native, %i native-special, %i non-virtual, %i virtual\n", node_identifier, dynamicCallCount_staticNative, dynamicCallCount_staticSpecial, dynamicCallCount_staticTitanium, dynamicCallCount_dynamic); } } #if defined(COMM_AMUDP) || defined(COMM_AMMPI) if (usingAMSPMD && TI_AMSTATS && BOXES > 1) { if (!sglobal) { /* we can't print stats here because it's an sglobal operation */ fprintf(stderr, "System.exit() called - unable to print AM stats"); fflush(stderr); } else { /* all boxes present - print AMUDP stats */ printGlobalStats(); } } #endif }