Beispiel #1
0
void
startTicker(void)
{
#if defined(USE_TIMER_CREATE)
    {
        struct itimerspec it;
        
        it.it_value.tv_sec  = TimeToSeconds(itimer_interval);
        it.it_value.tv_nsec = TimeToNS(itimer_interval) % 1000000000;
        it.it_interval = it.it_value;
        
        if (timer_settime(timer, 0, &it, NULL) != 0) {
            sysErrorBelch("timer_settime");
            stg_exit(EXIT_FAILURE);
        }
    }
#else
    {
        struct itimerval it;

        it.it_value.tv_sec = TimeToSeconds(itimer_interval);
        it.it_value.tv_usec = TimeToUS(itimer_interval) % 1000000;
        it.it_interval = it.it_value;
        
        if (setitimer(ITIMER_REAL, &it, NULL) != 0) {
            sysErrorBelch("setitimer");
            stg_exit(EXIT_FAILURE);
        }
    }
#endif
}
Beispiel #2
0
static void *itimer_thread_func(void *_handle_tick)
{
    TickProc handle_tick = _handle_tick;
    uint64_t nticks;
    int timerfd = -1;

#if defined(USE_TIMERFD_FOR_ITIMER) && USE_TIMERFD_FOR_ITIMER
    struct itimerspec it;
    it.it_value.tv_sec  = TimeToSeconds(itimer_interval);
    it.it_value.tv_nsec = TimeToNS(itimer_interval) % 1000000000;
    it.it_interval = it.it_value;

    timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
    if (timerfd == -1) {
        sysErrorBelch("timerfd_create");
        stg_exit(EXIT_FAILURE);
    }
    if (!TFD_CLOEXEC) {
      fcntl(timerfd, F_SETFD, FD_CLOEXEC);
    }
    if (timerfd_settime(timerfd, 0, &it, NULL)) {
        sysErrorBelch("timerfd_settime");
        stg_exit(EXIT_FAILURE);
    }
#endif

    while (!exited) {
        if (USE_TIMERFD_FOR_ITIMER) {
            if (read(timerfd, &nticks, sizeof(nticks)) != sizeof(nticks)) {
                if (errno != EINTR) {
                    sysErrorBelch("Itimer: read(timerfd) failed");
                }
            }
        } else {
            if (usleep(TimeToUS(itimer_interval)) != 0 && errno != EINTR) {
                sysErrorBelch("usleep(TimeToUS(itimer_interval) failed");
            }
        }

        // first try a cheap test
        if (stopped) {
            ACQUIRE_LOCK(&mutex);
            // should we really stop?
            if (stopped) {
                waitCondition(&start_cond, &mutex);
            }
            RELEASE_LOCK(&mutex);
        } else {
            handle_tick(0);
        }
    }

    if (USE_TIMERFD_FOR_ITIMER)
        close(timerfd);
    closeMutex(&mutex);
    closeCondition(&start_cond);
    return NULL;
}
Beispiel #3
0
Datei: Stats.c Projekt: kod3r/ghc
void
stat_startGC (Capability *cap, gc_thread *gct)
{
    nat bell = RtsFlags.GcFlags.ringBell;

    if (bell) {
	if (bell > 1) {
	    debugBelch(" GC ");
	    rub_bell = 1;
	} else {
	    debugBelch("\007");
	}
    }

#if USE_PAPI
    if(papi_is_reporting) {
      /* Switch to counting GC events */
      papi_stop_mutator_count();
      papi_start_gc_count();
    }
#endif

    getProcessTimes(&gct->gc_start_cpu, &gct->gc_start_elapsed);

    // Post EVENT_GC_START with the same timestamp as used for stats
    // (though converted from Time=StgInt64 to EventTimestamp=StgWord64).
    // Here, as opposed to other places, the event is emitted on the cap
    // that initiates the GC and external tools expect it to have the same
    // timestamp as used in +RTS -s calculcations.
    traceEventGcStartAtT(cap,
                         TimeToNS(gct->gc_start_elapsed - start_init_elapsed));

    gct->gc_start_thread_cpu = getThreadCPUTime();

    if (RtsFlags.GcFlags.giveStats != NO_GC_STATS)
    {
        gct->gc_start_faults = getPageFaults();
    }
}
Beispiel #4
0
void
stat_endGC (Capability *cap, gc_thread *gct,
            W_ live, W_ copied, W_ slop, nat gen,
            nat par_n_threads, W_ par_max_copied, W_ par_tot_copied)
{
    W_ tot_alloc;
    W_ alloc;

    if (RtsFlags.GcFlags.giveStats != NO_GC_STATS ||
        RtsFlags.ProfFlags.doHeapProfile)
        // heap profiling needs GC_tot_time
    {
        Time cpu, elapsed, gc_cpu, gc_elapsed;

        // Has to be emitted while all caps stopped for GC, but before GC_END.
        // See trac.haskell.org/ThreadScope/wiki/RTSsummaryEvents
        // for a detailed design rationale of the current setup
        // of GC eventlog events.
        traceEventGcGlobalSync(cap);
	
        // Emitted before GC_END on all caps, which simplifies tools code.
        traceEventGcStats(cap,
                          CAPSET_HEAP_DEFAULT,
                          gen,
                          copied * sizeof(W_),
                          slop   * sizeof(W_),
                          /* current loss due to fragmentation */
                          (mblocks_allocated * BLOCKS_PER_MBLOCK - n_alloc_blocks)
                                 * BLOCK_SIZE_W * sizeof(W_),
                          par_n_threads,
                          par_max_copied * sizeof(W_),
                          par_tot_copied * sizeof(W_));

        getProcessTimes(&cpu, &elapsed);

        // Post EVENT_GC_END with the same timestamp as used for stats
        // (though converted from Time=StgInt64 to EventTimestamp=StgWord64).
        // Here, as opposed to other places, the event is emitted on the cap
        // that initiates the GC and external tools expect it to have the same
        // timestamp as used in +RTS -s calculcations.
        traceEventGcEndAtT(cap, TimeToNS(elapsed - start_init_elapsed));

        gc_elapsed = elapsed - gct->gc_start_elapsed;
        gc_cpu = cpu - gct->gc_start_cpu;

        /* For the moment we calculate both per-HEC and total allocation.
	 * There is thus redundancy here, but for the moment we will calculate
	 * it both the old and new way and assert they're the same.
	 * When we're sure it's working OK then we can simplify things.
         */
        tot_alloc = calcTotalAllocated();

        // allocated since the last GC
        alloc = tot_alloc - GC_tot_alloc;
        GC_tot_alloc = tot_alloc;

        if (RtsFlags.GcFlags.giveStats == VERBOSE_GC_STATS) {
	    W_ faults = getPageFaults();
	    
	    statsPrintf("%9" FMT_SizeT " %9" FMT_SizeT " %9" FMT_SizeT,
		    alloc*sizeof(W_), copied*sizeof(W_), 
			live*sizeof(W_));
            statsPrintf(" %6.3f %6.3f %8.3f %8.3f %4" FMT_Word " %4" FMT_Word "  (Gen: %2d)\n",
                    TimeToSecondsDbl(gc_cpu),
		    TimeToSecondsDbl(gc_elapsed),
		    TimeToSecondsDbl(cpu),
		    TimeToSecondsDbl(elapsed - start_init_elapsed),
		    faults - gct->gc_start_faults,
                        gct->gc_start_faults - GC_end_faults,
                    gen);

            GC_end_faults = faults;
	    statsFlush();
	}

        GC_coll_cpu[gen] += gc_cpu;
        GC_coll_elapsed[gen] += gc_elapsed;
        if (GC_coll_max_pause[gen] < gc_elapsed) {
            GC_coll_max_pause[gen] = gc_elapsed;
        }

	GC_tot_copied += (StgWord64) copied;
        GC_par_max_copied += (StgWord64) par_max_copied;
        GC_par_tot_copied += (StgWord64) par_tot_copied;
	GC_tot_cpu   += gc_cpu;
        
        traceEventHeapSize(cap,
	                   CAPSET_HEAP_DEFAULT,
			   mblocks_allocated * MBLOCK_SIZE_W * sizeof(W_));

	if (gen == RtsFlags.GcFlags.generations-1) { /* major GC? */
	    if (live > max_residency) {
		max_residency = live;
	    }
            current_residency = live;
	    residency_samples++;
	    cumulative_residency += live;
	    traceEventHeapLive(cap, 
    	    	    	       CAPSET_HEAP_DEFAULT,
	                       live * sizeof(W_));
	}

        if (slop > max_slop) max_slop = slop;
    }

    if (rub_bell) {
	debugBelch("\b\b\b  \b\b\b");
	rub_bell = 0;
    }

#if USE_PAPI
    if(papi_is_reporting) {
      /* Switch to counting mutator events */
      if (gen == 0) {
          papi_stop_gc0_count();
      } else {
          papi_stop_gc1_count();
      }
      papi_start_mutator_count();
    }
#endif
}